static int wrap_is_usable_file(char *filename) { struct stat statbuf; pr_fh_t *fh = NULL; /* check the easy case first */ if (filename == NULL) return FALSE; if (pr_fsio_stat(filename, &statbuf) == -1) { pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": \"%s\": %s", filename, strerror(errno)); return FALSE; } /* OK, the file exists. Now, to make sure that the current process * can _read_ the file */ fh = pr_fsio_open(filename, O_RDONLY); if (fh == NULL) { pr_log_pri(PR_LOG_INFO, MOD_WRAP_VERSION ": \"%s\": %s", filename, strerror(errno)); return FALSE; } pr_fsio_close(fh); return TRUE; }
static int wrap_is_usable_file(char *filename) { struct stat st; pr_fh_t *fh = NULL; /* check the easy case first */ if (filename == NULL) return FALSE; /* Make sure that the current process can _read_ the file. */ fh = pr_fsio_open(filename, O_RDONLY); if (fh == NULL) { int xerrno = errno; pr_log_pri(PR_LOG_NOTICE, MOD_WRAP_VERSION ": failed to read \"%s\": %s", filename, strerror(xerrno)); errno = xerrno; return FALSE; } if (pr_fsio_fstat(fh, &st) < 0) { int xerrno = errno; pr_log_pri(PR_LOG_NOTICE, MOD_WRAP_VERSION ": failed to stat \"%s\": %s", filename, strerror(xerrno)); pr_fsio_close(fh); errno = xerrno; return FALSE; } if (S_ISDIR(st.st_mode)) { int xerrno = EISDIR; pr_log_pri(PR_LOG_NOTICE, MOD_WRAP_VERSION ": unable to use \"%s\": %s", filename, strerror(xerrno)); pr_fsio_close(fh); errno = xerrno; return FALSE; } pr_fsio_close(fh); return TRUE; }
static int filetab_close_cb(wrap2_table_t *filetab) { int res = pr_fsio_close((pr_fh_t *) filetab->tab_handle); filetab->tab_handle = NULL; filetab_clients_list = NULL; filetab_daemons_list = NULL; filetab_options_list = NULL; filetab_service_name = NULL; return res; }
static sftp_keystore_t *filestore_open(pool *parent_pool, int requested_key_type, const char *store_info, const char *user) { int xerrno; sftp_keystore_t *store; pool *filestore_pool; struct filestore_data *store_data; pr_fh_t *fh; char buf[PR_TUNABLE_PATH_MAX+1], *path; struct stat st; filestore_pool = make_sub_pool(parent_pool); pr_pool_tag(filestore_pool, "SFTP File-based Keystore Pool"); store = pcalloc(filestore_pool, sizeof(sftp_keystore_t)); store->keystore_pool = filestore_pool; /* Open the file. The given path (store_info) may need to be * interpolated. */ session.user = (char *) user; memset(buf, '\0', sizeof(buf)); switch (pr_fs_interpolate(store_info, buf, sizeof(buf)-1)) { case 1: /* Interpolate occurred; make a copy of the interpolated path. */ path = pstrdup(filestore_pool, buf); break; default: /* Otherwise, use the path as is. */ path = pstrdup(filestore_pool, store_info); break; } session.user = NULL; PRIVS_ROOT fh = pr_fsio_open(path, O_RDONLY|O_NONBLOCK); xerrno = errno; PRIVS_RELINQUISH if (fh == NULL) { destroy_pool(filestore_pool); errno = xerrno; return NULL; } if (pr_fsio_set_block(fh) < 0) { xerrno = errno; destroy_pool(filestore_pool); (void) pr_fsio_close(fh); errno = xerrno; return NULL; } /* Stat the opened file to determine the optimal buffer size for IO. */ memset(&st, 0, sizeof(st)); if (pr_fsio_fstat(fh, &st) < 0) { xerrno = errno; destroy_pool(filestore_pool); (void) pr_fsio_close(fh); errno = xerrno; return NULL; } if (S_ISDIR(st.st_mode)) { destroy_pool(filestore_pool); (void) pr_fsio_close(fh); errno = EISDIR; return NULL; } fh->fh_iosz = st.st_blksize; store_data = pcalloc(filestore_pool, sizeof(struct filestore_data)); store->keystore_data = store_data; store_data->path = path; store_data->fh = fh; store_data->lineno = 0; store->store_ktypes = requested_key_type; switch (requested_key_type) { case SFTP_SSH2_HOST_KEY_STORE: store->verify_host_key = filestore_verify_host_key; break; case SFTP_SSH2_USER_KEY_STORE: store->verify_user_key = filestore_verify_user_key; break; } store->store_close = filestore_close; return store; }
static int filestore_close(sftp_keystore_t *store) { struct filestore_data *store_data = store->keystore_data; pr_fsio_close(store_data->fh); return 0; }
int pr_parser_parse_file(pool *p, const char *path, config_rec *start, int flags) { pr_fh_t *fh; struct stat st; struct config_src *cs; cmd_rec *cmd; pool *tmp_pool; char *buf, *report_path; size_t bufsz; if (path == NULL) { errno = EINVAL; return -1; } if (parser_servstack == NULL) { errno = EPERM; return -1; } tmp_pool = make_sub_pool(p ? p : permanent_pool); pr_pool_tag(tmp_pool, "parser file pool"); report_path = (char *) path; if (session.chroot_path) { report_path = pdircat(tmp_pool, session.chroot_path, path, NULL); } if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) { pr_trace_msg(trace_channel, 3, "parsing '%s' configuration", report_path); } fh = pr_fsio_open(path, O_RDONLY); if (fh == NULL) { int xerrno = errno; destroy_pool(tmp_pool); errno = xerrno; return -1; } /* Stat the opened file to determine the optimal buffer size for IO. */ memset(&st, 0, sizeof(st)); if (pr_fsio_fstat(fh, &st) < 0) { int xerrno = errno; pr_fsio_close(fh); destroy_pool(tmp_pool); errno = xerrno; return -1; } if (S_ISDIR(st.st_mode)) { pr_fsio_close(fh); destroy_pool(tmp_pool); errno = EISDIR; return -1; } /* Advise the platform that we will be only reading this file * sequentially. */ pr_fs_fadvise(PR_FH_FD(fh), 0, 0, PR_FS_FADVISE_SEQUENTIAL); /* Check for world-writable files (and later, files in world-writable * directories). * * For now, just warn about these; later, we will be more draconian. */ if (st.st_mode & S_IWOTH) { pr_log_pri(PR_LOG_WARNING, "warning: config file '%s' is world-writable", path); } fh->fh_iosz = st.st_blksize; /* Push the configuration information onto the stack of configuration * sources. */ cs = add_config_source(fh); if (start != NULL) { (void) pr_parser_config_ctxt_push(start); } bufsz = PR_TUNABLE_PARSER_BUFFER_SIZE; buf = pcalloc(tmp_pool, bufsz + 1); while (pr_parser_read_line(buf, bufsz) != NULL) { pr_signals_handle(); cmd = pr_parser_parse_line(tmp_pool, buf, 0); if (cmd == NULL) { continue; } if (cmd->argc) { conftable *conftab; char found = FALSE; cmd->server = *parser_curr_server; cmd->config = *parser_curr_config; conftab = pr_stash_get_symbol2(PR_SYM_CONF, cmd->argv[0], NULL, &cmd->stash_index, &cmd->stash_hash); while (conftab != NULL) { modret_t *mr; pr_signals_handle(); cmd->argv[0] = conftab->directive; pr_trace_msg(trace_channel, 7, "dispatching directive '%s' to module mod_%s", conftab->directive, conftab->m->name); mr = pr_module_call(conftab->m, conftab->handler, cmd); if (mr != NULL) { if (MODRET_ISERROR(mr)) { if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) { pr_log_pri(PR_LOG_WARNING, "fatal: %s on line %u of '%s'", MODRET_ERRMSG(mr), cs->cs_lineno, report_path); destroy_pool(tmp_pool); errno = EPERM; return -1; } pr_log_pri(PR_LOG_WARNING, "warning: %s on line %u of '%s'", MODRET_ERRMSG(mr), cs->cs_lineno, report_path); } } if (!MODRET_ISDECLINED(mr)) { found = TRUE; } conftab = pr_stash_get_symbol2(PR_SYM_CONF, cmd->argv[0], conftab, &cmd->stash_index, &cmd->stash_hash); } if (cmd->tmp_pool) { destroy_pool(cmd->tmp_pool); } if (found == FALSE) { register unsigned int i; char *name; size_t namelen; int non_ascii = FALSE; /* I encountered a case where a particular configuration file had * what APPEARED to be a valid directive, but the parser kept reporting * that the directive was unknown. I now suspect that the file in * question had embedded UTF8 characters (spaces, perhaps), which * would appear as normal spaces in e.g. UTF8-aware editors/terminals, * but which the parser would rightly refuse. * * So to indicate that this might be the case, check for any non-ASCII * characters in the "unknown" directive name, and if found, log * about them. */ name = cmd->argv[0]; namelen = strlen(name); for (i = 0; i < namelen; i++) { if (!isascii((int) name[i])) { non_ascii = TRUE; break; } } if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) { pr_log_pri(PR_LOG_WARNING, "fatal: unknown configuration directive " "'%s' on line %u of '%s'", name, cs->cs_lineno, report_path); if (non_ascii) { pr_log_pri(PR_LOG_WARNING, "fatal: malformed directive name " "'%s' (contains non-ASCII characters)", name); } else { array_header *directives, *similars; directives = get_all_directives(tmp_pool); similars = pr_str_get_similars(tmp_pool, name, directives, 0, PR_STR_FL_IGNORE_CASE); if (similars != NULL && similars->nelts > 0) { unsigned int nelts; const char **names, *msg; names = similars->elts; nelts = similars->nelts; if (nelts > 4) { nelts = 4; } msg = "fatal: Did you mean:"; if (nelts == 1) { msg = pstrcat(tmp_pool, msg, " ", names[0], NULL); } else { for (i = 0; i < nelts; i++) { msg = pstrcat(tmp_pool, msg, "\n ", names[i], NULL); } } pr_log_pri(PR_LOG_WARNING, "%s", msg); } } destroy_pool(tmp_pool); errno = EPERM; return -1; } pr_log_pri(PR_LOG_WARNING, "warning: unknown configuration directive " "'%s' on line %u of '%s'", name, cs->cs_lineno, report_path); if (non_ascii) { pr_log_pri(PR_LOG_WARNING, "warning: malformed directive name " "'%s' (contains non-ASCII characters)", name); } } } destroy_pool(cmd->pool); memset(buf, '\0', bufsz); } /* Pop this configuration stream from the stack. */ remove_config_source(); pr_fsio_close(fh); destroy_pool(tmp_pool); return 0; }
static int counter_sess_init(void) { config_rec *c; c = find_config(main_server->conf, CONF_PARAM, "CounterEngine", FALSE); if (c != NULL) { counter_engine = *((int *) c->argv[0]); } if (counter_engine == FALSE) { return 0; } c = find_config(main_server->conf, CONF_PARAM, "CounterLog", FALSE); if (c != NULL) { const char *path = c->argv[0]; if (strcasecmp(path, "none") != 0) { int res, xerrno; PRIVS_ROOT res = pr_log_openfile(path, &counter_logfd, 0660); xerrno = errno; PRIVS_RELINQUISH; if (res < 0) { pr_log_debug(DEBUG2, MOD_COUNTER_VERSION ": error opening CounterLog '%s': %s", path, strerror(xerrno)); counter_logfd = -1; } } } /* Find all CounterFile directives for this vhost, and make sure they * have open handles. We need to do this here, and not in a POST_CMD * PASS handler because of the need to open handles that may be outside * of a chroot. */ c = find_config(main_server->conf, CONF_PARAM, "CounterFile", TRUE); while (c != NULL) { int xerrno = 0; const char *area = NULL, *path; pr_fh_t *fh; struct counter_fh *cfh; pr_signals_handle(); path = c->argv[0]; if (c->parent != NULL) { if (c->parent->config_type == CONF_ANON || c->parent->config_type == CONF_DIR) { area = c->parent->name; } else { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "unhandled configuration parent type (%d) for CounterFile, skipping", c->parent->config_type); c = find_config_next(c, c->next, CONF_PARAM, "CounterFile", TRUE); continue; } } else { /* Toplevel CounterFile directive, in "server config" or <VirtualHost> * sections. */ area = "/"; } PRIVS_ROOT fh = pr_fsio_open(path, O_RDWR|O_CREAT); xerrno = errno; PRIVS_RELINQUISH if (fh == NULL) { pr_log_debug(DEBUG1, MOD_COUNTER_VERSION ": error opening CounterFile '%s': %s", path, strerror(xerrno)); counter_engine = FALSE; if (counter_fhs != NULL) { for (cfh = (struct counter_fh *) counter_fhs->xas_list; cfh; cfh = cfh->next) { (void) pr_fsio_close(cfh->fh); } } return 0; } (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "opened CounterFile '%s'", path); if (counter_fhs == NULL) { counter_fhs = xaset_create(counter_pool, NULL); } cfh = pcalloc(counter_pool, sizeof(struct counter_fh)); /* Ignore any trailing slash. */ cfh->arealen = strlen(area); if (cfh->arealen > 1 && area[cfh->arealen-1] == '/') { cfh->arealen--; } cfh->area = pstrndup(counter_pool, area, cfh->arealen); /* Mark any areas that use glob(3) characters. */ if (strpbrk(cfh->area, "[*?") != NULL) { cfh->isglob = TRUE; } cfh->fh = fh; xaset_insert(counter_fhs, (xasetmember_t *) cfh); c = find_config_next(c, c->next, CONF_PARAM, "CounterFile", TRUE); } if (counter_fhs == NULL) { (void) pr_log_writefile(counter_logfd, MOD_COUNTER_VERSION, "no CounterFiles configured, disabling module"); counter_engine = FALSE; return 0; } pr_event_register(&counter_module, "core.exit", counter_exit_ev, NULL); /* If mod_vroot is present, we need to do a little more magic to counter * the mod_vroot magic. */ if (pr_module_exists("mod_vroot.c") == TRUE) { pr_event_register(&counter_module, "core.chroot", counter_chroot_ev, NULL); } return 0; }
int pr_parser_parse_file(pool *p, const char *path, config_rec *start, int flags) { pr_fh_t *fh; struct stat st; struct config_src *cs; cmd_rec *cmd; pool *tmp_pool; char *report_path; if (path == NULL) { errno = EINVAL; return -1; } tmp_pool = make_sub_pool(p ? p : permanent_pool); pr_pool_tag(tmp_pool, "parser file pool"); report_path = (char *) path; if (session.chroot_path) report_path = pdircat(tmp_pool, session.chroot_path, path, NULL); if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) pr_trace_msg(trace_channel, 3, "parsing '%s' configuration", report_path); fh = pr_fsio_open(path, O_RDONLY); if (fh == NULL) { int xerrno = errno; destroy_pool(tmp_pool); errno = xerrno; return -1; } /* Stat the opened file to determine the optimal buffer size for IO. */ memset(&st, 0, sizeof(st)); if (pr_fsio_fstat(fh, &st) < 0) { int xerrno = errno; pr_fsio_close(fh); destroy_pool(tmp_pool); errno = xerrno; return -1; } if (S_ISDIR(st.st_mode)) { pr_fsio_close(fh); destroy_pool(tmp_pool); errno = EISDIR; return -1; } /* Check for world-writable files (and later, files in world-writable * directories). * * For now, just warn about these; later, we will be more draconian. */ if (st.st_mode & S_IWOTH) { pr_log_pri(PR_LOG_WARNING, "warning: config file '%s' is world-writable", path); } fh->fh_iosz = st.st_blksize; /* Push the configuration information onto the stack of configuration * sources. */ cs = add_config_source(fh); if (start) add_config_ctxt(start); while ((cmd = pr_parser_parse_line(tmp_pool)) != NULL) { pr_signals_handle(); if (cmd->argc) { conftable *conftab; char found = FALSE; cmd->server = *parser_curr_server; cmd->config = *parser_curr_config; conftab = pr_stash_get_symbol2(PR_SYM_CONF, cmd->argv[0], NULL, &cmd->stash_index, &cmd->stash_hash); while (conftab) { modret_t *mr; pr_signals_handle(); cmd->argv[0] = conftab->directive; pr_trace_msg(trace_channel, 7, "dispatching directive '%s' to module mod_%s", conftab->directive, conftab->m->name); mr = pr_module_call(conftab->m, conftab->handler, cmd); if (mr != NULL) { if (MODRET_ISERROR(mr)) { if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) { pr_log_pri(PR_LOG_WARNING, "fatal: %s on line %u of '%s'", MODRET_ERRMSG(mr), cs->cs_lineno, report_path); exit(1); } else { pr_log_pri(PR_LOG_WARNING, "warning: %s on line %u of '%s'", MODRET_ERRMSG(mr), cs->cs_lineno, report_path); } } } if (!MODRET_ISDECLINED(mr)) { found = TRUE; } conftab = pr_stash_get_symbol2(PR_SYM_CONF, cmd->argv[0], conftab, &cmd->stash_index, &cmd->stash_hash); } if (cmd->tmp_pool) destroy_pool(cmd->tmp_pool); if (!found) { if (!(flags & PR_PARSER_FL_DYNAMIC_CONFIG)) { pr_log_pri(PR_LOG_WARNING, "fatal: unknown configuration directive " "'%s' on line %u of '%s'", cmd->argv[0], cs->cs_lineno, report_path); exit(1); } else { pr_log_pri(PR_LOG_WARNING, "warning: unknown configuration directive " "'%s' on line %u of '%s'", cmd->argv[0], cs->cs_lineno, report_path); } } } destroy_pool(cmd->pool); } /* Pop this configuration stream from the stack. */ remove_config_source(); pr_fsio_close(fh); destroy_pool(tmp_pool); return 0; }