UNIXworkcode

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 #include <inttypes.h> 42 43 #include "../util/util.h" 44 #include "../util/pblock.h" 45 #include "../daemon/protocol.h" 46 47 48 //----------------------------------------------------------------------------- 49 // Macros 50 //----------------------------------------------------------------------------- 51 52 #define CGI_VERSION "CGI/1.1" 53 54 // CGI env sizing 55 #define MAX_CGI_COMMON_VARS 23 56 #define MAX_CGI_SPECIFIC_VARS 10 57 #define MAX_CGI_CLIENT_AUTH_VARS 64 58 59 //----------------------------------------------------------------------------- 60 // cgi_parse_query 61 //----------------------------------------------------------------------------- 62 63 int cgi_parse_query(char **argv, int n, char *q) 64 { 65 int i = 0; 66 67 for (;;) { 68 // Parse an arg from the query string 69 char *arg = q; 70 while (*q != ' ' && *q != '\0') 71 q++; 72 73 // Caller must ensure argv[] is appropriately sized 74 WS_ASSERT(i < n); 75 if (i >= n) 76 return -1; 77 78 // Escape any shell characters (does a MALLOC on our behalf) 79 char c = *q; 80 *q = '\0'; 81 argv[i] = util_sh_escape(arg); 82 *q = c; 83 84 // Unescape this arg, bailing on error 85 if (!argv[i] || !util_uri_unescape_strict(argv[i])) 86 return -1; 87 88 // We successfully parsed another arg 89 i++; 90 91 // We're done when we hit the end of the query string 92 if (*q == '\0') 93 break; 94 95 q++; 96 } 97 98 return i; 99 } 100 101 //----------------------------------------------------------------------------- 102 // cgi_create_argv 103 //----------------------------------------------------------------------------- 104 105 char **cgi_create_argv(const char *program, const char *script, const char *query) 106 { 107 int nargs = 1; 108 109 // The script name, if any, will be argv[1] 110 if (script) 111 nargs++; 112 113 // Turn '+' into ' ' in query string, counting the number of arg as we go 114 char *qargs = NULL; 115 if (query && !strchr(query, '=')) { 116 qargs = STRDUP(query); 117 if (!qargs) 118 return NULL; 119 nargs++; 120 for (char *t = qargs; *t; t++) { 121 if (*t == '+') 122 *t = ' '; 123 if (*t == ' ') 124 nargs++; 125 } 126 } 127 128 // Allocate the argv[] array, leaving room for the trailing NULL 129 char **argv = (char **) MALLOC((nargs + 1) * sizeof(char *)); 130 if (!argv) 131 return NULL; 132 133 int i = 0; 134 135 // Set argv[0] to the program name 136 argv[i] = STRDUP(program); 137 i++; 138 139 // Set argv[1] to the script name 140 if (script) { 141 argv[i] = STRDUP(script); 142 i++; 143 } 144 145 // Parse the query string into argv[] 146 if (qargs) { 147 int n = cgi_parse_query(&argv[i], nargs - i, qargs); 148 if (n > 0) 149 i += n; 150 } 151 152 // Mark end of argv[] 153 argv[i] = NULL; 154 155 return argv; 156 } 157 158 void cgi_free_argv(char **args) { 159 int i = 0; 160 while(args[i] != NULL) { 161 free(args[i]); 162 i++; 163 } 164 free(args); 165 } 166 167 //---------------------------------------------------------------------------- 168 // cgi_get_request_uri 169 //---------------------------------------------------------------------------- 170 171 char* cgi_get_request_uri(Request *req) 172 { 173 // Extract the encoded URI from the request line if possible 174 char *clf_request = pblock_findkeyval(pb_key_clf_request, req->reqpb); 175 if (clf_request) { 176 // Find the beginning of the method 177 char *method = clf_request; 178 while (*method && isspace(*method)) 179 method++; 180 181 // Skip over the method 182 char *uri = method; 183 while (*uri && !isspace(*uri)) 184 uri++; 185 186 // Find the beginning of the URI 187 while (*uri && isspace(*uri)) 188 uri++; 189 190 // Find the end of the URI 191 char *end = uri; 192 while (*end && !isspace(*end)) 193 end++; 194 195 // Make a copy of the uri 196 int len = end - uri; 197 char* request_uri = (char*) MALLOC(len+1); 198 memcpy(request_uri, uri, len); 199 request_uri[len] = '\0'; 200 201 return request_uri; 202 } 203 204 // No request line. 205 return NULL; 206 } 207 208 //----------------------------------------------------------------------------- 209 // cgi_specific_vars 210 //----------------------------------------------------------------------------- 211 212 char** cgi_specific_vars(Session *sn, Request *rq, const char *args, 213 char** env, int scriptVars) 214 { 215 int y; 216 register pblock *pb; 217 char c, *t, *u; 218 219 pb = rq->reqpb; 220 221 int x; 222 env = util_env_create(env, MAX_CGI_SPECIFIC_VARS, &x); 223 env[x++] = util_env_str("GATEWAY_INTERFACE", CGI_VERSION); 224 225 // Added error check for missing request information. 226 t = pblock_findval("protocol", pb); 227 if (t == NULL) { 228 log_ereport(LOG_FAILURE, "cgi_specific_vars", "missing \"protocol\" in rq->reqpb"); 229 return NULL; 230 } 231 env[x++] = util_env_str("SERVER_PROTOCOL", t); 232 233 t = pblock_findval("method", pb); 234 if (t == NULL) { 235 log_ereport(LOG_FAILURE, "cgi_specific_vars", "missing \"request method\" in rq->reqpb"); 236 return NULL; 237 } 238 env[x++] = util_env_str("REQUEST_METHOD", t); 239 240 if (args) 241 env[x++] = util_env_str("QUERY_STRING", args); 242 243 // set REQUEST_URI 244 if (rq->orig_rq) { 245 t = cgi_get_request_uri(rq->orig_rq); 246 } else { 247 t = cgi_get_request_uri(rq); 248 } 249 if (t) { 250 env[x++] = util_env_str("REQUEST_URI", t); 251 FREE(t); 252 } 253 254 if (scriptVars) { 255 t = pblock_findval("uri", pb); 256 257 /* Simulate CGI URIs by truncating path info */ 258 if ((u = pblock_findval("path-info", rq->vars))) { 259 y = strlen(t) - strlen(u); 260 if (y >= 0) { 261 c = t[y]; 262 t[y] = '\0'; 263 } 264 env[x++] = util_env_str("SCRIPT_NAME", t); 265 if (y >= 0) { 266 t[y] = c; 267 } 268 269 env[x++] = util_env_str("PATH_INFO", u); 270 271 // TODO 272 /* 273 if((t = INTservact_translate_uri2(u, sn, rq))) { 274 env[x++] = util_env_str("PATH_TRANSLATED", t); 275 // keep path-translated in rq->vars since we may need it 276 // during fastcgi processing 277 pblock_nvinsert("path-translated", t, rq->vars); 278 FREE(t); 279 } 280 */ 281 } else { 282 env[x++] = util_env_str("SCRIPT_NAME", t); 283 } 284 285 if ((t = pblock_findval("path", rq->vars))) 286 env[x++] = util_env_str("SCRIPT_FILENAME", t); 287 } 288 289 env[x] = NULL; 290 return env; 291 } 292 293 //----------------------------------------------------------------------------- 294 // cgi_common_vars 295 //----------------------------------------------------------------------------- 296 297 char** cgi_common_vars(Session *sn, Request *rq, char **env) 298 { 299 char *t; 300 int x; 301 302 env = util_env_create(env, MAX_CGI_COMMON_VARS, &x); 303 304 /* 305 if (!_env_initialized) cgi_env_init(); 306 if (_env_path) env[x++] = util_env_str("PATH", _env_path); 307 if (_env_tz) env[x++] = util_env_str("TZ", _env_tz); 308 if (_env_lang) env[x++] = util_env_str("LANG", _env_lang); 309 if (_env_ldpath) env[x++] = util_env_str(LIBRARY_PATH, _env_ldpath); 310 env[x++] = util_env_str("SERVER_SOFTWARE", PRODUCT_HEADER_ID"/"PRODUCT_VERSION_ID); 311 */ // TODO: enable 312 313 //Ncx_string srvName, portStr; 314 //char buf1[256], buf2[64]; 315 //srvName.useStatic(buf1, sizeof(buf1), 0); 316 //portStr.useStatic(buf2, sizeof(buf2), 0); 317 //GetServerHostnameAndPort(*rq, *sn, srvName, portStr); 318 char *scheme; 319 char *host; 320 uint16_t port; 321 http_get_scheme_host_port(sn, rq, &scheme, &host, &port); 322 char portstr[8]; 323 snprintf(portstr, 8, "%" PRIu16, (int)port); 324 env[x++] = util_env_str("SERVER_PORT", portstr); 325 env[x++] = util_env_str("SERVER_NAME", host); 326 327 //t = http_uri2url_dynamic("","",sn,rq); 328 //env[x++] = util_env_str("SERVER_URL", t); 329 //FREE(t); 330 331 char *ip; 332 ip = pblock_findval("ip", sn->client); 333 t = session_dns(sn); 334 env[x++] = util_env_str("REMOTE_HOST", (t ? t : ip)); 335 env[x++] = util_env_str("REMOTE_ADDR", ip); 336 337 if((t = pblock_findval("auth-user", rq->vars))) { 338 env[x++] = util_env_str("REMOTE_USER", t); 339 if((t = pblock_findval("auth-type", rq->vars))) { 340 env[x++] = util_env_str("AUTH_TYPE", t); 341 } 342 if((t = pblock_findval("auth-userdn", rq->vars))) { 343 env[x++] = util_env_str("REMOTE_USERDN", t); 344 } 345 } 346 if((t = pblock_findval("password-policy", rq->vars))) { 347 /* chrisk made up this variable name */ 348 env[x++] = util_env_str("PASSWORD_POLICY", t); 349 } 350 351 // Handle Apache ErrorDocument-style variables from the send-error SAF 352 if (rq->orig_rq != rq) { 353 if ((t = pblock_findval("uri", rq->orig_rq->reqpb))) { 354 env[x++] = util_env_str("REDIRECT_URL", t); 355 } 356 if ((t = pblock_findval("status", rq->orig_rq->srvhdrs))) { 357 env[x++] = util_env_str("REDIRECT_STATUS", t); 358 } 359 } 360 361 if(sn->ssl) { 362 env[x++] = util_env_str("HTTPS", "ON"); 363 } 364 365 #if 0 366 if (GetSecurity(sn)) { 367 env[x++] = util_env_str("HTTPS", "ON"); 368 369 if (t = pblock_findval("keysize", sn->client)) 370 env[x++] = util_env_str("HTTPS_KEYSIZE", t); 371 372 if (t = pblock_findval("secret-keysize", sn->client)) 373 env[x++] = util_env_str("HTTPS_SECRETKEYSIZE", t); 374 375 t = pblock_findval("ssl-id", sn->client); 376 env[x++] = util_env_str("HTTPS_SESSIONID", t ? t : (char *)""); 377 378 unsigned char random_bytes[NUM_RANDOM_BYTES + 2]; 379 char random_string[NUM_RANDOM_BYTES*2 + 2]; 380 PK11_GenerateRandom(random_bytes, NUM_RANDOM_BYTES); 381 382 int i; 383 for(i = 0; i < NUM_RANDOM_BYTES; i++) { 384 sprintf(&random_string[i*2], "%02x", 385 (unsigned int)(random_bytes[i] & 0xff)); 386 } 387 random_string[NUM_RANDOM_BYTES*2] = '\0'; 388 env[x++] = util_env_str("HTTPS_RANDOM", random_string); 389 390 } else { 391 env[x++] = util_env_str("HTTPS", "OFF"); 392 } 393 #endif 394 395 env[x] = NULL; 396 397 //env = cgi_client_auth_vars(sn, rq, env); // TODO: enable 398 399 return env; 400 401 } 402