⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_cgid.c

📁 linux网络服务器工具
💻 C
📖 第 1 页 / 共 4 页
字号:
    cgid_server_conf *conf = ap_get_module_config(s->module_config,                                                  &cgid_module);    conf->logname = ap_server_root_relative(cmd->pool, arg);    if (!conf->logname) {        return apr_pstrcat(cmd->pool, "Invalid ScriptLog path ",                           arg, NULL);    }    return NULL;}static const char *set_scriptlog_length(cmd_parms *cmd, void *dummy, const char *arg){    server_rec *s = cmd->server;    cgid_server_conf *conf = ap_get_module_config(s->module_config,                                                  &cgid_module);    conf->logbytes = atol(arg);    return NULL;}static const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy, const char *arg){    server_rec *s = cmd->server;    cgid_server_conf *conf = ap_get_module_config(s->module_config,                                                  &cgid_module);    conf->bufbytes = atoi(arg);    return NULL;}static const char *set_script_socket(cmd_parms *cmd, void *dummy, const char *arg){    const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);    if (err != NULL) {        return err;    }    /* Make sure the pid is appended to the sockname */    sockname = ap_append_pid(cmd->pool, arg, ".");    sockname = ap_server_root_relative(cmd->pool, sockname);    if (!sockname) {        return apr_pstrcat(cmd->pool, "Invalid ScriptSock path",                           arg, NULL);    }    return NULL;}static const command_rec cgid_cmds[] ={    AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF,                  "the name of a log for script debugging info"),    AP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF,                  "the maximum length (in bytes) of the script debug log"),    AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF,                  "the maximum size (in bytes) to record of a POST request"),    AP_INIT_TAKE1("ScriptSock", set_script_socket, NULL, RSRC_CONF,                  "the name of the socket to use for communication with "                  "the cgi daemon."),    {NULL}};static int log_scripterror(request_rec *r, cgid_server_conf * conf, int ret,                           apr_status_t rv, char *error){    apr_file_t *f = NULL;    struct stat finfo;    char time_str[APR_CTIME_LEN];    int log_flags = rv ? APLOG_ERR : APLOG_ERR;    ap_log_rerror(APLOG_MARK, log_flags, rv, r,                "%s: %s", error, r->filename);    /* XXX Very expensive mainline case! Open, then getfileinfo! */    if (!conf->logname ||        ((stat(conf->logname, &finfo) == 0)         && (finfo.st_size > conf->logbytes)) ||         (apr_file_open(&f, conf->logname,                  APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) {        return ret;    }    /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */    apr_ctime(time_str, apr_time_now());    apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,            r->args ? "?" : "", r->args ? r->args : "", r->protocol);    /* "%% 500 /usr/local/apache/cgid-bin */    apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);    apr_file_printf(f, "%%error\n%s\n", error);    apr_file_close(f);    return ret;}static int log_script(request_rec *r, cgid_server_conf * conf, int ret,                      char *dbuf, const char *sbuf, apr_bucket_brigade *bb,                      apr_file_t *script_err){    const apr_array_header_t *hdrs_arr = apr_table_elts(r->headers_in);    const apr_table_entry_t *hdrs = (apr_table_entry_t *) hdrs_arr->elts;    char argsbuffer[HUGE_STRING_LEN];    apr_file_t *f = NULL;    apr_bucket *e;    const char *buf;    apr_size_t len;    apr_status_t rv;    int first;    int i;    struct stat finfo;    char time_str[APR_CTIME_LEN];    /* XXX Very expensive mainline case! Open, then getfileinfo! */    if (!conf->logname ||        ((stat(conf->logname, &finfo) == 0)         && (finfo.st_size > conf->logbytes)) ||         (apr_file_open(&f, conf->logname,                  APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT, r->pool) != APR_SUCCESS)) {        /* Soak up script output */        discard_script_output(bb);        if (script_err) {            while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,                                 script_err) == APR_SUCCESS)                continue;        }        return ret;    }    /* "%% [Wed Jun 19 10:53:21 1996] GET /cgid-bin/printenv HTTP/1.0" */    apr_ctime(time_str, apr_time_now());    apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,            r->args ? "?" : "", r->args ? r->args : "", r->protocol);    /* "%% 500 /usr/local/apache/cgid-bin" */    apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);    apr_file_puts("%request\n", f);    for (i = 0; i < hdrs_arr->nelts; ++i) {        if (!hdrs[i].key)            continue;        apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);    }    if ((r->method_number == M_POST || r->method_number == M_PUT)        && *dbuf) {        apr_file_printf(f, "\n%s\n", dbuf);    }    apr_file_puts("%response\n", f);    hdrs_arr = apr_table_elts(r->err_headers_out);    hdrs = (const apr_table_entry_t *) hdrs_arr->elts;    for (i = 0; i < hdrs_arr->nelts; ++i) {        if (!hdrs[i].key)            continue;        apr_file_printf(f, "%s: %s\n", hdrs[i].key, hdrs[i].val);    }    if (sbuf && *sbuf)        apr_file_printf(f, "%s\n", sbuf);    first = 1;    for (e = APR_BRIGADE_FIRST(bb);         e != APR_BRIGADE_SENTINEL(bb);         e = APR_BUCKET_NEXT(e))    {        if (APR_BUCKET_IS_EOS(e)) {            break;        }        rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);        if (rv != APR_SUCCESS || (len == 0)) {            break;        }        if (first) {            apr_file_puts("%stdout\n", f);            first = 0;        }        apr_file_write(f, buf, &len);        apr_file_puts("\n", f);    }    if (script_err) {        if (apr_file_gets(argsbuffer, HUGE_STRING_LEN,                          script_err) == APR_SUCCESS) {            apr_file_puts("%stderr\n", f);            apr_file_puts(argsbuffer, f);            while (apr_file_gets(argsbuffer, HUGE_STRING_LEN,                                 script_err) == APR_SUCCESS)                apr_file_puts(argsbuffer, f);            apr_file_puts("\n", f);        }    }    if (script_err) {        apr_file_close(script_err);    }    apr_file_close(f);    return ret;}static apr_status_t close_unix_socket(void *thefd){    int fd = (int)((long)thefd);    return close(fd);}static int connect_to_daemon(int *sdptr, request_rec *r,                             cgid_server_conf *conf){    struct sockaddr_un unix_addr;    int sd;    int connect_tries;    apr_interval_time_t sliding_timer;    memset(&unix_addr, 0, sizeof(unix_addr));    unix_addr.sun_family = AF_UNIX;    apr_cpystrn(unix_addr.sun_path, sockname, sizeof unix_addr.sun_path);    connect_tries = 0;    sliding_timer = 100000; /* 100 milliseconds */    while (1) {        ++connect_tries;        if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {            return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, errno,                                   "unable to create socket to cgi daemon");        }        if (connect(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) {            if (errno == ECONNREFUSED && connect_tries < DEFAULT_CONNECT_ATTEMPTS) {                ap_log_rerror(APLOG_MARK, APLOG_DEBUG, errno, r,                              "connect #%d to cgi daemon failed, sleeping before retry",                              connect_tries);                close(sd);                apr_sleep(sliding_timer);                if (sliding_timer < apr_time_from_sec(2)) {                    sliding_timer *= 2;                }            }            else {                close(sd);                return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, errno,                                       "unable to connect to cgi daemon after multiple tries");            }        }        else {            apr_pool_cleanup_register(r->pool, (void *)((long)sd),                                      close_unix_socket, apr_pool_cleanup_null);            break; /* we got connected! */        }        /* gotta try again, but make sure the cgid daemon is still around */        if (kill(daemon_pid, 0) != 0) {            return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, errno,                                   "cgid daemon is gone; is Apache terminating?");        }    }    *sdptr = sd;    return OK;}static void discard_script_output(apr_bucket_brigade *bb){    apr_bucket *e;    const char *buf;    apr_size_t len;    apr_status_t rv;    for (e = APR_BRIGADE_FIRST(bb);         e != APR_BRIGADE_SENTINEL(bb);         e = APR_BUCKET_NEXT(e))    {        if (APR_BUCKET_IS_EOS(e)) {            break;        }        rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);        if (rv != APR_SUCCESS) {            break;        }    }}/**************************************************************** * * Actual cgid handling... */struct cleanup_script_info {    request_rec *r;    unsigned long conn_id;    cgid_server_conf *conf;};static apr_status_t dead_yet(pid_t pid, apr_interval_time_t max_wait){    apr_interval_time_t interval = 10000; /* 10 ms */    apr_interval_time_t total = 0;    do {#ifdef _AIX        /* On AIX, for processes like mod_cgid's script children where         * SIGCHLD is ignored, kill(pid,0) returns success for up to         * one second after the script child exits, based on when a         * daemon runs to clean up unnecessary process table entries.         * getpgid() can report the proper info (-1/ESRCH) immediately.         */        if (getpgid(pid) < 0) {#else        if (kill(pid, 0) < 0) {#endif            return APR_SUCCESS;        }        apr_sleep(interval);        total = total + interval;        if (interval < 500000) {            interval *= 2;        }    } while (total < max_wait);    return APR_EGENERAL;}static apr_status_t cleanup_nonchild_process(request_rec *r, pid_t pid){    kill(pid, SIGTERM); /* in case it isn't dead yet */    if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) {        return APR_SUCCESS;    }    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,                  "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL",                  pid);    kill(pid, SIGKILL);    if (dead_yet(pid, apr_time_from_sec(3)) == APR_SUCCESS) {        return APR_SUCCESS;    }    ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,                  "CGI process %" APR_PID_T_FMT " didn't exit, sending SIGKILL again",                  pid);    kill(pid, SIGKILL);    return APR_EGENERAL;}static apr_status_t cleanup_script(void *vptr){    struct cleanup_script_info *info = vptr;    int sd;    int rc;    cgid_req_t req = {0};    pid_t pid;    apr_status_t stat;    rc = connect_to_daemon(&sd, info->r, info->conf);    if (rc != OK) {        return APR_EGENERAL;    }    /* we got a socket, and there is already a cleanup registered for it */    req.req_type = GETPID_REQ;    req.ppid = parent_pid;    req.conn_id = info->r->connection->id;    stat = sock_write(sd, &req, sizeof(req));    if (stat != APR_SUCCESS) {        return stat;    }    /* wait for pid of script */    stat = sock_read(sd, &pid, sizeof(pid));    if (stat != APR_SUCCESS) {        return stat;    }    if (pid == 0) {        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, info->r,                      "daemon couldn't find CGI process for connection %lu",                      info->conn_id);        return APR_EGENERAL;    }    return cleanup_nonchild_process(info->r, pid);}static int cgid_handler(request_rec *r){    conn_rec *c = r->connection;    int retval, nph, dbpos = 0;    char *argv0, *dbuf = NULL;    apr_bucket_brigade *bb;    apr_bucket *b;    cgid_server_conf *conf;    int is_included;    int seen_eos, child_stopped_reading;    int sd;    char **env;    apr_file_t *tempsock;    struct cleanup_script_info *info;    apr_status_t rv;    if (strcmp(r->handler,CGI_MAGIC_TYPE) && strcmp(r->handler,"cgi-script"))        return DECLINED;    conf = ap_get_module_config(r->server->module_config, &cgid_module);    is_included = !strcmp(r->protocol, "INCLUDED");    if ((argv0 = strrchr(r->filename, '/')) != NULL)        argv0++;    else        argv0 = r->filename;    nph = !(strncmp(argv0, "nph-", 4));    argv0 = r->filename;    if (!(ap_allow_options(r) & OPT_EXECCGI) && !is_scriptaliased(r))        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,                               "Options ExecCGI is off in this directory");    if (nph && is_included)        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,                               "attempt to include NPH CGI script");#if defined(OS2) || defined(WIN32)#error mod_cgid does not work on this platform.  If you teach it to, look#error at mod_cgi.c for required code in this path.#else    if (r->finfo.filetype == 0)        return log_scripterror(r, conf, HTTP_NOT_FOUND, 0,                               "script not found or unable to stat");#endif    if (r->finfo.filetype == APR_DIR)        return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,                               "attempt to invoke directory as script");    if ((r->used_path_info == AP_REQ_REJECT_PATH_INFO) &&        r->path_info && *r->path_info)    {        /* default to accept */        return log_scripterror(r, conf, HTTP_NOT_FOUND, 0,                               "AcceptPathInfo off disallows user's path");    }/*    if (!ap_suexec_enabled) {        if (!ap_can_exec(&r->finfo))            return log_scripterror(r, conf, HTTP_FORBIDDEN, 0,                                   "file permissions deny server execution");    }*/    ap_add_common_vars(r);    ap_add_cgi_vars(r);    env = ap_create_environment(r->pool, r->subprocess_env);    if ((retval = connect_to_daemon(&sd, r, conf)) != OK) {        return retval;    }    rv = send_req(sd, r, argv0, env, CGI_REQ);    if (rv != APR_SUCCESS) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -