1 |
nmav |
1.1 |
/* |
2 |
nmav |
1.14 |
* Hydra, an http server |
3 |
nmav |
1.1 |
* Copyright (C) 1995 Paul Phillips <paulp@go2net.com> |
4 |
|
|
* Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@boa.org> |
5 |
|
|
* Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com> |
6 |
|
|
* Some changes Copyright (C) 1997-2002 Jon Nelson <jnelson@boa.org> |
7 |
|
|
* |
8 |
|
|
* This program is free software; you can redistribute it and/or modify |
9 |
|
|
* it under the terms of the GNU General Public License as published by |
10 |
|
|
* the Free Software Foundation; either version 1, or (at your option) |
11 |
|
|
* any later version. |
12 |
|
|
* |
13 |
|
|
* This program is distributed in the hope that it will be useful, |
14 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
|
|
* GNU General Public License for more details. |
17 |
|
|
* |
18 |
|
|
* You should have received a copy of the GNU General Public License |
19 |
|
|
* along with this program; if not, write to the Free Software |
20 |
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 |
|
|
* |
22 |
|
|
*/ |
23 |
|
|
|
24 |
nmav |
1.21 |
/* $Id: cgi.c,v 1.20 2002/10/04 19:09:12 nmav Exp $ */ |
25 |
nmav |
1.1 |
|
26 |
|
|
#include "boa.h" |
27 |
|
|
|
28 |
|
|
static char *env_gen_extra(const char *key, const char *value, int extra); |
29 |
|
|
|
30 |
|
|
int verbose_cgi_logs = 0; |
31 |
|
|
/* The +1 is for the the NULL in complete_env */ |
32 |
|
|
static char *common_cgi_env[COMMON_CGI_COUNT + 1]; |
33 |
|
|
|
34 |
|
|
/* |
35 |
|
|
* Name: create_common_env |
36 |
|
|
* |
37 |
|
|
* Description: Set up the environment variables that are common to |
38 |
|
|
* all CGI scripts |
39 |
|
|
*/ |
40 |
|
|
|
41 |
|
|
void create_common_env() |
42 |
|
|
{ |
43 |
nmav |
1.7 |
int index = 0, i; |
44 |
nmav |
1.1 |
|
45 |
|
|
|
46 |
nmav |
1.7 |
/* NOTE NOTE NOTE: |
47 |
|
|
If you (the reader) someday modify this chunk of code to |
48 |
|
|
handle more "common" CGI environment variables, then bump the |
49 |
|
|
value COMMON_CGI_COUNT in defines.h UP |
50 |
|
|
|
51 |
|
|
Also, in the case of document_root and server_admin, two variables |
52 |
|
|
that may or may not be defined depending on the way the server |
53 |
|
|
is configured, we check for null values and use an empty |
54 |
|
|
string to denote a NULL value to the environment, as per the |
55 |
|
|
specification. The quote for which follows: |
56 |
|
|
|
57 |
|
|
"In all cases, a missing environment variable is |
58 |
|
|
equivalent to a zero-length (NULL) value, and vice versa." |
59 |
|
|
*/ |
60 |
|
|
common_cgi_env[index++] = env_gen_extra("PATH", |
61 |
|
|
((cgi_path != |
62 |
|
|
NULL) ? cgi_path : |
63 |
|
|
DEFAULT_PATH), 0); |
64 |
|
|
common_cgi_env[index++] = |
65 |
|
|
env_gen_extra("SERVER_SOFTWARE", SERVER_NAME "/" SERVER_VERSION, 0); |
66 |
|
|
common_cgi_env[index++] = |
67 |
|
|
env_gen_extra("GATEWAY_INTERFACE", CGI_VERSION, 0); |
68 |
|
|
|
69 |
|
|
/* removed the SERVER_PORT which may change due to SSL support |
70 |
|
|
* Also removed the DOCUMENT_ROOT, SERVER_NAME, which are now per request. |
71 |
|
|
*/ |
72 |
|
|
|
73 |
|
|
|
74 |
|
|
/* NCSA added */ |
75 |
|
|
/* common_cgi_env[index++] = env_gen_extra("SERVER_ROOT", server_root); */ |
76 |
|
|
|
77 |
|
|
/* APACHE added */ |
78 |
|
|
common_cgi_env[index++] = |
79 |
|
|
env_gen_extra("SERVER_ADMIN", server_admin, 0); |
80 |
|
|
common_cgi_env[index] = NULL; |
81 |
|
|
|
82 |
|
|
/* Sanity checking -- make *sure* the memory got allocated */ |
83 |
|
|
if (index > COMMON_CGI_COUNT) { |
84 |
|
|
log_error_time(); |
85 |
|
|
fprintf(stderr, "COMMON_CGI_COUNT not high enough.\n"); |
86 |
|
|
exit(1); |
87 |
|
|
} |
88 |
|
|
|
89 |
|
|
for (i = 0; i < index; ++i) { |
90 |
|
|
if (common_cgi_env[i] == NULL) { |
91 |
|
|
log_error_time(); |
92 |
|
|
fprintf(stderr, |
93 |
|
|
"Unable to allocate a component of common_cgi_env - out of memory.\n"); |
94 |
|
|
exit(1); |
95 |
|
|
} |
96 |
|
|
} |
97 |
nmav |
1.1 |
} |
98 |
|
|
|
99 |
|
|
void clear_common_env(void) |
100 |
|
|
{ |
101 |
nmav |
1.7 |
int i; |
102 |
nmav |
1.1 |
|
103 |
nmav |
1.7 |
for (i = 0; i <= COMMON_CGI_COUNT; ++i) { |
104 |
|
|
if (common_cgi_env[i] != NULL) { |
105 |
|
|
free(common_cgi_env[i]); |
106 |
|
|
common_cgi_env[i] = NULL; |
107 |
|
|
} |
108 |
|
|
} |
109 |
nmav |
1.1 |
} |
110 |
|
|
|
111 |
|
|
/* |
112 |
|
|
* Name: env_gen_extra |
113 |
|
|
* (and via a not-so-tricky #define, env_gen) |
114 |
|
|
* This routine calls malloc: please free the memory when you are done |
115 |
|
|
*/ |
116 |
|
|
static char *env_gen_extra(const char *key, const char *value, int extra) |
117 |
|
|
{ |
118 |
nmav |
1.7 |
char *result; |
119 |
|
|
int key_len, value_len; |
120 |
nmav |
1.1 |
|
121 |
nmav |
1.7 |
if (value == NULL) /* ServerAdmin may not be defined, eg */ |
122 |
|
|
value = ""; |
123 |
|
|
key_len = strlen(key); |
124 |
|
|
value_len = strlen(value); |
125 |
|
|
/* leave room for '=' sign and null terminator */ |
126 |
|
|
result = malloc(extra + key_len + value_len + 2); |
127 |
|
|
if (result) { |
128 |
|
|
memcpy(result + extra, key, key_len); |
129 |
|
|
*(result + extra + key_len) = '='; |
130 |
|
|
memcpy(result + extra + key_len + 1, value, value_len); |
131 |
|
|
*(result + extra + key_len + value_len + 1) = '\0'; |
132 |
|
|
} else { |
133 |
|
|
log_error_time(); |
134 |
|
|
perror("malloc"); |
135 |
|
|
log_error_time(); |
136 |
|
|
fprintf(stderr, |
137 |
|
|
"tried to allocate (key=value) extra=%d: %s=%s\n", |
138 |
|
|
extra, key, value); |
139 |
|
|
} |
140 |
|
|
return result; |
141 |
nmav |
1.1 |
} |
142 |
|
|
|
143 |
|
|
/* |
144 |
|
|
* Name: add_cgi_env |
145 |
|
|
* |
146 |
|
|
* Description: adds a variable to CGI's environment |
147 |
|
|
* Used for HTTP_ headers |
148 |
|
|
*/ |
149 |
|
|
|
150 |
nmav |
1.10 |
int add_cgi_env(request * req, const char *key, const char *value, |
151 |
|
|
int http_prefix) |
152 |
nmav |
1.1 |
{ |
153 |
nmav |
1.7 |
char *p; |
154 |
|
|
int prefix_len; |
155 |
nmav |
1.1 |
|
156 |
nmav |
1.7 |
if (http_prefix) { |
157 |
|
|
prefix_len = 5; |
158 |
|
|
} else { |
159 |
|
|
prefix_len = 0; |
160 |
|
|
} |
161 |
|
|
|
162 |
|
|
if (req->cgi_env_index < CGI_ENV_MAX) { |
163 |
|
|
p = env_gen_extra(key, value, prefix_len); |
164 |
|
|
if (!p) { |
165 |
|
|
log_error_time(); |
166 |
|
|
fprintf(stderr, "Unable to generate additional CGI Environment" |
167 |
|
|
"variable -- ran out of memory!\n"); |
168 |
|
|
} |
169 |
|
|
if (prefix_len) |
170 |
|
|
memcpy(p, "HTTP_", 5); |
171 |
|
|
req->cgi_env[req->cgi_env_index++] = p; |
172 |
|
|
return 1; |
173 |
|
|
} else { |
174 |
|
|
log_error_time(); |
175 |
|
|
fprintf(stderr, "Unable to generate additional CGI Environment" |
176 |
|
|
"variable -- not enough space!\n"); |
177 |
|
|
} |
178 |
|
|
return 0; |
179 |
nmav |
1.1 |
} |
180 |
|
|
|
181 |
|
|
#define my_add_cgi_env(req, key, value) { \ |
182 |
|
|
int ok = add_cgi_env(req, key, value, 0); \ |
183 |
|
|
if (!ok) return 0; \ |
184 |
|
|
} |
185 |
|
|
|
186 |
nmav |
1.10 |
const char *hydra_method_str(int method) |
187 |
nmav |
1.1 |
{ |
188 |
nmav |
1.10 |
char *w; |
189 |
|
|
switch (method) { |
190 |
|
|
case M_POST: |
191 |
|
|
w = "POST"; |
192 |
|
|
break; |
193 |
|
|
case M_HEAD: |
194 |
|
|
w = "HEAD"; |
195 |
|
|
break; |
196 |
|
|
case M_GET: |
197 |
|
|
w = "GET"; |
198 |
|
|
break; |
199 |
|
|
default: |
200 |
|
|
w = "UNKNOWN"; |
201 |
|
|
break; |
202 |
|
|
} |
203 |
|
|
return w; |
204 |
nmav |
1.8 |
} |
205 |
|
|
|
206 |
|
|
/* |
207 |
|
|
* Name: complete_env |
208 |
|
|
* |
209 |
|
|
* Description: adds the known client header env variables |
210 |
|
|
* and terminates the environment array |
211 |
|
|
*/ |
212 |
|
|
|
213 |
|
|
int complete_env(request * req) |
214 |
|
|
{ |
215 |
|
|
int i; |
216 |
|
|
char buf[22]; |
217 |
nmav |
1.10 |
const char *w; |
218 |
nmav |
1.8 |
|
219 |
|
|
for (i = 0; common_cgi_env[i]; i++) |
220 |
|
|
req->cgi_env[i] = common_cgi_env[i]; |
221 |
|
|
|
222 |
nmav |
1.10 |
w = hydra_method_str(req->method); |
223 |
nmav |
1.8 |
my_add_cgi_env(req, "REQUEST_METHOD", w); |
224 |
nmav |
1.7 |
|
225 |
|
|
if (req->secure) { |
226 |
|
|
simple_itoa(ssl_port, buf); |
227 |
|
|
} else { |
228 |
|
|
simple_itoa(server_port, buf); |
229 |
|
|
} |
230 |
|
|
my_add_cgi_env(req, "SERVER_PORT", buf); |
231 |
|
|
my_add_cgi_env(req, "SERVER_NAME", req->hostname); |
232 |
|
|
|
233 |
|
|
/* NCSA and APACHE added -- not in CGI spec */ |
234 |
|
|
/* my_add_cgi_env( req, "DOCUMENT_ROOT", req->document_root); */ |
235 |
|
|
|
236 |
|
|
my_add_cgi_env(req, "SERVER_ADDR", req->local_ip_addr); |
237 |
|
|
my_add_cgi_env(req, "SERVER_PROTOCOL", req->http_version); |
238 |
|
|
my_add_cgi_env(req, "REQUEST_URI", req->request_uri); |
239 |
|
|
|
240 |
|
|
if (req->path_info) |
241 |
|
|
my_add_cgi_env(req, "PATH_INFO", req->path_info); |
242 |
|
|
|
243 |
|
|
if (req->path_translated) |
244 |
|
|
/* while path_translated depends on path_info, |
245 |
|
|
* there are cases when path_translated might |
246 |
|
|
* not exist when path_info does |
247 |
|
|
*/ |
248 |
|
|
my_add_cgi_env(req, "PATH_TRANSLATED", req->path_translated); |
249 |
|
|
|
250 |
|
|
my_add_cgi_env(req, "SCRIPT_NAME", req->script_name); |
251 |
|
|
|
252 |
|
|
if (req->query_string) |
253 |
|
|
my_add_cgi_env(req, "QUERY_STRING", req->query_string); |
254 |
|
|
my_add_cgi_env(req, "REMOTE_ADDR", req->remote_ip_addr); |
255 |
|
|
|
256 |
|
|
simple_itoa(req->remote_port, buf); |
257 |
|
|
my_add_cgi_env(req, "REMOTE_PORT", buf); |
258 |
|
|
|
259 |
|
|
if (req->method == M_POST) { |
260 |
|
|
if (req->content_type) { |
261 |
|
|
my_add_cgi_env(req, "CONTENT_TYPE", req->content_type); |
262 |
|
|
} else { |
263 |
|
|
my_add_cgi_env(req, "CONTENT_TYPE", default_type); |
264 |
|
|
} |
265 |
|
|
if (req->content_length) { |
266 |
|
|
my_add_cgi_env(req, "CONTENT_LENGTH", req->content_length); |
267 |
|
|
} |
268 |
|
|
} |
269 |
nmav |
1.1 |
#ifdef ACCEPT_ON |
270 |
nmav |
1.7 |
if (req->accept[0]) |
271 |
|
|
my_add_cgi_env(req, "HTTP_ACCEPT", req->accept); |
272 |
nmav |
1.1 |
#endif |
273 |
|
|
|
274 |
nmav |
1.7 |
if (req->cgi_env_index < CGI_ENV_MAX + 1) { |
275 |
|
|
req->cgi_env[req->cgi_env_index] = NULL; /* terminate */ |
276 |
|
|
return 1; |
277 |
|
|
} |
278 |
|
|
log_error_time(); |
279 |
|
|
fprintf(stderr, "Not enough space in CGI environment for remainder" |
280 |
|
|
" of variables.\n"); |
281 |
|
|
return 0; |
282 |
nmav |
1.1 |
} |
283 |
|
|
|
284 |
|
|
/* |
285 |
|
|
* Name: make_args_cgi |
286 |
|
|
* |
287 |
|
|
* Build argv list for a CGI script according to spec |
288 |
|
|
* |
289 |
|
|
*/ |
290 |
|
|
|
291 |
|
|
void create_argv(request * req, char **aargv) |
292 |
|
|
{ |
293 |
nmav |
1.7 |
char *p, *q, *r; |
294 |
|
|
int aargc; |
295 |
nmav |
1.1 |
|
296 |
nmav |
1.7 |
q = req->query_string; |
297 |
|
|
aargv[0] = req->pathname; |
298 |
nmav |
1.1 |
|
299 |
nmav |
1.7 |
/* here, we handle a special "indexed" query string. |
300 |
|
|
* Taken from the CGI/1.1 SPEC: |
301 |
|
|
* This is identified by a GET or HEAD request with a query string |
302 |
|
|
* with no *unencoded* '=' in it. |
303 |
|
|
* For such a request, I'm supposed to parse the search string |
304 |
|
|
* into words, according to the following rules: |
305 |
|
|
|
306 |
|
|
search-string = search-word *( "+" search-word ) |
307 |
|
|
search-word = 1*schar |
308 |
|
|
schar = xunreserved | escaped | xreserved |
309 |
|
|
xunreserved = alpha | digit | xsafe | extra |
310 |
|
|
xsafe = "$" | "-" | "_" | "." |
311 |
|
|
xreserved = ";" | "/" | "?" | ":" | "@" | "&" |
312 |
|
|
|
313 |
|
|
After parsing, each word is URL-decoded, optionally encoded in a system |
314 |
|
|
defined manner, and then the argument list |
315 |
|
|
is set to the list of words. |
316 |
|
|
|
317 |
|
|
|
318 |
|
|
Thus, schar is alpha|digit|"$"|"-"|"_"|"."|";"|"/"|"?"|":"|"@"|"&" |
319 |
|
|
|
320 |
|
|
As of this writing, escape.pl escapes the following chars: |
321 |
|
|
|
322 |
|
|
"-", "_", ".", "!", "~", "*", "'", "(", ")", |
323 |
|
|
"0".."9", "A".."Z", "a".."z", |
324 |
|
|
";", "/", "?", ":", "@", "&", "=", "+", "\$", "," |
325 |
|
|
|
326 |
|
|
Which therefore means |
327 |
|
|
"=", "+", "~", "!", "*", "'", "(", ")", "," |
328 |
|
|
are *not* escaped and should be? |
329 |
|
|
Wait, we don't do any escaping, and nor should we. |
330 |
|
|
According to the RFC draft, we unescape and then re-escape |
331 |
|
|
in a "system defined manner" (here: none). |
332 |
|
|
|
333 |
|
|
The CGI/1.1 draft (03, latest is 1999???) is very unclear here. |
334 |
|
|
|
335 |
|
|
I am using the latest published RFC, 2396, for what does and does |
336 |
|
|
not need escaping. |
337 |
|
|
|
338 |
|
|
Since boa builds the argument list and does not call /bin/sh, |
339 |
|
|
(boa uses execve for CGI) |
340 |
|
|
*/ |
341 |
|
|
|
342 |
|
|
if (q && !strchr(q, '=')) { |
343 |
|
|
/* we have an 'index' style */ |
344 |
|
|
q = strdup(q); |
345 |
|
|
if (!q) { |
346 |
|
|
WARN("unable to strdup 'q' in create_argv!"); |
347 |
|
|
} |
348 |
|
|
for (aargc = 1; q && (aargc < CGI_ARGC_MAX);) { |
349 |
|
|
r = q; |
350 |
|
|
/* for an index-style CGI, + is used to seperate arguments |
351 |
|
|
* an escaped '+' is of no concern to us |
352 |
|
|
*/ |
353 |
|
|
if ((p = strchr(q, '+'))) { |
354 |
|
|
*p = '\0'; |
355 |
|
|
q = p + 1; |
356 |
|
|
} else { |
357 |
|
|
q = NULL; |
358 |
|
|
} |
359 |
|
|
if (unescape_uri(r, NULL)) { |
360 |
|
|
/* printf("parameter %d: %s\n",aargc,r); */ |
361 |
|
|
aargv[aargc++] = r; |
362 |
|
|
} |
363 |
|
|
} |
364 |
|
|
aargv[aargc] = NULL; |
365 |
|
|
} else { |
366 |
|
|
aargv[1] = NULL; |
367 |
|
|
} |
368 |
nmav |
1.1 |
} |
369 |
|
|
|
370 |
|
|
/* |
371 |
|
|
* Name: init_cgi |
372 |
|
|
* |
373 |
|
|
* Description: Called for GET/POST requests that refer to ScriptAlias |
374 |
nmav |
1.7 |
* directories or application/x-httpd-cgi files. Pipes are used for the |
375 |
|
|
* communication with the child. |
376 |
nmav |
1.1 |
* stderr remains tied to our log file; is this good? |
377 |
|
|
* |
378 |
|
|
* Returns: |
379 |
|
|
* 0 - error or NPH, either way the socket is closed |
380 |
|
|
* 1 - success |
381 |
|
|
*/ |
382 |
|
|
|
383 |
|
|
int init_cgi(request * req) |
384 |
|
|
{ |
385 |
nmav |
1.7 |
int child_pid; |
386 |
|
|
int pipes[2]; |
387 |
|
|
|
388 |
|
|
SQUASH_KA(req); |
389 |
|
|
|
390 |
nmav |
1.10 |
if (req->is_cgi == NPH || req->is_cgi == CGI || req->is_cgi == HIC_CGI) { |
391 |
nmav |
1.20 |
if (req->secure && complete_env_ssl(req) == 0) { |
392 |
|
|
return 0; |
393 |
|
|
} |
394 |
nmav |
1.7 |
if (complete_env(req) == 0) { |
395 |
|
|
return 0; |
396 |
|
|
} |
397 |
|
|
} |
398 |
nmav |
1.1 |
#ifdef FASCIST_LOGGING |
399 |
nmav |
1.7 |
{ |
400 |
|
|
int i; |
401 |
|
|
for (i = 0; i < req->cgi_env_index; ++i) |
402 |
|
|
fprintf(stderr, "%s - environment variable for cgi: \"%s\"\n", |
403 |
|
|
__FILE__, req->cgi_env[i]); |
404 |
|
|
} |
405 |
nmav |
1.1 |
#endif |
406 |
|
|
|
407 |
nmav |
1.7 |
if (req->is_cgi) { |
408 |
|
|
if (pipe(pipes) == -1) { |
409 |
|
|
log_error_time(); |
410 |
|
|
perror("pipe"); |
411 |
|
|
return 0; |
412 |
|
|
} |
413 |
|
|
|
414 |
|
|
/* set the read end of the socket to non-blocking */ |
415 |
|
|
if (set_nonblock_fd(pipes[0]) == -1) { |
416 |
|
|
log_error_time(); |
417 |
|
|
perror("cgi-fcntl"); |
418 |
|
|
close(pipes[0]); |
419 |
|
|
close(pipes[1]); |
420 |
|
|
return 0; |
421 |
|
|
} |
422 |
|
|
} else { |
423 |
|
|
log_error_time(); |
424 |
|
|
fprintf(stderr, "Non CGI in init_cgi()!\n"); |
425 |
|
|
return 0; |
426 |
|
|
} |
427 |
|
|
|
428 |
nmav |
1.10 |
if (req->is_cgi == HIC_CGI) { /* internally handled cgi */ |
429 |
nmav |
1.15 |
#ifdef ENABLE_HIC |
430 |
nmav |
1.18 |
/* Move the post_data_fd pointer to start. |
431 |
|
|
*/ |
432 |
|
|
lseek(req->post_data_fd, SEEK_SET, 0); |
433 |
|
|
|
434 |
nmav |
1.10 |
if (hic_send_command(req, pipes[1]) == -1) { |
435 |
|
|
log_error_time(); |
436 |
|
|
fprintf(stderr, "Error in HIC\n"); |
437 |
|
|
close(pipes[0]); |
438 |
|
|
close(pipes[1]); |
439 |
|
|
return 0; |
440 |
|
|
} |
441 |
nmav |
1.15 |
#else /* No hic! */ |
442 |
|
|
close(pipes[0]); |
443 |
|
|
close(pipes[1]); |
444 |
|
|
return 0; |
445 |
|
|
#endif |
446 |
nmav |
1.10 |
} else { /* plain cgi... do fork */ |
447 |
|
|
child_pid = fork(); |
448 |
|
|
switch (child_pid) { |
449 |
|
|
case -1: |
450 |
|
|
/* fork unsuccessful */ |
451 |
|
|
log_error_time(); |
452 |
|
|
perror("fork"); |
453 |
nmav |
1.7 |
|
454 |
nmav |
1.10 |
close(pipes[0]); |
455 |
|
|
close(pipes[1]); |
456 |
nmav |
1.7 |
|
457 |
nmav |
1.10 |
send_r_error(req); |
458 |
|
|
/* FIXME: There is aproblem here. send_r_error would work |
459 |
|
|
for NPH and CGI, but not for GUNZIP. Fix that. */ |
460 |
|
|
/* i'd like to send_r_error, but.... */ |
461 |
|
|
return 0; |
462 |
|
|
break; |
463 |
|
|
case 0: |
464 |
|
|
/* child */ |
465 |
|
|
if (req->is_cgi == CGI || req->is_cgi == NPH) { |
466 |
|
|
char *foo = strdup(req->pathname); |
467 |
|
|
char *c; |
468 |
|
|
|
469 |
|
|
if (!foo) { |
470 |
|
|
WARN("unable to strdup pathname for req->pathname"); |
471 |
|
|
_exit(1); |
472 |
|
|
} |
473 |
|
|
c = strrchr(foo, '/'); |
474 |
|
|
if (c) { |
475 |
|
|
++c; |
476 |
|
|
*c = '\0'; |
477 |
|
|
} else { |
478 |
|
|
/* we have a serious problem */ |
479 |
|
|
log_error_time(); |
480 |
|
|
perror("chdir"); |
481 |
|
|
close(pipes[1]); |
482 |
|
|
_exit(1); |
483 |
|
|
} |
484 |
|
|
if (chdir(foo) != 0) { |
485 |
|
|
log_error_time(); |
486 |
|
|
perror("chdir"); |
487 |
|
|
close(pipes[1]); |
488 |
|
|
_exit(1); |
489 |
|
|
} |
490 |
nmav |
1.7 |
} |
491 |
nmav |
1.10 |
close(pipes[0]); |
492 |
|
|
/* tie cgi's STDOUT to it's write end of pipe */ |
493 |
|
|
if (dup2(pipes[1], STDOUT_FILENO) == -1) { |
494 |
nmav |
1.7 |
log_error_time(); |
495 |
nmav |
1.10 |
perror("dup2 - pipes"); |
496 |
nmav |
1.7 |
close(pipes[1]); |
497 |
|
|
_exit(1); |
498 |
|
|
} |
499 |
nmav |
1.10 |
close(pipes[1]); |
500 |
|
|
if (set_block_fd(STDOUT_FILENO) == -1) { |
501 |
nmav |
1.7 |
log_error_time(); |
502 |
nmav |
1.10 |
perror("cgi-fcntl"); |
503 |
nmav |
1.7 |
_exit(1); |
504 |
|
|
} |
505 |
nmav |
1.10 |
|
506 |
|
|
/* tie post_data_fd to POST stdin */ |
507 |
|
|
if (req->method == M_POST) { /* tie stdin to file */ |
508 |
|
|
lseek(req->post_data_fd, SEEK_SET, 0); |
509 |
|
|
dup2(req->post_data_fd, STDIN_FILENO); |
510 |
|
|
close(req->post_data_fd); |
511 |
|
|
} |
512 |
|
|
/* Close access log, so CGI program can't scribble |
513 |
|
|
* where it shouldn't |
514 |
|
|
*/ |
515 |
|
|
close_access_log(); |
516 |
|
|
|
517 |
|
|
/* |
518 |
|
|
* tie STDERR to cgi_log_fd |
519 |
|
|
* cgi_log_fd will automatically close, close-on-exec rocks! |
520 |
|
|
* if we don't tied STDERR (current log_error) to cgi_log_fd, |
521 |
|
|
* then we ought to close it. |
522 |
|
|
*/ |
523 |
|
|
if (!cgi_log_fd) |
524 |
|
|
dup2(devnullfd, STDERR_FILENO); |
525 |
|
|
else |
526 |
|
|
dup2(cgi_log_fd, STDERR_FILENO); |
527 |
|
|
|
528 |
|
|
if (req->is_cgi == NPH || req->is_cgi == CGI) { |
529 |
|
|
char *aargv[CGI_ARGC_MAX + 1]; |
530 |
nmav |
1.19 |
create_argv(req, aargv); |
531 |
nmav |
1.10 |
execve(req->pathname, aargv, req->cgi_env); |
532 |
|
|
} else { |
533 |
|
|
if (req->is_cgi == INDEXER_CGI) |
534 |
|
|
execl(dirmaker, dirmaker, req->pathname, req->request_uri, |
535 |
|
|
NULL); |
536 |
|
|
} |
537 |
|
|
/* execve failed */ |
538 |
|
|
WARN(req->pathname); |
539 |
nmav |
1.7 |
_exit(1); |
540 |
|
|
|
541 |
nmav |
1.10 |
break; /* it doesn't matter, we never make it until here */ |
542 |
|
|
|
543 |
|
|
default: |
544 |
|
|
/* parent */ |
545 |
|
|
/* if here, fork was successful */ |
546 |
|
|
if (verbose_cgi_logs) { |
547 |
|
|
log_error_time(); |
548 |
|
|
fprintf(stderr, "Forked child \"%s\" pid %d\n", |
549 |
|
|
req->pathname, child_pid); |
550 |
|
|
} |
551 |
nmav |
1.7 |
|
552 |
nmav |
1.10 |
if (req->method == M_POST) { |
553 |
|
|
close(req->post_data_fd); /* child closed it too */ |
554 |
|
|
req->post_data_fd = -1; |
555 |
|
|
} |
556 |
nmav |
1.7 |
|
557 |
nmav |
1.10 |
/* NPH, etc... all go straight to the fd */ |
558 |
nmav |
1.7 |
|
559 |
nmav |
1.10 |
close(pipes[1]); |
560 |
|
|
break; |
561 |
nmav |
1.7 |
} |
562 |
nmav |
1.18 |
} /* HIC */ |
563 |
nmav |
1.7 |
|
564 |
nmav |
1.10 |
/* we only get here in parent case, and |
565 |
|
|
* success. |
566 |
|
|
*/ |
567 |
nmav |
1.7 |
|
568 |
nmav |
1.10 |
req->data_fd = pipes[0]; |
569 |
nmav |
1.7 |
|
570 |
nmav |
1.10 |
req->status = PIPE_READ; |
571 |
nmav |
1.21 |
if (req->is_cgi == CGI || req->is_cgi == HIC_CGI) { |
572 |
nmav |
1.10 |
req->cgi_status = CGI_PARSE; /* got to parse cgi header */ |
573 |
|
|
/* for cgi_header... I get half the buffer! */ |
574 |
|
|
req->header_line = req->header_end = (req->buffer + BUFFER_SIZE / 2); |
575 |
nmav |
1.17 |
} else { /* HIC CGIs and NPH CGIs */ |
576 |
nmav |
1.10 |
req->cgi_status = CGI_BUFFER; |
577 |
|
|
/* I get all the buffer! */ |
578 |
|
|
req->header_line = req->header_end = req->buffer; |
579 |
|
|
} |
580 |
nmav |
1.7 |
|
581 |
nmav |
1.10 |
/* reset req->filepos for logging (it's used in pipe.c) */ |
582 |
|
|
/* still don't know why req->filesize might be reset though */ |
583 |
|
|
req->filepos = 0; |
584 |
nmav |
1.1 |
|
585 |
nmav |
1.7 |
return 1; |
586 |
nmav |
1.1 |
} |