|
1 /* |
|
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
|
3 * |
|
4 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
|
5 * |
|
6 * THE BSD LICENSE |
|
7 * |
|
8 * Redistribution and use in source and binary forms, with or without |
|
9 * modification, are permitted provided that the following conditions are met: |
|
10 * |
|
11 * Redistributions of source code must retain the above copyright notice, this |
|
12 * list of conditions and the following disclaimer. |
|
13 * Redistributions in binary form must reproduce the above copyright notice, |
|
14 * this list of conditions and the following disclaimer in the documentation |
|
15 * and/or other materials provided with the distribution. |
|
16 * |
|
17 * Neither the name of the nor the names of its contributors may be |
|
18 * used to endorse or promote products derived from this software without |
|
19 * specific prior written permission. |
|
20 * |
|
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER |
|
25 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
|
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
|
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
|
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
32 */ |
|
33 |
|
34 // code from open webserver |
|
35 // safs/cgi.cpp |
|
36 |
|
37 #include "cgiutils.h" |
|
38 |
|
39 #include <stdio.h> |
|
40 #include <stdlib.h> |
|
41 |
|
42 #include "../util/util.h" |
|
43 #include "../util/pblock.h" |
|
44 |
|
45 |
|
46 //----------------------------------------------------------------------------- |
|
47 // Macros |
|
48 //----------------------------------------------------------------------------- |
|
49 |
|
50 #define CGI_VERSION "CGI/1.1" |
|
51 |
|
52 // CGI env sizing |
|
53 #define MAX_CGI_COMMON_VARS 23 |
|
54 #define MAX_CGI_SPECIFIC_VARS 10 |
|
55 #define MAX_CGI_CLIENT_AUTH_VARS 64 |
|
56 |
|
57 //----------------------------------------------------------------------------- |
|
58 // cgi_parse_query |
|
59 //----------------------------------------------------------------------------- |
|
60 |
|
61 int cgi_parse_query(char **argv, int n, char *q) |
|
62 { |
|
63 int i = 0; |
|
64 |
|
65 for (;;) { |
|
66 // Parse an arg from the query string |
|
67 char *arg = q; |
|
68 while (*q != ' ' && *q != '\0') |
|
69 q++; |
|
70 |
|
71 // Caller must ensure argv[] is appropriately sized |
|
72 WS_ASSERT(i < n); |
|
73 if (i >= n) |
|
74 return -1; |
|
75 |
|
76 // Escape any shell characters (does a MALLOC on our behalf) |
|
77 char c = *q; |
|
78 *q = '\0'; |
|
79 argv[i] = util_sh_escape(arg); // TODO |
|
80 *q = c; |
|
81 |
|
82 // Unescape this arg, bailing on error |
|
83 if (!argv[i] || !util_uri_unescape_strict(argv[i])) |
|
84 return -1; |
|
85 |
|
86 // We successfully parsed another arg |
|
87 i++; |
|
88 |
|
89 // We're done when we hit the end of the query string |
|
90 if (*q == '\0') |
|
91 break; |
|
92 |
|
93 q++; |
|
94 } |
|
95 |
|
96 return i; |
|
97 } |
|
98 |
|
99 //----------------------------------------------------------------------------- |
|
100 // cgi_create_argv |
|
101 //----------------------------------------------------------------------------- |
|
102 |
|
103 char **cgi_create_argv(const char *program, const char *script, const char *query) |
|
104 { |
|
105 int nargs = 1; |
|
106 |
|
107 // The script name, if any, will be argv[1] |
|
108 if (script) |
|
109 nargs++; |
|
110 |
|
111 // Turn '+' into ' ' in query string, counting the number of arg as we go |
|
112 char *qargs = NULL; |
|
113 if (query && !strchr(query, '=')) { |
|
114 qargs = STRDUP(query); |
|
115 if (!qargs) |
|
116 return NULL; |
|
117 nargs++; |
|
118 for (char *t = qargs; *t; t++) { |
|
119 if (*t == '+') |
|
120 *t = ' '; |
|
121 if (*t == ' ') |
|
122 nargs++; |
|
123 } |
|
124 } |
|
125 |
|
126 // Allocate the argv[] array, leaving room for the trailing NULL |
|
127 char **argv = (char **) MALLOC((nargs + 1) * sizeof(char *)); |
|
128 if (!argv) |
|
129 return NULL; |
|
130 |
|
131 int i = 0; |
|
132 |
|
133 // Set argv[0] to the program name |
|
134 argv[i] = STRDUP(program); |
|
135 i++; |
|
136 |
|
137 // Set argv[1] to the script name |
|
138 if (script) { |
|
139 argv[i] = STRDUP(script); |
|
140 i++; |
|
141 } |
|
142 |
|
143 // Parse the query string into argv[] |
|
144 if (qargs) { |
|
145 int n = cgi_parse_query(&argv[i], nargs - i, qargs); |
|
146 if (n > 0) |
|
147 i += n; |
|
148 } |
|
149 |
|
150 // Mark end of argv[] |
|
151 argv[i] = NULL; |
|
152 |
|
153 return argv; |
|
154 } |
|
155 |
|
156 //---------------------------------------------------------------------------- |
|
157 // cgi_get_request_uri |
|
158 //---------------------------------------------------------------------------- |
|
159 |
|
160 char* cgi_get_request_uri(Request *req) |
|
161 { |
|
162 // Extract the encoded URI from the request line if possible |
|
163 char *clf_request = pblock_findkeyval(pb_key_clf_request, req->reqpb); |
|
164 if (clf_request) { |
|
165 // Find the beginning of the method |
|
166 char *method = clf_request; |
|
167 while (*method && isspace(*method)) |
|
168 method++; |
|
169 |
|
170 // Skip over the method |
|
171 char *uri = method; |
|
172 while (*uri && !isspace(*uri)) |
|
173 uri++; |
|
174 |
|
175 // Find the beginning of the URI |
|
176 while (*uri && isspace(*uri)) |
|
177 uri++; |
|
178 |
|
179 // Find the end of the URI |
|
180 char *end = uri; |
|
181 while (*end && !isspace(*end)) |
|
182 end++; |
|
183 |
|
184 // Make a copy of the uri |
|
185 int len = end - uri; |
|
186 char* request_uri = (char*) MALLOC(len+1); |
|
187 memcpy(request_uri, uri, len); |
|
188 request_uri[len] = '\0'; |
|
189 |
|
190 return request_uri; |
|
191 } |
|
192 |
|
193 // No request line. |
|
194 return NULL; |
|
195 } |
|
196 |
|
197 //----------------------------------------------------------------------------- |
|
198 // cgi_specific_vars |
|
199 //----------------------------------------------------------------------------- |
|
200 |
|
201 char** cgi_specific_vars(Session *sn, Request *rq, const char *args, |
|
202 char** env, int scriptVars) |
|
203 { |
|
204 int y; |
|
205 register pblock *pb; |
|
206 char c, *t, *u; |
|
207 |
|
208 pb = rq->reqpb; |
|
209 |
|
210 int x; |
|
211 env = util_env_create(env, MAX_CGI_SPECIFIC_VARS, &x); |
|
212 env[x++] = util_env_str("GATEWAY_INTERFACE", CGI_VERSION); |
|
213 |
|
214 // Added error check for missing request information. |
|
215 t = pblock_findval("protocol", pb); |
|
216 if (t == NULL) { |
|
217 log_ereport(LOG_FAILURE, "cgi_specific_vars", "missing \"protocol\" in rq->reqpb"); |
|
218 return NULL; |
|
219 } |
|
220 env[x++] = util_env_str("SERVER_PROTOCOL", t); |
|
221 |
|
222 t = pblock_findval("method", pb); |
|
223 if (t == NULL) { |
|
224 log_ereport(LOG_FAILURE, "cgi_specific_vars", "missing \"request method\" in rq->reqpb"); |
|
225 return NULL; |
|
226 } |
|
227 env[x++] = util_env_str("REQUEST_METHOD", t); |
|
228 |
|
229 if (args) |
|
230 env[x++] = util_env_str("QUERY_STRING", args); |
|
231 |
|
232 // set REQUEST_URI |
|
233 if (rq->orig_rq) { |
|
234 t = cgi_get_request_uri(rq->orig_rq); |
|
235 } else { |
|
236 t = cgi_get_request_uri(rq); |
|
237 } |
|
238 if (t) { |
|
239 env[x++] = util_env_str("REQUEST_URI", t); |
|
240 FREE(t); |
|
241 } |
|
242 |
|
243 if (scriptVars) { |
|
244 t = pblock_findval("uri", pb); |
|
245 |
|
246 /* Simulate CGI URIs by truncating path info */ |
|
247 if ((u = pblock_findval("path-info", rq->vars))) { |
|
248 y = strlen(t) - strlen(u); |
|
249 if (y >= 0) { |
|
250 c = t[y]; |
|
251 t[y] = '\0'; |
|
252 } |
|
253 env[x++] = util_env_str("SCRIPT_NAME", t); |
|
254 if (y >= 0) { |
|
255 t[y] = c; |
|
256 } |
|
257 |
|
258 env[x++] = util_env_str("PATH_INFO", u); |
|
259 |
|
260 // TODO |
|
261 /* |
|
262 if((t = INTservact_translate_uri2(u, sn, rq))) { |
|
263 env[x++] = util_env_str("PATH_TRANSLATED", t); |
|
264 // keep path-translated in rq->vars since we may need it |
|
265 // during fastcgi processing |
|
266 pblock_nvinsert("path-translated", t, rq->vars); |
|
267 FREE(t); |
|
268 } |
|
269 */ |
|
270 } else { |
|
271 env[x++] = util_env_str("SCRIPT_NAME", t); |
|
272 } |
|
273 |
|
274 if (t = pblock_findval("path", rq->vars)) |
|
275 env[x++] = util_env_str("SCRIPT_FILENAME", t); |
|
276 } |
|
277 |
|
278 env[x] = NULL; |
|
279 return env; |
|
280 } |
|
281 |
|
282 //----------------------------------------------------------------------------- |
|
283 // cgi_common_vars |
|
284 //----------------------------------------------------------------------------- |
|
285 |
|
286 char** cgi_common_vars(Session *sn, Request *rq, char **env) |
|
287 { |
|
288 // TODO: enable code and add cgi_client_auth_vars() |
|
289 return env; |
|
290 #if 0 |
|
291 char *t; |
|
292 int x; |
|
293 |
|
294 env = util_env_create(env, MAX_CGI_COMMON_VARS, &x); |
|
295 |
|
296 if (!_env_initialized) cgi_env_init(); |
|
297 if (_env_path) env[x++] = util_env_str("PATH", _env_path); |
|
298 if (_env_tz) env[x++] = util_env_str("TZ", _env_tz); |
|
299 if (_env_lang) env[x++] = util_env_str("LANG", _env_lang); |
|
300 if (_env_ldpath) env[x++] = util_env_str(LIBRARY_PATH, _env_ldpath); |
|
301 env[x++] = util_env_str("SERVER_SOFTWARE", PRODUCT_HEADER_ID"/"PRODUCT_VERSION_ID); |
|
302 |
|
303 NSString srvName, portStr; |
|
304 char buf1[256], buf2[64]; |
|
305 srvName.useStatic(buf1, sizeof(buf1), 0); |
|
306 portStr.useStatic(buf2, sizeof(buf2), 0); |
|
307 GetServerHostnameAndPort(*rq, *sn, srvName, portStr); |
|
308 env[x++] = util_env_str("SERVER_PORT", (char*)(const char*)portStr); |
|
309 env[x++] = util_env_str("SERVER_NAME", (char*)(const char*)srvName); |
|
310 |
|
311 t = http_uri2url_dynamic("","",sn,rq); |
|
312 env[x++] = util_env_str("SERVER_URL", t); |
|
313 FREE(t); |
|
314 |
|
315 char *ip; |
|
316 ip = pblock_findval("ip", sn->client); |
|
317 t = session_dns(sn); |
|
318 env[x++] = util_env_str("REMOTE_HOST", (t ? t : ip)); |
|
319 env[x++] = util_env_str("REMOTE_ADDR", ip); |
|
320 |
|
321 if((t = pblock_findval("auth-user", rq->vars))) { |
|
322 env[x++] = util_env_str("REMOTE_USER", t); |
|
323 if((t = pblock_findval("auth-type", rq->vars))) { |
|
324 env[x++] = util_env_str("AUTH_TYPE", t); |
|
325 } |
|
326 if((t = pblock_findval("auth-userdn", rq->vars))) { |
|
327 env[x++] = util_env_str("REMOTE_USERDN", t); |
|
328 } |
|
329 } |
|
330 if((t = pblock_findval("password-policy", rq->vars))) { |
|
331 /* chrisk made up this variable name */ |
|
332 env[x++] = util_env_str("PASSWORD_POLICY", t); |
|
333 } |
|
334 |
|
335 // Handle Apache ErrorDocument-style variables from the send-error SAF |
|
336 if (rq->orig_rq != rq) { |
|
337 if (t = pblock_findval("uri", rq->orig_rq->reqpb)) { |
|
338 env[x++] = util_env_str("REDIRECT_URL", t); |
|
339 } |
|
340 if (t = pblock_findval("status", rq->orig_rq->srvhdrs)) { |
|
341 env[x++] = util_env_str("REDIRECT_STATUS", t); |
|
342 } |
|
343 } |
|
344 |
|
345 if (GetSecurity(sn)) { |
|
346 env[x++] = util_env_str("HTTPS", "ON"); |
|
347 |
|
348 if (t = pblock_findval("keysize", sn->client)) |
|
349 env[x++] = util_env_str("HTTPS_KEYSIZE", t); |
|
350 |
|
351 if (t = pblock_findval("secret-keysize", sn->client)) |
|
352 env[x++] = util_env_str("HTTPS_SECRETKEYSIZE", t); |
|
353 |
|
354 t = pblock_findval("ssl-id", sn->client); |
|
355 env[x++] = util_env_str("HTTPS_SESSIONID", t ? t : (char *)""); |
|
356 |
|
357 unsigned char random_bytes[NUM_RANDOM_BYTES + 2]; |
|
358 char random_string[NUM_RANDOM_BYTES*2 + 2]; |
|
359 PK11_GenerateRandom(random_bytes, NUM_RANDOM_BYTES); |
|
360 |
|
361 int i; |
|
362 for(i = 0; i < NUM_RANDOM_BYTES; i++) { |
|
363 sprintf(&random_string[i*2], "%02x", |
|
364 (unsigned int)(random_bytes[i] & 0xff)); |
|
365 } |
|
366 random_string[NUM_RANDOM_BYTES*2] = '\0'; |
|
367 env[x++] = util_env_str("HTTPS_RANDOM", random_string); |
|
368 |
|
369 } else { |
|
370 env[x++] = util_env_str("HTTPS", "OFF"); |
|
371 } |
|
372 |
|
373 env[x] = NULL; |
|
374 |
|
375 env = cgi_client_auth_vars(sn, rq, env); |
|
376 |
|
377 return env; |
|
378 #endif |
|
379 } |