void create_argv(request * req, char **aargv) { char *p, *q, *r; int aargc; q = req->query_string; aargv[0] = req->pathname; if (q && !strchr(q, '=')) { /* fprintf(stderr,"Parsing string %s\n",q); */ q = strdup(q); for (aargc = 1; q && (aargc < ARGC_MAX);) { r = q; if ((p = strchr(q, '+'))) { *p = '\0'; q = p + 1; } else { q = NULL; } if (unescape_uri(r)) { /* printf("parameter %d: %s\n",aargc,r); */ aargv[aargc++] = r; } } aargv[aargc] = NULL; } else { aargv[1] = NULL; } }
/* Execute this program, passing all the URIs in the list as arguments. * URIs that are files on the local machine will be passed as simple * pathnames. The uri_list should be freed after this function returns. */ void run_with_files(const char *path, GList *uri_list) { const char **argv; int argc = 0, i; struct stat info; MIME_type *type; if (stat(path, &info)) { delayed_error(_("Program %s not found - deleted?"), path); return; } argv = g_malloc(sizeof(char *) * (g_list_length(uri_list) + 2)); if (S_ISDIR(info.st_mode)) argv[argc++] = make_path(path, "AppRun"); else argv[argc++] = path; while (uri_list) { const EscapedPath *uri = uri_list->data; char *local; local = get_local_path(uri); if (local) argv[argc++] = local; else argv[argc++] = unescape_uri(uri); uri_list = uri_list->next; } argv[argc++] = NULL; type = type_from_path(argv[0]); if (type && type == application_x_desktop) { run_desktop(argv[0], argv + 1, home_dir); } else { rox_spawn(home_dir, argv); } for (i = 1; i < argc; i++) g_free((gchar *) argv[i]); g_free(argv); }
int process_header_end(request * req) { if (!req->logline) { send_r_error(req); return 0; } /* Percent-decode request */ if (unescape_uri(req->request_uri, &(req->query_string)) == 0) { log_error_doc(req); fputs("Problem unescaping uri\n", stderr); send_r_bad_request(req); return 0; } /* clean pathname */ clean_pathname(req->request_uri); if (req->request_uri[0] != '/') { send_r_bad_request(req); return 0; } if (translate_uri(req) == 0) { /* unescape, parse uri */ SQUASH_KA(req); return 0; /* failure, close down */ } if (req->method == M_POST) { req->post_data_fd = create_temporary_file(1, NULL, 0); if (req->post_data_fd == 0) return(0); return(1); /* success */ } if (req->is_cgi) { return init_cgi(req); } req->status = WRITE; return init_get(req); /* get and head */ }
static void create_argv(request * req, char **aargv) { char *p, *q, *r; int aargc; q = req->query_string; aargv[0] = req->pathname; /* here, we handle a special "indexed" query string. * Taken from the CGI/1.1 SPEC: * This is identified by a GET or HEAD request with a query string * with no *unencoded* '=' in it. * For such a request, I'm supposed to parse the search string * into words, according to the following rules: search-string = search-word *( "+" search-word ) search-word = 1*schar schar = xunreserved | escaped | xreserved xunreserved = alpha | digit | xsafe | extra xsafe = "$" | "-" | "_" | "." xreserved = ";" | "/" | "?" | ":" | "@" | "&" After parsing, each word is URL-decoded, optionally encoded in a system defined manner, and then the argument list is set to the list of words. Thus, schar is alpha|digit|"$"|"-"|"_"|"."|";"|"/"|"?"|":"|"@"|"&" As of this writing, escape.pl escapes the following chars: "-", "_", ".", "!", "~", "*", "'", "(", ")", "0".."9", "A".."Z", "a".."z", ";", "/", "?", ":", "@", "&", "=", "+", "\$", "," Which therefore means "=", "+", "~", "!", "*", "'", "(", ")", "," are *not* escaped and should be? Wait, we don't do any escaping, and nor should we. According to the RFC draft, we unescape and then re-escape in a "system defined manner" (here: none). The CGI/1.1 draft (03, latest is 1999???) is very unclear here. I am using the latest published RFC, 2396, for what does and does not need escaping. Since boa builds the argument list and does not call /bin/sh, (boa uses execve for CGI) */ if (q && !strchr(q, '=')) { /* we have an 'index' style */ q = strdup(q); if (!q) { log_error_doc(req); fputs("unable to strdup 'q' in create_argv!\n", stderr); _exit(EXIT_FAILURE); } for (aargc = 1; q && (aargc < CGI_ARGC_MAX);) { r = q; /* for an index-style CGI, + is used to separate arguments * an escaped '+' is of no concern to us */ if ((p = strchr(q, '+'))) { *p = '\0'; q = p + 1; } else { q = NULL; } if (unescape_uri(r, NULL)) { /* printf("parameter %d: %s\n",aargc,r); */ aargv[aargc++] = r; } } aargv[aargc] = NULL; } else { aargv[1] = NULL; } }
int process_header_end(request * req) { if (!req->logline) { log_error_doc(req); fputs("No logline in process_header_end\n", stderr); send_r_error(req); return 0; } /* Percent-decode request */ if (unescape_uri(req->request_uri, &(req->query_string)) == 0) { log_error_doc(req); fputs("URI contains bogus characters\n", stderr); send_r_bad_request(req); return 0; } /* clean pathname */ clean_pathname(req->request_uri); if (req->request_uri[0] != '/') { log_error("URI does not begin with '/'\n"); send_r_bad_request(req); return 0; } if (vhost_root) { char *c; if (!req->header_host) { req->host = strdup(default_vhost); } else { req->host = strdup(req->header_host); } if (!req->host) { log_error_doc(req); fputs("unable to strdup default_vhost/req->header_host\n", stderr); send_r_error(req); return 0; } strlower(req->host); /* check for port, and remove * we essentially ignore the port, because we cannot * as yet report a different port than the one we are * listening on */ c = strchr(req->host, ':'); if (c) *c = '\0'; if (check_host(req->host) < 1) { log_error_doc(req); fputs("host invalid!\n", stderr); send_r_bad_request(req); return 0; } } if (translate_uri(req) == 0) { /* unescape, parse uri */ /* errors already logged */ SQUASH_KA(req); return 0; /* failure, close down */ } if (req->method == M_POST) { req->post_data_fd = create_temporary_file(1, NULL, 0); if (req->post_data_fd == 0) { /* errors already logged */ send_r_error(req); return 0; } if (fcntl(req->post_data_fd, F_SETFD, 1) == -1) { log_error_doc(req); fputs("unable to set close-on-exec for req->post_data_fd!\n", stderr); close(req->post_data_fd); req->post_data_fd = 0; send_r_error(req); return 0; } return 1; /* success */ } if (req->cgi_type) { return init_cgi(req); } req->status = WRITE; // return complete_response(req); return init_control(req); // return init_get(req); /* get and head */ }
int process_header_end(request * req) { if (!req->logline) { log_error_doc(req); fputs("No logline in process_header_end\n", stderr); send_r_error(req); return 0; } /* Percent-decode request */ if (unescape_uri(req->request_uri, &(req->query_string)) == 0) { log_error_doc(req); fputs("URI contains bogus characters\n", stderr); send_r_bad_request(req); return 0; } /* clean pathname */ clean_pathname(req->request_uri); if (req->request_uri[0] != '/') { log_error("URI does not begin with '/'\n"); send_r_bad_request(req); return 0; } if (use_caudium_hack) { /* We check whether the path is of the form "/(ll)/foo/..." which is used by the Caudium webserver for caching purposes and people have bookmarked it. To cope with this we simply strip it of. */ if (req->request_uri[0] == '/' && req->request_uri[1] == '(' && req->request_uri[2] >= 'a' && req->request_uri[2] <= 'z' && req->request_uri[3] >= 'a' && req->request_uri[3] <= 'z' && req->request_uri[4] == ')' && req->request_uri[5] == '/' && req->request_uri[6] ) { unsigned int len = strlen(req->request_uri); memmove (req->request_uri, req->request_uri+5, len - 5 + 1); } } if (vhost_root) { char *c; if (!req->header_host) { req->host = strdup(default_vhost); } else { req->host = strdup(req->header_host); } if (!req->host) { log_error_doc(req); fputs("unable to strdup default_vhost/req->header_host\n", stderr); send_r_error(req); return 0; } strlower(req->host); /* check for port, and remove * we essentially ignore the port, because we cannot * as yet report a different port than the one we are * listening on */ c = strchr(req->host, ':'); if (c) *c = '\0'; if (check_host(req->host) < 1) { log_error_doc(req); fputs("host invalid!\n", stderr); send_r_bad_request(req); return 0; } } if (translate_uri(req) == 0) { /* unescape, parse uri */ /* errors already logged */ SQUASH_KA(req); return 0; /* failure, close down */ } if (req->method == M_POST) { req->post_data_fd = create_temporary_file(1, NULL, 0); if (req->post_data_fd == 0) { /* errors already logged */ send_r_error(req); return 0; } if (fcntl(req->post_data_fd, F_SETFD, 1) == -1) { boa_perror(req, "unable to set close-on-exec for req->post_data_fd!"); close(req->post_data_fd); req->post_data_fd = 0; return 0; } return 1; /* success */ } if (req->cgi_type) { return init_cgi(req); } req->status = WRITE; return init_get(req); /* get and head */ }