static ret_t add_environment (cherokee_handler_cgi_t *cgi, cherokee_connection_t *conn) { ret_t ret; cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); cherokee_buffer_t *tmp = THREAD_TMP_BUF2(CONN_THREAD(conn)); ret = cherokee_handler_cgi_base_build_envp (HDL_CGI_BASE(cgi), conn); if (unlikely (ret != ret_ok)) return ret; /* CONTENT_LENGTH */ if (http_method_with_input (conn->header.method)) { cherokee_buffer_clean (tmp); cherokee_buffer_add_ullong10 (tmp, conn->post.len); set_env (cgi_base, "CONTENT_LENGTH", tmp->buf, tmp->len); } /* SCRIPT_FILENAME */ if (cgi_base->executable.len <= 0) return ret_error; set_env (cgi_base, "SCRIPT_FILENAME", cgi_base->executable.buf, cgi_base->executable.len); return ret_ok; }
static ret_t process_buffer (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *inbuf, cherokee_buffer_t *outbuf) { ret_t ret; do { ret = process_package (hdl, inbuf, outbuf); } while (ret == ret_eagain); if (ret == ret_ok) { if (cherokee_buffer_is_empty (outbuf)) return (HDL_CGI_BASE(hdl)->got_eof) ? ret_eof : ret_eagain; } return ret; }
ret_t cherokee_handler_cgi_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props) { int i; CHEROKEE_NEW_STRUCT (n, handler_cgi); /* Init the base class */ cherokee_handler_cgi_base_init (HDL_CGI_BASE(n), cnt, PLUGIN_INFO_HANDLER_PTR(cgi), HANDLER_PROPS(props), cherokee_handler_cgi_add_env_pair, read_from_cgi); /* Virtual methods */ MODULE(n)->init = (module_func_init_t) cherokee_handler_cgi_init; MODULE(n)->free = (module_func_free_t) cherokee_handler_cgi_free; HANDLER(n)->read_post = (handler_func_read_post_t) cherokee_handler_cgi_read_post; /* Virtual methods: implemented by handler_cgi_base */ HANDLER(n)->add_headers = (handler_func_add_headers_t) cherokee_handler_cgi_base_add_headers; HANDLER(n)->step = (handler_func_step_t) cherokee_handler_cgi_base_step; /* Init */ n->pipeInput = -1; n->pipeOutput = -1; #ifdef _WIN32 n->process = NULL; n->thread = NULL; cherokee_buffer_init (&n->envp); #else n->pid = -1; n->envp_last = 0; for (i=0; i<ENV_VAR_NUM; i++) n->envp[i] = NULL; #endif /* Return the object */ *hdl = HANDLER(n); return ret_ok; }
ret_t cherokee_handler_cgi_init (cherokee_handler_cgi_t *cgi) { ret_t ret; cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); cherokee_connection_t *conn = HANDLER_CONN(cgi); switch (cgi_base->init_phase) { case hcgi_phase_build_headers: /* Extracts PATH_INFO and filename from request uri */ if (cherokee_buffer_is_empty (&cgi_base->executable)) { ret = cherokee_handler_cgi_base_extract_path (cgi_base, true); if (unlikely (ret < ret_ok)) { return ret; } } /* It has to update the timeout of the connection, * otherwhise the server will drop it for the CGI * isn't fast enough */ conn->timeout = cherokee_bogonow_now + CGI_TIMEOUT; cgi_base->init_phase = hcgi_phase_connect; case hcgi_phase_connect: /* Launch the CGI */ ret = fork_and_execute_cgi_via_spawner(cgi); if (unlikely (ret != ret_ok)) { ret = fork_and_execute_cgi(cgi); if (unlikely (ret != ret_ok)) { return ret; } } default: break; } TRACE (ENTRIES, "finishing %s\n", "ret_ok"); return ret_ok; }
static ret_t fork_and_execute_cgi_win32 (cherokee_handler_cgi_t *cgi) { int re; PROCESS_INFORMATION pi; STARTUPINFO si; char *cmd; cherokee_buffer_t cmd_line = CHEROKEE_BUF_INIT; cherokee_buffer_t exec_dir = CHEROKEE_BUF_INIT; cherokee_connection_t *conn = HANDLER_CONN(cgi); SECURITY_ATTRIBUTES saSecAtr; HANDLE hProc; HANDLE hChildStdinRd = INVALID_HANDLE_VALUE; HANDLE hChildStdinWr = INVALID_HANDLE_VALUE; HANDLE hChildStdoutRd = INVALID_HANDLE_VALUE; HANDLE hChildStdoutWr = INVALID_HANDLE_VALUE; /* Create the environment for the process */ add_environment (cgi, conn); cherokee_buffer_add (&cgi->envp, "\0", 1); /* Command line */ cmd = HDL_CGI_BASE(cgi)->executable.buf; cherokee_buffer_add (&cmd_line, cmd, strlen(cmd)); // cherokee_buffer_add_va (&cmd_line, " \"%s\"", HDL_CGI_BASE(cgi)->param.buf); /* Execution directory */ if (! cherokee_buffer_is_empty (&conn->effective_directory)) { cherokee_buffer_add_buffer (&exec_dir, &conn->effective_directory); } else { char *file = strrchr (cmd, '/'); char *end = HDL_CGI_BASE(cgi)->executable.buf + HDL_CGI_BASE(cgi)->executable.len; cherokee_buffer_add (&exec_dir, cmd, HDL_CGI_BASE(cgi)->executable.len - (end - file)); } /* Set the bInheritHandle flag so pipe handles are inherited. */ memset(&saSecAtr, 0, sizeof(SECURITY_ATTRIBUTES)); saSecAtr.nLength = sizeof(SECURITY_ATTRIBUTES); saSecAtr.lpSecurityDescriptor = NULL; saSecAtr.bInheritHandle = TRUE; /* Create the pipes */ hProc = GetCurrentProcess(); re = CreatePipe (&hChildStdoutRd, &hChildStdoutWr, &saSecAtr, 0); if (!re) return ret_error; re = CreatePipe (&hChildStdinRd, &hChildStdinWr, &saSecAtr, 0); if (!re) return ret_error; /* Make them inheritable */ re = DuplicateHandle (hProc, hChildStdoutRd, hProc, &hChildStdoutRd, 0, TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); if (!re) return ret_error; re = DuplicateHandle (hProc, hChildStdinWr, hProc, &hChildStdinWr, 0, TRUE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); if (!re) return ret_error; /* Starting information */ ZeroMemory (&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.hStdOutput = hChildStdoutWr; si.hStdError = hChildStdoutWr; si.hStdInput = hChildStdinRd; si.dwFlags |= STARTF_USESTDHANDLES; TRACE (ENTRIES, "exec %s dir %s\n", cmd_line.buf, exec_dir.buf); /* Launch the child process */ re = CreateProcess (cmd, /* ApplicationName */ cmd_line.buf, /* Command line */ NULL, /* Process handle not inheritable */ NULL, /* Thread handle not inheritable */ TRUE, /* Handle inheritance */ 0, /* Creation flags */ cgi->envp.buf, /* Use parent's environment block */ exec_dir.buf, /* Use parent's starting directory */ &si, /* Pointer to STARTUPINFO structure */ &pi); /* Pointer to PROCESS_INFORMATION structure */ CloseHandle (hChildStdinRd); CloseHandle (hChildStdoutWr); if (!re) { LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_CREATEPROCESS, GetLastError()); CloseHandle (pi.hProcess); CloseHandle (pi.hThread); conn->error_code = http_internal_error; return ret_error; } cherokee_buffer_mrproper (&cmd_line); cherokee_buffer_mrproper (&exec_dir); cgi->thread = pi.hThread; cgi->process = pi.hProcess; /* Wait for the CGI process to be ready */ WaitForInputIdle (pi.hProcess, INFINITE); /* Extract the file descriptors */ cgi->pipeInput = _open_osfhandle((LONG)hChildStdoutRd, O_BINARY|_O_RDONLY); if (! conn->post.len <= 0) { CloseHandle (hChildStdinWr); } else { cgi->pipeOutput = _open_osfhandle((LONG)hChildStdinWr, O_BINARY|_O_WRONLY); } TRACE (ENTRIES, "In fd %d, Out fd %d\n", cgi->pipeInput, cgi->pipeOutput); return ret_ok; }
static NORETURN void manage_child_cgi_process (cherokee_handler_cgi_t *cgi, int pipe_cgi[2], int pipe_server[2]) { /* Child process */ int re; char *script; cherokee_connection_t *conn = HANDLER_CONN(cgi); cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); char *absolute_path = cgi_base->executable.buf; char *argv[2] = { NULL, NULL }; #ifdef TRACE_ENABLED TRACE(ENTRIES, "About to execute: '%s'\n", absolute_path); if (! cherokee_buffer_is_empty (&conn->effective_directory)) TRACE(ENTRIES, "Effective directory: '%s'\n", conn->effective_directory.buf); else TRACE(ENTRIES, "No Effective directory %s", "\n"); #endif /* Close useless sides */ cherokee_fd_close (pipe_cgi[0]); cherokee_fd_close (pipe_server[1]); /* Change stdin and out */ re = dup2 (pipe_server[0], STDIN_FILENO); cherokee_fd_close (pipe_server[0]); if (unlikely (re != 0)) { printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d" CRLF_CRLF, __FILE__, __LINE__); exit(1); } re |= dup2 (pipe_cgi[1], STDOUT_FILENO); cherokee_fd_close (pipe_cgi[1]); /* Redirect the stderr */ if ((CONN_VSRV(conn)->error_writer != NULL) && (CONN_VSRV(conn)->error_writer->fd != -1)) { dup2 (CONN_VSRV(conn)->error_writer->fd, STDERR_FILENO); } # if 0 /* Set unbuffered */ setvbuf (stdin, NULL, _IONBF, 0); setvbuf (stdout, NULL, _IONBF, 0); # endif /* Enable blocking mode */ _fd_set_properties (STDIN_FILENO, 0, O_NONBLOCK); _fd_set_properties (STDOUT_FILENO, 0, O_NONBLOCK); _fd_set_properties (STDERR_FILENO, 0, O_NONBLOCK); /* Sets the new environ. */ add_environment (cgi, conn); /* Change the directory */ if (! cherokee_buffer_is_empty (&conn->effective_directory)) { re = chdir (conn->effective_directory.buf); } else { char *file = strrchr (absolute_path, '/'); *file = '\0'; re = chdir (absolute_path); *file = '/'; } if (re < 0) { printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d" CRLF_CRLF, __FILE__, __LINE__); exit(1); } /* Build de argv array */ script = absolute_path; argv[0] = absolute_path; /* Change the execution user? */ if (HANDLER_CGI_PROPS(cgi_base)->change_user) { struct stat info; re = stat (script, &info); if (re >= 0) { re = setuid (info.st_uid); if (re != 0) { LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_SETID, script, info.st_uid); } } } /* Reset the server-wide signal handlers */ #ifdef SIGPIPE signal (SIGPIPE, SIG_DFL); #endif #ifdef SIGHUP signal (SIGHUP, SIG_DFL); #endif #ifdef SIGSEGV signal (SIGSEGV, SIG_DFL); #endif #ifdef SIGBUS signal (SIGBUS, SIG_DFL); #endif #ifdef SIGTERM signal (SIGTERM, SIG_DFL); #endif /* Lets go.. execute it! */ re = execve (absolute_path, argv, cgi->envp); if (re < 0) { int err = errno; char buferr[ERROR_MAX_BUFSIZE]; switch (err) { case ENOENT: printf ("Status: 404" CRLF_CRLF); break; default: printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d cmd=%s: %s" CRLF_CRLF, __FILE__, __LINE__, absolute_path, strerror(err)); } /* Don't use the logging system (concurrency issues) */ LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_EXECUTE, absolute_path, cherokee_strerror_r(err, buferr, sizeof(buferr))); exit(1); } /* There is no way, it could reach this point. */ SHOULDNT_HAPPEN; exit(2); }
ret_t cherokee_handler_cgi_free (cherokee_handler_cgi_t *cgi) { int i; /* Free the rest of the handler CGI memory */ cherokee_handler_cgi_base_free (HDL_CGI_BASE(cgi)); /* Close the connection with the CGI */ if (cgi->pipeInput > 0) { cherokee_fd_close (cgi->pipeInput); cgi->pipeInput = -1; } if (cgi->pipeOutput > 0) { cherokee_fd_close (cgi->pipeOutput); cgi->pipeOutput = -1; } /* Kill the CGI */ #ifndef _WIN32 if (cgi->pid > 0) { pid_t pid; cint_t tries = 2; while (true) { do { pid = waitpid (cgi->pid, NULL, WNOHANG); } while ((pid == 1) && (errno == EINTR)); if (pid > 0) { /* Ok */ break; } else if (errno == ECHILD) { /* Already death */ break; } /* Failed */ kill (cgi->pid, SIGTERM); tries--; if (tries < 0) break; } } #else if (cgi->process) { WaitForSingleObject (cgi->process, INFINITE); CloseHandle (cgi->process); } if (cgi->thread) { CloseHandle (cgi->thread); } #endif /* Free the environment variables */ #ifdef _WIN32 cherokee_buffer_mrproper (&cgi->envp); #else for (i=0; i<cgi->envp_last; i++) { free (cgi->envp[i]); cgi->envp[i] = NULL; } #endif /* For some reason, we have seen that the SIGCHLD signal does not call to * our handler in a server with a lot of requests, so the wait() call, * necessary to free the resources used by the CGI, is not called. So I * think that a possible solution couble be to put the waitpid call in the * _free method of this handler, so when the handler ends, this will free * the resources used by our cool CGI. */ do_reap(); return ret_ok; }
/* Methods implementation */ static ret_t process_package (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *inbuf, cherokee_buffer_t *outbuf) { FCGI_Header *header; cuint_t len; char *data; cuint_t type; cuint_t id; cuint_t padding; /* Is there enough information? */ if (inbuf->len < sizeof(FCGI_Header)) return ret_ok; /* At least there is a header */ header = (FCGI_Header *)inbuf->buf; if (header->version != 1) { cherokee_buffer_print_debug (inbuf, -1); LOG_ERROR_S (CHEROKEE_ERROR_HANDLER_FCGI_VERSION); return ret_error; } if (header->type != FCGI_STDERR && header->type != FCGI_STDOUT && header->type != FCGI_END_REQUEST) { cherokee_buffer_print_debug (inbuf, -1); LOG_ERROR_S (CHEROKEE_ERROR_HANDLER_FCGI_PARSING); return ret_error; } /* Read the header */ type = header->type; padding = header->paddingLength; id = (header->requestIdB0 | (header->requestIdB1 << 8)); len = (header->contentLengthB0 | (header->contentLengthB1 << 8)); data = inbuf->buf + FCGI_HEADER_LEN; /* printf ("have %d, hdr=%d exp_len=%d pad=%d\n", inbuf->len, FCGI_HEADER_LEN, len, padding); */ /* Is the package complete? */ if (len + padding > inbuf->len - FCGI_HEADER_LEN) { /* printf ("Incomplete: %d < %d\n", len + padding, inbuf->len - FCGI_HEADER_LEN); */ return ret_ok; } /* It has received the full package content */ switch (type) { case FCGI_STDERR: /* printf ("READ:STDERR (%d): %s", len, data?data:""); */ LOG_ERROR (CHEROKEE_ERROR_HANDLER_FCGI_STDERR, data); /* Debug mode */ if (SOURCE_INT(hdl->src_ref)->debug) { PRINT_MSG ("%.*s\n", len, data); } break; case FCGI_STDOUT: /* printf ("READ:STDOUT eof=%d: %d", HDL_CGI_BASE(hdl)->got_eof, len); */ cherokee_buffer_add (outbuf, data, len); break; case FCGI_END_REQUEST: /* printf ("READ:END"); */ HDL_CGI_BASE(hdl)->got_eof = true; break; default: SHOULDNT_HAPPEN; } cherokee_buffer_move_to_begin (inbuf, len + FCGI_HEADER_LEN + padding); /* printf ("- FCGI left %d\n", inbuf->len); */ return ret_eagain; }
static ret_t fork_and_execute_cgi_via_spawner(cherokee_handler_cgi_t *cgi) { int re; int pid = -1; cherokee_connection_t *conn = HANDLER_CONN(cgi); cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); ret_t ret; uid_t uid; gid_t gid; cherokee_buffer_t empty = CHEROKEE_BUF_INIT; cherokee_buffer_t username = CHEROKEE_BUF_INIT; cherokee_services_fdmap_t fd_map; cherokee_buffer_t *chdir = NULL; cherokee_buffer_t chdir_backing = CHEROKEE_BUF_INIT; struct passwd ent; char ent_tmp[1024]; struct { int cgi[2]; int server[2]; } pipes; TRACE (ENTRIES, "Trying to create CGI via spawner\n"); if (! cherokee_buffer_is_empty (&conn->effective_directory)) { chdir = &conn->effective_directory; } else { int ofs = cgi_base->executable.len - 1; while (ofs >= 0 && cgi_base->executable.buf[ofs] != '/') { ofs--; } TRACE (ENTRIES, "While building chdir, ofs=%d\n", ofs); if (ofs < 0 || cherokee_buffer_add (&chdir_backing, cgi_base->executable.buf, ofs + 1) != ret_ok) { conn->error_code = http_internal_error; TRACE (ENTRIES, "Failed, cannot build chdir entry\n"); cherokee_buffer_mrproper(&chdir_backing); return ret_error; } chdir = &chdir_backing; } /* Creates the pipes ... */ re = cherokee_pipe (pipes.cgi); re |= cherokee_pipe (pipes.server); if (re != 0) { conn->error_code = http_internal_error; cherokee_buffer_mrproper(&chdir_backing); TRACE (ENTRIES, "Failed, cannot build pipes\n"); return ret_error; } if (HANDLER_CGI_PROPS(cgi_base)->change_user) { struct stat nocache_info; struct stat *info; cherokee_iocache_entry_t *io_entry = NULL; cherokee_server_t *srv = CONN_SRV(conn); cherokee_handler_cgi_base_props_t *props = HANDLER_CGI_BASE_PROPS(cgi); ret = cherokee_io_stat (srv->iocache, &cgi_base->executable, props->use_cache, &nocache_info, &io_entry, &info); if (ret != ret_ok) { info = &nocache_info; nocache_info.st_uid = getuid(); nocache_info.st_gid = getgid(); } uid = info->st_uid; gid = info->st_gid; cherokee_iocache_entry_unref(&io_entry); } else { /* Not changing, so launch as the same uid/gid as the worker */ uid = getuid(); gid = getgid(); } /* Determine the username of the owner of the file */ ret = cherokee_getpwuid(uid, &ent, ent_tmp, sizeof (ent_tmp)); if (ret != ret_ok || cherokee_buffer_add(&username, ent.pw_name, strlen(ent.pw_name) != ret_ok)) { cherokee_fd_close(pipes.cgi[0]); cherokee_fd_close(pipes.cgi[1]); cherokee_fd_close(pipes.server[0]); cherokee_fd_close(pipes.server[1]); conn->error_code = http_internal_error; cherokee_buffer_mrproper(&chdir_backing); cherokee_buffer_mrproper(&username); TRACE (ENTRIES, "Failed, Unable to retrieve username for uid %d\n", uid); return ret_error; } /* Update the environment ready to run */ add_environment (cgi, conn); /* Set up the FD map */ fd_map.fd_in = pipes.server[0]; fd_map.fd_out = pipes.cgi[1]; if ((CONN_VSRV(conn)->error_writer != NULL) && (CONN_VSRV(conn)->error_writer->fd != -1)) { fd_map.fd_err = CONN_VSRV(conn)->error_writer->fd; } else { fd_map.fd_err = fd_map.fd_out; } TRACE (ENTRIES, "Doing Spawn\n"); ret = cherokee_services_client_spawn (&cgi_base->executable, &username, uid, gid, &empty, chdir, false, cgi->envp, CONN_VSRV(conn)->error_writer, &pid, &fd_map); cherokee_buffer_mrproper(&chdir_backing); cherokee_buffer_mrproper(&username); /* Close the client FDs */ cherokee_fd_close (pipes.server[0]); cherokee_fd_close (pipes.cgi[1]); /* Did we fail to try to spawn? */ if (ret != ret_ok) { /* Close the server FDs too */ cherokee_fd_close (pipes.server[1]); cherokee_fd_close (pipes.cgi[0]); TRACE (ENTRIES, "Failed to spawn\n"); return ret; } /* Did we try, but fail, to spawn? */ if (pid == -1) { /* Close the server FDs too */ cherokee_fd_close (pipes.server[1]); cherokee_fd_close (pipes.cgi[0]); TRACE (ENTRIES, "Spawned, but failed server side\n"); return ret_error; } /* Successfully launched */ cgi->pid = pid; cgi->pipeInput = pipes.cgi[0]; cgi->pipeOutput = pipes.server[1]; /* Set to Input to NON-BLOCKING */ _fd_set_properties (cgi->pipeInput, O_NDELAY|O_NONBLOCK, 0); TRACE (ENTRIES, "CGI running, PID=%d\n", pid); return ret_ok; }
static NORETURN void manage_child_cgi_process (cherokee_handler_cgi_t *cgi, int pipe_cgi[2], int pipe_server[2]) { /* Child process */ int re; cherokee_connection_t *conn = HANDLER_CONN(cgi); cherokee_handler_cgi_base_t *cgi_base = HDL_CGI_BASE(cgi); char *absolute_path = cgi_base->executable.buf; char *argv[2] = { NULL, NULL }; #ifdef TRACE_ENABLED TRACE(ENTRIES, "About to execute: '%s'\n", absolute_path); if (! cherokee_buffer_is_empty (&conn->effective_directory)) TRACE(ENTRIES, "Effective directory: '%s'\n", conn->effective_directory.buf); else TRACE(ENTRIES, "No Effective directory %s", "\n"); #endif /* Close useless sides */ cherokee_fd_close (pipe_cgi[0]); cherokee_fd_close (pipe_server[1]); /* Change stdin and out */ cherokee_fd_close (STDIN_FILENO); re = dup2 (pipe_server[0], STDIN_FILENO); cherokee_fd_close (pipe_server[0]); if (unlikely (re != 0)) { printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d" CRLF_CRLF, __FILE__, __LINE__); exit(1); } cherokee_fd_close (STDOUT_FILENO); re |= dup2 (pipe_cgi[1], STDOUT_FILENO); cherokee_fd_close (pipe_cgi[1]); /* Redirect the stderr */ if ((CONN_VSRV(conn)->error_writer != NULL) && (CONN_VSRV(conn)->error_writer->fd != -1)) { cherokee_fd_close (STDERR_FILENO); dup2 (CONN_VSRV(conn)->error_writer->fd, STDERR_FILENO); } # if 0 /* Set unbuffered */ setvbuf (stdin, NULL, _IONBF, 0); setvbuf (stdout, NULL, _IONBF, 0); # endif /* Enable blocking mode */ _fd_set_properties (STDIN_FILENO, 0, O_NONBLOCK); _fd_set_properties (STDOUT_FILENO, 0, O_NONBLOCK); _fd_set_properties (STDERR_FILENO, 0, O_NONBLOCK); /* Sets the new environ. */ add_environment (cgi, conn); /* Change the directory */ if (! cherokee_buffer_is_empty (&conn->effective_directory)) { re = chdir (conn->effective_directory.buf); } else { char *file = strrchr (absolute_path, '/'); if (file != NULL) { *file = '\0'; re = chdir (absolute_path); *file = '/'; } else { re = -1; } } if (re < 0) { printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d" CRLF_CRLF, __FILE__, __LINE__); exit(1); } /* Build de argv array */ argv[0] = absolute_path; /* Change the execution user? */ if (HANDLER_CGI_PROPS(cgi_base)->change_user) { struct stat nocache_info; struct stat *info; cherokee_iocache_entry_t *io_entry = NULL; cherokee_server_t *srv = CONN_SRV(conn); cherokee_handler_cgi_base_props_t *props = HANDLER_CGI_BASE_PROPS(cgi); ret_t ret = cherokee_io_stat (srv->iocache, &cgi_base->executable, props->use_cache, &nocache_info, &io_entry, &info); if (ret != ret_ok) { info = &nocache_info; } re = setuid (info->st_uid); if (re != 0) { LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_SETID, absolute_path, info->st_uid); } cherokee_iocache_entry_unref(&io_entry); } /* Reset the server-wide signal handlers */ cherokee_reset_signals(); /* Lets go.. execute it! */ do { re = execve (absolute_path, argv, cgi->envp); } while ((re == -1) && (errno == EINTR)); if (re < 0) { int err = errno; char buferr[ERROR_MAX_BUFSIZE]; switch (err) { case ENODEV: case ENOTDIR: case ENOENT: printf ("Status: 404" CRLF_CRLF); exit(0); case EPERM: case EACCES: case ENOEXEC: printf ("Status: 403" CRLF_CRLF); exit(0); default: printf ("Status: 500" CRLF_CRLF); printf ("X-Debug: file=%s line=%d cmd=%s errno=%d: %s" CRLF_CRLF, __FILE__, __LINE__, absolute_path, err, strerror(err)); } /* Don't use the logging system (concurrency issues) */ LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_EXECUTE, absolute_path, cherokee_strerror_r(err, buferr, sizeof(buferr))); exit(1); } /* There is no way, it could reach this point. */ SHOULDNT_HAPPEN; exit(2); }