Initial import
This commit is contained in:
		
							
								
								
									
										339
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								COPYING
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,339 @@ | ||||
|                     GNU GENERAL PUBLIC LICENSE | ||||
|                        Version 2, June 1991 | ||||
|  | ||||
|  Copyright (C) 1989, 1991 Free Software Foundation, Inc., | ||||
|  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  Everyone is permitted to copy and distribute verbatim copies | ||||
|  of this license document, but changing it is not allowed. | ||||
|  | ||||
|                             Preamble | ||||
|  | ||||
|   The licenses for most software are designed to take away your | ||||
| freedom to share and change it.  By contrast, the GNU General Public | ||||
| License is intended to guarantee your freedom to share and change free | ||||
| software--to make sure the software is free for all its users.  This | ||||
| General Public License applies to most of the Free Software | ||||
| Foundation's software and to any other program whose authors commit to | ||||
| using it.  (Some other Free Software Foundation software is covered by | ||||
| the GNU Lesser General Public License instead.)  You can apply it to | ||||
| your programs, too. | ||||
|  | ||||
|   When we speak of free software, we are referring to freedom, not | ||||
| price.  Our General Public Licenses are designed to make sure that you | ||||
| have the freedom to distribute copies of free software (and charge for | ||||
| this service if you wish), that you receive source code or can get it | ||||
| if you want it, that you can change the software or use pieces of it | ||||
| in new free programs; and that you know you can do these things. | ||||
|  | ||||
|   To protect your rights, we need to make restrictions that forbid | ||||
| anyone to deny you these rights or to ask you to surrender the rights. | ||||
| These restrictions translate to certain responsibilities for you if you | ||||
| distribute copies of the software, or if you modify it. | ||||
|  | ||||
|   For example, if you distribute copies of such a program, whether | ||||
| gratis or for a fee, you must give the recipients all the rights that | ||||
| you have.  You must make sure that they, too, receive or can get the | ||||
| source code.  And you must show them these terms so they know their | ||||
| rights. | ||||
|  | ||||
|   We protect your rights with two steps: (1) copyright the software, and | ||||
| (2) offer you this license which gives you legal permission to copy, | ||||
| distribute and/or modify the software. | ||||
|  | ||||
|   Also, for each author's protection and ours, we want to make certain | ||||
| that everyone understands that there is no warranty for this free | ||||
| software.  If the software is modified by someone else and passed on, we | ||||
| want its recipients to know that what they have is not the original, so | ||||
| that any problems introduced by others will not reflect on the original | ||||
| authors' reputations. | ||||
|  | ||||
|   Finally, any free program is threatened constantly by software | ||||
| patents.  We wish to avoid the danger that redistributors of a free | ||||
| program will individually obtain patent licenses, in effect making the | ||||
| program proprietary.  To prevent this, we have made it clear that any | ||||
| patent must be licensed for everyone's free use or not licensed at all. | ||||
|  | ||||
|   The precise terms and conditions for copying, distribution and | ||||
| modification follow. | ||||
|  | ||||
|                     GNU GENERAL PUBLIC LICENSE | ||||
|    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | ||||
|  | ||||
|   0. This License applies to any program or other work which contains | ||||
| a notice placed by the copyright holder saying it may be distributed | ||||
| under the terms of this General Public License.  The "Program", below, | ||||
| refers to any such program or work, and a "work based on the Program" | ||||
| means either the Program or any derivative work under copyright law: | ||||
| that is to say, a work containing the Program or a portion of it, | ||||
| either verbatim or with modifications and/or translated into another | ||||
| language.  (Hereinafter, translation is included without limitation in | ||||
| the term "modification".)  Each licensee is addressed as "you". | ||||
|  | ||||
| Activities other than copying, distribution and modification are not | ||||
| covered by this License; they are outside its scope.  The act of | ||||
| running the Program is not restricted, and the output from the Program | ||||
| is covered only if its contents constitute a work based on the | ||||
| Program (independent of having been made by running the Program). | ||||
| Whether that is true depends on what the Program does. | ||||
|  | ||||
|   1. You may copy and distribute verbatim copies of the Program's | ||||
| source code as you receive it, in any medium, provided that you | ||||
| conspicuously and appropriately publish on each copy an appropriate | ||||
| copyright notice and disclaimer of warranty; keep intact all the | ||||
| notices that refer to this License and to the absence of any warranty; | ||||
| and give any other recipients of the Program a copy of this License | ||||
| along with the Program. | ||||
|  | ||||
| You may charge a fee for the physical act of transferring a copy, and | ||||
| you may at your option offer warranty protection in exchange for a fee. | ||||
|  | ||||
|   2. You may modify your copy or copies of the Program or any portion | ||||
| of it, thus forming a work based on the Program, and copy and | ||||
| distribute such modifications or work under the terms of Section 1 | ||||
| above, provided that you also meet all of these conditions: | ||||
|  | ||||
|     a) You must cause the modified files to carry prominent notices | ||||
|     stating that you changed the files and the date of any change. | ||||
|  | ||||
|     b) You must cause any work that you distribute or publish, that in | ||||
|     whole or in part contains or is derived from the Program or any | ||||
|     part thereof, to be licensed as a whole at no charge to all third | ||||
|     parties under the terms of this License. | ||||
|  | ||||
|     c) If the modified program normally reads commands interactively | ||||
|     when run, you must cause it, when started running for such | ||||
|     interactive use in the most ordinary way, to print or display an | ||||
|     announcement including an appropriate copyright notice and a | ||||
|     notice that there is no warranty (or else, saying that you provide | ||||
|     a warranty) and that users may redistribute the program under | ||||
|     these conditions, and telling the user how to view a copy of this | ||||
|     License.  (Exception: if the Program itself is interactive but | ||||
|     does not normally print such an announcement, your work based on | ||||
|     the Program is not required to print an announcement.) | ||||
|  | ||||
| These requirements apply to the modified work as a whole.  If | ||||
| identifiable sections of that work are not derived from the Program, | ||||
| and can be reasonably considered independent and separate works in | ||||
| themselves, then this License, and its terms, do not apply to those | ||||
| sections when you distribute them as separate works.  But when you | ||||
| distribute the same sections as part of a whole which is a work based | ||||
| on the Program, the distribution of the whole must be on the terms of | ||||
| this License, whose permissions for other licensees extend to the | ||||
| entire whole, and thus to each and every part regardless of who wrote it. | ||||
|  | ||||
| Thus, it is not the intent of this section to claim rights or contest | ||||
| your rights to work written entirely by you; rather, the intent is to | ||||
| exercise the right to control the distribution of derivative or | ||||
| collective works based on the Program. | ||||
|  | ||||
| In addition, mere aggregation of another work not based on the Program | ||||
| with the Program (or with a work based on the Program) on a volume of | ||||
| a storage or distribution medium does not bring the other work under | ||||
| the scope of this License. | ||||
|  | ||||
|   3. You may copy and distribute the Program (or a work based on it, | ||||
| under Section 2) in object code or executable form under the terms of | ||||
| Sections 1 and 2 above provided that you also do one of the following: | ||||
|  | ||||
|     a) Accompany it with the complete corresponding machine-readable | ||||
|     source code, which must be distributed under the terms of Sections | ||||
|     1 and 2 above on a medium customarily used for software interchange; or, | ||||
|  | ||||
|     b) Accompany it with a written offer, valid for at least three | ||||
|     years, to give any third party, for a charge no more than your | ||||
|     cost of physically performing source distribution, a complete | ||||
|     machine-readable copy of the corresponding source code, to be | ||||
|     distributed under the terms of Sections 1 and 2 above on a medium | ||||
|     customarily used for software interchange; or, | ||||
|  | ||||
|     c) Accompany it with the information you received as to the offer | ||||
|     to distribute corresponding source code.  (This alternative is | ||||
|     allowed only for noncommercial distribution and only if you | ||||
|     received the program in object code or executable form with such | ||||
|     an offer, in accord with Subsection b above.) | ||||
|  | ||||
| The source code for a work means the preferred form of the work for | ||||
| making modifications to it.  For an executable work, complete source | ||||
| code means all the source code for all modules it contains, plus any | ||||
| associated interface definition files, plus the scripts used to | ||||
| control compilation and installation of the executable.  However, as a | ||||
| special exception, the source code distributed need not include | ||||
| anything that is normally distributed (in either source or binary | ||||
| form) with the major components (compiler, kernel, and so on) of the | ||||
| operating system on which the executable runs, unless that component | ||||
| itself accompanies the executable. | ||||
|  | ||||
| If distribution of executable or object code is made by offering | ||||
| access to copy from a designated place, then offering equivalent | ||||
| access to copy the source code from the same place counts as | ||||
| distribution of the source code, even though third parties are not | ||||
| compelled to copy the source along with the object code. | ||||
|  | ||||
|   4. You may not copy, modify, sublicense, or distribute the Program | ||||
| except as expressly provided under this License.  Any attempt | ||||
| otherwise to copy, modify, sublicense or distribute the Program is | ||||
| void, and will automatically terminate your rights under this License. | ||||
| However, parties who have received copies, or rights, from you under | ||||
| this License will not have their licenses terminated so long as such | ||||
| parties remain in full compliance. | ||||
|  | ||||
|   5. You are not required to accept this License, since you have not | ||||
| signed it.  However, nothing else grants you permission to modify or | ||||
| distribute the Program or its derivative works.  These actions are | ||||
| prohibited by law if you do not accept this License.  Therefore, by | ||||
| modifying or distributing the Program (or any work based on the | ||||
| Program), you indicate your acceptance of this License to do so, and | ||||
| all its terms and conditions for copying, distributing or modifying | ||||
| the Program or works based on it. | ||||
|  | ||||
|   6. Each time you redistribute the Program (or any work based on the | ||||
| Program), the recipient automatically receives a license from the | ||||
| original licensor to copy, distribute or modify the Program subject to | ||||
| these terms and conditions.  You may not impose any further | ||||
| restrictions on the recipients' exercise of the rights granted herein. | ||||
| You are not responsible for enforcing compliance by third parties to | ||||
| this License. | ||||
|  | ||||
|   7. If, as a consequence of a court judgment or allegation of patent | ||||
| infringement or for any other reason (not limited to patent issues), | ||||
| conditions are imposed on you (whether by court order, agreement or | ||||
| otherwise) that contradict the conditions of this License, they do not | ||||
| excuse you from the conditions of this License.  If you cannot | ||||
| distribute so as to satisfy simultaneously your obligations under this | ||||
| License and any other pertinent obligations, then as a consequence you | ||||
| may not distribute the Program at all.  For example, if a patent | ||||
| license would not permit royalty-free redistribution of the Program by | ||||
| all those who receive copies directly or indirectly through you, then | ||||
| the only way you could satisfy both it and this License would be to | ||||
| refrain entirely from distribution of the Program. | ||||
|  | ||||
| If any portion of this section is held invalid or unenforceable under | ||||
| any particular circumstance, the balance of the section is intended to | ||||
| apply and the section as a whole is intended to apply in other | ||||
| circumstances. | ||||
|  | ||||
| It is not the purpose of this section to induce you to infringe any | ||||
| patents or other property right claims or to contest validity of any | ||||
| such claims; this section has the sole purpose of protecting the | ||||
| integrity of the free software distribution system, which is | ||||
| implemented by public license practices.  Many people have made | ||||
| generous contributions to the wide range of software distributed | ||||
| through that system in reliance on consistent application of that | ||||
| system; it is up to the author/donor to decide if he or she is willing | ||||
| to distribute software through any other system and a licensee cannot | ||||
| impose that choice. | ||||
|  | ||||
| This section is intended to make thoroughly clear what is believed to | ||||
| be a consequence of the rest of this License. | ||||
|  | ||||
|   8. If the distribution and/or use of the Program is restricted in | ||||
| certain countries either by patents or by copyrighted interfaces, the | ||||
| original copyright holder who places the Program under this License | ||||
| may add an explicit geographical distribution limitation excluding | ||||
| those countries, so that distribution is permitted only in or among | ||||
| countries not thus excluded.  In such case, this License incorporates | ||||
| the limitation as if written in the body of this License. | ||||
|  | ||||
|   9. The Free Software Foundation may publish revised and/or new versions | ||||
| of the General Public License from time to time.  Such new versions will | ||||
| be similar in spirit to the present version, but may differ in detail to | ||||
| address new problems or concerns. | ||||
|  | ||||
| Each version is given a distinguishing version number.  If the Program | ||||
| specifies a version number of this License which applies to it and "any | ||||
| later version", you have the option of following the terms and conditions | ||||
| either of that version or of any later version published by the Free | ||||
| Software Foundation.  If the Program does not specify a version number of | ||||
| this License, you may choose any version ever published by the Free Software | ||||
| Foundation. | ||||
|  | ||||
|   10. If you wish to incorporate parts of the Program into other free | ||||
| programs whose distribution conditions are different, write to the author | ||||
| to ask for permission.  For software which is copyrighted by the Free | ||||
| Software Foundation, write to the Free Software Foundation; we sometimes | ||||
| make exceptions for this.  Our decision will be guided by the two goals | ||||
| of preserving the free status of all derivatives of our free software and | ||||
| of promoting the sharing and reuse of software generally. | ||||
|  | ||||
|                             NO WARRANTY | ||||
|  | ||||
|   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | ||||
| FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN | ||||
| OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | ||||
| PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | ||||
| OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||||
| MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS | ||||
| TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE | ||||
| PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | ||||
| REPAIR OR CORRECTION. | ||||
|  | ||||
|   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||||
| WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | ||||
| REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | ||||
| INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | ||||
| OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | ||||
| TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | ||||
| YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | ||||
| PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | ||||
| POSSIBILITY OF SUCH DAMAGES. | ||||
|  | ||||
|                      END OF TERMS AND CONDITIONS | ||||
|  | ||||
|             How to Apply These Terms to Your New Programs | ||||
|  | ||||
|   If you develop a new program, and you want it to be of the greatest | ||||
| possible use to the public, the best way to achieve this is to make it | ||||
| free software which everyone can redistribute and change under these terms. | ||||
|  | ||||
|   To do so, attach the following notices to the program.  It is safest | ||||
| to attach them to the start of each source file to most effectively | ||||
| convey the exclusion of warranty; and each file should have at least | ||||
| the "copyright" line and a pointer to where the full notice is found. | ||||
|  | ||||
|     <one line to give the program's name and a brief idea of what it does.> | ||||
|     Copyright (C) <year>  <name of author> | ||||
|  | ||||
|     This program is free software; you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation; either version 2 of the License, or | ||||
|     (at your option) any later version. | ||||
|  | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
|  | ||||
|     You should have received a copy of the GNU General Public License along | ||||
|     with this program; if not, write to the Free Software Foundation, Inc., | ||||
|     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||||
|  | ||||
| Also add information on how to contact you by electronic and paper mail. | ||||
|  | ||||
| If the program is interactive, make it output a short notice like this | ||||
| when it starts in an interactive mode: | ||||
|  | ||||
|     Gnomovision version 69, Copyright (C) year name of author | ||||
|     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. | ||||
|     This is free software, and you are welcome to redistribute it | ||||
|     under certain conditions; type `show c' for details. | ||||
|  | ||||
| The hypothetical commands `show w' and `show c' should show the appropriate | ||||
| parts of the General Public License.  Of course, the commands you use may | ||||
| be called something other than `show w' and `show c'; they could even be | ||||
| mouse-clicks or menu items--whatever suits your program. | ||||
|  | ||||
| You should also get your employer (if you work as a programmer) or your | ||||
| school, if any, to sign a "copyright disclaimer" for the program, if | ||||
| necessary.  Here is a sample; alter the names: | ||||
|  | ||||
|   Yoyodyne, Inc., hereby disclaims all copyright interest in the program | ||||
|   `Gnomovision' (which makes passes at compilers) written by James Hacker. | ||||
|  | ||||
|   <signature of Ty Coon>, 1 April 1989 | ||||
|   Ty Coon, President of Vice | ||||
|  | ||||
| This General Public License does not permit incorporating your program into | ||||
| proprietary programs.  If your program is a subroutine library, you may | ||||
| consider it more useful to permit linking proprietary applications with the | ||||
| library.  If this is what you want to do, use the GNU Lesser General | ||||
| Public License instead of this License. | ||||
							
								
								
									
										39
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| CC =		gcc | ||||
| CFLAGS =	-O2 -s -D_GNU_SOURCE | ||||
| LDLIBS = | ||||
| PREFIX = | ||||
| BINDIR =	$(PREFIX)/usr/bin | ||||
|  | ||||
| all: cbsi | ||||
| 	@echo "All done!" | ||||
|  | ||||
| cbsi: buffer.o cbsi.o error.o mimetype.o subshell.o | ||||
| 	$(CC) $(CFLAGS) $(LDLIBS) buffer.o cbsi.o error.o mimetype.o subshell.o -o cbsi | ||||
|  | ||||
| buffer.o: buffer.c | ||||
| 	$(CC) $(CFLAGS) -c buffer.c | ||||
|  | ||||
| cbsi.o: cbsi.c | ||||
| 	$(CC) $(CFLAGS) -c cbsi.c | ||||
|  | ||||
| error.o: error.c | ||||
| 	$(CC) $(CFLAGS) -c error.c | ||||
|  | ||||
| mimetype.o: mimetype.c | ||||
| 	$(CC) $(CFLAGS) -c mimetype.c | ||||
|  | ||||
| subshell.o: subshell.c | ||||
| 	$(CC) $(CFLAGS) -c subshell.c | ||||
|  | ||||
| install: | ||||
| 	mkdir -p $(BINDIR) | ||||
| 	cp cbsi $(BINDIR) | ||||
| 	@echo "All done!" | ||||
|  | ||||
| uninstall: | ||||
| 	@rm -f $(BINDIR)/cbsi | ||||
| 	@echo "All done!" | ||||
|  | ||||
| clean: | ||||
| 	rm -f cbsi *.o | ||||
| 	@echo "All done!" | ||||
							
								
								
									
										34
									
								
								README
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								README
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| CGI Bash Shell Interface | ||||
| ======================== | ||||
|  | ||||
| CBSI is a small program that makes CGI programming in the Bash Shell a lot | ||||
| easier, or at least more tolerable. It is intended for Kagera Firmware, where | ||||
| other languages are too big. | ||||
|  | ||||
| It parses POST and GET requests in addiction to COOKIES, placing elements as | ||||
| `name=value` pairs into the environment for the CGI script to use. | ||||
|  | ||||
| It combines three features into an engine:  | ||||
|  * It opens a shell, and translates all text into printable statements. All | ||||
|    text within <% ... %> constructs are passed verbatim to the shell. | ||||
|  * It opens a shell, and prints the shell expression. Everything within | ||||
|    <%: ... %> tags are supposed to be parsed into 'echo' statement. | ||||
|  * It supports multilanguage and allows to easily put all texts within | ||||
|    <%@ ... %> tags to be quick and easily translated into chosen language. | ||||
|  | ||||
| Additional parameters that can be passed to CBSI: | ||||
|  * --language-dir=pathspec  - specifies a directory where CBSI should look for | ||||
|                               scripts translations. Default value is | ||||
|                               '/usr/lib/kagera/langs' | ||||
|  * --shell=pathspec         - specifies an alternate bash-like shell to use. | ||||
|                               This defaults to '/bin/sh' | ||||
|  * --translation=filename   - specifies a dictionary filename to be loaded in | ||||
|                               addiction to common.dic from language directory. | ||||
|                               The extension is added automatically. | ||||
|  * --upload-dir=pathspec    - this specifies a temporary directory where all | ||||
|                               uploaded files are created. Defaults to '/tmp' | ||||
|  * --upload-limit=limit     - allows a mime-encoded file up to limit KB to be | ||||
|                               uploaded. The default value is 0KB (no limit). | ||||
|  | ||||
|  | ||||
| This software is based on Haserl <http://haserl.sourceforge.net/>. | ||||
							
								
								
									
										126
									
								
								buffer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								buffer.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			buffer.c | ||||
|  * @PURPOSE			CBSI Buffers | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
|  | ||||
| #include "buffer.h" | ||||
|  | ||||
| void buffer_add(buffer_t* buf, const void* data, unsigned long size) { | ||||
| 	unsigned long newsize; | ||||
| 	unsigned long index; | ||||
|  | ||||
| 	if((buf->ptr + size) >= buf->limit) { | ||||
| 		index = (buf->limit - buf->data); | ||||
| 		newsize = index; | ||||
| 		while(newsize <= index + size) { | ||||
| 			newsize += 1024; | ||||
| 		} | ||||
| 		index = buf->ptr - buf->data; | ||||
| 		buf->data = realloc(buf->data, newsize); | ||||
| 		buf->limit = buf->data + newsize; | ||||
| 		buf->ptr = buf->data + index; | ||||
| 	} | ||||
| 	memcpy(buf->ptr, data, size); | ||||
| 	buf->ptr += size; | ||||
| } | ||||
|  | ||||
| void buffer_destroy(buffer_t* buf) { | ||||
| 	if(buf->data) { | ||||
| 		free(buf->data); | ||||
| 	} | ||||
| 	buffer_init(buf); | ||||
| } | ||||
|  | ||||
| void buffer_init(buffer_t* buf) { | ||||
| 	buf->data = NULL; | ||||
| 	buf->ptr = NULL; | ||||
| 	buf->limit = NULL; | ||||
| } | ||||
|  | ||||
| void buffer_reset(buffer_t* buf) { | ||||
| 	if(buf->data) { | ||||
| 		buf->ptr = buf->data; | ||||
| 	} else { | ||||
| 		buf->ptr = NULL; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void sbuffer_destroy(sbuffer_t* sbuf) { | ||||
| 	free(sbuf->buf); | ||||
| } | ||||
|  | ||||
| int sbuffer_init(sbuffer_t* sbuf, int size) { | ||||
| 	sbuf->maxsize = size; | ||||
| 	sbuf->buf = malloc (sbuf->maxsize); | ||||
| 	sbuf->maxsize -= 1; | ||||
| 	sbuf->fh = 0; | ||||
| 	sbuf->eof = 0; | ||||
| 	sbuf->len = 0; | ||||
| 	sbuf->ptr = sbuf->buf; | ||||
| 	sbuf->bufsize = 0; | ||||
| 	sbuf->maxread = 0; | ||||
| 	sbuf->nrread = 0; | ||||
| 	return (sbuf->buf != NULL); | ||||
| } | ||||
|  | ||||
| int sbuffer_read(sbuffer_t* sbuf, char* matchstr) { | ||||
| 	int len, pos; | ||||
| 	int r; | ||||
|  | ||||
| 	if((sbuf->eof) && (sbuf->ptr > sbuf->buf)) { | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if((sbuf->bufsize == 0) || (sbuf->ptr >= (sbuf->buf + sbuf->bufsize - strlen (matchstr)))) { | ||||
| 		len = sbuf->bufsize - (sbuf->ptr - sbuf->buf); | ||||
| 		if(len) { | ||||
| 			memmove(sbuf->buf, sbuf->ptr, len); | ||||
| 		} | ||||
| 		sbuf->ptr = sbuf->buf; | ||||
| 		sbuf->bufsize = len; | ||||
| 		if(fcntl(sbuf->fh, F_GETFL) == -1) { | ||||
| 			r = 0; | ||||
| 		} else { | ||||
| 			size_t n = sbuf->maxsize - len; | ||||
| 			if(sbuf->maxread && sbuf->maxread < sbuf->nrread + n) { | ||||
| 				n = sbuf->maxread - sbuf->nrread; | ||||
| 			} | ||||
| 			r = read(sbuf->fh, sbuf->buf + len, n); | ||||
| 		} | ||||
| 		if(r == 0 || (r < 0 && errno != EINTR)) { | ||||
| 			sbuf->eof = -1; | ||||
| 		} else { | ||||
| 			sbuf->bufsize += (r > 0) ? r : 0; | ||||
| 			sbuf->nrread += (r > 0) ? r : 0; | ||||
| 		} | ||||
| 	} | ||||
| 	pos = 0; | ||||
| 	len = sbuf->bufsize - (int) (sbuf->ptr - sbuf->buf) - strlen(matchstr); | ||||
| 	while(memcmp(matchstr, sbuf->ptr + pos, strlen(matchstr)) && (pos < len)) { | ||||
| 		pos++; | ||||
| 	} | ||||
| 	if(pos < len) { | ||||
| 		sbuf->len = pos; | ||||
| 		sbuf->segment = sbuf->ptr; | ||||
| 		sbuf->ptr = sbuf->segment + pos + strlen(matchstr); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if(sbuf->eof) { | ||||
| 		len += strlen(matchstr); | ||||
| 	} | ||||
| 	sbuf->segment = sbuf->ptr; | ||||
| 	sbuf->len = len; | ||||
| 	sbuf->ptr += sbuf->len; | ||||
| 	return (sbuf->eof) ? (-1) : (0); | ||||
| } | ||||
							
								
								
									
										40
									
								
								buffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								buffer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			buffer.h | ||||
|  * @PURPOSE			CBSI Buffers | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #ifndef __BUFFER_H | ||||
| #define __BUFFER_H | ||||
|  | ||||
| typedef struct { | ||||
| 	unsigned char* data; | ||||
| 	unsigned char* ptr; | ||||
| 	unsigned char* limit; | ||||
| } buffer_t; | ||||
|  | ||||
| typedef struct { | ||||
| 	int fh; | ||||
| 	unsigned char* buf; | ||||
| 	unsigned char* ptr; | ||||
| 	unsigned char* segment; | ||||
| 	size_t len; | ||||
| 	size_t maxsize; | ||||
| 	size_t bufsize; | ||||
| 	size_t maxread; | ||||
| 	size_t nrread; | ||||
| 	int eof; | ||||
| } sbuffer_t; | ||||
|  | ||||
| void buffer_add(buffer_t* buf, const void* data, unsigned long size); | ||||
| void buffer_destroy(buffer_t* buf); | ||||
| void buffer_init(buffer_t* buf); | ||||
| void buffer_reset(buffer_t* buf); | ||||
| void sbuffer_destroy(sbuffer_t* sbuf); | ||||
| int sbuffer_init(sbuffer_t* sbuf, int size); | ||||
| int sbuffer_read(sbuffer_t* sbuf, char* matchstr); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										658
									
								
								cbsi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										658
									
								
								cbsi.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,658 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			cbsi.c | ||||
|  * @PURPOSE			Common CBSI | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <time.h> | ||||
| #include <getopt.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/fcntl.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <grp.h> | ||||
|  | ||||
| #include "common.h" | ||||
| #include "error.h" | ||||
| #include "buffer.h" | ||||
| #include "subshell.h" | ||||
| #include "mimetype.h" | ||||
| #include "cbsi.h" | ||||
|  | ||||
| struct option ga_long_options[] = { | ||||
| 	{"language-dir", required_argument, 0, 'l'}, | ||||
| 	{"translation", required_argument, 0, 't'}, | ||||
| 	{"upload-limit", required_argument, 0, 'u'}, | ||||
| 	{"upload-dir", required_argument, 0, 'd'}, | ||||
| 	{"shell", required_argument, 0, 's'}, | ||||
| 	{0, 0, 0, 0} | ||||
| }; | ||||
|  | ||||
| const char *gs_short_options = "+u:d:l:t:s:"; | ||||
|  | ||||
| int argc_argv(char* instr, argv_t** argv) { | ||||
| 	char quote = '\0'; | ||||
| 	int arg_count = 0; | ||||
| 	enum state_t { WHITESPACE, WORDSPACE, TOKENSTART } state = WHITESPACE; | ||||
| 	argv_t* argv_array = NULL; | ||||
| 	int argc_slots = 0; | ||||
| 	size_t len, pos; | ||||
|  | ||||
| 	len = strlen(instr); | ||||
| 	pos = 0; | ||||
| 	while(pos < len) { | ||||
| 		switch(*instr) { | ||||
| 			case '"': | ||||
| 			case '\'': | ||||
| 				if(state == WHITESPACE) { | ||||
| 					quote = *instr; | ||||
| 					state = TOKENSTART; | ||||
| 					if(*(instr + 1) == quote) { | ||||
| 						quote = '\0'; | ||||
| 						*instr = '\0'; | ||||
| 						argv_array[arg_count].quoted = -1; | ||||
| 					} else { | ||||
| 						instr++; | ||||
| 						pos++; | ||||
| 					} | ||||
| 				} else { | ||||
| 					if(*instr == quote) { | ||||
| 						argv_array[arg_count - 1].quoted = -1; | ||||
| 						quote = '\0'; | ||||
| 						*instr = '\0'; | ||||
| 						state = WHITESPACE; | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			case '\\': | ||||
| 				if((quote) && (*(instr + 1) == quote)) { | ||||
| 					memmove(instr, instr + 1, strlen(instr)); | ||||
| 					len--; | ||||
| 				} else { | ||||
| 					if(state == WHITESPACE) { | ||||
| 						state = TOKENSTART; | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			case ' ': | ||||
| 			case '\t': | ||||
| 			case '\r': | ||||
| 			case '\n': | ||||
| 				if((state == WORDSPACE) && (quote == '\0')) { | ||||
| 					state = WHITESPACE; | ||||
| 					*instr = '\0'; | ||||
| 				} | ||||
| 				break; | ||||
| 			case '\0': | ||||
| 				break; | ||||
| 			default: | ||||
| 				if(state == WHITESPACE) { | ||||
| 					state = TOKENSTART; | ||||
| 				} | ||||
| 		} | ||||
| 		if(state == TOKENSTART) { | ||||
| 			arg_count++; | ||||
| 			if(arg_count > argc_slots) { | ||||
| 				argc_slots += ALLOC_CHUNK; | ||||
| 				argv_array = (argv_t*) xrealloc(argv_array, sizeof(argv_t) * (argc_slots + ALLOC_CHUNK)); | ||||
| 			} | ||||
| 			if(argv_array == NULL) { | ||||
| 				return -1; | ||||
| 			} | ||||
| 			argv_array[arg_count - 1].string = instr; | ||||
| 			argv_array[arg_count].quoted = 0; | ||||
| 			state = WORDSPACE; | ||||
| 		} | ||||
| 		instr++; | ||||
| 		pos++; | ||||
| 	} | ||||
| 	argv_array[arg_count].string = NULL; | ||||
| 	*argv = argv_array; | ||||
| 	return arg_count; | ||||
| } | ||||
|  | ||||
| void assignGlobalStartupValues() { | ||||
| 	global.uploadkb = -1; | ||||
| 	global.shell = SUBSHELL_CMD; | ||||
| 	global.langdir = LANGDIR; | ||||
| 	global.translation = NULL; | ||||
| 	global.uploaddir = TEMPDIR; | ||||
| 	global.uploadlist = NULL; | ||||
| 	global.file_prefix = "FILE_"; | ||||
| 	global.filename_prefix = "FILENAME_"; | ||||
| 	global.get_prefix = "GET_"; | ||||
| 	global.post_prefix = "POST_"; | ||||
| 	global.cbsi_prefix = "CBSI_"; | ||||
| 	global.cookie_prefix = "COOKIE_"; | ||||
| 	global.null_prefix = ""; | ||||
| } | ||||
|  | ||||
| int BecomeUser(uid_t uid, gid_t gid) { | ||||
| 	if(getuid() == 0) { | ||||
| 		setgroups(1, &gid); | ||||
| 	} | ||||
| 	setgid(gid); | ||||
| 	setgid(getgid()); | ||||
| 	setuid(uid); | ||||
| 	setuid(getuid()); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void cbsiflags(list_t* env) { | ||||
| 	char buf[200]; | ||||
|  | ||||
| 	snprintf(buf, 200, "UPLOAD_DIR=%s", global.uploaddir); | ||||
| 	myputenv(env, buf, global.cbsi_prefix); | ||||
| 	snprintf(buf, 200, "UPLOAD_LIMIT=%lu", global.uploadkb); | ||||
| 	myputenv(env, buf, global.cbsi_prefix); | ||||
| 	snprintf(buf, 200, "SHELL=%s", global.shell); | ||||
| 	myputenv(env, buf, global.cbsi_prefix); | ||||
| } | ||||
|  | ||||
| void cleanup(void) { | ||||
| 	int i; | ||||
|  | ||||
| 	if(global.uploadlist) { | ||||
| 		unlink_uploadlist(); | ||||
| 		free_token_list(global.uploadlist); | ||||
| 		global.uploadlist = NULL; | ||||
| 	} | ||||
| 	if(language != NULL && translations > 0) { | ||||
| 		for (i = 0; i < HASH_BUF; ++i) { | ||||
| 			if(ltable[i]) { | ||||
| 				free(ltable[i]->msgid); | ||||
| 				free(ltable[i]->msgstr); | ||||
| 				free(ltable[i]); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CookieVars(list_t* env) { | ||||
| 	char* qs; | ||||
| 	char* token; | ||||
|  | ||||
| 	if(getenv("HTTP_COOKIE") != NULL) { | ||||
| 		qs = strdup(getenv("HTTP_COOKIE")); | ||||
| 	} else { | ||||
| 		return; | ||||
| 	} | ||||
| 	token = strtok(qs, ";"); | ||||
| 	while(token) { | ||||
| 		while(token[0] == ' ') { | ||||
| 			token++; | ||||
| 		} | ||||
| 		myputenv(env, token, global.cookie_prefix); | ||||
| 		token = strtok(NULL, ";"); | ||||
| 	} | ||||
| 	free(qs); | ||||
| } | ||||
|  | ||||
| int count_lines(char* instr, size_t len, char* where) { | ||||
| 	size_t line = 1; | ||||
|  | ||||
| 	while((where > instr) && (len)) { | ||||
| 		if(*instr == '\n') { | ||||
| 			line++; | ||||
| 		} | ||||
| 		len--; | ||||
| 		instr++; | ||||
| 	} | ||||
| 	return line; | ||||
| } | ||||
|  | ||||
| char* find_whitespace(char* instr) { | ||||
| 	while(!isspace(*instr) && *instr) { | ||||
| 		instr++; | ||||
| 	} | ||||
| 	return instr; | ||||
| } | ||||
|  | ||||
| void free_list_chain(list_t* list) { | ||||
| 	list_t *next; | ||||
|  | ||||
| 	while(list) { | ||||
| 		next = list->next; | ||||
| 		free(list->buf); | ||||
| 		free(list); | ||||
| 		list = next; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| unsigned short generateHash(char* str) { | ||||
| 	unsigned long hash = 5381; | ||||
| 	int c; | ||||
|  | ||||
| 	while(c = *str++) { | ||||
| 		hash = ((hash << 5) + hash) + c; | ||||
| 	} | ||||
| 	return hash % HASH_BUF; | ||||
| } | ||||
|  | ||||
| void loadDictionary(const char* filename) { | ||||
| 	char* b; | ||||
| 	FILE* fp; | ||||
| 	short hash; | ||||
| 	char msgid[TRANS_BUF]; | ||||
| 	char msgstr[TRANS_BUF]; | ||||
| 	lstr* p; | ||||
| 	lstr* s; | ||||
|  | ||||
| 	sprintf(buffer, "%s/%s/%s.dic", global.langdir, language, filename); | ||||
| 	if((fp = fopen(buffer, "r")) != NULL) { | ||||
| 		memset(ltable, 0, sizeof(lstr*) * HASH_BUF); | ||||
| 		memset(msgid, '\0', TRANS_BUF); | ||||
| 		memset(msgstr, '\0', TRANS_BUF); | ||||
| 		while(!feof(fp) && (fgets(buffer, TRANS_BUF - 1, fp) != NULL)) { | ||||
| 			b = skip_whitespace(buffer); | ||||
| 			if((!*b) || (*b == '#')) { | ||||
| 				continue; | ||||
| 			} | ||||
| 			if(strstr(b, "msgid") != NULL) { | ||||
| 				b = trim(b + 5); | ||||
| 				strncpy(msgid, b, strlen(b) + 1); | ||||
| 			} else if(strstr(b, "msgstr") != NULL) { | ||||
| 				b = trim(b + 6); | ||||
| 				strncpy(msgstr, b, strlen(b) + 1); | ||||
| 			} else { | ||||
| 				continue; | ||||
| 			} | ||||
| 			if(msgid[0] != 0 && msgstr[0] != 0) { | ||||
| 				hash = generateHash(msgid); | ||||
| 				s = malloc(sizeof(lstr)); | ||||
| 				s->msgid = (char*) malloc(strlen(msgid) + 1); | ||||
| 				s->msgstr = (char*) malloc(strlen(msgstr) + 1); | ||||
| 				strcpy(s->msgid, msgid); | ||||
| 				strcpy(s->msgstr, msgstr); | ||||
| 				s->next = NULL; | ||||
| 				if(ltable[hash] == NULL) { | ||||
| 					ltable[hash] = s; | ||||
| 				} else { | ||||
| 					for(p = ltable[hash]; p->next != NULL; p = p->next); | ||||
| 					p->next = s; | ||||
| 				} | ||||
| 				translations++; | ||||
| 				msgid[0] = 0; | ||||
| 				msgstr[0] = 0; | ||||
| 			} | ||||
| 		} | ||||
| 		fclose(fp); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void lowercase(char* instr) { | ||||
| 	while(*instr != '\0') { | ||||
| 		*instr = tolower (*instr); | ||||
| 		instr++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int main(int argc, char* argv[]) { | ||||
| 	token_t* tokenchain = NULL; | ||||
| 	buffer_t script_text; | ||||
| 	script_t* scriptchain; | ||||
| 	int retval = 0; | ||||
| 	char* filename = NULL; | ||||
| 	argv_t* av = NULL; | ||||
| 	char** av2 = argv; | ||||
| 	int av2c = argc; | ||||
| 	int command; | ||||
| 	int count; | ||||
| 	list_t* env = NULL; | ||||
|  | ||||
| 	if(atexit(cleanup) != 0) { | ||||
| 		die_with_message(NULL, NULL, "atexit() failed"); | ||||
| 	} | ||||
| 	assignGlobalStartupValues(); | ||||
| 	buffer_init(&script_text); | ||||
| 	switch(argc) { | ||||
| 		case 1: | ||||
| 			puts("This is CBSI version " CBSI_VERSION "\nThis program runs as a CGI interface, not interactively.\n"); | ||||
| 			return 0; | ||||
| 			break; | ||||
| 		default: | ||||
| 			command = argc_argv(argv[1], &av); | ||||
| 			if(command > 1) { | ||||
| 				av2c = argc - 1 + command; | ||||
| 				av2 = xmalloc(sizeof(char*) * av2c); | ||||
| 				av2[0] = argv[0]; | ||||
| 				for(count = 1; count <= command; count++) { | ||||
| 					av2[count] = av[count - 1].string; | ||||
| 				} | ||||
| 				for(; count < av2c; count++) { | ||||
| 					av2[count] = argv[count - command + 1]; | ||||
| 				} | ||||
| 			} | ||||
| 			parseCommandLine(av2c, av2); | ||||
| 			free(av); | ||||
| 			if(av2 != argv) { | ||||
| 				free(av2); | ||||
| 			} | ||||
| 			if(optind < av2c) { | ||||
| 				filename = av2[optind]; | ||||
| 			} else { | ||||
| 				die_with_message(NULL, NULL, "No script file specified"); | ||||
| 			} | ||||
| 			break; | ||||
| 	} | ||||
| 	scriptchain = load_script(filename, NULL); | ||||
| 	BecomeUser(scriptchain->uid, scriptchain->gid); | ||||
| 	env = wcversion(env); | ||||
| 	readenv(env); | ||||
| 	sessionid(env); | ||||
| 	cbsiflags(env); | ||||
| 	prepareDictionary(); | ||||
| 	tokenchain = build_token_list(scriptchain, NULL); | ||||
| 	preprocess_token_list(tokenchain); | ||||
| 	CookieVars(env); | ||||
| 	ReadCGIPOSTValues(env); | ||||
| 	ReadCGIQueryString(env); | ||||
| 	process_token_list(&script_text, tokenchain); | ||||
| 	subshell_setup(global.shell, env); | ||||
| 	subshell_doscript(&script_text, scriptchain->name); | ||||
| 	subshell_destroy(); | ||||
| 	buffer_destroy(&script_text); | ||||
| 	free_token_list(tokenchain); | ||||
| 	free_list_chain(env); | ||||
| 	free_script_list(scriptchain); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| list_t* myputenv(list_t* cur, char* str, char* prefix) { | ||||
| 	list_t* prev = NULL; | ||||
| 	size_t keylen; | ||||
| 	char* entry = NULL; | ||||
| 	char* temp = NULL; | ||||
| 	int array = 0; | ||||
| 	int len; | ||||
|  | ||||
| 	temp = memchr(str, '=', strlen(str)); | ||||
| 	if(temp == 0) { | ||||
| 		return cur; | ||||
| 	} | ||||
| 	keylen = (size_t) (temp - str); | ||||
| 	if(memcmp(str + keylen - 2, "[]", 2) == 0) { | ||||
| 		keylen = keylen - 2; | ||||
| 		array = 1; | ||||
| 	} | ||||
| 	entry = xmalloc(strlen (str) + strlen(prefix) + 1); | ||||
| 	entry[0] = '\0'; | ||||
| 	if(strlen(prefix)) { | ||||
| 		strncat(entry, prefix, strlen(prefix)); | ||||
| 	} | ||||
| 	if(array == 1) { | ||||
| 		strncat(entry, str, keylen); | ||||
| 		strcat(entry, str + keylen + 2); | ||||
| 	} else { | ||||
| 		strcat(entry, str); | ||||
| 	} | ||||
| 	len = keylen + strlen(prefix) + 1; | ||||
| 	while(cur != NULL) { | ||||
| 		if(memcmp(cur->buf, entry, len) == 0) { | ||||
| 			if(array == 1) { | ||||
| 				temp = xmalloc(strlen(cur->buf) + strlen(entry) - len + 2); | ||||
| 				memmove(temp, cur->buf, strlen(cur->buf) + 1); | ||||
| 				strcat(temp, "\n"); | ||||
| 				strcat(temp, str + keylen + 3); | ||||
| 				free(entry); | ||||
| 				entry = temp; | ||||
| 			} | ||||
| 			free(cur->buf); | ||||
| 			if(prev != NULL) { | ||||
| 				prev->next = cur->next; | ||||
| 			} | ||||
| 			free(cur); | ||||
| 			cur = prev; | ||||
| 		} | ||||
| 		prev = cur; | ||||
| 		if(cur) { | ||||
| 			cur = (list_t*) cur->next; | ||||
| 		} | ||||
| 	} | ||||
| 	cur = xmalloc(sizeof(list_t)); | ||||
| 	cur->buf = entry; | ||||
| 	if(prev != NULL) { | ||||
| 		prev->next = cur; | ||||
| 	} | ||||
| 	return cur; | ||||
| } | ||||
|  | ||||
| int parseCommandLine(int argc, char *argv[]) { | ||||
| 	int c; | ||||
| 	int option_index = 0; | ||||
|  | ||||
| 	optopt = 0; | ||||
| 	optind = 0; | ||||
| 	while((c = getopt_long(argc, argv, gs_short_options, ga_long_options, &option_index)) != -1) { | ||||
| 		switch(c) { | ||||
| 			case 's': | ||||
| 				global.shell = optarg; | ||||
| 				break; | ||||
| 			case 'u': | ||||
| 				global.uploadkb = atoi (optarg); | ||||
| 				break; | ||||
| 			case 'l': | ||||
| 				global.langdir = optarg; | ||||
| 				break; | ||||
| 			case 't': | ||||
| 				global.translation = optarg; | ||||
| 				break; | ||||
| 			case 'd': | ||||
| 				global.uploaddir = optarg; | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| 	return optind; | ||||
| } | ||||
|  | ||||
| void prepareDictionary() { | ||||
| 	translations = 0; | ||||
| 	if(getenv("WEBUI_LANGUAGE") != NULL) { | ||||
| 		language = strdup(getenv("WEBUI_LANGUAGE")); | ||||
| 		if(global.translation != NULL) { | ||||
| 			loadDictionary(global.translation); | ||||
| 		} else { | ||||
| 			loadDictionary("common"); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int ReadCGIPOSTValues(list_t* env) { | ||||
| 	size_t content_length = 0; | ||||
| 	size_t max_len; | ||||
| 	size_t i, j, x; | ||||
| 	sbuffer_t sbuf; | ||||
| 	buffer_t token; | ||||
| 	unsigned char* data; | ||||
| 	const char* CONTENT_LENGTH = "CONTENT_LENGTH"; | ||||
|  | ||||
| 	if((getenv(CONTENT_LENGTH) == NULL) || (strtoul(getenv(CONTENT_LENGTH), NULL, 10) == 0)) { | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if(getenv("CONTENT_TYPE")) { | ||||
| 		if(strncasecmp(getenv("CONTENT_TYPE"), "multipart/form-data", 19) == 0) { | ||||
| 			i = rfc2388_handler(env); | ||||
| 			return i; | ||||
| 		} | ||||
| 	} | ||||
| 	sbuffer_init(&sbuf, 32768); | ||||
| 	sbuf.fh = STDIN; | ||||
| 	if(getenv(CONTENT_LENGTH)) { | ||||
| 		sbuf.maxread = strtoul(getenv(CONTENT_LENGTH), NULL, 10); | ||||
| 	} | ||||
| 	buffer_init(&token); | ||||
| 	max_len = ((global.uploadkb == 0) ? 2048 : abs(global.uploadkb)) * 1024; | ||||
| 	do { | ||||
| 		x = sbuffer_read(&sbuf, "&"); | ||||
| 		content_length += sbuf.len; | ||||
| 		if(content_length >= max_len && global.uploadkb != -1) { | ||||
| 			die_with_message(NULL, NULL, "Attempted to send content larger than allowed limits."); | ||||
| 		} | ||||
| 		if((x == 0) || (token.data)) { | ||||
| 			buffer_add(&token, (char*) sbuf.segment, sbuf.len); | ||||
| 		} | ||||
| 		if(x) { | ||||
| 			data = sbuf.segment; | ||||
| 			sbuf.segment[sbuf.len] = '\0'; | ||||
| 			if(token.data) { | ||||
| 				buffer_add(&token, sbuf.segment + sbuf.len, 1); | ||||
| 				data = token.data; | ||||
| 			} | ||||
| 			j = strlen((char*) data); | ||||
| 			for(i = 0; i <= j; i++) { | ||||
| 				if(data[i] == '+') { | ||||
| 					data[i] = ' '; | ||||
| 				} | ||||
| 			} | ||||
| 			unescape_url((char*) data); | ||||
| 			myputenv(env, (char*) data, global.post_prefix); | ||||
| 			if(token.data) { | ||||
| 				buffer_reset(&token); | ||||
| 			} | ||||
| 		} | ||||
| 	} while(!sbuf.eof); | ||||
| 	sbuffer_destroy(&sbuf); | ||||
| 	buffer_destroy(&token); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int ReadCGIQueryString(list_t* env) { | ||||
| 	char* qs; | ||||
| 	char* token; | ||||
| 	int i; | ||||
|  | ||||
| 	if(getenv("QUERY_STRING") != NULL) { | ||||
| 		qs = strdup(getenv("QUERY_STRING")); | ||||
| 	} else { | ||||
| 		return 0; | ||||
| 	} | ||||
| 	for(i = 0; qs[i]; i++) { | ||||
| 		if(qs[i] == '+') { | ||||
| 			qs[i] = ' '; | ||||
| 		} | ||||
| 	} | ||||
| 	token = strtok(qs, "&;"); | ||||
| 	while(token) { | ||||
| 		unescape_url(token); | ||||
| 		myputenv(env, token, global.get_prefix); | ||||
| 		token = strtok(NULL, "&;"); | ||||
| 	} | ||||
| 	free(qs); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void readenv(list_t* env) { | ||||
| 	extern char** environ; | ||||
| 	int count = 0; | ||||
|  | ||||
| 	while(environ[count] != NULL) { | ||||
| 		myputenv(env, environ[count], global.null_prefix); | ||||
| 		count++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void sessionid(list_t* env) { | ||||
| 	char session[29]; | ||||
|  | ||||
| 	sprintf(session, "SESSIONID=%x%x", getpid(), (int) time(NULL)); | ||||
| 	myputenv(env, session, global.cbsi_prefix); | ||||
| } | ||||
|  | ||||
| char* skip_whitespace(char* instr) { | ||||
| 	while(isspace(*instr) && *instr) { | ||||
| 		instr++; | ||||
| 	} | ||||
| 	return instr; | ||||
| } | ||||
|  | ||||
| char* trim(char* str) { | ||||
| 	char* end; | ||||
|  | ||||
| 	while(isspace(*str) || *str == '"') { | ||||
| 		str++; | ||||
| 	} | ||||
| 	if(*str == 0) { | ||||
| 		return str; | ||||
| 	} | ||||
| 	end = str + strlen(str) - 1; | ||||
| 	while(end > str && (isspace(*end) || *end == '"')) { | ||||
| 		end--; | ||||
| 	} | ||||
| 	*(end + 1) = 0; | ||||
| 	return str; | ||||
| } | ||||
|  | ||||
| void unescape_url(char* url) { | ||||
| 	int i, j; | ||||
|  | ||||
| 	for(i = 0, j = 0; url[j]; ++i, ++j) { | ||||
| 		if((url[i] = url[j]) != '%') { | ||||
| 			continue; | ||||
| 		} | ||||
| 		if(!url[j + 1] || !url[j + 2]) { | ||||
| 			break; | ||||
| 		} | ||||
| 		url[i] = x2c(&url[j + 1]); | ||||
| 		j += 2; | ||||
| 	} | ||||
| 	url[i] = '\0'; | ||||
| } | ||||
|  | ||||
| void unlink_uploadlist() { | ||||
| 	token_t* me; | ||||
| 	me = global.uploadlist; | ||||
|  | ||||
| 	while(me) { | ||||
| 		unlink(me->buf); | ||||
| 		free(me->buf); | ||||
| 		me = me->next; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void uppercase(char* instr) { | ||||
| 	while(*instr != '\0') { | ||||
| 		*instr = toupper(*instr); | ||||
| 		instr++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| list_t* wcversion(list_t* env) { | ||||
| 	char version[200]; | ||||
|  | ||||
| 	sprintf(version, "VERSION=%s", CBSI_VERSION); | ||||
| 	return(myputenv(env, version, global.cbsi_prefix)); | ||||
| } | ||||
|  | ||||
| char x2c(char* what) { | ||||
| 	char digit; | ||||
|  | ||||
| 	digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); | ||||
| 	digit *= 16; | ||||
| 	digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); | ||||
| 	return digit; | ||||
| } | ||||
|  | ||||
| void* xmalloc(size_t size) { | ||||
| 	void* buf; | ||||
|  | ||||
| 	if((buf = malloc(size)) == NULL) { | ||||
| 		die_with_message(NULL, NULL, g_err_msg[E_MALLOC_FAIL]); | ||||
| 	} | ||||
| 	memset(buf, 0, size); | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| void* xrealloc(void* buf, size_t size) { | ||||
| 	if((buf = realloc(buf, size)) == NULL) { | ||||
| 		die_with_message(NULL, NULL, g_err_msg[E_MALLOC_FAIL]); | ||||
| 	} | ||||
| 	return buf; | ||||
| } | ||||
							
								
								
									
										74
									
								
								cbsi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								cbsi.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			cbsi.h | ||||
|  * @PURPOSE			Common CBSI | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #ifndef __CBSI_H | ||||
| #define __CBSI_H | ||||
|  | ||||
| typedef struct { | ||||
| 	unsigned long uploadkb; | ||||
| 	char* shell; | ||||
| 	char* langdir; | ||||
| 	char* translation; | ||||
| 	char* uploaddir; | ||||
| 	char* uploadhandler; | ||||
| 	char* file_prefix; | ||||
| 	char* filename_prefix; | ||||
| 	char* get_prefix; | ||||
| 	char* post_prefix; | ||||
| 	char* cookie_prefix; | ||||
| 	char* null_prefix; | ||||
| 	char* cbsi_prefix; | ||||
| 	token_t* uploadlist; | ||||
| 	int debug; | ||||
| 	int acceptall; | ||||
| 	int silent; | ||||
| } cbsi_t; | ||||
|  | ||||
| typedef struct lstr { | ||||
| 	char* msgid; | ||||
| 	char* msgstr; | ||||
| 	struct lstr* next; | ||||
| } lstr; | ||||
|  | ||||
| cbsi_t global; | ||||
| char buffer[TRANS_BUF]; | ||||
| char* language; | ||||
| lstr* ltable[HASH_BUF]; | ||||
| int translations; | ||||
|  | ||||
| int argc_argv(char* instr, argv_t** argv); | ||||
| void assignGlobalStartupValues(void); | ||||
| int BecomeUser(uid_t uid, gid_t gid); | ||||
| void cbsiflags(list_t* env); | ||||
| void cleanup(void); | ||||
| void CookieVars(list_t* env); | ||||
| int count_lines(char* instr, size_t len, char* where); | ||||
| char* find_whitespace (char* instr); | ||||
| void free_list_chain(list_t* env); | ||||
| unsigned short generateHash(char* str); | ||||
| void loadDictionary(const char* filename); | ||||
| void lowercase(char* instr); | ||||
| list_t* myputenv(list_t* cur, char* str, char* prefix); | ||||
| int parseCommandLine(int argc, char* argv[]); | ||||
| void prepareDictionary(); | ||||
| int ReadCGIPOSTValues(list_t* env); | ||||
| int ReadCGIQueryString(list_t* env); | ||||
| void readenv(list_t* env); | ||||
| void sessionid(list_t* env); | ||||
| char* skip_whitespace (char* instr); | ||||
| char* trim(char* str); | ||||
| void unescape_url(char* url); | ||||
| void unlink_uploadlist(void); | ||||
| void uppercase(char* instr); | ||||
| list_t* wcversion(list_t* env); | ||||
| char x2c(char* what); | ||||
| void* xmalloc(size_t size); | ||||
| void* xrealloc(void* buf, size_t size); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										38
									
								
								common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								common.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			common.h | ||||
|  * @PURPOSE			Common CBSI | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #ifndef __COMMON_H | ||||
| #define __COMMON_H | ||||
|  | ||||
| #define ALLOC_CHUNK	10 | ||||
|  | ||||
| #define CBSI_VERSION "0.91" | ||||
|  | ||||
| #define STDIN	0 | ||||
| #define STDOUT  1 | ||||
| #define STDERR	2 | ||||
|  | ||||
| #define HASH_BUF 1536 | ||||
| #define TRANS_BUF 2048 | ||||
|  | ||||
| #define LANGDIR "/usr/lib/kagera/langs" | ||||
| #define SUBSHELL_CMD "/bin/sh" | ||||
| #define TEMPDIR "/tmp" | ||||
|  | ||||
| typedef struct { | ||||
| 	char* string; | ||||
| 	unsigned char quoted; | ||||
| } argv_t; | ||||
|  | ||||
| typedef struct { | ||||
| 	char* buf; | ||||
| 	void* next; | ||||
| } list_t; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										57
									
								
								error.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								error.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			error.c | ||||
|  * @PURPOSE			Error handling | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
| #include <stdarg.h> | ||||
|  | ||||
| #include "common.h" | ||||
| #include "buffer.h" | ||||
| #include "subshell.h" | ||||
| #include "cbsi.h" | ||||
| #include "error.h" | ||||
|  | ||||
| char* g_err_msg[] = { | ||||
| 	"", | ||||
| 	"Memory Allocation Failure", | ||||
| 	"Unable to open file %s", | ||||
| 	"%c> before <%c", | ||||
| 	"Missing %c>", | ||||
| 	"Unknown operation", | ||||
| 	"Unable to start subshell", | ||||
| 	"Unspecified Error", | ||||
| }; | ||||
|  | ||||
| void die_with_error(char* msg) { | ||||
| 	fprintf(stderr, "Error: %s\n", msg); | ||||
| 	exit(-1); | ||||
| } | ||||
|  | ||||
| void die_with_message(void* sp, char* where, const char* s, ...) { | ||||
| 	script_t* script = sp; | ||||
| 	va_list p; | ||||
| 	FILE* fo = stderr; | ||||
|  | ||||
| 	fo = stdout; | ||||
| 	fprintf(fo, "HTTP/1.0 500 Server Error\nContent-Type: text/html\n\n<html><body><b><font color=#CC0000>CBSI Error</font></b><br><pre>\n"); | ||||
| 	va_start(p, s); | ||||
| 	vfprintf(fo, s, p); | ||||
| 	va_end(p); | ||||
| 	if(where && sp) { | ||||
| 		fprintf(fo, " near line %d of %s\n", | ||||
| 		count_lines(script->buf, script->size, where), | ||||
| 		script->name); | ||||
| 	} | ||||
| 	printf("\n"); | ||||
| 	fprintf(fo, "</pre></body></html>\n"); | ||||
| 	exit(-1); | ||||
| } | ||||
							
								
								
									
										19
									
								
								error.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								error.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			error.h | ||||
|  * @PURPOSE			Error handling | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #ifndef __ERROR_H | ||||
| #define __ERROR_H | ||||
|  | ||||
| enum error_types { E_NO_ERROR, E_MALLOC_FAIL, E_FILE_OPEN_FAIL, E_END_BEFORE_BEGIN, E_NO_END_MARKER , E_NO_OP, E_SUBSHELL_FAIL, E_WHATEVER }; | ||||
| extern char *g_err_msg[]; | ||||
|  | ||||
| void die_with_error(char* msg); | ||||
| void die_with_message(void* sp, char* where, const char* s, ...); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										346
									
								
								mimetype.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								mimetype.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,346 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			mimetype.c | ||||
|  * @PURPOSE			Mimetype and file upload handler | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <time.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/fcntl.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #include "common.h" | ||||
| #include "buffer.h" | ||||
| #include "error.h" | ||||
| #include "subshell.h" | ||||
| #include "buffer.h" | ||||
| #include "mimetype.h" | ||||
| #include "cbsi.h" | ||||
|  | ||||
| void empty_stdin(void) { | ||||
| 	char c[2000]; | ||||
| 	while(read(STDIN_FILENO, &c, 2000)) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void mime_var_init(mime_var_t* obj) { | ||||
| 	obj->name = NULL; | ||||
| 	obj->filename = NULL; | ||||
| 	obj->type = NULL; | ||||
| 	obj->tempname = NULL; | ||||
| 	buffer_init(&(obj->value)); | ||||
| 	obj->fh = 0; | ||||
| } | ||||
|  | ||||
| void mime_var_destroy(mime_var_t* obj) { | ||||
| 	int status; | ||||
| 	struct sigaction new_action; | ||||
|  | ||||
| 	if(obj->name) { | ||||
| 		free(obj->name); | ||||
| 		obj->name = NULL; | ||||
| 	} | ||||
| 	if(obj->filename) { | ||||
| 		free(obj->filename); | ||||
| 		obj->filename = NULL; | ||||
| 	} | ||||
| 	if(obj->type) { | ||||
| 		free(obj->type); | ||||
| 		obj->type = NULL; | ||||
| 	} | ||||
| 	if(obj->tempname) { | ||||
| 		free(obj->tempname); | ||||
| 		obj->tempname = NULL; | ||||
| 	} | ||||
| 	buffer_destroy(&(obj->value)); | ||||
| 	if(obj->fh) { | ||||
| 		close(abs(obj->fh)); | ||||
| 		obj->fh = 0; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| char* mime_substr(char* start, int len) { | ||||
| 	char* ptr; | ||||
|  | ||||
| 	if(!start) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	if(len < 0) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	ptr = xmalloc(len + 2); | ||||
| 	memcpy(ptr, start, len); | ||||
| 	return ptr; | ||||
| } | ||||
|  | ||||
| void mime_tag_add(mime_var_t* obj, char* str) { | ||||
| 	char* a = NULL; | ||||
| 	char* b = NULL; | ||||
| 	static char* tag[] = { "name=\"", "filename=\"", "Content-Type: " }; | ||||
|  | ||||
| 	a = strcasestr(str, tag[0]); | ||||
| 	if(a) { | ||||
| 		a += strlen(tag[0]); | ||||
| 		b = strchr(a, '"'); | ||||
| 		if(!obj->name) { | ||||
| 			obj->name = mime_substr(a, b - a); | ||||
| 		} | ||||
| 	} | ||||
| 	a = strcasestr(str, tag[1]); | ||||
| 	if(a) { | ||||
| 		a += strlen(tag[1]); | ||||
| 		b = strchr(a, '"'); | ||||
| 		if(!obj->filename) { | ||||
| 			obj->filename = mime_substr(a, b - a); | ||||
| 		} | ||||
| 	} | ||||
| 	a = strcasestr(str, tag[2]); | ||||
| 	if(a) { | ||||
| 		a += strlen(tag[2]); | ||||
| 		b = a + strlen(a); | ||||
| 		if(!obj->type) { | ||||
| 			obj->type = mime_substr(a, b - a); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void mime_var_putenv(list_t* env, mime_var_t* obj) { | ||||
| 	buffer_t buf; | ||||
|  | ||||
| 	buffer_init(&buf); | ||||
| 	if(obj->filename) { | ||||
| 		buffer_add(&buf, obj->name, strlen(obj->name)); | ||||
| 		buffer_add(&buf, "=", 1); | ||||
| 		buffer_add(&buf, (char*) obj->value.data, | ||||
| 		strlen((char*) obj->value.data) + 1); | ||||
| 		myputenv(env, (char*) buf.data, global.file_prefix); | ||||
| 		buffer_reset(&buf); | ||||
| 		buffer_add(&buf, obj->name, strlen(obj->name)); | ||||
| 		buffer_add(&buf, "=", 1); | ||||
| 		buffer_add(&buf, obj->filename, strlen(obj->filename) + 1); | ||||
| 		myputenv(env, (char*) buf.data, global.filename_prefix); | ||||
| 		buffer_reset (&buf); | ||||
| 	} else if(obj->name) { | ||||
| 		buffer_add(&(obj->value), "", 1); | ||||
| 		buffer_add(&buf, obj->name, strlen(obj->name)); | ||||
| 		buffer_add(&buf, "=", 1); | ||||
| 		buffer_add(&buf, (char*) obj->value.data, | ||||
| 		strlen((char*) obj->value.data) + 1); | ||||
| 		myputenv(env, (char*) buf.data, global.file_prefix); | ||||
| 		buffer_reset(&buf); | ||||
| 	} | ||||
| 	buffer_destroy(&buf); | ||||
| } | ||||
|  | ||||
| void mime_exec(mime_var_t* obj, char* fifo) { | ||||
| 	int pid; | ||||
| 	char* type; | ||||
| 	char* filename; | ||||
| 	char* name; | ||||
| 	char *c; | ||||
| 	int fh; | ||||
| 	struct sigaction new_action; | ||||
|  | ||||
| 	pid = fork(); | ||||
| 	if(pid == -1) { | ||||
| 		empty_stdin(); | ||||
| 		die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); | ||||
| 	} | ||||
| 	if(pid == 0) { | ||||
| 		if(obj->type) { | ||||
| 			type = xmalloc(13 + strlen(obj->type) + 1); | ||||
| 			sprintf(type, "CONTENT_TYPE=%s", obj->type); | ||||
| 			putenv(type); | ||||
| 		} | ||||
| 		if(obj->filename) { | ||||
| 			filename = xmalloc (9 + strlen(obj->filename) + 1); | ||||
| 			sprintf(filename, "FILENAME=%s", obj->filename); | ||||
| 			putenv(filename); | ||||
| 		} | ||||
| 		if(obj->name) { | ||||
| 			name = xmalloc(5 + strlen(obj->name) + 1); | ||||
| 			sprintf(name, "NAME=%s", obj->name); | ||||
| 			putenv(name); | ||||
| 		} | ||||
| 		fh = open(fifo, O_RDONLY); | ||||
| 		while(read(fh, &c, 1)) { | ||||
| 		} | ||||
| 		exit(-1); | ||||
| 	} else { | ||||
| 		new_action.sa_handler = SIG_IGN; | ||||
| 		sigemptyset(&new_action.sa_mask); | ||||
| 		new_action.sa_flags = 0; | ||||
| 		sigaction(SIGPIPE, &new_action, NULL); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void mime_var_open_target(mime_var_t* obj) { | ||||
| 	char* tmpname; | ||||
| 	token_t* curtoken; | ||||
| 	curtoken = global.uploadlist; | ||||
| 	int ok; | ||||
|  | ||||
| 	if(global.uploadkb == 0) { | ||||
| 		empty_stdin(); | ||||
| 		die_with_message(NULL, NULL, "File uploads are not allowed."); | ||||
| 	} | ||||
| 	ok = -1; | ||||
| 	tmpname = xmalloc(strlen(global.uploaddir) + 8); | ||||
| 	strcpy(tmpname, global.uploaddir); | ||||
| 	strcat(tmpname, "/XXXXXX"); | ||||
| 	obj->fh = mkstemp(tmpname); | ||||
| 	if(obj->fh == -1) { | ||||
| 		ok = 0; | ||||
| 	} | ||||
| 	buffer_add(&(obj->value), tmpname, strlen(tmpname)); | ||||
| 	if(!ok) { | ||||
| 		empty_stdin(); | ||||
| 		die_with_message(NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], tmpname); | ||||
| 	} | ||||
| 	curtoken = push_token_on_list(curtoken, NULL, tmpname, strlen(tmpname) + 1); | ||||
| 	if(global.uploadlist == NULL) { | ||||
| 		global.uploadlist = curtoken; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void mime_var_writer(mime_var_t* obj, char* str, int len) { | ||||
| 	int err; | ||||
|  | ||||
| 	if(!obj->filename) { | ||||
| 		buffer_add(&(obj->value), str, len); | ||||
| 	} | ||||
| 	if((!obj->fh) && (obj->filename)) { | ||||
| 		mime_var_open_target(obj); | ||||
| 	} | ||||
| 	if(obj->fh > 0) { | ||||
| 		err = write(obj->fh, str, len); | ||||
| 		if(err == -1) { | ||||
| 			obj->fh = abs(obj->fh) * -1; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int rfc2388_handler(list_t* env) { | ||||
| 	enum mime_state_t { DISCARD, BOUNDARY, HEADER, CONTENT }; | ||||
| 	int state; | ||||
| 	int i, x; | ||||
| 	unsigned long max_len, content_length; | ||||
| 	sbuffer_t sbuf; | ||||
| 	char* crlf = "\r\n"; | ||||
| 	char* boundary; | ||||
| 	char* str; | ||||
| 	buffer_t buf; | ||||
| 	mime_var_t var; | ||||
|  | ||||
| 	str = getenv("CONTENT_TYPE"); | ||||
| 	i = strlen(str) - 9; | ||||
| 	while((i >= 0) && (memcmp("boundary=", str + i, 9))) { | ||||
| 		i--; | ||||
| 	} | ||||
| 	if(i == -1) { | ||||
| 		empty_stdin(); | ||||
| 		die_with_message(NULL, NULL, "No Mime Boundary Information Found"); | ||||
| 	} | ||||
| 	i = i + 9; | ||||
| 	if(str[i] == '"') { | ||||
| 		i++; | ||||
| 	} | ||||
| 	boundary = xmalloc(strlen(str + i) + 5); | ||||
| 	memcpy(boundary, crlf, 2); | ||||
| 	memcpy(boundary + 2, "--", 2); | ||||
| 	memcpy(boundary + 4, str + i, strlen(str + i) + 1); | ||||
| 	if((i > 0) && (str[i - 1] == '"')) { | ||||
| 		while((boundary[i]) && (boundary[i] != '"')) { | ||||
| 			i++; | ||||
| 		} | ||||
| 		boundary[i] = '\0'; | ||||
| 	} | ||||
| 	max_len = ((global.uploadkb == 0) ? 2048 : abs(global.uploadkb)) * 1024; | ||||
| 	content_length = 0; | ||||
| 	sbuffer_init(&sbuf, 1024 * 128); | ||||
| 	sbuf.fh = STDIN; | ||||
| 	if(getenv("CONTENT_LENGTH")) { | ||||
| 		sbuf.maxread = strtoul(getenv("CONTENT_LENGTH"), NULL, 10); | ||||
| 	} | ||||
| 	buffer_init(&buf); | ||||
| 	buffer_add(&buf, "", 1); | ||||
| 	buffer_reset(&buf); | ||||
| 	state = DISCARD; | ||||
| 	str = boundary + 2; | ||||
| 	do { | ||||
| 		x = sbuffer_read(&sbuf, str); | ||||
| 		content_length += sbuf.len; | ||||
| 		if(content_length >= max_len && global.uploadkb != -1) { | ||||
| 			empty_stdin(); | ||||
| 			free(boundary); | ||||
| 			sbuffer_destroy(&sbuf); | ||||
| 			buffer_destroy(&buf); | ||||
| 			if(var.name) { | ||||
| 				mime_var_destroy(&var); | ||||
| 			} | ||||
| 			die_with_message(NULL, NULL, "Attempted to send content larger than allowed limits."); | ||||
| 		} | ||||
| 		switch(state) { | ||||
| 			case DISCARD: | ||||
| 				if(x) { | ||||
| 					state = BOUNDARY; | ||||
| 					str = crlf; | ||||
| 					buffer_reset(&buf); | ||||
| 				} | ||||
| 				break; | ||||
| 			case BOUNDARY: | ||||
| 				if(x) { | ||||
| 					buffer_add(&buf, sbuf.segment, sbuf.len); | ||||
| 					if(!memcmp(buf.data, boundary + 2, 2)) { | ||||
| 						str = boundary + 2; | ||||
| 						state = DISCARD; | ||||
| 					} else { | ||||
| 						buffer_reset(&buf); | ||||
| 						mime_var_init(&var); | ||||
| 						state = HEADER; | ||||
| 						str = crlf; | ||||
| 					} | ||||
| 				} else { | ||||
| 					buffer_add(&buf, sbuf.segment, sbuf.len); | ||||
| 				} | ||||
| 				break; | ||||
| 			case HEADER: | ||||
| 				buffer_add(&buf, sbuf.segment, sbuf.len); | ||||
| 				if(x) { | ||||
| 					if(sbuf.len == 0) { | ||||
| 						buffer_reset(&buf); | ||||
| 						state = CONTENT; | ||||
| 						str = boundary; | ||||
| 					} else { | ||||
| 						buffer_add(&buf, "", 1); | ||||
| 						mime_tag_add(&var, (char*) buf.data); | ||||
| 						buffer_reset(&buf); | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			case CONTENT: | ||||
| 				mime_var_writer(&var, (char*) sbuf.segment, sbuf.len); | ||||
| 				if(x) { | ||||
| 					buffer_reset(&buf); | ||||
| 					mime_var_putenv(env, &var); | ||||
| 					mime_var_destroy(&var); | ||||
| 					state = BOUNDARY; | ||||
| 					str = crlf; | ||||
| 				} | ||||
| 				break; | ||||
| 		} | ||||
| 	} while(!sbuf.eof); | ||||
| 	free(boundary); | ||||
| 	sbuffer_destroy(&sbuf); | ||||
| 	buffer_destroy(&buf); | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										33
									
								
								mimetype.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								mimetype.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			mimetype.h | ||||
|  * @PURPOSE			Mimetype and file upload handler | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #ifndef __MIMETYPE_H | ||||
| #define __MIMETYPE_H | ||||
|  | ||||
| typedef struct { | ||||
| 	char* name; | ||||
| 	char* filename; | ||||
| 	char* type; | ||||
| 	char* tempname; | ||||
| 	buffer_t value; | ||||
| 	int fh; | ||||
| } mime_var_t; | ||||
|  | ||||
| void empty_stdin(void); | ||||
| void mime_exec(mime_var_t* obj, char* fifo); | ||||
| char* mime_substr(char* start, int len); | ||||
| void mime_tag_add(mime_var_t* obj, char* str); | ||||
| void mime_var_destroy(mime_var_t* obj); | ||||
| void mime_var_init(mime_var_t* obj); | ||||
| void mime_var_open_target(mime_var_t* obj); | ||||
| void mime_var_putenv(list_t* env, mime_var_t* obj); | ||||
| void mime_var_writer(mime_var_t* obj, char* str, int len); | ||||
| int rfc2388_handler(list_t* env); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										373
									
								
								subshell.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								subshell.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,373 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			subshell.c | ||||
|  * @PURPOSE			Subshell execution | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <time.h> | ||||
| #include <getopt.h> | ||||
| #include <sys/mman.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/wait.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/fcntl.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
|  | ||||
| #include "common.h" | ||||
| #include "buffer.h" | ||||
| #include "error.h" | ||||
| #include "subshell.h" | ||||
| #include "cbsi.h" | ||||
|  | ||||
| char open_tag[3] = "<%"; | ||||
| char close_tag[3] = "%>"; | ||||
|  | ||||
| const char* g_tag[] = { | ||||
| 	"", | ||||
| 	"", | ||||
| 	":", | ||||
| 	"@", | ||||
| 	"" | ||||
| }; | ||||
|  | ||||
| token_t* build_token_list(script_t* scriptbuf, token_t* tokenlist) { | ||||
| 	char* start; | ||||
| 	char* end; | ||||
| 	char* curpos; | ||||
| 	char* endpos; | ||||
| 	token_t* curtoken; | ||||
| 	token_t* firsttoken; | ||||
|  | ||||
| 	curtoken = tokenlist; | ||||
| 	firsttoken = tokenlist; | ||||
| 	curpos = scriptbuf->buf + scriptbuf->curpos; | ||||
| 	endpos = scriptbuf->buf + scriptbuf->size; | ||||
| 	while(curpos < endpos) { | ||||
| 		start = strstr(curpos, open_tag); | ||||
| 		end = strstr(curpos, close_tag); | ||||
| 		if(start && !end) { | ||||
| 			die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]); | ||||
| 		} | ||||
| 		if((start > end) || (!start && end)) { | ||||
| 			die_with_message(scriptbuf, end, g_err_msg[E_END_BEFORE_BEGIN], open_tag[1], open_tag[1]); | ||||
| 		} | ||||
| 		if(start && (strstr(start + 1, open_tag) && (strstr (start + 1, open_tag) < end))) | ||||
| 			die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]); | ||||
| 		if(end) { | ||||
| 			curtoken = push_token_on_list(curtoken, scriptbuf, curpos, start - curpos); | ||||
| 			if(firsttoken == NULL) { | ||||
| 				firsttoken = curtoken; | ||||
| 			} | ||||
| 			curtoken = push_token_on_list(curtoken, scriptbuf, start, end - start); | ||||
| 			if(firsttoken == NULL) { | ||||
| 				firsttoken = curtoken; | ||||
| 			} | ||||
| 			curpos = end + 2; | ||||
| 		} else { | ||||
| 			curtoken = push_token_on_list(curtoken, scriptbuf, curpos, endpos - curpos); | ||||
| 			if(firsttoken == NULL) { | ||||
| 				firsttoken = curtoken; | ||||
| 			} | ||||
| 			curpos = endpos; | ||||
| 		} | ||||
| 	} | ||||
| 	return firsttoken; | ||||
| } | ||||
|  | ||||
| void free_script_list(script_t* script) { | ||||
| 	script_t* next; | ||||
|  | ||||
| 	while(script) { | ||||
| 		next = script->next; | ||||
| 		if(script->name) { | ||||
| 			free(script->name); | ||||
| 		} | ||||
| 		if(script->buf) { | ||||
| 			free(script->buf); | ||||
| 		} | ||||
| 		free(script); | ||||
| 		script = next; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void free_token_list(token_t* tokenlist) { | ||||
| 	token_t* next; | ||||
|  | ||||
| 	while(tokenlist) { | ||||
| 		next = tokenlist->next; | ||||
| 		free(tokenlist); | ||||
| 		tokenlist = next; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| script_t* load_script(char* filename, script_t* scriptlist) { | ||||
| 	script_t* scriptbuf; | ||||
| 	int scriptfp; | ||||
| 	struct stat filestat; | ||||
|  | ||||
| 	scriptfp = open(filename, O_NONBLOCK + O_RDONLY); | ||||
| 	if(scriptfp == -1) { | ||||
| 		die_with_message(NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], filename); | ||||
| 	} | ||||
| 	fstat(scriptfp, &filestat); | ||||
| 	scriptbuf = (script_t *) xmalloc(sizeof (script_t)); | ||||
| 	scriptbuf->name = (char *) xmalloc(strlen (filename) + 1); | ||||
| 	scriptbuf->buf = (char *) xmalloc(filestat.st_size + 1); | ||||
| 	memset(scriptbuf->name, 0, strlen(filename) + 1); | ||||
| 	memcpy(scriptbuf->name, filename, strlen(filename)); | ||||
| 	memset(scriptbuf->buf, 0, filestat.st_size + 1); | ||||
| 	read(scriptfp, scriptbuf->buf, filestat.st_size); | ||||
| 	scriptbuf->size = filestat.st_size; | ||||
| 	scriptbuf->uid = filestat.st_uid; | ||||
| 	scriptbuf->gid = filestat.st_gid; | ||||
| 	scriptbuf->curpos = 0; | ||||
| 	scriptbuf->next = NULL; | ||||
| 	if(scriptlist != NULL) { | ||||
| 		while(scriptlist->next) { | ||||
| 			scriptlist = scriptlist->next; | ||||
| 		} | ||||
| 		scriptlist->next = scriptbuf; | ||||
| 	} | ||||
| 	if(memcmp(scriptbuf->buf, "#!", 2) == 0) { | ||||
| 		while((scriptbuf->curpos < scriptbuf->size) && ((char) scriptbuf->buf[scriptbuf->curpos] != '\n')) { | ||||
| 			(scriptbuf->curpos)++; | ||||
| 		} | ||||
| 		(scriptbuf->curpos)++; | ||||
| 	} | ||||
| 	close(scriptfp); | ||||
| 	return scriptbuf; | ||||
| } | ||||
|  | ||||
| void preprocess_token_list(token_t* tokenlist) { | ||||
| 	script_t* newscript; | ||||
| 	token_t* me; | ||||
| 	char* cp; | ||||
|  | ||||
| 	me = tokenlist; | ||||
| 	while(me) { | ||||
| 		if(memcmp(me->buf, open_tag, 2)) { | ||||
| 			me->tag = HTML; | ||||
| 		} else { | ||||
| 			me->tag = NOOP; | ||||
| 			me->buf[me->len] = '\0'; | ||||
| 			cp = me->buf + 2; | ||||
| 			if(memcmp(cp, g_tag[ECHO], 1) == 0) { | ||||
| 				me->tag = ECHO; | ||||
| 				me->buf = find_whitespace(me->buf); | ||||
| 				me->len = strlen(me->buf); | ||||
| 			} else if(memcmp(cp, g_tag[TRANSLATE], 1) == 0) { | ||||
| 				me->tag = TRANSLATE; | ||||
| 				me->buf = find_whitespace(me->buf); | ||||
| 				me->len = strlen(me->buf); | ||||
| 			} | ||||
| 			if(isspace(*cp)) { | ||||
| 				me->tag = RUN; | ||||
| 				me->buf = cp; | ||||
| 			} | ||||
| 			if(me->tag == NOOP) { | ||||
| 				die_with_message(me->script, cp, g_err_msg[E_NO_OP]); | ||||
| 			} | ||||
| 			me->len = strlen(me->buf); | ||||
| 		} | ||||
| 		me = me->next; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| token_t* process_token_list(buffer_t* buf, token_t* token) { | ||||
| 	char *c; | ||||
|  | ||||
| 	buffer_init(buf); | ||||
| 	subshell_exec(buf, "\n"); | ||||
| 	while(token) { | ||||
| 		switch(token->tag) { | ||||
| 			case HTML: | ||||
| 				c = token->buf; | ||||
| 				while((c < (token->buf + token->len)) && (isspace(*c))) { | ||||
| 					c++; | ||||
| 				} | ||||
| 				if(c != token->buf + token->len) { | ||||
| 					subshell_echo (buf, token->buf, token->len); | ||||
| 				} | ||||
| 				break; | ||||
| 			case RUN: | ||||
| 				subshell_exec(buf, token->buf); | ||||
| 				subshell_exec(buf, "\n"); | ||||
| 				break; | ||||
| 			case ECHO: | ||||
| 				subshell_eval(buf, token->buf, token->len); | ||||
| 				break; | ||||
| 			case TRANSLATE: | ||||
| 				subshell_translate(buf, token->buf, token->len); | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
| 		token = token->next; | ||||
| 	} | ||||
| 	return token; | ||||
| } | ||||
|  | ||||
| token_t* push_token_on_list(token_t* tokenlist, script_t* scriptbuf, char* start, size_t len) { | ||||
| 	token_t* me; | ||||
| 	token_t* next; | ||||
|  | ||||
| 	if(len == 0) { | ||||
| 		return tokenlist; | ||||
| 	} | ||||
| 	me = (token_t*) xmalloc(sizeof(token_t)); | ||||
| 	if(tokenlist == NULL) { | ||||
| 		next = NULL; | ||||
| 	} else { | ||||
| 		next = tokenlist->next; | ||||
| 		tokenlist->next = me; | ||||
| 	} | ||||
| 	me->next = next; | ||||
| 	me->script = scriptbuf; | ||||
| 	me->buf = start; | ||||
| 	me->len = len; | ||||
| 	return me; | ||||
| } | ||||
|  | ||||
| void subshell_destroy(void) { | ||||
| 	int status; | ||||
| 	waitpid(subshell_pid, &status, 0); | ||||
| } | ||||
|  | ||||
| void subshell_doscript(buffer_t* script, char* name) { | ||||
| 	static char postfix[] = "\nexit\n"; | ||||
|  | ||||
| 	write(subshell_pipe[PARENT_OUT], script->data, script->ptr - script->data); | ||||
| 	write(subshell_pipe[PARENT_OUT], postfix, strlen(postfix)); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void subshell_echo(buffer_t* buf, char* str, size_t len) { | ||||
| 	static char echo_start[] = "printf '%s' '"; | ||||
| 	static char echo_quote[] = "'\\''"; | ||||
| 	static char echo_end[] = "'\n"; | ||||
| 	const size_t maxlen = 3096; | ||||
| 	size_t pos; | ||||
|  | ||||
| 	if(len == 0) { | ||||
| 		return; | ||||
| 	} | ||||
| 	pos = 0; | ||||
| 	buffer_add(buf, echo_start, strlen(echo_start)); | ||||
| 	while(pos < len) { | ||||
| 		if (str[pos] == '\'') { | ||||
| 			buffer_add(buf, echo_quote, strlen(echo_quote)); | ||||
| 		} else { | ||||
| 			buffer_add(buf, str + pos, 1); | ||||
| 		} | ||||
| 		pos++; | ||||
| 		if((pos % maxlen) == 0) { | ||||
| 			buffer_add(buf, echo_end, strlen(echo_end)); | ||||
| 			buffer_add(buf, echo_start, strlen(echo_start)); | ||||
| 		} | ||||
| 	} | ||||
| 	buffer_add(buf, echo_end, strlen(echo_end)); | ||||
| } | ||||
|  | ||||
| void subshell_eval(buffer_t* buf, char* str, size_t len) { | ||||
| 	static char echo_start[] = "echo -n "; | ||||
| 	static char echo_end[] = "\n"; | ||||
|  | ||||
| 	if(len == 0) { | ||||
| 		return; | ||||
| 	} | ||||
| 	str = trim(str); | ||||
| 	if(!*str) { | ||||
| 		return; | ||||
| 	} | ||||
| 	buffer_add(buf, echo_start, strlen(echo_start)); | ||||
| 	buffer_add(buf, str, len); | ||||
| 	buffer_add(buf, echo_end, strlen(echo_end)); | ||||
| } | ||||
|  | ||||
| void subshell_exec(buffer_t* buf, char* str) { | ||||
| 	buffer_add (buf, str, strlen (str)); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| void subshell_setup (char* shell, list_t* env) { | ||||
| 	int retcode = 0; | ||||
| 	int count; | ||||
| 	argv_t* argv; | ||||
| 	char* av[20]; | ||||
| 	list_t* next; | ||||
|  | ||||
| 	if(shell == NULL) { | ||||
| 		return; | ||||
| 	} | ||||
| 	retcode = pipe(&subshell_pipe[PARENT_IN]); | ||||
| 	if(retcode == 0) { | ||||
| 		subshell_pid = fork(); | ||||
| 		if(subshell_pid == -1) { | ||||
| 			die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); | ||||
| 		} | ||||
| 		if(subshell_pid == 0) { | ||||
| 			dup2(subshell_pipe[PARENT_IN], STDIN_FILENO); | ||||
| 			close(subshell_pipe[PARENT_IN]); | ||||
| 			close(subshell_pipe[PARENT_OUT]); | ||||
| 			count = argc_argv(shell, &argv); | ||||
| 			if(count > 19) { | ||||
| 				av[19] = "\0"; | ||||
| 				count = 18; | ||||
| 			} | ||||
| 			while(count >= 0) { | ||||
| 				av[count] = argv[count].string; | ||||
| 				count--; | ||||
| 			} | ||||
| 			while(env) { | ||||
| 				next = env->next; | ||||
| 				putenv(env->buf); | ||||
| 				env = next; | ||||
| 			} | ||||
| 			execv(argv[0].string, av); | ||||
| 			free(argv); | ||||
| 			die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); | ||||
| 		} else { | ||||
| 			close(subshell_pipe[PARENT_IN]); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void subshell_translate(buffer_t* buf, char* str, size_t len) { | ||||
| 	static char echo_start[] = "echo -n \""; | ||||
| 	static char echo_end[] = "\"\n"; | ||||
| 	short hash; | ||||
| 	lstr* i; | ||||
| 	char* text = NULL; | ||||
|  | ||||
| 	if(len == 0) { | ||||
| 		return; | ||||
| 	} | ||||
| 	str = trim(str); | ||||
| 	if(!*str) { | ||||
| 		return; | ||||
| 	} | ||||
| 	if(language != NULL && translations > 0) { | ||||
| 		hash = generateHash(str); | ||||
| 		i = ltable[hash]; | ||||
| 		while(text == NULL && i != NULL) { | ||||
| 			if(strcmp(str, i->msgid) == 0) { | ||||
| 				text = i->msgstr; | ||||
| 			} else { | ||||
| 				i = i->next; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if(text == NULL) { | ||||
| 		text = str; | ||||
| 	} | ||||
| 	buffer_add(buf, echo_start, strlen(echo_start)); | ||||
| 	buffer_add(buf, text, strlen(text)); | ||||
| 	buffer_add(buf, echo_end, strlen(echo_end)); | ||||
| } | ||||
							
								
								
									
										52
									
								
								subshell.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								subshell.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| /** | ||||
|  * @PROJECT			CGI Bash Shell Interface | ||||
|  * @COPYRIGHT		See COPYING in the top level directory | ||||
|  * @FILE			subshell.h | ||||
|  * @PURPOSE			Subshell execution | ||||
|  * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net> | ||||
|  *					Rafal Kupiec <belliash@asiotec.eu.org> | ||||
|  */ | ||||
|  | ||||
| #ifndef __SUBSHELL_H | ||||
| #define __SUBSHELL_H | ||||
|  | ||||
| static int subshell_pid; | ||||
| static int subshell_pipe[2]; | ||||
|  | ||||
| enum pipe_t { PARENT_IN, PARENT_OUT }; | ||||
| enum tag_t { HTML, RUN, ECHO, TRANSLATE, NOOP }; | ||||
|  | ||||
| typedef struct { | ||||
| 	char* name; | ||||
| 	int size; | ||||
| 	uid_t uid; | ||||
| 	gid_t gid; | ||||
| 	char* buf; | ||||
| 	size_t curpos; | ||||
| 	void* next; | ||||
| } script_t; | ||||
|  | ||||
| typedef struct { | ||||
| 	script_t* script; | ||||
| 	enum tag_t tag; | ||||
| 	size_t len; | ||||
| 	char* buf; | ||||
| 	void* next; | ||||
| } token_t; | ||||
|  | ||||
| token_t* build_token_list(script_t* scriptbuf, token_t* tokenlist); | ||||
| void free_script_list(script_t* script); | ||||
| void free_token_list(token_t* tokenlist); | ||||
| script_t* load_script(char* filename, script_t* scriptlist); | ||||
| void preprocess_token_list(token_t* tokenlist); | ||||
| token_t* process_token_list(buffer_t* buf, token_t* tokenlist); | ||||
| token_t* push_token_on_list(token_t* tokenlist, script_t* scriptbuf, char* start, size_t len); | ||||
| void subshell_destroy(void); | ||||
| void subshell_doscript(buffer_t* script, char* name); | ||||
| void subshell_echo(buffer_t* buf, char* str, size_t len); | ||||
| void subshell_eval(buffer_t* buf, char* str, size_t len); | ||||
| void subshell_exec(buffer_t* buf, char* str); | ||||
| void subshell_setup(char* shell, list_t* env); | ||||
| void subshell_translate(buffer_t* buf, char* str, size_t len); | ||||
|  | ||||
| #endif | ||||
		Reference in New Issue
	
	Block a user