static void set_up(void) { unsigned long feature_flags = 0UL; if (p == NULL) { p = permanent_pool = make_sub_pool(NULL); } aws_http_init(p, &feature_flags, NULL); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("aws.http", 1, 20); pr_trace_set_levels("aws.cloudwatch.conn", 1, 20); } }
static void set_up(void) { if (p == NULL) { p = permanent_pool = make_sub_pool(NULL); } init_netaddr(); init_netio(); init_inet(); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("inet", 1, 20); } pr_inet_set_default_family(p, AF_INET); }
static void set_up(void) { if (p == NULL) { p = permanent_pool = make_sub_pool(NULL); } repeat_cb = FALSE; timer_triggered_count = 0; timers_init(); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_use_stderr(TRUE); pr_trace_set_levels("timers", 1, 20); } }
int init_stash(void) { if (symbol_pool != NULL) { destroy_pool(symbol_pool); } symbol_pool = make_sub_pool(permanent_pool); pr_pool_tag(symbol_pool, "Stash Pool"); memset(conf_symbol_table, '\0', sizeof(conf_symbol_table)); memset(cmd_symbol_table, '\0', sizeof(cmd_symbol_table)); memset(auth_symbol_table, '\0', sizeof(auth_symbol_table)); memset(hook_symbol_table, '\0', sizeof(hook_symbol_table)); return 0; }
static void data_new_xfer(char *filename, int direction) { pr_data_clear_xfer_pool(); session.xfer.p = make_sub_pool(session.pool); pr_pool_tag(session.xfer.p, "data transfer pool"); session.xfer.filename = pstrdup(session.xfer.p, filename); session.xfer.direction = direction; session.xfer.bufsize = pr_config_get_server_xfer_bufsz(direction); session.xfer.buf = pcalloc(session.xfer.p, session.xfer.bufsize + 1); pr_trace_msg("data", 8, "allocated data transfer buffer of %lu bytes", (unsigned long) session.xfer.bufsize); session.xfer.buf++; /* leave room for ascii translation */ session.xfer.buflen = 0; }
static void set_up(void) { (void) unlink(db_test_table); if (p == NULL) { p = permanent_pool = make_sub_pool(NULL); session.c = NULL; session.notes = NULL; } if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("proxy.db", 1, 20); } mark_point(); proxy_db_init(p); }
pr_netio_t *pr_alloc_netio2(pool *parent_pool, module *owner) { pr_netio_t *netio = NULL; pool *netio_pool = NULL; if (parent_pool == NULL) { errno = EINVAL; return NULL; } netio_pool = make_sub_pool(parent_pool); /* If this is the daemon process, we are allocating a sub-pool from the * permanent_pool. You might wonder why the daemon process needs netio * objects. It doesn't, really -- but it's for use by all of the session * processes that will be forked. They will be able to reuse the memory * already allocated for the main ctrl/data/other netios, as is. * * This being the case, we should label the sub-pool accordingly. */ if (mpid == getpid()) { pr_pool_tag(netio_pool, "Shared Netio Pool"); } else { pr_pool_tag(netio_pool, "netio pool"); } netio = pcalloc(netio_pool, sizeof(pr_netio_t)); netio->pool = netio_pool; netio->owner = owner; if (owner != NULL) { netio->owner_name = pstrdup(netio_pool, owner->name); } /* Set the default NetIO handlers to the core handlers. */ netio->abort = core_netio_abort_cb; netio->close = core_netio_close_cb; netio->open = core_netio_open_cb; netio->poll = core_netio_poll_cb; netio->postopen = core_netio_postopen_cb; netio->read = core_netio_read_cb; netio->reopen = core_netio_reopen_cb; netio->shutdown = core_netio_shutdown_cb; netio->write = core_netio_write_cb; return netio; }
/* Copy a connection structure, also creates a sub pool for the new * connection. */ conn_t *pr_inet_copy_conn(pool *p, conn_t *c) { conn_t *res = NULL; pool *sub_pool = NULL; sub_pool = make_sub_pool(p); pr_pool_tag(sub_pool, "inet_copy_conn pool"); res = (conn_t *) pcalloc(sub_pool, sizeof(conn_t)); memcpy(res, c, sizeof(conn_t)); res->pool = sub_pool; res->instrm = res->outstrm = NULL; if (c->local_addr) { res->local_addr = pr_netaddr_alloc(res->pool); if (pr_netaddr_set_family(res->local_addr, pr_netaddr_get_family(c->local_addr)) < 0) { destroy_pool(res->pool); return NULL; } pr_netaddr_set_sockaddr(res->local_addr, pr_netaddr_get_sockaddr(c->local_addr)); } if (c->remote_addr) { res->remote_addr = pr_netaddr_alloc(res->pool); if (pr_netaddr_set_family(res->remote_addr, pr_netaddr_get_family(c->remote_addr)) < 0) { destroy_pool(res->pool); return NULL; } pr_netaddr_set_sockaddr(res->remote_addr, pr_netaddr_get_sockaddr(c->remote_addr)); } if (c->remote_name) { res->remote_name = pstrdup(res->pool, c->remote_name); } register_cleanup(res->pool, (void *) res, conn_cleanup_cb, conn_cleanup_cb); return res; }
static void set_up(void) { (void) unlink(display_test_file); if (p == NULL) { p = session.pool = permanent_pool = make_sub_pool(NULL); } init_dirtree(); init_fs(); init_netio(); init_inet(); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("netio", 1, 20); pr_trace_set_levels("response", 1, 20); } }
static void set_up(void) { (void) unlink(misc_test_shutmsg); if (p == NULL) { p = permanent_pool = make_sub_pool(NULL); } init_fs(); pr_fs_statcache_set_policy(PR_TUNABLE_FS_STATCACHE_SIZE, PR_TUNABLE_FS_STATCACHE_MAX_AGE, 0); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("fsio", 1, 20); pr_trace_set_levels("fs.statcache", 1, 20); } schedule_called = 0; }
int sftp_tap_set_policy(const char *policy) { register unsigned int i; if (tap_pool) { /* Special case: IFF the existing policy is 'none' AND the given * policy is 'rogaway', just return. The 'none' policy must have been * explicitly configured, and it should override the automatic use of * the 'rogaway' policy. */ if (strncmp(curr_policy.policy, "none", 5) == 0 && strncasecmp(policy, "rogaway", 8) == 0) { (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION, "'none' traffic policy explicitly configured, ignoring '%s' policy", policy); return 0; } destroy_pool(tap_pool); if (tap_timerno > 0) { pr_timer_remove(tap_timerno, &sftp_module); tap_timerno = -1; } } tap_pool = make_sub_pool(sftp_pool); pr_pool_tag(tap_pool, "SFTP TAP Pool"); memset(&curr_policy, 0, sizeof(struct sftp_tap_policy)); for (i = 0; tap_policies[i].policy; i++) { if (strcasecmp(tap_policies[i].policy, policy) == 0) { copy_policy(&curr_policy, &(tap_policies[i])); set_policy_chance(&curr_policy); set_policy_timer(&curr_policy); return 0; } } errno = ENOENT; return -1; }
static void set_up(void) { server_rec *s = NULL; if (p == NULL) { p = permanent_pool = make_sub_pool(NULL); } pr_trace_use_stderr(TRUE); init_stash(); init_auth(); s = pcalloc(p, sizeof(server_rec)); tests_stubs_set_main_server(s); test_pwd.pw_name = PR_TEST_AUTH_NAME; test_pwd.pw_uid = PR_TEST_AUTH_UID; test_pwd.pw_gid = PR_TEST_AUTH_GID; test_pwd.pw_dir = PR_TEST_AUTH_HOME; test_pwd.pw_shell = PR_TEST_AUTH_SHELL; test_grp.gr_name = PR_TEST_AUTH_NAME; test_grp.gr_gid = PR_TEST_AUTH_GID; /* Reset counters. */ setpwent_count = 0; endpwent_count = 0; getpwent_count = 0; getpwnam_count = 0; getpwuid_count = 0; name2uid_count = 0; uid2name_count = 0; setgrent_count = 0; endgrent_count = 0; getgrent_count = 0; getgrnam_count = 0; getgrgid_count = 0; name2gid_count = 0; gid2name_count = 0; getgroups_count = 0; pr_auth_cache_clear(); }
void init_ctrls(void) { if (ctrls_pool) destroy_pool(ctrls_pool); ctrls_pool = make_sub_pool(permanent_pool); pr_pool_tag(ctrls_pool, "Controls Pool"); /* Make sure all of the lists are zero'd out. */ ctrls_action_list = NULL; ctrls_active_list = NULL; ctrls_free_list = NULL; /* And that the lookup indices are (re)set as well... */ action_lookup_next = NULL; action_lookup_action = NULL; action_lookup_module = NULL; return; }
static void set_up(void) { if (p == NULL) { p = permanent_pool = proxy_pool = make_sub_pool(NULL); server_list = NULL; main_server = NULL; session.c = NULL; session.notes = NULL; } (void) tests_rmpath(p, test_dir); create_main_server(); (void) create_test_dir(); init_netio(); proxy_db_init(p); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("proxy.db", 1, 20); pr_trace_set_levels("proxy.tls", 1, 20); } }
static void set_up(void) { if (p == NULL) { p = permanent_pool = session.pool = make_sub_pool(NULL); session.c = NULL; session.notes = NULL; } init_netaddr(); init_netio(); init_inet(); create_main_server(); if (getenv("TEST_VERBOSE") != NULL) { pr_trace_set_levels("netio", 1, 20); pr_trace_set_levels("inet", 1, 20); pr_trace_set_levels("proxy.ftp.conn", 1, 20); } pr_inet_set_default_family(p, AF_INET); }
int sftp_kbdint_register_driver(const char *name, sftp_kbdint_driver_t *driver) { struct kbdint_driver *kd; if (name == NULL || driver == NULL) { errno = EINVAL; return -1; } if (kbdint_pool == NULL) { kbdint_pool = make_sub_pool(permanent_pool); pr_pool_tag(kbdint_pool, "SFTP keyboard-interactive API Pool"); } /* Make sure that the driver hasn't already been registered. */ if (sftp_kbdint_get_driver(name) != NULL) { errno = EEXIST; return -1; } kd = pcalloc(kbdint_pool, sizeof(struct kbdint_driver)); /* XXX Should this name string be dup'd from the kbdint_pool? */ kd->name = name; driver->driver_name = pstrdup(kbdint_pool, name); kd->driver = driver; if (drivers) { kd->next = drivers; } else { kd->next = NULL; } drivers = kd; ndrivers++; return 0; }
int proxy_ftp_sess_send_host(pool *p, struct proxy_session *proxy_sess) { pool *tmp_pool; int xerrno = 0; cmd_rec *cmd; pr_response_t *resp; unsigned int resp_nlines = 0; const char *host; if (pr_table_get(proxy_sess->backend_features, C_HOST, NULL) == NULL) { pr_trace_msg(trace_channel, 9, "HOST not supported by backend server, ignoring"); return 0; } tmp_pool = make_sub_pool(p); host = proxy_conn_get_host(proxy_sess->dst_pconn); cmd = pr_cmd_alloc(tmp_pool, 2, C_HOST, host); cmd->arg = pstrdup(tmp_pool, host); resp = send_recv(tmp_pool, proxy_sess->backend_ctrl_conn, cmd, &resp_nlines); if (resp == NULL) { xerrno = errno; destroy_pool(tmp_pool); errno = xerrno; return -1; } if (resp->num[0] != '2') { pr_trace_msg(trace_channel, 4, "received unexpected %s response code %s from backend", (char *) cmd->argv[0], resp->num); destroy_pool(tmp_pool); errno = EPERM; return -1; } destroy_pool(tmp_pool); return 0; }
static int log_failure_init(void) { #if defined(PR_SHARED_MODULE) pr_event_register(&log_failure_module, "core.module-unload", log_failure_mod_unload_ev, NULL); #endif /* PR_SHARED_MODULE */ pr_event_register(&log_failure_module, "core.restart", log_failure_restart_ev, NULL); log_failure_pool = make_sub_pool(permanent_pool); pr_pool_tag(log_failure_pool, MOD_LOG_FAILURE_VERSION); if (log_failure_mkfields(log_failure_pool) < 0) { return -1; } #if PROFTPD_VERSION_NUMBER >= 0x0001030603 /* Use our own OOM handler. */ json_set_oom(log_failure_oom); #endif /* ProFTPD 1.3.6rc3 and later */ return 0; }
static pr_netio_stream_t *netio_stream_alloc(pool *parent_pool) { pool *netio_pool = NULL; pr_netio_stream_t *nstrm = NULL; if (!parent_pool) { errno = EINVAL; return NULL; } netio_pool = make_sub_pool(parent_pool); nstrm = pcalloc(netio_pool, sizeof(pr_netio_stream_t)); nstrm->strm_pool = netio_pool; nstrm->strm_fd = -1; nstrm->strm_mode = 0; nstrm->strm_flags = 0; nstrm->strm_buf = NULL; nstrm->strm_data = NULL; nstrm->strm_errno = 0; return nstrm; }
void timers_init(void) { /* Reset some of the key static variables. */ _current_timeout = 0; _total_time = 0; nalarms = 0; _alarmed_time = 0; dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO; /* Don't inherit the parent's timer lists. */ timers = NULL; recycled = NULL; free_timers = NULL; /* Reset the timer pool. */ if (timer_pool) destroy_pool(timer_pool); timer_pool = make_sub_pool(permanent_pool); pr_pool_tag(timer_pool, "Timer Pool"); return; }
static cmd_rec *sql_cmd_create(pool *parent_pool, int argc, ...) { pool *cmd_pool = NULL; cmd_rec *cmd = NULL; register unsigned int i = 0; va_list argp; cmd_pool = make_sub_pool(parent_pool); cmd = (cmd_rec *) pcalloc(cmd_pool, sizeof(cmd_rec)); cmd->pool = cmd_pool; cmd->argc = argc; cmd->argv = (char **) pcalloc(cmd->pool, argc * sizeof(char *)); /* Hmmm... */ cmd->tmp_pool = cmd->pool; va_start(argp, argc); for (i = 0; i < argc; i++) cmd->argv[i] = va_arg(argp, char *); va_end(argp); return cmd; }
static void mcache_restart_ev(const void *event_data, void *user_data) { register unsigned int i; memcached_server_st **mcache_servers = NULL; mcache_servers = memcache_server_lists->elts; for (i = 0; i < memcache_server_lists->nelts; i++) { memcached_server_list_free(mcache_servers[i]); } /* Make sure to clear the pointer in the Memcache API as well, to prevent * a dangling pointer situation. */ memcache_set_servers(NULL); /* Now we can recycle the mod_memcache pool and its associated resources. */ destroy_pool(memcache_pool); memcache_pool = make_sub_pool(permanent_pool); pr_pool_tag(memcache_pool, MOD_MEMCACHE_VERSION); memcache_server_lists = make_array(memcache_pool, 2, sizeof(memcached_server_st **)); }
server_rec *pr_parser_server_ctxt_open(const char *addrstr) { server_rec *s; pool *p; p = make_sub_pool(permanent_pool); pr_pool_tag(p, "<VirtualHost> Pool"); s = (server_rec *) pcalloc(p, sizeof(server_rec)); s->pool = p; s->config_type = CONF_VIRTUAL; s->sid = ++parser_sid; s->notes = pr_table_nalloc(p, 0, 8); /* TCP KeepAlive is enabled by default, with the system defaults. */ s->tcp_keepalive = palloc(s->pool, sizeof(struct tcp_keepalive)); s->tcp_keepalive->keepalive_enabled = TRUE; s->tcp_keepalive->keepalive_idle = -1; s->tcp_keepalive->keepalive_count = -1; s->tcp_keepalive->keepalive_intvl = -1; /* Have to make sure it ends up on the end of the chain, otherwise * main_server becomes useless. */ xaset_insert_end(*parser_server_list, (xasetmember_t *) s); s->set = *parser_server_list; if (addrstr) { s->ServerAddress = pstrdup(s->pool, addrstr); } /* Default server port */ s->ServerPort = pr_inet_getservport(s->pool, "ftp", "tcp"); parser_curr_server = (server_rec **) push_array(parser_servstack); *parser_curr_server = s; return s; }
int vroot_fsio_utimes(pr_fs_t *fs, const char *utimes_path, struct timeval *tvs) { int res, xerrno; char vpath[PR_TUNABLE_PATH_MAX + 1], *path = NULL; pool *tmp_pool = NULL; if (session.curr_phase == LOG_CMD || session.curr_phase == LOG_CMD_ERR || (session.sf_flags & SF_ABORT) || vroot_path_have_base() == FALSE) { /* NOTE: once stackable FS modules are supported, have this fall through * to the next module in the stack. */ return utimes(utimes_path, tvs); } tmp_pool = make_sub_pool(session.pool); pr_pool_tag(tmp_pool, "VRoot FSIO utimes pool"); path = vroot_realpath(tmp_pool, utimes_path, VROOT_REALPATH_FL_ABS_PATH); if (vroot_path_lookup(NULL, vpath, sizeof(vpath)-1, path, 0, NULL) < 0) { xerrno = errno; destroy_pool(tmp_pool); errno = xerrno; return -1; } res = utimes(vpath, tvs); xerrno = errno; destroy_pool(tmp_pool); errno = xerrno; return res; }
void pr_help_add(const char *cmd, const char *syntax, int impl) { struct help_rec *help; if (!cmd || !syntax) return; /* If no list has been allocated, create one. */ if (!help_pool) { help_pool = make_sub_pool(permanent_pool); pr_pool_tag(help_pool, "HELP Pool"); help_list = make_array(help_pool, 0, sizeof(struct help_rec)); } /* Make sure that the command being added isn't already in the list. * However, if it _is_ already in the list, but it's marked as not * implemented, _and_ the given impl flag is TRUE, then handle it * accordingly. */ if (help_list->nelts > 0) { register unsigned int i = 0; struct help_rec *helps = help_list->elts; for (i = 0; i < help_list->nelts; i++) if (strcmp(helps[i].cmd, cmd) == 0) { if (helps[i].impl == FALSE) helps[i].impl = impl; return; } } help = push_array(help_list); help->cmd = pstrdup(help_pool, cmd); help->syntax = pstrdup(help_pool, syntax); help->impl = impl; }
int pr_timer_add(int seconds, int timerno, module *mod, callback_t cb, const char *desc) { struct timer *t = NULL; if (seconds <= 0 || cb == NULL || desc == NULL) { errno = EINVAL; return -1; } if (!timers) timers = xaset_create(timer_pool, (XASET_COMPARE) timer_cmp); /* Check to see that, if specified, the timerno is not already in use. */ if (timerno >= 0) { for (t = (struct timer *) timers->xas_list; t; t = t->next) { if (t->timerno == timerno) { errno = EPERM; return -1; } } } if (!free_timers) free_timers = xaset_create(timer_pool, NULL); /* Try to use an old timer first */ pr_alarms_block(); t = (struct timer *) free_timers->xas_list; if (t != NULL) { xaset_remove(free_timers, (xasetmember_t *) t); } else { if (timer_pool == NULL) { timer_pool = make_sub_pool(permanent_pool); pr_pool_tag(timer_pool, "Timer Pool"); } /* Must allocate a new one */ t = palloc(timer_pool, sizeof(struct timer)); } if (timerno < 0) { /* Dynamic timer */ if (dynamic_timerno < PR_TIMER_DYNAMIC_TIMERNO) { dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO; } timerno = dynamic_timerno++; } t->timerno = timerno; t->count = t->interval = seconds; t->callback = cb; t->mod = mod; t->remove = 0; t->desc = desc; /* If called while _indispatch, add to the recycled list to prevent * list corruption */ if (_indispatch) { if (!recycled) recycled = xaset_create(timer_pool, NULL); xaset_insert(recycled, (xasetmember_t *) t); } else { xaset_insert_sort(timers, (xasetmember_t *) t, TRUE); nalarms++; set_sig_alarm(); /* The handle_alarm() function also readjusts the timers lists * as part of its processing, so it needs to be called when a timer * is added. */ handle_alarm(); } pr_alarms_unblock(); pr_trace_msg("timer", 7, "added timer ID %d ('%s', for module '%s'), " "triggering in %ld %s", t->timerno, t->desc, t->mod ? t->mod->name : "[none]", t->interval, t->interval != 1 ? "seconds" : "second"); return timerno; }
static void set_up(void) { if (p == NULL) { p = make_sub_pool(NULL); } }
static int check_facl(pool *p, const char *path, int mode, void *acl, int nents, struct stat *st, uid_t uid, gid_t gid, array_header *suppl_gids) { # if defined(HAVE_BSD_POSIX_ACL) || defined(HAVE_LINUX_POSIX_ACL) register unsigned int i; int have_access_entry = FALSE, res = -1; pool *acl_pool; acl_t facl = acl; acl_entry_t ae; acl_tag_t ae_type; acl_entry_t acl_user_entry = NULL; acl_entry_t acl_group_entry = NULL; acl_entry_t acl_other_entry = NULL; acl_entry_t acl_mask_entry = NULL; array_header *acl_groups; array_header *acl_users; /* Iterate through all of the ACL entries, sorting them for later * checking. */ res = acl_get_entry(facl, ACL_FIRST_ENTRY, &ae); if (res < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve first ACL entry for '%s': %s", path, strerror(errno)); errno = EACCES; return -1; } if (res == 0) { pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s' has no entries!", path); errno = EACCES; return -1; } acl_pool = make_sub_pool(p); acl_groups = make_array(acl_pool, 1, sizeof(acl_entry_t)); acl_users = make_array(acl_pool, 1, sizeof(acl_entry_t)); while (res > 0) { if (acl_get_tag_type(ae, &ae_type) < 0) { pr_log_debug(DEBUG5, "FS: error retrieving type of ACL entry for '%s': %s", path, strerror(errno)); res = acl_get_entry(facl, ACL_NEXT_ENTRY, &ae); continue; } if (ae_type & ACL_USER_OBJ) { acl_copy_entry(acl_user_entry, ae); } else if (ae_type & ACL_USER) { acl_entry_t *ae_dup = push_array(acl_users); acl_copy_entry(*ae_dup, ae); } else if (ae_type & ACL_GROUP_OBJ) { acl_copy_entry(acl_group_entry, ae); } else if (ae_type & ACL_GROUP) { acl_entry_t *ae_dup = push_array(acl_groups); acl_copy_entry(*ae_dup, ae); } else if (ae_type & ACL_OTHER) { acl_copy_entry(acl_other_entry, ae); } else if (ae_type & ACL_MASK) { acl_copy_entry(acl_mask_entry, ae); } res = acl_get_entry(facl, ACL_NEXT_ENTRY, &ae); } /* Select the ACL entry that determines access. */ res = -1; /* 1. If the given user ID matches the file owner, use that entry for * access. */ if (uid == st->st_uid) { /* Check the acl_user_entry for access. */ acl_copy_entry(ae, acl_user_entry); ae_type = ACL_USER_OBJ; have_access_entry = TRUE; } /* 2. If not matched above, and f the given user ID matches one of the * named user entries, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_users->nelts; i++) { acl_entry_t e = ((acl_entry_t *) acl_users->elts)[i]; if (uid == *((uid_t *) acl_get_qualifier(e))) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ acl_copy_entry(ae, e); ae_type = ACL_USER; have_access_entry = TRUE; break; } } /* 3. If not matched above, and if one of the group IDs matches the * group owner entry, and the group owner entry contains the * requested permissions, use that entry for access. */ if (!have_access_entry && gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ acl_permset_t perms; acl_get_permset(acl_group_entry, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, acl_group_entry); ae_type = ACL_GROUP_OBJ; have_access_entry = TRUE; } } if (suppl_gids) { for (i = 0; !have_access_entry && i < suppl_gids->nelts; i++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[i]; if (suppl_gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ acl_permset_t perms; acl_get_permset(acl_group_entry, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, acl_group_entry); ae_type = ACL_GROUP_OBJ; have_access_entry = TRUE; break; } } } } /* 5. If not matched above, and if one of the group IDs matches one * of the named group entries, and that entry contains the requested * permissions, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_groups->nelts; i++) { acl_entry_t e = ((acl_entry_t *) acl_groups->elts)[i]; if (gid == *((gid_t *) acl_get_qualifier(e))) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ acl_permset_t perms; acl_get_permset(e, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, e); ae_type = ACL_GROUP; have_access_entry = TRUE; break; } } if (suppl_gids) { register unsigned int j; for (j = 0; !have_access_entry && j < suppl_gids->nelts; j++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[j]; if (suppl_gid == *((gid_t *) acl_get_qualifier(e))) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ acl_permset_t perms; acl_get_permset(e, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif acl_copy_entry(ae, e); ae_type = ACL_GROUP; have_access_entry = TRUE; break; } } } } } /* 6. If not matched above, and if one of the group IDs matches * the group owner or any of the named group entries, but neither * the group owner entry nor any of the named group entries contains * the requested permissions, access is denied. */ /* 7. If not matched above, the other entry determines access. */ if (!have_access_entry) { acl_copy_entry(ae, acl_other_entry); ae_type = ACL_OTHER; have_access_entry = TRUE; } /* Access determination: * * If either the user owner entry or other entry were used, and the * entry contains the requested permissions, access is permitted. * * Otherwise, if the selected entry and the mask entry both contain * the requested permissions, access is permitted. * * Otherwise, access is denied. */ switch (ae_type) { case ACL_USER_OBJ: case ACL_OTHER: { acl_permset_t perms; acl_get_permset(ae, &perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(perms, mode) == 1) { # endif res = 0; } break; } default: { acl_permset_t ent_perms, mask_perms; acl_get_permset(ae, &ent_perms); acl_get_permset(acl_mask_entry, &mask_perms); # if defined(HAVE_BSD_POSIX_ACL) if (acl_get_perm_np(ent_perms, mode) == 1 && acl_get_perm_np(mask_perms, mode) == 1) { # elif defined(HAVE_LINUX_POSIX_ACL) if (acl_get_perm(ent_perms, mode) == 1 && acl_get_perm(mask_perms, mode) == 1) { # endif res = 0; } break; } } destroy_pool(acl_pool); if (res < 0) errno = EACCES; return res; # elif defined(HAVE_SOLARIS_POSIX_ACL) register unsigned int i; int have_access_entry = FALSE, idx, res = -1; pool *acl_pool; aclent_t *acls = acl; aclent_t ae; int ae_type = 0; aclent_t acl_user_entry; aclent_t acl_group_entry; aclent_t acl_other_entry; aclent_t acl_mask_entry; array_header *acl_groups; array_header *acl_users; /* In the absence of any clear documentation, I'll assume that * Solaris ACLs follow the same selection and checking algorithm * as do BSD and Linux. */ res = aclcheck(acls, nents, &idx); switch (res) { case 0: break; case GRP_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many GROUP entries"); errno = EACCES; return -1; case USER_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many USER entries"); errno = EACCES; return -1; case OTHER_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many OTHER entries"); errno = EACCES; return -1; case CLASS_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "too many CLASS entries"); errno = EACCES; return -1; case DUPLICATE_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "duplicate entries"); errno = EACCES; return -1; case MISS_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "missing required entry"); errno = EACCES; return -1; case MEM_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "Out of memory!"); errno = EACCES; return -1; case ENTRY_ERROR: pr_log_debug(DEBUG3, "FS: ill-formed ACL for '%s': %s", path, "invalid entry type"); errno = EACCES; return -1; } /* Iterate through all of the ACL entries, sorting them for later * checking. */ acl_pool = make_sub_pool(p); acl_groups = make_array(acl_pool, 1, sizeof(aclent_t)); acl_users = make_array(acl_pool, 1, sizeof(aclent_t)); for (i = 0; i < nents; i++) { if (acls[i].a_type & USER_OBJ) { memcpy(&acl_user_entry, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & USER) { aclent_t *ae_dup = push_array(acl_users); memcpy(ae_dup, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & GROUP_OBJ) { memcpy(&acl_group_entry, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & GROUP) { aclent_t *ae_dup = push_array(acl_groups); memcpy(ae_dup, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & OTHER_OBJ) { memcpy(&acl_other_entry, &(acls[i]), sizeof(aclent_t)); } else if (acls[i].a_type & CLASS_OBJ) { memcpy(&acl_mask_entry, &(acls[i]), sizeof(aclent_t)); } } /* Select the ACL entry that determines access. */ res = -1; /* 1. If the given user ID matches the file owner, use that entry for * access. */ if (uid == st->st_uid) { /* Check the acl_user_entry for access. */ memcpy(&ae, &acl_user_entry, sizeof(aclent_t)); ae_type = USER_OBJ; have_access_entry = TRUE; } /* 2. If not matched above, and f the given user ID matches one of the * named user entries, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_users->nelts; i++) { aclent_t e; memcpy(&e, &(((aclent_t *) acl_users->elts)[i]), sizeof(aclent_t)); if (uid == e.a_id) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ memcpy(&ae, &e, sizeof(aclent_t)); ae_type = USER; have_access_entry = TRUE; break; } } /* 3. If not matched above, and if one of the group IDs matches the * group owner entry, and the group owner entry contains the * requested permissions, use that entry for access. */ if (!have_access_entry && gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ if (acl_group_entry.a_perm & mode) { memcpy(&ae, &acl_group_entry, sizeof(aclent_t)); ae_type = GROUP_OBJ; have_access_entry = TRUE; } } if (suppl_gids) { for (i = 0; !have_access_entry && i < suppl_gids->nelts; i++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[i]; if (suppl_gid == st->st_gid) { /* Check the acl_group_entry for access. First though, we need to * see if the acl_group_entry contains the requested permissions. */ if (acl_group_entry.a_perm & mode) { memcpy(&ae, &acl_group_entry, sizeof(aclent_t)); ae_type = GROUP_OBJ; have_access_entry = TRUE; break; } } } } /* 5. If not matched above, and if one of the group IDs matches one * of the named group entries, and that entry contains the requested * permissions, use that entry for access. */ for (i = 0; !have_access_entry && i < acl_groups->nelts; i++) { aclent_t e; memcpy(&e, &(((aclent_t *) acl_groups->elts)[i]), sizeof(aclent_t)); if (gid == e.a_id) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ if (e.a_perm & mode) { memcpy(&ae, &e, sizeof(aclent_t)); ae_type = GROUP; have_access_entry = TRUE; break; } } if (suppl_gids) { register unsigned int j; for (j = 0; !have_access_entry && j < suppl_gids->nelts; j++) { gid_t suppl_gid = ((gid_t *) suppl_gids->elts)[j]; if (suppl_gid == e.a_id) { /* Check this entry for access. Note that it'll need to * be modified by the mask, if any, later. */ if (e.a_perm & mode) { memcpy(&ae, &e, sizeof(aclent_t)); ae_type = GROUP; have_access_entry = TRUE; break; } } } } } /* 6. If not matched above, and if one of the group IDs matches * the group owner or any of the named group entries, but neither * the group owner entry nor any of the named group entries contains * the requested permissions, access is denied. */ /* 7. If not matched above, the other entry determines access. */ if (!have_access_entry) { memcpy(&ae, &acl_other_entry, sizeof(aclent_t)); ae_type = OTHER_OBJ; have_access_entry = TRUE; } /* Access determination: * * If either the user owner entry or other entry were used, and the * entry contains the requested permissions, access is permitted. * * Otherwise, if the selected entry and the mask entry both contain * the requested permissions, access is permitted. * * Otherwise, access is denied. */ switch (ae_type) { case USER_OBJ: case OTHER_OBJ: if (ae.a_perm & mode) res = 0; break; default: if ((ae.a_perm & mode) && (acl_mask_entry.a_perm & mode)) res = 0; break; } destroy_pool(acl_pool); if (res < 0) errno = EACCES; return res; # endif /* HAVE_SOLARIS_POSIX_ACL */ } /* FSIO handlers */ static int facl_fsio_access(pr_fs_t *fs, const char *path, int mode, uid_t uid, gid_t gid, array_header *suppl_gids) { int nents = 0; struct stat st; void *acls; pr_fs_clear_cache(); if (pr_fsio_stat(path, &st) < 0) return -1; /* Look up the acl for this path. */ # if defined(HAVE_BSD_POSIX_ACL) || defined(HAVE_LINUX_POSIX_ACL) acls = acl_get_file(path, ACL_TYPE_ACCESS); if (!acls) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", path, strerror(errno)); return -1; } # elif defined(HAVE_SOLARIS_POSIX_ACL) nents = acl(path, GETACLCNT, 0, NULL); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL count for '%s': %s", path, strerror(errno)); return -1; } acls = pcalloc(fs->fs_pool, nents * sizeof(aclent_t)); nents = acl(path, GETACL, nents, acls); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", path, strerror(errno)); return -1; } # endif return check_facl(fs->fs_pool, path, mode, acls, nents, &st, uid, gid, suppl_gids); } static int facl_fsio_faccess(pr_fh_t *fh, int mode, uid_t uid, gid_t gid, array_header *suppl_gids) { int nents = 0; struct stat st; void *acls; pr_fs_clear_cache(); if (pr_fsio_fstat(fh, &st) < 0) return -1; /* Look up the acl for this fd. */ # if defined(HAVE_BSD_POSIX_ACL) || defined(HAVE_LINUX_POSIX_ACL) acls = acl_get_fd(PR_FH_FD(fh)); if (!acls) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", fh->fh_path, strerror(errno)); return -1; } # elif defined(HAVE_SOLARIS_POSIX_ACL) nents = facl(PR_FH_FD(fh), GETACLCNT, 0, NULL); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL count for '%s': %s", fh->fh_path, strerror(errno)); return -1; } acls = pcalloc(fh->fh_fs->fs_pool, nents * sizeof(aclent_t)); nents = facl(PR_FH_FD(fh), GETACL, nents, acls); if (nents < 0) { pr_log_debug(DEBUG10, "FS: unable to retrieve ACL for '%s': %s", fh->fh_path, strerror(errno)); return -1; } # endif return check_facl(fh->fh_fs->fs_pool, fh->fh_path, mode, acls, nents, &st, uid, gid, suppl_gids); } #endif /* HAVE_POSIX_ACL */ /* Initialization routines */ static int facl_init(void) { #if defined(PR_USE_FACL) && defined(HAVE_POSIX_ACL) pr_fs_t *fs = pr_register_fs(permanent_pool, "facl", "/"); if (!fs) { pr_log_pri(PR_LOG_ERR, MOD_FACL_VERSION ": error registering fs: %s", strerror(errno)); return -1; } /* Ensure that our ACL-checking handlers are used. */ fs->access = facl_fsio_access; fs->faccess = facl_fsio_faccess; #endif /* PR_USE_FACL and HAVE_POSIX_ACL */ return 0; } /* Module Tables */ module facl_module = { /* Always NULL */ NULL, NULL, /* Module API version */ 0x20, /* Module name */ "facl", /* Module configuration directive handlers */ NULL, /* Module command handlers */ NULL, /* Module authentication handlers */ NULL, /* Module initialization */ facl_init, /* Session initialization */ NULL, /* Module version */ MOD_FACL_VERSION };
int pr_log_openfile(const char *log_file, int *log_fd, mode_t log_mode) { int res; pool *tmp_pool = NULL; char *tmp = NULL, *lf; unsigned char have_stat = FALSE, *allow_log_symlinks = NULL; struct stat st; /* Sanity check */ if (!log_file || !log_fd) { errno = EINVAL; return -1; } /* Make a temporary copy of log_file in case it's a constant */ tmp_pool = make_sub_pool(permanent_pool); pr_pool_tag(tmp_pool, "log_openfile() tmp pool"); lf = pstrdup(tmp_pool, log_file); tmp = strrchr(lf, '/'); if (tmp == NULL) { pr_log_debug(DEBUG0, "inappropriate log file: %s", lf); destroy_pool(tmp_pool); errno = EINVAL; return -1; } /* Set the path separator to zero, in order to obtain the directory * name, so that checks of the directory may be made. */ *tmp = '\0'; if (stat(lf, &st) < 0) { int xerrno = errno; pr_log_debug(DEBUG0, "error: unable to stat() %s: %s", lf, strerror(errno)); destroy_pool(tmp_pool); errno = xerrno; return -1; } /* The path must be in a valid directory */ if (!S_ISDIR(st.st_mode)) { pr_log_debug(DEBUG0, "error: %s is not a directory", lf); destroy_pool(tmp_pool); errno = ENOTDIR; return -1; } /* Do not log to world-writable directories */ if (st.st_mode & S_IWOTH) { pr_log_pri(PR_LOG_NOTICE, "error: %s is a world-writable directory", lf); destroy_pool(tmp_pool); return PR_LOG_WRITABLE_DIR; } /* Restore the path separator so that checks on the file itself may be * done. */ *tmp = '/'; allow_log_symlinks = get_param_ptr(main_server->conf, "AllowLogSymlinks", FALSE); if (allow_log_symlinks == NULL || *allow_log_symlinks == FALSE) { int flags = O_APPEND|O_CREAT|O_WRONLY; #ifdef PR_USE_NONBLOCKING_LOG_OPEN /* Use the O_NONBLOCK flag when opening log files, as they might be * FIFOs whose other end is not currently running; we do not want to * block indefinitely in such cases. */ flags |= O_NONBLOCK; #endif /* PR_USE_NONBLOCKING_LOG_OPEN */ #ifdef O_NOFOLLOW /* On systems that support the O_NOFOLLOW flag (e.g. Linux and FreeBSD), * use it so that the path being opened, if it is a symlink, is not * followed. */ flags |= O_NOFOLLOW; #elif defined(SOLARIS2) /* Solaris doesn't support the O_NOFOLLOW flag. Instead, in their * wisdom (hah!), Solaris decided that if the given path is a symlink * and the flags O_CREAT and O_EXCL are set, the link is not followed. * Right. The problem here is the case where the path is not a symlink; * using O_CREAT|O_EXCL will then cause the open() to fail if the * file already exists. */ flags |= O_EXCL; #endif /* O_NOFOLLOW or SOLARIS2 */ *log_fd = open(lf, flags, log_mode); if (*log_fd < 0) { if (errno != EEXIST) { destroy_pool(tmp_pool); /* More portability fun: Linux likes to report ELOOP if O_NOFOLLOW * is used to open a symlink file; FreeBSD likes to return EMLINK. * Both would lead to rather misleading error messages being * logged. Catch these errnos, and return the value that properly * informs the caller that the given path was an illegal symlink. */ switch (errno) { #ifdef ELOOP case ELOOP: return PR_LOG_SYMLINK; #endif /* ELOOP */ #ifdef EMLINK case EMLINK: return PR_LOG_SYMLINK; #endif /* EMLINK */ } return -1; } else { #if defined(SOLARIS2) /* On Solaris, because of the stupid multiplexing of O_CREAT and * O_EXCL to get open() not to follow a symlink, it's possible that * the path already exists. Now, we'll try to open() without * O_EXCL, then lstat() the path to see if this pre-existing file is * a symlink or a regular file. * * Note that because this check cannot be done atomically on Solaris, * the possibility of a race condition/symlink attack still exists. * Solaris doesn't provide a good way around this situation. */ flags &= ~O_EXCL; *log_fd = open(lf, flags, log_mode); if (*log_fd < 0) { destroy_pool(tmp_pool); return -1; } /* The race condition on Solaris is here, between the open() call * above and the lstat() call below... */ if (lstat(lf, &st) != -1) have_stat = TRUE; #else destroy_pool(tmp_pool); return -1; #endif /* SOLARIS2 */ } } /* Stat the file using the descriptor, not the path */ if (!have_stat && fstat(*log_fd, &st) != -1) have_stat = TRUE; if (!have_stat || S_ISLNK(st.st_mode)) { pr_log_debug(DEBUG0, !have_stat ? "error: unable to stat %s" : "error: %s is a symbolic link", lf); close(*log_fd); *log_fd = -1; destroy_pool(tmp_pool); return PR_LOG_SYMLINK; } } else { int flags = O_CREAT|O_APPEND|O_WRONLY; #ifdef PR_USE_NONBLOCKING_LOG_OPEN /* Use the O_NONBLOCK flag when opening log files, as they might be * FIFOs whose other end is not currently running; we do not want to * block indefinitely in such cases. */ flags |= O_NONBLOCK; #endif /* PR_USE_NONBLOCKING_LOG_OPEN */ *log_fd = open(lf, flags, log_mode); if (*log_fd < 0) { destroy_pool(tmp_pool); return -1; } } /* Find a usable fd for the just-opened log fd. */ if (*log_fd <= STDERR_FILENO) { res = pr_fs_get_usable_fd(*log_fd); if (res < 0) { pr_log_debug(DEBUG0, "warning: unable to find good fd for logfd %d: %s", *log_fd, strerror(errno)); } else { close(*log_fd); *log_fd = res; } } if (fcntl(*log_fd, F_SETFD, FD_CLOEXEC) < 0) { pr_log_pri(PR_LOG_WARNING, "unable to set CLO_EXEC on log fd %d: %s", *log_fd, strerror(errno)); } #ifdef PR_USE_NONBLOCKING_LOG_OPEN /* Return the fd to blocking mode. */ (void) fd_set_block(*log_fd); #endif /* PR_USE_NONBLOCKING_LOG_OPEN */ destroy_pool(tmp_pool); return 0; }
int main(int argc, char **argv) { int c = 0; char *ptr, *progname = *argv; const char *cmdopts = "hqv", *secret = NULL; ptr = strrchr(progname, '/'); if (ptr != NULL) { progname = ptr+1; } opterr = 0; while ((c = #ifdef HAVE_GETOPT_LONG getopt_long(argc, argv, cmdopts, opts, NULL) #else /* HAVE_GETOPT_LONG */ getopt(argc, argv, cmdopts) #endif /* HAVE_GETOPT_LONG */ ) != -1) { switch (c) { case 'h': show_usage(progname, 0); break; case 'q': verbose = FALSE; quiet = TRUE; break; case 'v': quiet = FALSE; verbose = TRUE; break; case '?': fprintf(stderr, "unknown option: %c\n", (char) optopt); show_usage(progname, 1); break; } } auth_otp_pool = make_sub_pool(NULL); #if OPENSSL_VERSION_NUMBER < 0x10100000L OPENSSL_config(NULL); #endif /* prior to OpenSSL-1.1.x */ ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); secret = generate_secret(auth_otp_pool); if (secret == NULL) { return 1; } if (quiet) { fprintf(stdout, "%s\n", secret); } else { int code; code = generate_code(auth_otp_pool, secret, strlen(secret)); if (code < 0) { fprintf(stderr, "%s: error generating verification code: %s\n", progname, strerror(errno)); destroy_pool(auth_otp_pool); return 1; } fprintf(stdout, "-------------------------------------------------\n"); fprintf(stdout, "Your new secret key is: %s\n\n", secret); fprintf(stdout, "To add this key to your SQL table, you might use:\n\n"); fprintf(stdout, " INSERT INTO auth_otp (secret, counter) VALUES ('%s', 0);\n\n", secret); fprintf(stdout, "Your verification code is: %06d\n", code); fprintf(stdout, "-------------------------------------------------\n"); } ERR_free_strings(); EVP_cleanup(); RAND_cleanup(); destroy_pool(auth_otp_pool); return 0; }