ib_status_t ib_util_mkpath(const char *path, mode_t mode) { char *ppath = NULL; char *cpath = NULL; ib_status_t rc; if (strcmp(path, ".") == 0 || strcmp(path, "/") == 0) { return IB_OK; } /* Attempt to create the dir. If it returns ENOENT, then * recursivly attempt to create the parent dir(s) until * they are all created. */ if ((mkdir(path, mode) == -1) && (errno == ENOENT)) { int ec; /* Some implementations may modify the path argument, * so make a copy first. */ if ((cpath = strdup(path)) == NULL) { return IB_EALLOC; } if ((ppath = dirname(cpath)) == NULL) { rc = IB_EINVAL; goto cleanup; } rc = ib_util_mkpath(ppath, mode); if (rc != IB_OK) { goto cleanup; } /* Parent path was created, so try again. */ ec = mkdir(path, mode); if (ec == -1) { ec = errno; ib_util_log_error(3, "Failed to create path \"%s\": %s (%d)", path, strerror(ec), ec); rc = IB_EINVAL; goto cleanup; } } rc = IB_OK; cleanup: if (cpath != NULL) { free(cpath); } return rc; }
/// @test Test util path functions - ib_util_mkpath() TEST_F(TestIBUtilMkPath, mkpath) { ib_status_t rc; char *tmp; char path[pathsize_full+1]; struct stat sbuf; strcpy(m_basedir, "/tmp/XXXXXX"); tmp = mkdtemp(m_basedir); ASSERT_STRNE(NULL, tmp) << "mkdtemp() returned " << strerror(errno) << std::endl; snprintf(path, pathsize_full, "%s/a", m_basedir); rc = ib_util_mkpath(path, 0700); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(0, stat(path, &sbuf)); ASSERT_TRUE(S_ISDIR(sbuf.st_mode)); ASSERT_EQ((mode_t)0700, (sbuf.st_mode & 0777)); snprintf(path, pathsize_full, "%s/a/b", m_basedir); rc = ib_util_mkpath(path, 0750); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(0, stat(path, &sbuf)); ASSERT_TRUE(S_ISDIR(sbuf.st_mode)); ASSERT_EQ((mode_t)0750, (sbuf.st_mode & 0777)); snprintf(path, pathsize_full, "%s/b/c/d/e", m_basedir); rc = ib_util_mkpath(path, 0755); ASSERT_EQ(IB_OK, rc); ASSERT_EQ(0, stat(path, &sbuf)); ASSERT_TRUE(S_ISDIR(sbuf.st_mode)); ASSERT_EQ((mode_t)0755, (sbuf.st_mode & 0777)); }
ib_status_t core_audit_open_auditfile(ib_engine_t *ib, ib_auditlog_t *log, ib_core_audit_cfg_t *cfg, ib_core_cfg_t *corecfg) { const int dtmp_sz = 64; const int dn_sz = 512; char *dtmp = (char *)malloc(dtmp_sz); char *dn = (char *)malloc(dn_sz); char *audit_filename; size_t audit_filename_sz; char *temp_filename; size_t temp_filename_sz; int fd; const time_t log_seconds = IB_CLOCK_SECS(log->tx->t.logtime); int sys_rc; ib_status_t ib_rc; struct tm gmtime_result; const ib_site_t *site; if (dtmp == NULL || dn == NULL) { if (dtmp != NULL) { free(dtmp); } if (dn != NULL) { free(dn); } return IB_EALLOC; } gmtime_r(&log_seconds, &gmtime_result); /* Generate the audit log filename template. */ if (*(corecfg->auditlog_sdir_fmt) != 0) { size_t ret = strftime(dtmp, dtmp_sz, corecfg->auditlog_sdir_fmt, &gmtime_result); if (ret == 0) { /// @todo Better error - probably should validate at cfg time ib_log_error(log->ib, "Failed to create audit log filename template, " "using default:" " name too long"); *dtmp = 0; } } else { *dtmp = 0; } /* Generate the full audit log directory name. */ sys_rc = snprintf(dn, dn_sz, "%s%s%s", corecfg->auditlog_dir, (*dtmp)?"/":"", dtmp); if (sys_rc >= dn_sz) { /// @todo Better error. ib_log_error(log->ib, "Failed to create audit log directory: name too long"); free(dtmp); free(dn); return IB_EINVAL; } /* Get the site */ ib_rc = ib_context_site_get(log->ctx, &site); if (ib_rc != IB_OK) { free(dtmp); free(dn); return ib_rc; } /* Generate the full audit log filename. */ if (site != NULL) { audit_filename_sz = strlen(dn) + strlen(cfg->tx->id) + strlen(site->id) + 7; audit_filename = (char *)ib_mm_alloc(cfg->tx->mm, audit_filename_sz); sys_rc = snprintf(audit_filename, audit_filename_sz, "%s/%s_%s.log", dn, cfg->tx->id,site->id); } else { audit_filename_sz = strlen(dn) + strlen(cfg->tx->id) + 6; audit_filename = (char *)ib_mm_alloc(cfg->tx->mm, audit_filename_sz); sys_rc = snprintf(audit_filename, audit_filename_sz, "%s/%s.log", dn, cfg->tx->id); } if (sys_rc >= (int)audit_filename_sz) { /// @todo Better error. ib_log_error(log->ib, "Failed to create audit log filename: name too long"); ib_rule_log_add_audit(cfg->tx->rule_exec, audit_filename, true); free(dtmp); free(dn); return IB_EINVAL; } ib_rc = ib_util_mkpath(dn, corecfg->auditlog_dmode); if (ib_rc != IB_OK) { ib_log_error(log->ib, "Failed to create audit log dir: %s", dn); ib_rule_log_add_audit(cfg->tx->rule_exec, audit_filename, true); free(dtmp); free(dn); return ib_rc; } // Create temporary filename to use while writing the audit log temp_filename_sz = strlen(audit_filename) + 6; temp_filename = (char *)ib_mm_alloc(cfg->tx->mm, temp_filename_sz); if (temp_filename == NULL) { free(dtmp); free(dn); return IB_EALLOC; } sys_rc = snprintf(temp_filename, temp_filename_sz, "%s.part", audit_filename); if (sys_rc >= (int)temp_filename_sz) { /// @todo Better error. ib_log_error(log->ib, "Failed to create temporary audit log filename: name too long"); ib_rule_log_add_audit(cfg->tx->rule_exec, audit_filename, true); free(dtmp); free(dn); return IB_EINVAL; } /* Open the file. Use open() & fdopen() to avoid chmod() */ fd = open(temp_filename, (O_WRONLY|O_APPEND|O_CREAT|O_BINARY), corecfg->auditlog_fmode); if (fd >= 0) { cfg->fp = fdopen(fd, "ab"); if (cfg->fp == NULL) { close(fd); } } if ( (fd < 0) || (cfg->fp == NULL) ) { sys_rc = errno; ib_log_error(log->ib, "Error opening audit log \"%s\": %s (%d)", temp_filename, strerror(sys_rc), sys_rc); ib_rule_log_add_audit(cfg->tx->rule_exec, audit_filename, true); free(dtmp); free(dn); return IB_EINVAL; } /* Track the relative audit log filename. */ cfg->fn = audit_filename + (strlen(corecfg->auditlog_dir) + 1); cfg->full_path = audit_filename; cfg->temp_path = temp_filename; /* Log it via the rule logger */ ib_rule_log_add_audit(cfg->tx->rule_exec, audit_filename, false); free(dtmp); free(dn); return IB_OK; }
ib_status_t core_audit_open_auditindexfile(ib_engine_t *ib, ib_auditlog_t *log, ib_core_audit_cfg_t *cfg, ib_core_cfg_t *corecfg) { char* index_file; size_t index_file_sz; ib_status_t ib_rc; int sys_rc; if (log->ctx->auditlog->index == NULL) { return IB_OK; } /* Lock the auditlog configuration for the context. * We lock up here to ensure that external resources are not * double-opened instead of locking only the assignment to * log->ctx->auditlog->index_fp at the bottom of this block. */ ib_rc = ib_lock_lock(log->ctx->auditlog->index_fp_lock); if (ib_rc != IB_OK) { return ib_rc; } if (log->ctx->auditlog->index[0] == '/') { index_file_sz = strlen(log->ctx->auditlog->index) + 1; index_file = (char *)ib_mm_alloc(cfg->tx->mm, index_file_sz); if (index_file == NULL) { ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EALLOC; } memcpy(index_file, log->ctx->auditlog->index, index_file_sz); } else if (log->ctx->auditlog->index[0] == '|') { /// @todo Probably should skip whitespace??? index_file_sz = strlen(log->ctx->auditlog->index + 1) + 1; index_file = (char *)ib_mm_alloc(cfg->tx->mm, index_file_sz); if (index_file == NULL) { ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EALLOC; } memcpy(index_file, log->ctx->auditlog->index + 1, index_file_sz); } else { ib_rc = ib_util_mkpath(corecfg->auditlog_dir, corecfg->auditlog_dmode); if (ib_rc != IB_OK) { ib_log_error(log->ib, "Failed to create audit log dir: %s", corecfg->auditlog_dir); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return ib_rc; } index_file_sz = strlen(corecfg->auditlog_dir) + strlen(log->ctx->auditlog->index) + 2; index_file = (char *)ib_mm_alloc(cfg->tx->mm, index_file_sz); if (index_file == NULL) { ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EALLOC; } sys_rc = snprintf(index_file, index_file_sz, "%s/%s", corecfg->auditlog_dir, log->ctx->auditlog->index); if ((size_t)sys_rc >= index_file_sz) { ib_log_error(log->ib, "Failed to create audit log index \"%s/%s\":" " name too long", corecfg->auditlog_dir, log->ctx->auditlog->index); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } } if (log->ctx->auditlog->index[0] == '|') { int p[2]; pid_t pipe_pid; /// @todo Handle exit of pipe_pid??? sys_rc = pipe(p); if (sys_rc != 0) { ib_log_error(log->ib, "Error creating piped audit log index: %s (%d)", strerror(errno), errno); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } /* Create a new process for executing the piped command. */ pipe_pid = fork(); if (pipe_pid == 0) { /* Child - piped audit log index process */ char *parg[4]; /// @todo Reset SIGCHLD in child??? /* Setup the filehandles to read from pipe. */ close(3); /// @todo stderr close(p[1]); dup2(p[0], 0); /* Execute piped command. */ parg[0] = (char *)ib_pipe_shell; parg[1] = (char *)"-c"; parg[2] = index_file; parg[3] = NULL; execvp(ib_pipe_shell, (char * const *)parg); /// @todo define shell sys_rc = errno; ib_log_error(log->ib, "Error executing piped audit log index " "\"%s\": %s (%d)", index_file, strerror(sys_rc), sys_rc); exit(1); } else if (pipe_pid == -1) { /* Error - no process created */ sys_rc = errno; ib_log_error(log->ib, "Error creating piped audit log index process: " "%s (%d)", strerror(sys_rc), sys_rc); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } /* Parent - IronBee process */ /* Setup the filehandles to write to the pipe. */ close(p[0]); cfg->index_fp = fdopen(p[1], "w"); if (cfg->index_fp == NULL) { sys_rc = errno; ib_log_error(log->ib, "Error opening piped audit log index: %s (%d)", strerror(sys_rc), sys_rc); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } } else { /// @todo Use corecfg->auditlog_fmode as file mode for new file cfg->index_fp = fopen(index_file, "ab"); if (cfg->index_fp == NULL) { sys_rc = errno; ib_log_error(log->ib, "Error opening audit log index \"%s\": %s (%d)", index_file, strerror(sys_rc), sys_rc); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } } log->ctx->auditlog->index_fp = cfg->index_fp; ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_OK; }
ib_status_t core_audit_open_auditfile(ib_provider_inst_t *lpi, ib_auditlog_t *log, core_audit_cfg_t *cfg, ib_core_cfg_t *corecfg) { IB_FTRACE_INIT(); const int dtmp_sz = 64; const int dn_sz = 512; char *dtmp = (char *)malloc(dtmp_sz); char *dn = (char *)malloc(dn_sz); char *audit_filename; int audit_filename_sz; char *temp_filename; int temp_filename_sz; const time_t log_seconds = IB_CLOCK_SECS(log->tx->t.logtime); int sys_rc; ib_status_t ib_rc; struct tm gmtime_result; ib_site_t *site; if (dtmp == NULL || dn == NULL) { ib_log_error(log->ib, "Failed to allocate internal buffers."); if (dtmp != NULL) { free(dtmp); } if (dn != NULL) { free(dn); } IB_FTRACE_RET_STATUS(IB_EALLOC); } gmtime_r(&log_seconds, &gmtime_result); /* Generate the audit log filename template. */ if (*(corecfg->auditlog_sdir_fmt) != 0) { size_t ret = strftime(dtmp, dtmp_sz, corecfg->auditlog_sdir_fmt, &gmtime_result); if (ret == 0) { /// @todo Better error - probably should validate at cfg time ib_log_error(log->ib, "Could not create audit log filename template, " "using default:" " too long"); *dtmp = 0; } } else { *dtmp = 0; } /* Generate the full audit log directory name. */ sys_rc = snprintf(dn, dn_sz, "%s%s%s", corecfg->auditlog_dir, (*dtmp)?"/":"", dtmp); if (sys_rc >= dn_sz) { /// @todo Better error. ib_log_error(log->ib, "Could not create audit log directory: too long"); free(dtmp); free(dn); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* Generate the full audit log filename. */ site = ib_context_site_get(log->ctx); if (site != NULL) { audit_filename_sz = strlen(dn) + strlen(cfg->tx->id) + strlen(site->id_str) + 7; audit_filename = (char *)ib_mpool_alloc(cfg->tx->mp, audit_filename_sz); sys_rc = snprintf(audit_filename, audit_filename_sz, "%s/%s_%s.log", dn, cfg->tx->id,site->id_str); } else { audit_filename_sz = strlen(dn) + strlen(cfg->tx->id) + 6; audit_filename = (char *)ib_mpool_alloc(cfg->tx->mp, audit_filename_sz); sys_rc = snprintf(audit_filename, audit_filename_sz, "%s/%s.log", dn, cfg->tx->id); } if (sys_rc >= (int)audit_filename_sz) { /// @todo Better error. ib_log_error(log->ib, "Could not create audit log filename: too long"); free(dtmp); free(dn); IB_FTRACE_RET_STATUS(IB_EINVAL); } ib_rc = ib_util_mkpath(dn, corecfg->auditlog_dmode); if (ib_rc != IB_OK) { ib_log_error(log->ib, "Could not create audit log dir: %s", dn); free(dtmp); free(dn); IB_FTRACE_RET_STATUS(ib_rc); } // Create temporary filename to use while writing the audit log temp_filename_sz = strlen(audit_filename) + 6; temp_filename = (char *)ib_mpool_alloc(cfg->tx->mp, temp_filename_sz); sys_rc = snprintf(temp_filename, temp_filename_sz, "%s.part", audit_filename); if (sys_rc >= (int)temp_filename_sz) { /// @todo Better error. ib_log_error(log->ib, "Could not create temporary audit log filename: too long"); free(dtmp); free(dn); IB_FTRACE_RET_STATUS(IB_EINVAL); } /// @todo Use corecfg->auditlog_fmode as file mode for new file cfg->fp = fopen(temp_filename, "ab"); if (cfg->fp == NULL) { sys_rc = errno; /// @todo Better error. ib_log_error(log->ib, "Could not open audit log \"%s\": %s (%d)", temp_filename, strerror(sys_rc), sys_rc); free(dtmp); free(dn); IB_FTRACE_RET_STATUS(IB_EINVAL); } /* Track the relative audit log filename. */ cfg->fn = audit_filename + (strlen(corecfg->auditlog_dir) + 1); cfg->full_path = audit_filename; cfg->temp_path = temp_filename; free(dtmp); free(dn); IB_FTRACE_RET_STATUS(IB_OK); }