Browse Source

Initial import

Rafal Kupiec 5 years ago
parent
commit
2e0fbca2e5
15 changed files with 2228 additions and 4 deletions
  1. 339
    0
      COPYING
  2. 39
    0
      Makefile
  3. 34
    0
      README
  4. 0
    4
      README.md
  5. 126
    0
      buffer.c
  6. 40
    0
      buffer.h
  7. 658
    0
      cbsi.c
  8. 74
    0
      cbsi.h
  9. 38
    0
      common.h
  10. 57
    0
      error.c
  11. 19
    0
      error.h
  12. 346
    0
      mimetype.c
  13. 33
    0
      mimetype.h
  14. 373
    0
      subshell.c
  15. 52
    0
      subshell.h

+ 339
- 0
COPYING View File

@@ -0,0 +1,339 @@
1
+                    GNU GENERAL PUBLIC LICENSE
2
+                       Version 2, June 1991
3
+
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
+ Everyone is permitted to copy and distribute verbatim copies
7
+ of this license document, but changing it is not allowed.
8
+
9
+                            Preamble
10
+
11
+  The licenses for most software are designed to take away your
12
+freedom to share and change it.  By contrast, the GNU General Public
13
+License is intended to guarantee your freedom to share and change free
14
+software--to make sure the software is free for all its users.  This
15
+General Public License applies to most of the Free Software
16
+Foundation's software and to any other program whose authors commit to
17
+using it.  (Some other Free Software Foundation software is covered by
18
+the GNU Lesser General Public License instead.)  You can apply it to
19
+your programs, too.
20
+
21
+  When we speak of free software, we are referring to freedom, not
22
+price.  Our General Public Licenses are designed to make sure that you
23
+have the freedom to distribute copies of free software (and charge for
24
+this service if you wish), that you receive source code or can get it
25
+if you want it, that you can change the software or use pieces of it
26
+in new free programs; and that you know you can do these things.
27
+
28
+  To protect your rights, we need to make restrictions that forbid
29
+anyone to deny you these rights or to ask you to surrender the rights.
30
+These restrictions translate to certain responsibilities for you if you
31
+distribute copies of the software, or if you modify it.
32
+
33
+  For example, if you distribute copies of such a program, whether
34
+gratis or for a fee, you must give the recipients all the rights that
35
+you have.  You must make sure that they, too, receive or can get the
36
+source code.  And you must show them these terms so they know their
37
+rights.
38
+
39
+  We protect your rights with two steps: (1) copyright the software, and
40
+(2) offer you this license which gives you legal permission to copy,
41
+distribute and/or modify the software.
42
+
43
+  Also, for each author's protection and ours, we want to make certain
44
+that everyone understands that there is no warranty for this free
45
+software.  If the software is modified by someone else and passed on, we
46
+want its recipients to know that what they have is not the original, so
47
+that any problems introduced by others will not reflect on the original
48
+authors' reputations.
49
+
50
+  Finally, any free program is threatened constantly by software
51
+patents.  We wish to avoid the danger that redistributors of a free
52
+program will individually obtain patent licenses, in effect making the
53
+program proprietary.  To prevent this, we have made it clear that any
54
+patent must be licensed for everyone's free use or not licensed at all.
55
+
56
+  The precise terms and conditions for copying, distribution and
57
+modification follow.
58
+
59
+                    GNU GENERAL PUBLIC LICENSE
60
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
+
62
+  0. This License applies to any program or other work which contains
63
+a notice placed by the copyright holder saying it may be distributed
64
+under the terms of this General Public License.  The "Program", below,
65
+refers to any such program or work, and a "work based on the Program"
66
+means either the Program or any derivative work under copyright law:
67
+that is to say, a work containing the Program or a portion of it,
68
+either verbatim or with modifications and/or translated into another
69
+language.  (Hereinafter, translation is included without limitation in
70
+the term "modification".)  Each licensee is addressed as "you".
71
+
72
+Activities other than copying, distribution and modification are not
73
+covered by this License; they are outside its scope.  The act of
74
+running the Program is not restricted, and the output from the Program
75
+is covered only if its contents constitute a work based on the
76
+Program (independent of having been made by running the Program).
77
+Whether that is true depends on what the Program does.
78
+
79
+  1. You may copy and distribute verbatim copies of the Program's
80
+source code as you receive it, in any medium, provided that you
81
+conspicuously and appropriately publish on each copy an appropriate
82
+copyright notice and disclaimer of warranty; keep intact all the
83
+notices that refer to this License and to the absence of any warranty;
84
+and give any other recipients of the Program a copy of this License
85
+along with the Program.
86
+
87
+You may charge a fee for the physical act of transferring a copy, and
88
+you may at your option offer warranty protection in exchange for a fee.
89
+
90
+  2. You may modify your copy or copies of the Program or any portion
91
+of it, thus forming a work based on the Program, and copy and
92
+distribute such modifications or work under the terms of Section 1
93
+above, provided that you also meet all of these conditions:
94
+
95
+    a) You must cause the modified files to carry prominent notices
96
+    stating that you changed the files and the date of any change.
97
+
98
+    b) You must cause any work that you distribute or publish, that in
99
+    whole or in part contains or is derived from the Program or any
100
+    part thereof, to be licensed as a whole at no charge to all third
101
+    parties under the terms of this License.
102
+
103
+    c) If the modified program normally reads commands interactively
104
+    when run, you must cause it, when started running for such
105
+    interactive use in the most ordinary way, to print or display an
106
+    announcement including an appropriate copyright notice and a
107
+    notice that there is no warranty (or else, saying that you provide
108
+    a warranty) and that users may redistribute the program under
109
+    these conditions, and telling the user how to view a copy of this
110
+    License.  (Exception: if the Program itself is interactive but
111
+    does not normally print such an announcement, your work based on
112
+    the Program is not required to print an announcement.)
113
+
114
+These requirements apply to the modified work as a whole.  If
115
+identifiable sections of that work are not derived from the Program,
116
+and can be reasonably considered independent and separate works in
117
+themselves, then this License, and its terms, do not apply to those
118
+sections when you distribute them as separate works.  But when you
119
+distribute the same sections as part of a whole which is a work based
120
+on the Program, the distribution of the whole must be on the terms of
121
+this License, whose permissions for other licensees extend to the
122
+entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
+Thus, it is not the intent of this section to claim rights or contest
125
+your rights to work written entirely by you; rather, the intent is to
126
+exercise the right to control the distribution of derivative or
127
+collective works based on the Program.
128
+
129
+In addition, mere aggregation of another work not based on the Program
130
+with the Program (or with a work based on the Program) on a volume of
131
+a storage or distribution medium does not bring the other work under
132
+the scope of this License.
133
+
134
+  3. You may copy and distribute the Program (or a work based on it,
135
+under Section 2) in object code or executable form under the terms of
136
+Sections 1 and 2 above provided that you also do one of the following:
137
+
138
+    a) Accompany it with the complete corresponding machine-readable
139
+    source code, which must be distributed under the terms of Sections
140
+    1 and 2 above on a medium customarily used for software interchange; or,
141
+
142
+    b) Accompany it with a written offer, valid for at least three
143
+    years, to give any third party, for a charge no more than your
144
+    cost of physically performing source distribution, a complete
145
+    machine-readable copy of the corresponding source code, to be
146
+    distributed under the terms of Sections 1 and 2 above on a medium
147
+    customarily used for software interchange; or,
148
+
149
+    c) Accompany it with the information you received as to the offer
150
+    to distribute corresponding source code.  (This alternative is
151
+    allowed only for noncommercial distribution and only if you
152
+    received the program in object code or executable form with such
153
+    an offer, in accord with Subsection b above.)
154
+
155
+The source code for a work means the preferred form of the work for
156
+making modifications to it.  For an executable work, complete source
157
+code means all the source code for all modules it contains, plus any
158
+associated interface definition files, plus the scripts used to
159
+control compilation and installation of the executable.  However, as a
160
+special exception, the source code distributed need not include
161
+anything that is normally distributed (in either source or binary
162
+form) with the major components (compiler, kernel, and so on) of the
163
+operating system on which the executable runs, unless that component
164
+itself accompanies the executable.
165
+
166
+If distribution of executable or object code is made by offering
167
+access to copy from a designated place, then offering equivalent
168
+access to copy the source code from the same place counts as
169
+distribution of the source code, even though third parties are not
170
+compelled to copy the source along with the object code.
171
+
172
+  4. You may not copy, modify, sublicense, or distribute the Program
173
+except as expressly provided under this License.  Any attempt
174
+otherwise to copy, modify, sublicense or distribute the Program is
175
+void, and will automatically terminate your rights under this License.
176
+However, parties who have received copies, or rights, from you under
177
+this License will not have their licenses terminated so long as such
178
+parties remain in full compliance.
179
+
180
+  5. You are not required to accept this License, since you have not
181
+signed it.  However, nothing else grants you permission to modify or
182
+distribute the Program or its derivative works.  These actions are
183
+prohibited by law if you do not accept this License.  Therefore, by
184
+modifying or distributing the Program (or any work based on the
185
+Program), you indicate your acceptance of this License to do so, and
186
+all its terms and conditions for copying, distributing or modifying
187
+the Program or works based on it.
188
+
189
+  6. Each time you redistribute the Program (or any work based on the
190
+Program), the recipient automatically receives a license from the
191
+original licensor to copy, distribute or modify the Program subject to
192
+these terms and conditions.  You may not impose any further
193
+restrictions on the recipients' exercise of the rights granted herein.
194
+You are not responsible for enforcing compliance by third parties to
195
+this License.
196
+
197
+  7. If, as a consequence of a court judgment or allegation of patent
198
+infringement or for any other reason (not limited to patent issues),
199
+conditions are imposed on you (whether by court order, agreement or
200
+otherwise) that contradict the conditions of this License, they do not
201
+excuse you from the conditions of this License.  If you cannot
202
+distribute so as to satisfy simultaneously your obligations under this
203
+License and any other pertinent obligations, then as a consequence you
204
+may not distribute the Program at all.  For example, if a patent
205
+license would not permit royalty-free redistribution of the Program by
206
+all those who receive copies directly or indirectly through you, then
207
+the only way you could satisfy both it and this License would be to
208
+refrain entirely from distribution of the Program.
209
+
210
+If any portion of this section is held invalid or unenforceable under
211
+any particular circumstance, the balance of the section is intended to
212
+apply and the section as a whole is intended to apply in other
213
+circumstances.
214
+
215
+It is not the purpose of this section to induce you to infringe any
216
+patents or other property right claims or to contest validity of any
217
+such claims; this section has the sole purpose of protecting the
218
+integrity of the free software distribution system, which is
219
+implemented by public license practices.  Many people have made
220
+generous contributions to the wide range of software distributed
221
+through that system in reliance on consistent application of that
222
+system; it is up to the author/donor to decide if he or she is willing
223
+to distribute software through any other system and a licensee cannot
224
+impose that choice.
225
+
226
+This section is intended to make thoroughly clear what is believed to
227
+be a consequence of the rest of this License.
228
+
229
+  8. If the distribution and/or use of the Program is restricted in
230
+certain countries either by patents or by copyrighted interfaces, the
231
+original copyright holder who places the Program under this License
232
+may add an explicit geographical distribution limitation excluding
233
+those countries, so that distribution is permitted only in or among
234
+countries not thus excluded.  In such case, this License incorporates
235
+the limitation as if written in the body of this License.
236
+
237
+  9. The Free Software Foundation may publish revised and/or new versions
238
+of the General Public License from time to time.  Such new versions will
239
+be similar in spirit to the present version, but may differ in detail to
240
+address new problems or concerns.
241
+
242
+Each version is given a distinguishing version number.  If the Program
243
+specifies a version number of this License which applies to it and "any
244
+later version", you have the option of following the terms and conditions
245
+either of that version or of any later version published by the Free
246
+Software Foundation.  If the Program does not specify a version number of
247
+this License, you may choose any version ever published by the Free Software
248
+Foundation.
249
+
250
+  10. If you wish to incorporate parts of the Program into other free
251
+programs whose distribution conditions are different, write to the author
252
+to ask for permission.  For software which is copyrighted by the Free
253
+Software Foundation, write to the Free Software Foundation; we sometimes
254
+make exceptions for this.  Our decision will be guided by the two goals
255
+of preserving the free status of all derivatives of our free software and
256
+of promoting the sharing and reuse of software generally.
257
+
258
+                            NO WARRANTY
259
+
260
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
262
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
266
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
267
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268
+REPAIR OR CORRECTION.
269
+
270
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
+POSSIBILITY OF SUCH DAMAGES.
279
+
280
+                     END OF TERMS AND CONDITIONS
281
+
282
+            How to Apply These Terms to Your New Programs
283
+
284
+  If you develop a new program, and you want it to be of the greatest
285
+possible use to the public, the best way to achieve this is to make it
286
+free software which everyone can redistribute and change under these terms.
287
+
288
+  To do so, attach the following notices to the program.  It is safest
289
+to attach them to the start of each source file to most effectively
290
+convey the exclusion of warranty; and each file should have at least
291
+the "copyright" line and a pointer to where the full notice is found.
292
+
293
+    <one line to give the program's name and a brief idea of what it does.>
294
+    Copyright (C) <year>  <name of author>
295
+
296
+    This program is free software; you can redistribute it and/or modify
297
+    it under the terms of the GNU General Public License as published by
298
+    the Free Software Foundation; either version 2 of the License, or
299
+    (at your option) any later version.
300
+
301
+    This program is distributed in the hope that it will be useful,
302
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
304
+    GNU General Public License for more details.
305
+
306
+    You should have received a copy of the GNU General Public License along
307
+    with this program; if not, write to the Free Software Foundation, Inc.,
308
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+Also add information on how to contact you by electronic and paper mail.
311
+
312
+If the program is interactive, make it output a short notice like this
313
+when it starts in an interactive mode:
314
+
315
+    Gnomovision version 69, Copyright (C) year name of author
316
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+    This is free software, and you are welcome to redistribute it
318
+    under certain conditions; type `show c' for details.
319
+
320
+The hypothetical commands `show w' and `show c' should show the appropriate
321
+parts of the General Public License.  Of course, the commands you use may
322
+be called something other than `show w' and `show c'; they could even be
323
+mouse-clicks or menu items--whatever suits your program.
324
+
325
+You should also get your employer (if you work as a programmer) or your
326
+school, if any, to sign a "copyright disclaimer" for the program, if
327
+necessary.  Here is a sample; alter the names:
328
+
329
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+  <signature of Ty Coon>, 1 April 1989
333
+  Ty Coon, President of Vice
334
+
335
+This General Public License does not permit incorporating your program into
336
+proprietary programs.  If your program is a subroutine library, you may
337
+consider it more useful to permit linking proprietary applications with the
338
+library.  If this is what you want to do, use the GNU Lesser General
339
+Public License instead of this License.

+ 39
- 0
Makefile View File

@@ -0,0 +1,39 @@
1
+CC =		gcc
2
+CFLAGS =	-O2 -s -D_GNU_SOURCE
3
+LDLIBS =
4
+PREFIX =
5
+BINDIR =	$(PREFIX)/usr/bin
6
+
7
+all: cbsi
8
+	@echo "All done!"
9
+
10
+cbsi: buffer.o cbsi.o error.o mimetype.o subshell.o
11
+	$(CC) $(CFLAGS) $(LDLIBS) buffer.o cbsi.o error.o mimetype.o subshell.o -o cbsi
12
+
13
+buffer.o: buffer.c
14
+	$(CC) $(CFLAGS) -c buffer.c
15
+
16
+cbsi.o: cbsi.c
17
+	$(CC) $(CFLAGS) -c cbsi.c
18
+
19
+error.o: error.c
20
+	$(CC) $(CFLAGS) -c error.c
21
+
22
+mimetype.o: mimetype.c
23
+	$(CC) $(CFLAGS) -c mimetype.c
24
+
25
+subshell.o: subshell.c
26
+	$(CC) $(CFLAGS) -c subshell.c
27
+
28
+install:
29
+	mkdir -p $(BINDIR)
30
+	cp cbsi $(BINDIR)
31
+	@echo "All done!"
32
+
33
+uninstall:
34
+	@rm -f $(BINDIR)/cbsi
35
+	@echo "All done!"
36
+
37
+clean:
38
+	rm -f cbsi *.o
39
+	@echo "All done!"

+ 34
- 0
README View File

@@ -0,0 +1,34 @@
1
+CGI Bash Shell Interface
2
+========================
3
+
4
+CBSI is a small program that makes CGI programming in the Bash Shell a lot
5
+easier, or at least more tolerable. It is intended for Kagera Firmware, where
6
+other languages are too big.
7
+
8
+It parses POST and GET requests in addiction to COOKIES, placing elements as
9
+`name=value` pairs into the environment for the CGI script to use.
10
+
11
+It combines three features into an engine: 
12
+ * It opens a shell, and translates all text into printable statements. All
13
+   text within <% ... %> constructs are passed verbatim to the shell.
14
+ * It opens a shell, and prints the shell expression. Everything within
15
+   <%: ... %> tags are supposed to be parsed into 'echo' statement.
16
+ * It supports multilanguage and allows to easily put all texts within
17
+   <%@ ... %> tags to be quick and easily translated into chosen language.
18
+
19
+Additional parameters that can be passed to CBSI:
20
+ * --language-dir=pathspec  - specifies a directory where CBSI should look for
21
+                              scripts translations. Default value is
22
+                              '/usr/lib/kagera/langs'
23
+ * --shell=pathspec         - specifies an alternate bash-like shell to use.
24
+                              This defaults to '/bin/sh'
25
+ * --translation=filename   - specifies a dictionary filename to be loaded in
26
+                              addiction to common.dic from language directory.
27
+                              The extension is added automatically.
28
+ * --upload-dir=pathspec    - this specifies a temporary directory where all
29
+                              uploaded files are created. Defaults to '/tmp'
30
+ * --upload-limit=limit     - allows a mime-encoded file up to limit KB to be
31
+                              uploaded. The default value is 0KB (no limit).
32
+
33
+
34
+This software is based on Haserl <http://haserl.sourceforge.net/>.

+ 0
- 4
README.md View File

@@ -1,4 +0,0 @@
1
-cbsi
2
-====
3
-
4
-CGI Bash Shell Interface

+ 126
- 0
buffer.c View File

@@ -0,0 +1,126 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			buffer.c
5
+ * @PURPOSE			CBSI Buffers
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#include <stdio.h>
11
+#include <unistd.h>
12
+#include <stdlib.h>
13
+#include <string.h>
14
+#include <ctype.h>
15
+#include <errno.h>
16
+#include <fcntl.h>
17
+
18
+#include "buffer.h"
19
+
20
+void buffer_add(buffer_t* buf, const void* data, unsigned long size) {
21
+	unsigned long newsize;
22
+	unsigned long index;
23
+
24
+	if((buf->ptr + size) >= buf->limit) {
25
+		index = (buf->limit - buf->data);
26
+		newsize = index;
27
+		while(newsize <= index + size) {
28
+			newsize += 1024;
29
+		}
30
+		index = buf->ptr - buf->data;
31
+		buf->data = realloc(buf->data, newsize);
32
+		buf->limit = buf->data + newsize;
33
+		buf->ptr = buf->data + index;
34
+	}
35
+	memcpy(buf->ptr, data, size);
36
+	buf->ptr += size;
37
+}
38
+
39
+void buffer_destroy(buffer_t* buf) {
40
+	if(buf->data) {
41
+		free(buf->data);
42
+	}
43
+	buffer_init(buf);
44
+}
45
+
46
+void buffer_init(buffer_t* buf) {
47
+	buf->data = NULL;
48
+	buf->ptr = NULL;
49
+	buf->limit = NULL;
50
+}
51
+
52
+void buffer_reset(buffer_t* buf) {
53
+	if(buf->data) {
54
+		buf->ptr = buf->data;
55
+	} else {
56
+		buf->ptr = NULL;
57
+	}
58
+}
59
+
60
+void sbuffer_destroy(sbuffer_t* sbuf) {
61
+	free(sbuf->buf);
62
+}
63
+
64
+int sbuffer_init(sbuffer_t* sbuf, int size) {
65
+	sbuf->maxsize = size;
66
+	sbuf->buf = malloc (sbuf->maxsize);
67
+	sbuf->maxsize -= 1;
68
+	sbuf->fh = 0;
69
+	sbuf->eof = 0;
70
+	sbuf->len = 0;
71
+	sbuf->ptr = sbuf->buf;
72
+	sbuf->bufsize = 0;
73
+	sbuf->maxread = 0;
74
+	sbuf->nrread = 0;
75
+	return (sbuf->buf != NULL);
76
+}
77
+
78
+int sbuffer_read(sbuffer_t* sbuf, char* matchstr) {
79
+	int len, pos;
80
+	int r;
81
+
82
+	if((sbuf->eof) && (sbuf->ptr > sbuf->buf)) {
83
+		return 0;
84
+	}
85
+	if((sbuf->bufsize == 0) || (sbuf->ptr >= (sbuf->buf + sbuf->bufsize - strlen (matchstr)))) {
86
+		len = sbuf->bufsize - (sbuf->ptr - sbuf->buf);
87
+		if(len) {
88
+			memmove(sbuf->buf, sbuf->ptr, len);
89
+		}
90
+		sbuf->ptr = sbuf->buf;
91
+		sbuf->bufsize = len;
92
+		if(fcntl(sbuf->fh, F_GETFL) == -1) {
93
+			r = 0;
94
+		} else {
95
+			size_t n = sbuf->maxsize - len;
96
+			if(sbuf->maxread && sbuf->maxread < sbuf->nrread + n) {
97
+				n = sbuf->maxread - sbuf->nrread;
98
+			}
99
+			r = read(sbuf->fh, sbuf->buf + len, n);
100
+		}
101
+		if(r == 0 || (r < 0 && errno != EINTR)) {
102
+			sbuf->eof = -1;
103
+		} else {
104
+			sbuf->bufsize += (r > 0) ? r : 0;
105
+			sbuf->nrread += (r > 0) ? r : 0;
106
+		}
107
+	}
108
+	pos = 0;
109
+	len = sbuf->bufsize - (int) (sbuf->ptr - sbuf->buf) - strlen(matchstr);
110
+	while(memcmp(matchstr, sbuf->ptr + pos, strlen(matchstr)) && (pos < len)) {
111
+		pos++;
112
+	}
113
+	if(pos < len) {
114
+		sbuf->len = pos;
115
+		sbuf->segment = sbuf->ptr;
116
+		sbuf->ptr = sbuf->segment + pos + strlen(matchstr);
117
+		return -1;
118
+	}
119
+	if(sbuf->eof) {
120
+		len += strlen(matchstr);
121
+	}
122
+	sbuf->segment = sbuf->ptr;
123
+	sbuf->len = len;
124
+	sbuf->ptr += sbuf->len;
125
+	return (sbuf->eof) ? (-1) : (0);
126
+}

+ 40
- 0
buffer.h View File

@@ -0,0 +1,40 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			buffer.h
5
+ * @PURPOSE			CBSI Buffers
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#ifndef __BUFFER_H
11
+#define __BUFFER_H
12
+
13
+typedef struct {
14
+	unsigned char* data;
15
+	unsigned char* ptr;
16
+	unsigned char* limit;
17
+} buffer_t;
18
+
19
+typedef struct {
20
+	int fh;
21
+	unsigned char* buf;
22
+	unsigned char* ptr;
23
+	unsigned char* segment;
24
+	size_t len;
25
+	size_t maxsize;
26
+	size_t bufsize;
27
+	size_t maxread;
28
+	size_t nrread;
29
+	int eof;
30
+} sbuffer_t;
31
+
32
+void buffer_add(buffer_t* buf, const void* data, unsigned long size);
33
+void buffer_destroy(buffer_t* buf);
34
+void buffer_init(buffer_t* buf);
35
+void buffer_reset(buffer_t* buf);
36
+void sbuffer_destroy(sbuffer_t* sbuf);
37
+int sbuffer_init(sbuffer_t* sbuf, int size);
38
+int sbuffer_read(sbuffer_t* sbuf, char* matchstr);
39
+
40
+#endif

+ 658
- 0
cbsi.c View File

@@ -0,0 +1,658 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			cbsi.c
5
+ * @PURPOSE			Common CBSI
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#include <stdio.h>
11
+#include <unistd.h>
12
+#include <time.h>
13
+#include <getopt.h>
14
+#include <sys/mman.h>
15
+#include <sys/types.h>
16
+#include <sys/wait.h>
17
+#include <sys/stat.h>
18
+#include <sys/fcntl.h>
19
+#include <stdlib.h>
20
+#include <string.h>
21
+#include <grp.h>
22
+
23
+#include "common.h"
24
+#include "error.h"
25
+#include "buffer.h"
26
+#include "subshell.h"
27
+#include "mimetype.h"
28
+#include "cbsi.h"
29
+
30
+struct option ga_long_options[] = {
31
+	{"language-dir", required_argument, 0, 'l'},
32
+	{"translation", required_argument, 0, 't'},
33
+	{"upload-limit", required_argument, 0, 'u'},
34
+	{"upload-dir", required_argument, 0, 'd'},
35
+	{"shell", required_argument, 0, 's'},
36
+	{0, 0, 0, 0}
37
+};
38
+
39
+const char *gs_short_options = "+u:d:l:t:s:";
40
+
41
+int argc_argv(char* instr, argv_t** argv) {
42
+	char quote = '\0';
43
+	int arg_count = 0;
44
+	enum state_t { WHITESPACE, WORDSPACE, TOKENSTART } state = WHITESPACE;
45
+	argv_t* argv_array = NULL;
46
+	int argc_slots = 0;
47
+	size_t len, pos;
48
+
49
+	len = strlen(instr);
50
+	pos = 0;
51
+	while(pos < len) {
52
+		switch(*instr) {
53
+			case '"':
54
+			case '\'':
55
+				if(state == WHITESPACE) {
56
+					quote = *instr;
57
+					state = TOKENSTART;
58
+					if(*(instr + 1) == quote) {
59
+						quote = '\0';
60
+						*instr = '\0';
61
+						argv_array[arg_count].quoted = -1;
62
+					} else {
63
+						instr++;
64
+						pos++;
65
+					}
66
+				} else {
67
+					if(*instr == quote) {
68
+						argv_array[arg_count - 1].quoted = -1;
69
+						quote = '\0';
70
+						*instr = '\0';
71
+						state = WHITESPACE;
72
+					}
73
+				}
74
+				break;
75
+			case '\\':
76
+				if((quote) && (*(instr + 1) == quote)) {
77
+					memmove(instr, instr + 1, strlen(instr));
78
+					len--;
79
+				} else {
80
+					if(state == WHITESPACE) {
81
+						state = TOKENSTART;
82
+					}
83
+				}
84
+				break;
85
+			case ' ':
86
+			case '\t':
87
+			case '\r':
88
+			case '\n':
89
+				if((state == WORDSPACE) && (quote == '\0')) {
90
+					state = WHITESPACE;
91
+					*instr = '\0';
92
+				}
93
+				break;
94
+			case '\0':
95
+				break;
96
+			default:
97
+				if(state == WHITESPACE) {
98
+					state = TOKENSTART;
99
+				}
100
+		}
101
+		if(state == TOKENSTART) {
102
+			arg_count++;
103
+			if(arg_count > argc_slots) {
104
+				argc_slots += ALLOC_CHUNK;
105
+				argv_array = (argv_t*) xrealloc(argv_array, sizeof(argv_t) * (argc_slots + ALLOC_CHUNK));
106
+			}
107
+			if(argv_array == NULL) {
108
+				return -1;
109
+			}
110
+			argv_array[arg_count - 1].string = instr;
111
+			argv_array[arg_count].quoted = 0;
112
+			state = WORDSPACE;
113
+		}
114
+		instr++;
115
+		pos++;
116
+	}
117
+	argv_array[arg_count].string = NULL;
118
+	*argv = argv_array;
119
+	return arg_count;
120
+}
121
+
122
+void assignGlobalStartupValues() {
123
+	global.uploadkb = -1;
124
+	global.shell = SUBSHELL_CMD;
125
+	global.langdir = LANGDIR;
126
+	global.translation = NULL;
127
+	global.uploaddir = TEMPDIR;
128
+	global.uploadlist = NULL;
129
+	global.file_prefix = "FILE_";
130
+	global.filename_prefix = "FILENAME_";
131
+	global.get_prefix = "GET_";
132
+	global.post_prefix = "POST_";
133
+	global.cbsi_prefix = "CBSI_";
134
+	global.cookie_prefix = "COOKIE_";
135
+	global.null_prefix = "";
136
+}
137
+
138
+int BecomeUser(uid_t uid, gid_t gid) {
139
+	if(getuid() == 0) {
140
+		setgroups(1, &gid);
141
+	}
142
+	setgid(gid);
143
+	setgid(getgid());
144
+	setuid(uid);
145
+	setuid(getuid());
146
+	return 0;
147
+}
148
+
149
+void cbsiflags(list_t* env) {
150
+	char buf[200];
151
+
152
+	snprintf(buf, 200, "UPLOAD_DIR=%s", global.uploaddir);
153
+	myputenv(env, buf, global.cbsi_prefix);
154
+	snprintf(buf, 200, "UPLOAD_LIMIT=%lu", global.uploadkb);
155
+	myputenv(env, buf, global.cbsi_prefix);
156
+	snprintf(buf, 200, "SHELL=%s", global.shell);
157
+	myputenv(env, buf, global.cbsi_prefix);
158
+}
159
+
160
+void cleanup(void) {
161
+	int i;
162
+
163
+	if(global.uploadlist) {
164
+		unlink_uploadlist();
165
+		free_token_list(global.uploadlist);
166
+		global.uploadlist = NULL;
167
+	}
168
+	if(language != NULL && translations > 0) {
169
+		for (i = 0; i < HASH_BUF; ++i) {
170
+			if(ltable[i]) {
171
+				free(ltable[i]->msgid);
172
+				free(ltable[i]->msgstr);
173
+				free(ltable[i]);
174
+			}
175
+		}
176
+	}
177
+}
178
+
179
+void CookieVars(list_t* env) {
180
+	char* qs;
181
+	char* token;
182
+
183
+	if(getenv("HTTP_COOKIE") != NULL) {
184
+		qs = strdup(getenv("HTTP_COOKIE"));
185
+	} else {
186
+		return;
187
+	}
188
+	token = strtok(qs, ";");
189
+	while(token) {
190
+		while(token[0] == ' ') {
191
+			token++;
192
+		}
193
+		myputenv(env, token, global.cookie_prefix);
194
+		token = strtok(NULL, ";");
195
+	}
196
+	free(qs);
197
+}
198
+
199
+int count_lines(char* instr, size_t len, char* where) {
200
+	size_t line = 1;
201
+
202
+	while((where > instr) && (len)) {
203
+		if(*instr == '\n') {
204
+			line++;
205
+		}
206
+		len--;
207
+		instr++;
208
+	}
209
+	return line;
210
+}
211
+
212
+char* find_whitespace(char* instr) {
213
+	while(!isspace(*instr) && *instr) {
214
+		instr++;
215
+	}
216
+	return instr;
217
+}
218
+
219
+void free_list_chain(list_t* list) {
220
+	list_t *next;
221
+
222
+	while(list) {
223
+		next = list->next;
224
+		free(list->buf);
225
+		free(list);
226
+		list = next;
227
+	}
228
+}
229
+
230
+unsigned short generateHash(char* str) {
231
+	unsigned long hash = 5381;
232
+	int c;
233
+
234
+	while(c = *str++) {
235
+		hash = ((hash << 5) + hash) + c;
236
+	}
237
+	return hash % HASH_BUF;
238
+}
239
+
240
+void loadDictionary(const char* filename) {
241
+	char* b;
242
+	FILE* fp;
243
+	short hash;
244
+	char msgid[TRANS_BUF];
245
+	char msgstr[TRANS_BUF];
246
+	lstr* p;
247
+	lstr* s;
248
+
249
+	sprintf(buffer, "%s/%s/%s.dic", global.langdir, language, filename);
250
+	if((fp = fopen(buffer, "r")) != NULL) {
251
+		memset(ltable, 0, sizeof(lstr*) * HASH_BUF);
252
+		memset(msgid, '\0', TRANS_BUF);
253
+		memset(msgstr, '\0', TRANS_BUF);
254
+		while(!feof(fp) && (fgets(buffer, TRANS_BUF - 1, fp) != NULL)) {
255
+			b = skip_whitespace(buffer);
256
+			if((!*b) || (*b == '#')) {
257
+				continue;
258
+			}
259
+			if(strstr(b, "msgid") != NULL) {
260
+				b = trim(b + 5);
261
+				strncpy(msgid, b, strlen(b) + 1);
262
+			} else if(strstr(b, "msgstr") != NULL) {
263
+				b = trim(b + 6);
264
+				strncpy(msgstr, b, strlen(b) + 1);
265
+			} else {
266
+				continue;
267
+			}
268
+			if(msgid[0] != 0 && msgstr[0] != 0) {
269
+				hash = generateHash(msgid);
270
+				s = malloc(sizeof(lstr));
271
+				s->msgid = (char*) malloc(strlen(msgid) + 1);
272
+				s->msgstr = (char*) malloc(strlen(msgstr) + 1);
273
+				strcpy(s->msgid, msgid);
274
+				strcpy(s->msgstr, msgstr);
275
+				s->next = NULL;
276
+				if(ltable[hash] == NULL) {
277
+					ltable[hash] = s;
278
+				} else {
279
+					for(p = ltable[hash]; p->next != NULL; p = p->next);
280
+					p->next = s;
281
+				}
282
+				translations++;
283
+				msgid[0] = 0;
284
+				msgstr[0] = 0;
285
+			}
286
+		}
287
+		fclose(fp);
288
+	}
289
+}
290
+
291
+void lowercase(char* instr) {
292
+	while(*instr != '\0') {
293
+		*instr = tolower (*instr);
294
+		instr++;
295
+	}
296
+}
297
+
298
+int main(int argc, char* argv[]) {
299
+	token_t* tokenchain = NULL;
300
+	buffer_t script_text;
301
+	script_t* scriptchain;
302
+	int retval = 0;
303
+	char* filename = NULL;
304
+	argv_t* av = NULL;
305
+	char** av2 = argv;
306
+	int av2c = argc;
307
+	int command;
308
+	int count;
309
+	list_t* env = NULL;
310
+
311
+	if(atexit(cleanup) != 0) {
312
+		die_with_message(NULL, NULL, "atexit() failed");
313
+	}
314
+	assignGlobalStartupValues();
315
+	buffer_init(&script_text);
316
+	switch(argc) {
317
+		case 1:
318
+			puts("This is CBSI version " CBSI_VERSION "\nThis program runs as a CGI interface, not interactively.\n");
319
+			return 0;
320
+			break;
321
+		default:
322
+			command = argc_argv(argv[1], &av);
323
+			if(command > 1) {
324
+				av2c = argc - 1 + command;
325
+				av2 = xmalloc(sizeof(char*) * av2c);
326
+				av2[0] = argv[0];
327
+				for(count = 1; count <= command; count++) {
328
+					av2[count] = av[count - 1].string;
329
+				}
330
+				for(; count < av2c; count++) {
331
+					av2[count] = argv[count - command + 1];
332
+				}
333
+			}
334
+			parseCommandLine(av2c, av2);
335
+			free(av);
336
+			if(av2 != argv) {
337
+				free(av2);
338
+			}
339
+			if(optind < av2c) {
340
+				filename = av2[optind];
341
+			} else {
342
+				die_with_message(NULL, NULL, "No script file specified");
343
+			}
344
+			break;
345
+	}
346
+	scriptchain = load_script(filename, NULL);
347
+	BecomeUser(scriptchain->uid, scriptchain->gid);
348
+	env = wcversion(env);
349
+	readenv(env);
350
+	sessionid(env);
351
+	cbsiflags(env);
352
+	prepareDictionary();
353
+	tokenchain = build_token_list(scriptchain, NULL);
354
+	preprocess_token_list(tokenchain);
355
+	CookieVars(env);
356
+	ReadCGIPOSTValues(env);
357
+	ReadCGIQueryString(env);
358
+	process_token_list(&script_text, tokenchain);
359
+	subshell_setup(global.shell, env);
360
+	subshell_doscript(&script_text, scriptchain->name);
361
+	subshell_destroy();
362
+	buffer_destroy(&script_text);
363
+	free_token_list(tokenchain);
364
+	free_list_chain(env);
365
+	free_script_list(scriptchain);
366
+	return 0;
367
+}
368
+
369
+list_t* myputenv(list_t* cur, char* str, char* prefix) {
370
+	list_t* prev = NULL;
371
+	size_t keylen;
372
+	char* entry = NULL;
373
+	char* temp = NULL;
374
+	int array = 0;
375
+	int len;
376
+
377
+	temp = memchr(str, '=', strlen(str));
378
+	if(temp == 0) {
379
+		return cur;
380
+	}
381
+	keylen = (size_t) (temp - str);
382
+	if(memcmp(str + keylen - 2, "[]", 2) == 0) {
383
+		keylen = keylen - 2;
384
+		array = 1;
385
+	}
386
+	entry = xmalloc(strlen (str) + strlen(prefix) + 1);
387
+	entry[0] = '\0';
388
+	if(strlen(prefix)) {
389
+		strncat(entry, prefix, strlen(prefix));
390
+	}
391
+	if(array == 1) {
392
+		strncat(entry, str, keylen);
393
+		strcat(entry, str + keylen + 2);
394
+	} else {
395
+		strcat(entry, str);
396
+	}
397
+	len = keylen + strlen(prefix) + 1;
398
+	while(cur != NULL) {
399
+		if(memcmp(cur->buf, entry, len) == 0) {
400
+			if(array == 1) {
401
+				temp = xmalloc(strlen(cur->buf) + strlen(entry) - len + 2);
402
+				memmove(temp, cur->buf, strlen(cur->buf) + 1);
403
+				strcat(temp, "\n");
404
+				strcat(temp, str + keylen + 3);
405
+				free(entry);
406
+				entry = temp;
407
+			}
408
+			free(cur->buf);
409
+			if(prev != NULL) {
410
+				prev->next = cur->next;
411
+			}
412
+			free(cur);
413
+			cur = prev;
414
+		}
415
+		prev = cur;
416
+		if(cur) {
417
+			cur = (list_t*) cur->next;
418
+		}
419
+	}
420
+	cur = xmalloc(sizeof(list_t));
421
+	cur->buf = entry;
422
+	if(prev != NULL) {
423
+		prev->next = cur;
424
+	}
425
+	return cur;
426
+}
427
+
428
+int parseCommandLine(int argc, char *argv[]) {
429
+	int c;
430
+	int option_index = 0;
431
+
432
+	optopt = 0;
433
+	optind = 0;
434
+	while((c = getopt_long(argc, argv, gs_short_options, ga_long_options, &option_index)) != -1) {
435
+		switch(c) {
436
+			case 's':
437
+				global.shell = optarg;
438
+				break;
439
+			case 'u':
440
+				global.uploadkb = atoi (optarg);
441
+				break;
442
+			case 'l':
443
+				global.langdir = optarg;
444
+				break;
445
+			case 't':
446
+				global.translation = optarg;
447
+				break;
448
+			case 'd':
449
+				global.uploaddir = optarg;
450
+				break;
451
+		}
452
+	}
453
+	return optind;
454
+}
455
+
456
+void prepareDictionary() {
457
+	translations = 0;
458
+	if(getenv("WEBUI_LANGUAGE") != NULL) {
459
+		language = strdup(getenv("WEBUI_LANGUAGE"));
460
+		if(global.translation != NULL) {
461
+			loadDictionary(global.translation);
462
+		} else {
463
+			loadDictionary("common");
464
+		}
465
+	}
466
+}
467
+
468
+int ReadCGIPOSTValues(list_t* env) {
469
+	size_t content_length = 0;
470
+	size_t max_len;
471
+	size_t i, j, x;
472
+	sbuffer_t sbuf;
473
+	buffer_t token;
474
+	unsigned char* data;
475
+	const char* CONTENT_LENGTH = "CONTENT_LENGTH";
476
+
477
+	if((getenv(CONTENT_LENGTH) == NULL) || (strtoul(getenv(CONTENT_LENGTH), NULL, 10) == 0)) {
478
+		return 0;
479
+	}
480
+	if(getenv("CONTENT_TYPE")) {
481
+		if(strncasecmp(getenv("CONTENT_TYPE"), "multipart/form-data", 19) == 0) {
482
+			i = rfc2388_handler(env);
483
+			return i;
484
+		}
485
+	}
486
+	sbuffer_init(&sbuf, 32768);
487
+	sbuf.fh = STDIN;
488
+	if(getenv(CONTENT_LENGTH)) {
489
+		sbuf.maxread = strtoul(getenv(CONTENT_LENGTH), NULL, 10);
490
+	}
491
+	buffer_init(&token);
492
+	max_len = ((global.uploadkb == 0) ? 2048 : abs(global.uploadkb)) * 1024;
493
+	do {
494
+		x = sbuffer_read(&sbuf, "&");
495
+		content_length += sbuf.len;
496
+		if(content_length >= max_len && global.uploadkb != -1) {
497
+			die_with_message(NULL, NULL, "Attempted to send content larger than allowed limits.");
498
+		}
499
+		if((x == 0) || (token.data)) {
500
+			buffer_add(&token, (char*) sbuf.segment, sbuf.len);
501
+		}
502
+		if(x) {
503
+			data = sbuf.segment;
504
+			sbuf.segment[sbuf.len] = '\0';
505
+			if(token.data) {
506
+				buffer_add(&token, sbuf.segment + sbuf.len, 1);
507
+				data = token.data;
508
+			}
509
+			j = strlen((char*) data);
510
+			for(i = 0; i <= j; i++) {
511
+				if(data[i] == '+') {
512
+					data[i] = ' ';
513
+				}
514
+			}
515
+			unescape_url((char*) data);
516
+			myputenv(env, (char*) data, global.post_prefix);
517
+			if(token.data) {
518
+				buffer_reset(&token);
519
+			}
520
+		}
521
+	} while(!sbuf.eof);
522
+	sbuffer_destroy(&sbuf);
523
+	buffer_destroy(&token);
524
+	return 0;
525
+}
526
+
527
+int ReadCGIQueryString(list_t* env) {
528
+	char* qs;
529
+	char* token;
530
+	int i;
531
+
532
+	if(getenv("QUERY_STRING") != NULL) {
533
+		qs = strdup(getenv("QUERY_STRING"));
534
+	} else {
535
+		return 0;
536
+	}
537
+	for(i = 0; qs[i]; i++) {
538
+		if(qs[i] == '+') {
539
+			qs[i] = ' ';
540
+		}
541
+	}
542
+	token = strtok(qs, "&;");
543
+	while(token) {
544
+		unescape_url(token);
545
+		myputenv(env, token, global.get_prefix);
546
+		token = strtok(NULL, "&;");
547
+	}
548
+	free(qs);
549
+	return 0;
550
+}
551
+
552
+void readenv(list_t* env) {
553
+	extern char** environ;
554
+	int count = 0;
555
+
556
+	while(environ[count] != NULL) {
557
+		myputenv(env, environ[count], global.null_prefix);
558
+		count++;
559
+	}
560
+}
561
+
562
+void sessionid(list_t* env) {
563
+	char session[29];
564
+
565
+	sprintf(session, "SESSIONID=%x%x", getpid(), (int) time(NULL));
566
+	myputenv(env, session, global.cbsi_prefix);
567
+}
568
+
569
+char* skip_whitespace(char* instr) {
570
+	while(isspace(*instr) && *instr) {
571
+		instr++;
572
+	}
573
+	return instr;
574
+}
575
+
576
+char* trim(char* str) {
577
+	char* end;
578
+
579
+	while(isspace(*str) || *str == '"') {
580
+		str++;
581
+	}
582
+	if(*str == 0) {
583
+		return str;
584
+	}
585
+	end = str + strlen(str) - 1;
586
+	while(end > str && (isspace(*end) || *end == '"')) {
587
+		end--;
588
+	}
589
+	*(end + 1) = 0;
590
+	return str;
591
+}
592
+
593
+void unescape_url(char* url) {
594
+	int i, j;
595
+
596
+	for(i = 0, j = 0; url[j]; ++i, ++j) {
597
+		if((url[i] = url[j]) != '%') {
598
+			continue;
599
+		}
600
+		if(!url[j + 1] || !url[j + 2]) {
601
+			break;
602
+		}
603
+		url[i] = x2c(&url[j + 1]);
604
+		j += 2;
605
+	}
606
+	url[i] = '\0';
607
+}
608
+
609
+void unlink_uploadlist() {
610
+	token_t* me;
611
+	me = global.uploadlist;
612
+
613
+	while(me) {
614
+		unlink(me->buf);
615
+		free(me->buf);
616
+		me = me->next;
617
+	}
618
+}
619
+
620
+void uppercase(char* instr) {
621
+	while(*instr != '\0') {
622
+		*instr = toupper(*instr);
623
+		instr++;
624
+	}
625
+}
626
+
627
+list_t* wcversion(list_t* env) {
628
+	char version[200];
629
+
630
+	sprintf(version, "VERSION=%s", CBSI_VERSION);
631
+	return(myputenv(env, version, global.cbsi_prefix));
632
+}
633
+
634
+char x2c(char* what) {
635
+	char digit;
636
+
637
+	digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
638
+	digit *= 16;
639
+	digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
640
+	return digit;
641
+}
642
+
643
+void* xmalloc(size_t size) {
644
+	void* buf;
645
+
646
+	if((buf = malloc(size)) == NULL) {
647
+		die_with_message(NULL, NULL, g_err_msg[E_MALLOC_FAIL]);
648
+	}
649
+	memset(buf, 0, size);
650
+	return buf;
651
+}
652
+
653
+void* xrealloc(void* buf, size_t size) {
654
+	if((buf = realloc(buf, size)) == NULL) {
655
+		die_with_message(NULL, NULL, g_err_msg[E_MALLOC_FAIL]);
656
+	}
657
+	return buf;
658
+}

+ 74
- 0
cbsi.h View File

@@ -0,0 +1,74 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			cbsi.h
5
+ * @PURPOSE			Common CBSI
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#ifndef __CBSI_H
11
+#define __CBSI_H
12
+
13
+typedef struct {
14
+	unsigned long uploadkb;
15
+	char* shell;
16
+	char* langdir;
17
+	char* translation;
18
+	char* uploaddir;
19
+	char* uploadhandler;
20
+	char* file_prefix;
21
+	char* filename_prefix;
22
+	char* get_prefix;
23
+	char* post_prefix;
24
+	char* cookie_prefix;
25
+	char* null_prefix;
26
+	char* cbsi_prefix;
27
+	token_t* uploadlist;
28
+	int debug;
29
+	int acceptall;
30
+	int silent;
31
+} cbsi_t;
32
+
33
+typedef struct lstr {
34
+	char* msgid;
35
+	char* msgstr;
36
+	struct lstr* next;
37
+} lstr;
38
+
39
+cbsi_t global;
40
+char buffer[TRANS_BUF];
41
+char* language;
42
+lstr* ltable[HASH_BUF];
43
+int translations;
44
+
45
+int argc_argv(char* instr, argv_t** argv);
46
+void assignGlobalStartupValues(void);
47
+int BecomeUser(uid_t uid, gid_t gid);
48
+void cbsiflags(list_t* env);
49
+void cleanup(void);
50
+void CookieVars(list_t* env);
51
+int count_lines(char* instr, size_t len, char* where);
52
+char* find_whitespace (char* instr);
53
+void free_list_chain(list_t* env);
54
+unsigned short generateHash(char* str);
55
+void loadDictionary(const char* filename);
56
+void lowercase(char* instr);
57
+list_t* myputenv(list_t* cur, char* str, char* prefix);
58
+int parseCommandLine(int argc, char* argv[]);
59
+void prepareDictionary();
60
+int ReadCGIPOSTValues(list_t* env);
61
+int ReadCGIQueryString(list_t* env);
62
+void readenv(list_t* env);
63
+void sessionid(list_t* env);
64
+char* skip_whitespace (char* instr);
65
+char* trim(char* str);
66
+void unescape_url(char* url);
67
+void unlink_uploadlist(void);
68
+void uppercase(char* instr);
69
+list_t* wcversion(list_t* env);
70
+char x2c(char* what);
71
+void* xmalloc(size_t size);
72
+void* xrealloc(void* buf, size_t size);
73
+
74
+#endif

+ 38
- 0
common.h View File

@@ -0,0 +1,38 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			common.h
5
+ * @PURPOSE			Common CBSI
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#ifndef __COMMON_H
11
+#define __COMMON_H
12
+
13
+#define ALLOC_CHUNK	10
14
+
15
+#define CBSI_VERSION "0.91"
16
+
17
+#define STDIN	0
18
+#define STDOUT  1
19
+#define STDERR	2
20
+
21
+#define HASH_BUF 1536
22
+#define TRANS_BUF 2048
23
+
24
+#define LANGDIR "/usr/lib/kagera/langs"
25
+#define SUBSHELL_CMD "/bin/sh"
26
+#define TEMPDIR "/tmp"
27
+
28
+typedef struct {
29
+	char* string;
30
+	unsigned char quoted;
31
+} argv_t;
32
+
33
+typedef struct {
34
+	char* buf;
35
+	void* next;
36
+} list_t;
37
+
38
+#endif

+ 57
- 0
error.c View File

@@ -0,0 +1,57 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			error.c
5
+ * @PURPOSE			Error handling
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#include <stdio.h>
11
+#include <unistd.h>
12
+#include <stdlib.h>
13
+#include <string.h>
14
+#include <ctype.h>
15
+#include <stdarg.h>
16
+
17
+#include "common.h"
18
+#include "buffer.h"
19
+#include "subshell.h"
20
+#include "cbsi.h"
21
+#include "error.h"
22
+
23
+char* g_err_msg[] = {
24
+	"",
25
+	"Memory Allocation Failure",
26
+	"Unable to open file %s",
27
+	"%c&gt; before &lt;%c",
28
+	"Missing %c&gt;",
29
+	"Unknown operation",
30
+	"Unable to start subshell",
31
+	"Unspecified Error",
32
+};
33
+
34
+void die_with_error(char* msg) {
35
+	fprintf(stderr, "Error: %s\n", msg);
36
+	exit(-1);
37
+}
38
+
39
+void die_with_message(void* sp, char* where, const char* s, ...) {
40
+	script_t* script = sp;
41
+	va_list p;
42
+	FILE* fo = stderr;
43
+
44
+	fo = stdout;
45
+	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");
46
+	va_start(p, s);
47
+	vfprintf(fo, s, p);
48
+	va_end(p);
49
+	if(where && sp) {
50
+		fprintf(fo, " near line %d of %s\n",
51
+		count_lines(script->buf, script->size, where),
52
+		script->name);
53
+	}
54
+	printf("\n");
55
+	fprintf(fo, "</pre></body></html>\n");
56
+	exit(-1);
57
+}

+ 19
- 0
error.h View File

@@ -0,0 +1,19 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			error.h
5
+ * @PURPOSE			Error handling
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#ifndef __ERROR_H
11
+#define __ERROR_H
12
+
13
+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 };
14
+extern char *g_err_msg[];
15
+
16
+void die_with_error(char* msg);
17
+void die_with_message(void* sp, char* where, const char* s, ...);
18
+
19
+#endif

+ 346
- 0
mimetype.c View File

@@ -0,0 +1,346 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			mimetype.c
5
+ * @PURPOSE			Mimetype and file upload handler
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#include <stdio.h>
11
+#include <unistd.h>
12
+#include <time.h>
13
+#include <sys/mman.h>
14
+#include <sys/types.h>
15
+#include <sys/wait.h>
16
+#include <sys/stat.h>
17
+#include <sys/fcntl.h>
18
+#include <stdlib.h>
19
+#include <string.h>
20
+
21
+#include "common.h"
22
+#include "buffer.h"
23
+#include "error.h"
24
+#include "subshell.h"
25
+#include "buffer.h"
26
+#include "mimetype.h"
27
+#include "cbsi.h"
28
+
29
+void empty_stdin(void) {
30
+	char c[2000];
31
+	while(read(STDIN_FILENO, &c, 2000)) {
32
+	}
33
+}
34
+
35
+void mime_var_init(mime_var_t* obj) {
36
+	obj->name = NULL;
37
+	obj->filename = NULL;
38
+	obj->type = NULL;
39
+	obj->tempname = NULL;
40
+	buffer_init(&(obj->value));
41
+	obj->fh = 0;
42
+}
43
+
44
+void mime_var_destroy(mime_var_t* obj) {
45
+	int status;
46
+	struct sigaction new_action;
47
+
48
+	if(obj->name) {
49
+		free(obj->name);
50
+		obj->name = NULL;
51
+	}
52
+	if(obj->filename) {
53
+		free(obj->filename);
54
+		obj->filename = NULL;
55
+	}
56
+	if(obj->type) {
57
+		free(obj->type);
58
+		obj->type = NULL;
59
+	}
60
+	if(obj->tempname) {
61
+		free(obj->tempname);
62
+		obj->tempname = NULL;
63
+	}
64
+	buffer_destroy(&(obj->value));
65
+	if(obj->fh) {
66
+		close(abs(obj->fh));
67
+		obj->fh = 0;
68
+	}
69
+}
70
+
71
+char* mime_substr(char* start, int len) {
72
+	char* ptr;
73
+
74
+	if(!start) {
75
+		return NULL;
76
+	}
77
+	if(len < 0) {
78
+		return NULL;
79
+	}
80
+	ptr = xmalloc(len + 2);
81
+	memcpy(ptr, start, len);
82
+	return ptr;
83
+}
84
+
85
+void mime_tag_add(mime_var_t* obj, char* str) {
86
+	char* a = NULL;
87
+	char* b = NULL;
88
+	static char* tag[] = { "name=\"", "filename=\"", "Content-Type: " };
89
+
90
+	a = strcasestr(str, tag[0]);
91
+	if(a) {
92
+		a += strlen(tag[0]);
93
+		b = strchr(a, '"');
94
+		if(!obj->name) {
95
+			obj->name = mime_substr(a, b - a);
96
+		}
97
+	}
98
+	a = strcasestr(str, tag[1]);
99
+	if(a) {
100
+		a += strlen(tag[1]);
101
+		b = strchr(a, '"');
102
+		if(!obj->filename) {
103
+			obj->filename = mime_substr(a, b - a);
104
+		}
105
+	}
106
+	a = strcasestr(str, tag[2]);
107
+	if(a) {
108
+		a += strlen(tag[2]);
109
+		b = a + strlen(a);
110
+		if(!obj->type) {
111
+			obj->type = mime_substr(a, b - a);
112
+		}
113
+	}
114
+}
115
+
116
+void mime_var_putenv(list_t* env, mime_var_t* obj) {
117
+	buffer_t buf;
118
+
119
+	buffer_init(&buf);
120
+	if(obj->filename) {
121
+		buffer_add(&buf, obj->name, strlen(obj->name));
122
+		buffer_add(&buf, "=", 1);
123
+		buffer_add(&buf, (char*) obj->value.data,
124
+		strlen((char*) obj->value.data) + 1);
125
+		myputenv(env, (char*) buf.data, global.file_prefix);
126
+		buffer_reset(&buf);
127
+		buffer_add(&buf, obj->name, strlen(obj->name));
128
+		buffer_add(&buf, "=", 1);
129
+		buffer_add(&buf, obj->filename, strlen(obj->filename) + 1);
130
+		myputenv(env, (char*) buf.data, global.filename_prefix);
131
+		buffer_reset (&buf);
132
+	} else if(obj->name) {
133
+		buffer_add(&(obj->value), "", 1);
134
+		buffer_add(&buf, obj->name, strlen(obj->name));
135
+		buffer_add(&buf, "=", 1);
136
+		buffer_add(&buf, (char*) obj->value.data,
137
+		strlen((char*) obj->value.data) + 1);
138
+		myputenv(env, (char*) buf.data, global.file_prefix);
139
+		buffer_reset(&buf);
140
+	}
141
+	buffer_destroy(&buf);
142
+}
143
+
144
+void mime_exec(mime_var_t* obj, char* fifo) {
145
+	int pid;
146
+	char* type;
147
+	char* filename;
148
+	char* name;
149
+	char *c;
150
+	int fh;
151
+	struct sigaction new_action;
152
+
153
+	pid = fork();
154
+	if(pid == -1) {
155
+		empty_stdin();
156
+		die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]);
157
+	}
158
+	if(pid == 0) {
159
+		if(obj->type) {
160
+			type = xmalloc(13 + strlen(obj->type) + 1);
161
+			sprintf(type, "CONTENT_TYPE=%s", obj->type);
162
+			putenv(type);
163
+		}
164
+		if(obj->filename) {
165
+			filename = xmalloc (9 + strlen(obj->filename) + 1);
166
+			sprintf(filename, "FILENAME=%s", obj->filename);
167
+			putenv(filename);
168
+		}
169
+		if(obj->name) {
170
+			name = xmalloc(5 + strlen(obj->name) + 1);
171
+			sprintf(name, "NAME=%s", obj->name);
172
+			putenv(name);
173
+		}
174
+		fh = open(fifo, O_RDONLY);
175
+		while(read(fh, &c, 1)) {
176
+		}
177
+		exit(-1);
178
+	} else {
179
+		new_action.sa_handler = SIG_IGN;
180
+		sigemptyset(&new_action.sa_mask);
181
+		new_action.sa_flags = 0;
182
+		sigaction(SIGPIPE, &new_action, NULL);
183
+	}
184
+}
185
+
186
+void mime_var_open_target(mime_var_t* obj) {
187
+	char* tmpname;
188
+	token_t* curtoken;
189
+	curtoken = global.uploadlist;
190
+	int ok;
191
+
192
+	if(global.uploadkb == 0) {
193
+		empty_stdin();
194
+		die_with_message(NULL, NULL, "File uploads are not allowed.");
195
+	}
196
+	ok = -1;
197
+	tmpname = xmalloc(strlen(global.uploaddir) + 8);
198
+	strcpy(tmpname, global.uploaddir);
199
+	strcat(tmpname, "/XXXXXX");
200
+	obj->fh = mkstemp(tmpname);
201
+	if(obj->fh == -1) {
202
+		ok = 0;
203
+	}
204
+	buffer_add(&(obj->value), tmpname, strlen(tmpname));
205
+	if(!ok) {
206
+		empty_stdin();
207
+		die_with_message(NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], tmpname);
208
+	}
209
+	curtoken = push_token_on_list(curtoken, NULL, tmpname, strlen(tmpname) + 1);
210
+	if(global.uploadlist == NULL) {
211
+		global.uploadlist = curtoken;
212
+	}
213
+}
214
+
215
+void mime_var_writer(mime_var_t* obj, char* str, int len) {
216
+	int err;
217
+
218
+	if(!obj->filename) {
219
+		buffer_add(&(obj->value), str, len);
220
+	}
221
+	if((!obj->fh) && (obj->filename)) {
222
+		mime_var_open_target(obj);
223
+	}
224
+	if(obj->fh > 0) {
225
+		err = write(obj->fh, str, len);
226
+		if(err == -1) {
227
+			obj->fh = abs(obj->fh) * -1;
228
+		}
229
+	}
230
+}
231
+
232
+int rfc2388_handler(list_t* env) {
233
+	enum mime_state_t { DISCARD, BOUNDARY, HEADER, CONTENT };
234
+	int state;
235
+	int i, x;
236
+	unsigned long max_len, content_length;
237
+	sbuffer_t sbuf;
238
+	char* crlf = "\r\n";
239
+	char* boundary;
240
+	char* str;
241
+	buffer_t buf;
242
+	mime_var_t var;
243
+
244
+	str = getenv("CONTENT_TYPE");
245
+	i = strlen(str) - 9;
246
+	while((i >= 0) && (memcmp("boundary=", str + i, 9))) {
247
+		i--;
248
+	}
249
+	if(i == -1) {
250
+		empty_stdin();
251
+		die_with_message(NULL, NULL, "No Mime Boundary Information Found");
252
+	}
253
+	i = i + 9;
254
+	if(str[i] == '"') {
255
+		i++;
256
+	}
257
+	boundary = xmalloc(strlen(str + i) + 5);
258
+	memcpy(boundary, crlf, 2);
259
+	memcpy(boundary + 2, "--", 2);
260
+	memcpy(boundary + 4, str + i, strlen(str + i) + 1);
261
+	if((i > 0) && (str[i - 1] == '"')) {
262
+		while((boundary[i]) && (boundary[i] != '"')) {
263
+			i++;
264
+		}
265
+		boundary[i] = '\0';
266
+	}
267
+	max_len = ((global.uploadkb == 0) ? 2048 : abs(global.uploadkb)) * 1024;
268
+	content_length = 0;
269
+	sbuffer_init(&sbuf, 1024 * 128);
270
+	sbuf.fh = STDIN;
271
+	if(getenv("CONTENT_LENGTH")) {
272
+		sbuf.maxread = strtoul(getenv("CONTENT_LENGTH"), NULL, 10);
273
+	}
274
+	buffer_init(&buf);
275
+	buffer_add(&buf, "", 1);
276
+	buffer_reset(&buf);
277
+	state = DISCARD;
278
+	str = boundary + 2;
279
+	do {
280
+		x = sbuffer_read(&sbuf, str);
281
+		content_length += sbuf.len;
282
+		if(content_length >= max_len && global.uploadkb != -1) {
283
+			empty_stdin();
284
+			free(boundary);
285
+			sbuffer_destroy(&sbuf);
286
+			buffer_destroy(&buf);
287
+			if(var.name) {
288
+				mime_var_destroy(&var);
289
+			}
290
+			die_with_message(NULL, NULL, "Attempted to send content larger than allowed limits.");
291
+		}
292
+		switch(state) {
293
+			case DISCARD:
294
+				if(x) {
295
+					state = BOUNDARY;
296
+					str = crlf;
297
+					buffer_reset(&buf);
298
+				}
299
+				break;
300
+			case BOUNDARY:
301
+				if(x) {
302
+					buffer_add(&buf, sbuf.segment, sbuf.len);
303
+					if(!memcmp(buf.data, boundary + 2, 2)) {
304
+						str = boundary + 2;
305
+						state = DISCARD;
306
+					} else {
307
+						buffer_reset(&buf);
308
+						mime_var_init(&var);
309
+						state = HEADER;
310
+						str = crlf;
311
+					}
312
+				} else {
313
+					buffer_add(&buf, sbuf.segment, sbuf.len);
314
+				}
315
+				break;
316
+			case HEADER:
317
+				buffer_add(&buf, sbuf.segment, sbuf.len);
318
+				if(x) {
319
+					if(sbuf.len == 0) {
320
+						buffer_reset(&buf);
321
+						state = CONTENT;
322
+						str = boundary;
323
+					} else {
324
+						buffer_add(&buf, "", 1);
325
+						mime_tag_add(&var, (char*) buf.data);
326
+						buffer_reset(&buf);
327
+					}
328
+				}
329
+				break;
330
+			case CONTENT:
331
+				mime_var_writer(&var, (char*) sbuf.segment, sbuf.len);
332
+				if(x) {
333
+					buffer_reset(&buf);
334
+					mime_var_putenv(env, &var);
335
+					mime_var_destroy(&var);
336
+					state = BOUNDARY;
337
+					str = crlf;
338
+				}
339
+				break;
340
+		}
341
+	} while(!sbuf.eof);
342
+	free(boundary);
343
+	sbuffer_destroy(&sbuf);
344
+	buffer_destroy(&buf);
345
+	return 0;
346
+}

+ 33
- 0
mimetype.h View File

@@ -0,0 +1,33 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			mimetype.h
5
+ * @PURPOSE			Mimetype and file upload handler
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#ifndef __MIMETYPE_H
11
+#define __MIMETYPE_H
12
+
13
+typedef struct {
14
+	char* name;
15
+	char* filename;
16
+	char* type;
17
+	char* tempname;
18
+	buffer_t value;
19
+	int fh;
20
+} mime_var_t;
21
+
22
+void empty_stdin(void);
23
+void mime_exec(mime_var_t* obj, char* fifo);
24
+char* mime_substr(char* start, int len);
25
+void mime_tag_add(mime_var_t* obj, char* str);
26
+void mime_var_destroy(mime_var_t* obj);
27
+void mime_var_init(mime_var_t* obj);
28
+void mime_var_open_target(mime_var_t* obj);
29
+void mime_var_putenv(list_t* env, mime_var_t* obj);
30
+void mime_var_writer(mime_var_t* obj, char* str, int len);
31
+int rfc2388_handler(list_t* env);
32
+
33
+#endif

+ 373
- 0
subshell.c View File

@@ -0,0 +1,373 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			subshell.c
5
+ * @PURPOSE			Subshell execution
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#include <stdio.h>
11
+#include <unistd.h>
12
+#include <time.h>
13
+#include <getopt.h>
14
+#include <sys/mman.h>
15
+#include <sys/types.h>
16
+#include <sys/wait.h>
17
+#include <sys/stat.h>
18
+#include <sys/fcntl.h>
19
+#include <stdlib.h>
20
+#include <string.h>
21
+#include <ctype.h>
22
+
23
+#include "common.h"
24
+#include "buffer.h"
25
+#include "error.h"
26
+#include "subshell.h"
27
+#include "cbsi.h"
28
+
29
+char open_tag[3] = "<%";
30
+char close_tag[3] = "%>";
31
+
32
+const char* g_tag[] = {
33
+	"",
34
+	"",
35
+	":",
36
+	"@",
37
+	""
38
+};
39
+
40
+token_t* build_token_list(script_t* scriptbuf, token_t* tokenlist) {
41
+	char* start;
42
+	char* end;
43
+	char* curpos;
44
+	char* endpos;
45
+	token_t* curtoken;
46
+	token_t* firsttoken;
47
+
48
+	curtoken = tokenlist;
49
+	firsttoken = tokenlist;
50
+	curpos = scriptbuf->buf + scriptbuf->curpos;
51
+	endpos = scriptbuf->buf + scriptbuf->size;
52
+	while(curpos < endpos) {
53
+		start = strstr(curpos, open_tag);
54
+		end = strstr(curpos, close_tag);
55
+		if(start && !end) {
56
+			die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]);
57
+		}
58
+		if((start > end) || (!start && end)) {
59
+			die_with_message(scriptbuf, end, g_err_msg[E_END_BEFORE_BEGIN], open_tag[1], open_tag[1]);
60
+		}
61
+		if(start && (strstr(start + 1, open_tag) && (strstr (start + 1, open_tag) < end)))
62
+			die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]);
63
+		if(end) {
64
+			curtoken = push_token_on_list(curtoken, scriptbuf, curpos, start - curpos);
65
+			if(firsttoken == NULL) {
66
+				firsttoken = curtoken;
67
+			}
68
+			curtoken = push_token_on_list(curtoken, scriptbuf, start, end - start);
69
+			if(firsttoken == NULL) {
70
+				firsttoken = curtoken;
71
+			}
72
+			curpos = end + 2;
73
+		} else {
74
+			curtoken = push_token_on_list(curtoken, scriptbuf, curpos, endpos - curpos);
75
+			if(firsttoken == NULL) {
76
+				firsttoken = curtoken;
77
+			}
78
+			curpos = endpos;
79
+		}
80
+	}
81
+	return firsttoken;
82
+}
83
+
84
+void free_script_list(script_t* script) {
85
+	script_t* next;
86
+
87
+	while(script) {
88
+		next = script->next;
89
+		if(script->name) {
90
+			free(script->name);
91
+		}
92
+		if(script->buf) {
93
+			free(script->buf);
94
+		}
95
+		free(script);
96
+		script = next;
97
+	}
98
+}
99
+
100
+void free_token_list(token_t* tokenlist) {
101
+	token_t* next;
102
+
103
+	while(tokenlist) {
104
+		next = tokenlist->next;
105
+		free(tokenlist);
106
+		tokenlist = next;
107
+	}
108
+}
109
+
110
+script_t* load_script(char* filename, script_t* scriptlist) {
111
+	script_t* scriptbuf;
112
+	int scriptfp;
113
+	struct stat filestat;
114
+
115
+	scriptfp = open(filename, O_NONBLOCK + O_RDONLY);
116
+	if(scriptfp == -1) {
117
+		die_with_message(NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], filename);
118
+	}
119
+	fstat(scriptfp, &filestat);
120
+	scriptbuf = (script_t *) xmalloc(sizeof (script_t));
121
+	scriptbuf->name = (char *) xmalloc(strlen (filename) + 1);
122
+	scriptbuf->buf = (char *) xmalloc(filestat.st_size + 1);
123
+	memset(scriptbuf->name, 0, strlen(filename) + 1);
124
+	memcpy(scriptbuf->name, filename, strlen(filename));
125
+	memset(scriptbuf->buf, 0, filestat.st_size + 1);
126
+	read(scriptfp, scriptbuf->buf, filestat.st_size);
127
+	scriptbuf->size = filestat.st_size;
128
+	scriptbuf->uid = filestat.st_uid;
129
+	scriptbuf->gid = filestat.st_gid;
130
+	scriptbuf->curpos = 0;
131
+	scriptbuf->next = NULL;
132
+	if(scriptlist != NULL) {
133
+		while(scriptlist->next) {
134
+			scriptlist = scriptlist->next;
135
+		}
136
+		scriptlist->next = scriptbuf;
137
+	}
138
+	if(memcmp(scriptbuf->buf, "#!", 2) == 0) {
139
+		while((scriptbuf->curpos < scriptbuf->size) && ((char) scriptbuf->buf[scriptbuf->curpos] != '\n')) {
140
+			(scriptbuf->curpos)++;
141
+		}
142
+		(scriptbuf->curpos)++;
143
+	}
144
+	close(scriptfp);
145
+	return scriptbuf;
146
+}
147
+
148
+void preprocess_token_list(token_t* tokenlist) {
149
+	script_t* newscript;
150
+	token_t* me;
151
+	char* cp;
152
+
153
+	me = tokenlist;
154
+	while(me) {
155
+		if(memcmp(me->buf, open_tag, 2)) {
156
+			me->tag = HTML;
157
+		} else {
158
+			me->tag = NOOP;
159
+			me->buf[me->len] = '\0';
160
+			cp = me->buf + 2;
161
+			if(memcmp(cp, g_tag[ECHO], 1) == 0) {
162
+				me->tag = ECHO;
163
+				me->buf = find_whitespace(me->buf);
164
+				me->len = strlen(me->buf);
165
+			} else if(memcmp(cp, g_tag[TRANSLATE], 1) == 0) {
166
+				me->tag = TRANSLATE;
167
+				me->buf = find_whitespace(me->buf);
168
+				me->len = strlen(me->buf);
169
+			}
170
+			if(isspace(*cp)) {
171
+				me->tag = RUN;
172
+				me->buf = cp;
173
+			}
174
+			if(me->tag == NOOP) {
175
+				die_with_message(me->script, cp, g_err_msg[E_NO_OP]);
176
+			}
177
+			me->len = strlen(me->buf);
178
+		}
179
+		me = me->next;
180
+	}
181
+}
182
+
183
+token_t* process_token_list(buffer_t* buf, token_t* token) {
184
+	char *c;
185
+
186
+	buffer_init(buf);
187
+	subshell_exec(buf, "\n");
188
+	while(token) {
189
+		switch(token->tag) {
190
+			case HTML:
191
+				c = token->buf;
192
+				while((c < (token->buf + token->len)) && (isspace(*c))) {
193
+					c++;
194
+				}
195
+				if(c != token->buf + token->len) {
196
+					subshell_echo (buf, token->buf, token->len);
197
+				}
198
+				break;
199
+			case RUN:
200
+				subshell_exec(buf, token->buf);
201
+				subshell_exec(buf, "\n");
202
+				break;
203
+			case ECHO:
204
+				subshell_eval(buf, token->buf, token->len);
205
+				break;
206
+			case TRANSLATE:
207
+				subshell_translate(buf, token->buf, token->len);
208
+				break;
209
+			default:
210
+				break;
211
+		}
212
+		token = token->next;
213
+	}
214
+	return token;
215
+}
216
+
217
+token_t* push_token_on_list(token_t* tokenlist, script_t* scriptbuf, char* start, size_t len) {
218
+	token_t* me;
219
+	token_t* next;
220
+
221
+	if(len == 0) {
222
+		return tokenlist;
223
+	}
224
+	me = (token_t*) xmalloc(sizeof(token_t));
225
+	if(tokenlist == NULL) {
226
+		next = NULL;
227
+	} else {
228
+		next = tokenlist->next;
229
+		tokenlist->next = me;
230
+	}
231
+	me->next = next;
232
+	me->script = scriptbuf;
233
+	me->buf = start;
234
+	me->len = len;
235
+	return me;
236
+}
237
+
238
+void subshell_destroy(void) {
239
+	int status;
240
+	waitpid(subshell_pid, &status, 0);
241
+}
242
+
243
+void subshell_doscript(buffer_t* script, char* name) {
244
+	static char postfix[] = "\nexit\n";
245
+
246
+	write(subshell_pipe[PARENT_OUT], script->data, script->ptr - script->data);
247
+	write(subshell_pipe[PARENT_OUT], postfix, strlen(postfix));
248
+	return;
249
+}
250
+
251
+void subshell_echo(buffer_t* buf, char* str, size_t len) {
252
+	static char echo_start[] = "printf '%s' '";
253
+	static char echo_quote[] = "'\\''";
254
+	static char echo_end[] = "'\n";
255
+	const size_t maxlen = 3096;
256
+	size_t pos;
257
+
258
+	if(len == 0) {
259
+		return;
260
+	}
261
+	pos = 0;
262
+	buffer_add(buf, echo_start, strlen(echo_start));
263
+	while(pos < len) {
264
+		if (str[pos] == '\'') {
265
+			buffer_add(buf, echo_quote, strlen(echo_quote));
266
+		} else {
267
+			buffer_add(buf, str + pos, 1);
268
+		}
269
+		pos++;
270
+		if((pos % maxlen) == 0) {
271
+			buffer_add(buf, echo_end, strlen(echo_end));
272
+			buffer_add(buf, echo_start, strlen(echo_start));
273
+		}
274
+	}
275
+	buffer_add(buf, echo_end, strlen(echo_end));
276
+}
277
+
278
+void subshell_eval(buffer_t* buf, char* str, size_t len) {
279
+	static char echo_start[] = "echo -n ";
280
+	static char echo_end[] = "\n";
281
+
282
+	if(len == 0) {
283
+		return;
284
+	}
285
+	str = trim(str);
286
+	if(!*str) {
287
+		return;
288
+	}
289
+	buffer_add(buf, echo_start, strlen(echo_start));
290
+	buffer_add(buf, str, len);
291
+	buffer_add(buf, echo_end, strlen(echo_end));
292
+}
293
+
294
+void subshell_exec(buffer_t* buf, char* str) {
295
+	buffer_add (buf, str, strlen (str));
296
+	return;
297
+}
298
+
299
+void subshell_setup (char* shell, list_t* env) {
300
+	int retcode = 0;
301
+	int count;
302
+	argv_t* argv;
303
+	char* av[20];
304
+	list_t* next;
305
+
306
+	if(shell == NULL) {
307
+		return;
308
+	}
309
+	retcode = pipe(&subshell_pipe[PARENT_IN]);
310
+	if(retcode == 0) {
311
+		subshell_pid = fork();
312
+		if(subshell_pid == -1) {
313
+			die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]);
314
+		}
315
+		if(subshell_pid == 0) {
316
+			dup2(subshell_pipe[PARENT_IN], STDIN_FILENO);
317
+			close(subshell_pipe[PARENT_IN]);
318
+			close(subshell_pipe[PARENT_OUT]);
319
+			count = argc_argv(shell, &argv);
320
+			if(count > 19) {
321
+				av[19] = "\0";
322
+				count = 18;
323
+			}
324
+			while(count >= 0) {
325
+				av[count] = argv[count].string;
326
+				count--;
327
+			}
328
+			while(env) {
329
+				next = env->next;
330
+				putenv(env->buf);
331
+				env = next;
332
+			}
333
+			execv(argv[0].string, av);
334
+			free(argv);
335
+			die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]);
336
+		} else {
337
+			close(subshell_pipe[PARENT_IN]);
338
+		}
339
+	}
340
+}
341
+
342
+void subshell_translate(buffer_t* buf, char* str, size_t len) {
343
+	static char echo_start[] = "echo -n \"";
344
+	static char echo_end[] = "\"\n";
345
+	short hash;
346
+	lstr* i;
347
+	char* text = NULL;
348
+
349
+	if(len == 0) {
350
+		return;
351
+	}
352
+	str = trim(str);
353
+	if(!*str) {
354
+		return;
355
+	}
356
+	if(language != NULL && translations > 0) {
357
+		hash = generateHash(str);
358
+		i = ltable[hash];
359
+		while(text == NULL && i != NULL) {
360
+			if(strcmp(str, i->msgid) == 0) {
361
+				text = i->msgstr;
362
+			} else {
363
+				i = i->next;
364
+			}
365
+		}
366
+	}
367
+	if(text == NULL) {
368
+		text = str;
369
+	}
370
+	buffer_add(buf, echo_start, strlen(echo_start));
371
+	buffer_add(buf, text, strlen(text));
372
+	buffer_add(buf, echo_end, strlen(echo_end));
373
+}

+ 52
- 0
subshell.h View File

@@ -0,0 +1,52 @@
1
+/**
2
+ * @PROJECT			CGI Bash Shell Interface
3
+ * @COPYRIGHT		See COPYING in the top level directory
4
+ * @FILE			subshell.h
5
+ * @PURPOSE			Subshell execution
6
+ * @DEVELOPERS		Nathan Angelacos <nangel@users.sourceforge.net>
7
+ *					Rafal Kupiec <belliash@asiotec.eu.org>
8
+ */
9
+
10
+#ifndef __SUBSHELL_H
11
+#define __SUBSHELL_H
12
+
13
+static int subshell_pid;
14
+static int subshell_pipe[2];
15
+
16
+enum pipe_t { PARENT_IN, PARENT_OUT };
17
+enum tag_t { HTML, RUN, ECHO, TRANSLATE, NOOP };
18
+
19
+typedef struct {
20
+	char* name;
21
+	int size;
22
+	uid_t uid;
23
+	gid_t gid;
24
+	char* buf;
25
+	size_t curpos;
26
+	void* next;
27
+} script_t;
28
+
29
+typedef struct {
30
+	script_t* script;
31
+	enum tag_t tag;
32
+	size_t len;
33
+	char* buf;
34
+	void* next;
35
+} token_t;
36
+
37
+token_t* build_token_list(script_t* scriptbuf, token_t* tokenlist);
38
+void free_script_list(script_t* script);
39
+void free_token_list(token_t* tokenlist);
40
+script_t* load_script(char* filename, script_t* scriptlist);
41
+void preprocess_token_list(token_t* tokenlist);
42
+token_t* process_token_list(buffer_t* buf, token_t* tokenlist);
43
+token_t* push_token_on_list(token_t* tokenlist, script_t* scriptbuf, char* start, size_t len);
44
+void subshell_destroy(void);
45
+void subshell_doscript(buffer_t* script, char* name);
46
+void subshell_echo(buffer_t* buf, char* str, size_t len);
47
+void subshell_eval(buffer_t* buf, char* str, size_t len);
48
+void subshell_exec(buffer_t* buf, char* str);
49
+void subshell_setup(char* shell, list_t* env);
50
+void subshell_translate(buffer_t* buf, char* str, size_t len);
51
+
52
+#endif

Loading…
Cancel
Save