/* Spawn the piped logger process pl->program. */ static apr_status_t piped_log_spawn(piped_log *pl) { apr_procattr_t *procattr; apr_proc_t *procnew = NULL; apr_status_t status; if (((status = apr_procattr_create(&procattr, pl->p)) != APR_SUCCESS) || ((status = apr_procattr_cmdtype_set(procattr, pl->cmdtype)) != APR_SUCCESS) || ((status = apr_procattr_child_in_set(procattr, ap_piped_log_read_fd(pl), ap_piped_log_write_fd(pl))) != APR_SUCCESS) || ((status = apr_procattr_child_errfn_set(procattr, log_child_errfn)) != APR_SUCCESS) || ((status = apr_procattr_error_check_set(procattr, 1)) != APR_SUCCESS)) { char buf[120]; /* Something bad happened, give up and go away. */ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "piped_log_spawn: unable to setup child process '%s': %s", pl->program, apr_strerror(status, buf, sizeof(buf))); } else { char **args; const char *pname; apr_file_t *outfile, *errfile; if ((status = apr_file_open_stdout(&outfile, pl->p)) == APR_SUCCESS) status = apr_procattr_child_out_set(procattr, outfile, NULL); if ((status = apr_file_open_stderr(&errfile, pl->p)) == APR_SUCCESS) status = apr_procattr_child_err_set(procattr, errfile, NULL); apr_tokenize_to_argv(pl->program, &args, pl->p); pname = apr_pstrdup(pl->p, args[0]); procnew = apr_pcalloc(pl->p, sizeof(apr_proc_t)); status = apr_proc_create(procnew, pname, (const char * const *) args, NULL, procattr, pl->p); if (status == APR_SUCCESS) { pl->pid = procnew; /* procnew->in was dup2'd from ap_piped_log_write_fd(pl); * since the original fd is still valid, close the copy to * avoid a leak. */ apr_file_close(procnew->in); procnew->in = NULL; apr_proc_other_child_register(procnew, piped_log_maintenance, pl, ap_piped_log_write_fd(pl), pl->p); close_handle_in_child(pl->p, ap_piped_log_read_fd(pl)); } else { char buf[120]; /* Something bad happened, give up and go away. */ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, "unable to start piped log program '%s': %s", pl->program, apr_strerror(status, buf, sizeof(buf))); } } return status; }
AP_DECLARE(piped_log *) ap_open_piped_log_ex(apr_pool_t *p, const char *program, apr_cmdtype_e cmdtype) { piped_log *pl; pl = apr_palloc(p, sizeof (*pl)); pl->p = p; pl->program = apr_pstrdup(p, program); pl->pid = NULL; pl->cmdtype = cmdtype; if (apr_file_pipe_create(&ap_piped_log_read_fd(pl), &ap_piped_log_write_fd(pl), p) != APR_SUCCESS) { return NULL; } apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup_for_exec); if (piped_log_spawn(pl) != APR_SUCCESS) { apr_pool_cleanup_kill(p, pl, piped_log_cleanup); apr_file_close(ap_piped_log_read_fd(pl)); apr_file_close(ap_piped_log_write_fd(pl)); return NULL; } return pl; }
static apr_status_t piped_log_cleanup(void *data) { piped_log *pl = data; apr_file_close(ap_piped_log_write_fd(pl)); return APR_SUCCESS; }
/** * This function is called when the "JSONMatchLog" configuration directive is parsed. */ static const char *set_jsonerrorlog_path(cmd_parms *cmd, void *cfg, const char *arg) { dir_config_t *dcfg = (dir_config_t *) cfg; char *jsonmatchlog_path = apr_pstrdup(cmd->pool, arg); if (jsonmatchlog_path[0] == '|') { const char *pipe_name = jsonmatchlog_path + 1; piped_log *pipe_log; pipe_log = ap_open_piped_log(cmd->pool, pipe_name); if (pipe_log == NULL) return apr_psprintf(cmd->pool, "mod_defender: Failed to open the json match log pipe: %s", pipe_name); dcfg->jsonmatchlog_file = ap_piped_log_write_fd(pipe_log); } else { const char *file_name = ap_server_root_relative(cmd->pool, jsonmatchlog_path); apr_status_t rc; rc = apr_file_open(&dcfg->jsonmatchlog_file, file_name, APR_WRITE | APR_APPEND | APR_CREATE | APR_BINARY, APR_UREAD | APR_UWRITE | APR_GREAD, cmd->pool); if (rc != APR_SUCCESS) return apr_psprintf(cmd->pool, "mod_defender: Failed to open the json match log file: %s", file_name); } return NULL; // success }
static void open_agent_log(server_rec *s, pool *p) { agent_log_state *cls = ap_get_module_config(s->module_config, &agent_log_module); char *fname = ap_server_root_relative(p, cls->fname); if (cls->agent_fd > 0) return; /* virtual log shared w/main server */ if (*cls->fname == '|') { piped_log *pl; pl = ap_open_piped_log(p, cls->fname + 1); if (pl == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, s, "couldn't spawn agent log pipe"); exit(1); } cls->agent_fd = ap_piped_log_write_fd(pl); } else if (*cls->fname != '\0') { if ((cls->agent_fd = ap_popenf(p, fname, xfer_flags, xfer_mode)) < 0) { ap_log_error(APLOG_MARK, APLOG_ERR, s, "could not open agent log file %s.", fname); exit(1); } } }
static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, const char* name) { if (*name == '|') { piped_log *pl; pl = ap_open_piped_log(p, name + 1); if (pl == NULL) { return NULL;; } return ap_piped_log_write_fd(pl); } else { const char *fname = ap_server_root_relative(p, name); apr_file_t *fd; apr_status_t rv; if (!fname) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, "invalid transfer log path %s.", name); return NULL; } rv = apr_file_open(&fd, fname, xfer_flags, xfer_perms, p); if (rv != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "could not open transfer log file %s.", fname); return NULL; } return fd; } }
static int mod_stlog_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *server) { stlog_config_t *conf = ap_get_module_config(server->module_config, &request_dumper_module); if (*conf->log_filename == '|') { piped_log *pl; pl = ap_open_piped_log(p, conf->log_filename + 1); if (pl == NULL) { ap_log_error(APLOG_MARK , APLOG_ERR , 0 , NULL , "%s ERROR %s: dump pipe log oepn failed: %s" , MODULE_NAME , __func__ , conf->log_filename ); return OK; } mod_stlog_fp = ap_piped_log_write_fd(pl); } else { if(apr_file_open(&mod_stlog_fp, conf->log_filename, APR_WRITE|APR_APPEND|APR_CREATE, APR_OS_DEFAULT, p) != APR_SUCCESS){ ap_log_error(APLOG_MARK , APLOG_ERR , 0 , NULL , "%s ERROR %s: dump log file oepn failed: %s" , MODULE_NAME , __func__ , conf->log_filename ); return OK; } } ap_log_perror(APLOG_MARK , APLOG_NOTICE , 0 , p , "%s %s: %s / %s mechanism enabled." , MODULE_NAME , __func__ , MODULE_NAME , MODULE_VERSION ); return OK; }
/* * Open the SSL logfile */ void ssl_log_open(server_rec *s_main, server_rec *s, pool *p) { char *szLogFile; SSLSrvConfigRec *sc_main = mySrvConfig(s_main); SSLSrvConfigRec *sc = mySrvConfig(s); piped_log *pl; char *cp; /* * Short-circuit for inherited logfiles in order to save * filedescriptors in mass-vhost situation. Be careful, this works * fine because the close happens implicitly by the pool facility. */ if ( s != s_main && sc_main->fileLogFile != NULL && ( (sc->szLogFile == NULL) || ( sc->szLogFile != NULL && sc_main->szLogFile != NULL && strEQ(sc->szLogFile, sc_main->szLogFile)))) { sc->fileLogFile = sc_main->fileLogFile; } else if (sc->szLogFile != NULL) { if (strEQ(sc->szLogFile, "/dev/null")) return; else if (sc->szLogFile[0] == '|') { cp = sc->szLogFile+1; while (*cp == ' ' || *cp == '\t') cp++; szLogFile = ssl_util_server_root_relative(p, "log", cp); if ((pl = ap_open_piped_log(p, szLogFile)) == NULL) { ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, "Cannot open reliable pipe to SSL logfile filter %s", szLogFile); ssl_die(); } sc->fileLogFile = ap_pfdopen(p, ap_piped_log_write_fd(pl), "a"); setbuf(sc->fileLogFile, NULL); } else { szLogFile = ssl_util_server_root_relative(p, "log", sc->szLogFile); if ((sc->fileLogFile = ap_pfopen(p, szLogFile, "a")) == NULL) { ssl_log(s, SSL_LOG_ERROR|SSL_ADD_ERRNO, "Cannot open SSL logfile %s", szLogFile); ssl_die(); } setbuf(sc->fileLogFile, NULL); } } return; }
AP_DECLARE(piped_log *) ap_open_piped_log(apr_pool_t *p, const char *program) { piped_log *pl; apr_file_t *dummy = NULL; int rc; rc = log_child(p, program, &dummy, 0); if (rc != APR_SUCCESS) { ap_log_error(APLOG_MARK, APLOG_STARTUP, rc, NULL, "Couldn't start piped log process"); return NULL; } pl = apr_palloc(p, sizeof (*pl)); pl->p = p; ap_piped_log_read_fd(pl) = NULL; ap_piped_log_write_fd(pl) = dummy; apr_pool_cleanup_register(p, pl, piped_log_cleanup, piped_log_cleanup); return pl; }
static config_log_state *open_config_log(server_rec *s, pool *p, config_log_state *cls, array_header *default_format) { if (cls->log_fd > 0) { return cls; /* virtual config shared w/main server */ } if (cls->fname == NULL) { return cls; /* Leave it NULL to decline. */ } if (*cls->fname == '|') { piped_log *pl; pl = ap_open_piped_log(p, cls->fname + 1); if (pl == NULL) { exit(1); } cls->log_fd = ap_piped_log_write_fd(pl); } else { char *fname = ap_server_root_relative(p, cls->fname); if ((cls->log_fd = ap_popenf_ex(p, fname, xfer_flags, xfer_mode, 1)) < 0) { ap_log_error(APLOG_MARK, APLOG_ERR, s, "could not open transfer log file %s.", fname); exit(1); } } #ifdef BUFFERED_LOGS cls->outcnt = 0; #endif return cls; }
static apr_file_t *ap_open_log(apr_pool_t *p, server_rec *s, const char *base, log_options *ls, apr_time_t tm) { if (*base == '|') { /* We have piped log handling here because once log rotation has been * enabled we become responsible for /all/ transfer log output server * wide. That's a consequence of the way the log output hooks in * mod_log_config are implemented. Unfortunately this means we have to * duplicate functionality from mod_log_config. Note that we don't * support the buffered logging mode that mlc implements. */ piped_log *pl; if (ls->enabled) { /* Can't rotate a piped log */ ls->enabled = 0; ap_log_error(APLOG_MARK, APLOG_WARNING, APR_SUCCESS, s, "disabled log rotation for piped log %s.", base); } if (pl = ap_open_piped_log(p, base + 1), NULL == pl) { return NULL; } return ap_piped_log_write_fd(pl); } else { apr_file_t *fd; apr_status_t rv; const char *name = ap_server_root_relative(p, base); if (NULL == name) { ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, "invalid transfer log path %s.", base); return NULL; } if (ls->enabled) { apr_time_t log_time = tm - ls->offset; if (strchr(base, '%') != NULL) { apr_time_exp_t e; apr_time_exp_gmt(&e, log_time); name = ap_pstrftime(p, name, &e); } else { /* Synthesize the log name using the specified time in seconds as a * suffix. We subtract the offset here because it was added when * quantizing the time but we want the name to reflect the actual * time when the log rotated. We don't reverse the local time * adjustment because, presumably, if you've specified local time * logging you want the filenames to use local time. */ name = apr_psprintf(p, "%s.%" APR_TIME_T_FMT, name, apr_time_sec(log_time)); } } if (rv = apr_file_open(&fd, name, xfer_flags, xfer_perms, p), APR_SUCCESS != rv) { ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "could not open transfer log file %s.", name); return NULL; } return fd; } }