Initial import
This commit is contained in:
parent
baf5eb02ed
commit
2e0fbca2e5
|
@ -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.
|
|
@ -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!"
|
|
@ -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/>.
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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));
|
||||||
|
}
|
|
@ -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
|
Loading…
Reference in New Issue