pr_regex_t *pr_regexp_alloc(module *m) { pr_regex_t *pre = NULL; pool *re_pool = NULL; /* If no regex-tracking list has been allocated, create one. Register a * cleanup handler for this pool, to free up the data in the list. */ if (regexp_pool == NULL) { regexp_pool = make_sub_pool(permanent_pool); pr_pool_tag(regexp_pool, "Regexp Pool"); regexp_list = make_array(regexp_pool, 0, sizeof(pr_regex_t *)); } re_pool = pr_pool_create_sz(regexp_pool, 128); pr_pool_tag(re_pool, "regexp pool"); pre = pcalloc(re_pool, sizeof(pr_regex_t)); pre->regex_pool = re_pool; pre->m = m; /* Add this pointer to the array. */ *((pr_regex_t **) push_array(regexp_list)) = pre; return pre; }
struct snmp_pdu *snmp_pdu_create(pool *p, unsigned char request_type) { pool *sub_pool; struct snmp_pdu *pdu; sub_pool = pr_pool_create_sz(p, 64); pdu = pcalloc(sub_pool, sizeof(struct snmp_pdu)); pdu->pool = sub_pool; pdu->request_type = request_type; pr_trace_msg(trace_channel, 19, "created PDU of type '%s'", snmp_pdu_get_request_type_desc(request_type)); return pdu; }
static struct stash *sym_alloc(void) { pool *sub_pool; struct stash *sym; /* XXX Use a smaller pool size, since there are lots of sub-pools allocated * for Stash symbols. The default pool size (PR_TUNABLE_POOL_SIZE, 512 * bytes by default) is a bit large for symbols. */ sub_pool = pr_pool_create_sz(symbol_pool, PR_SYM_POOL_SIZE); sym = pcalloc(sub_pool, sizeof(struct stash)); sym->sym_pool = sub_pool; pr_pool_tag(sub_pool, "symbol"); return sym; }
static struct config_src *add_config_source(pr_fh_t *fh) { pool *p = pr_pool_create_sz(parser_pool, PARSER_CONFIG_SRC_POOL_SZ); struct config_src *cs = pcalloc(p, sizeof(struct config_src)); pr_pool_tag(p, "configuration source pool"); cs->cs_next = NULL; cs->cs_pool = p; cs->cs_fh = fh; cs->cs_lineno = 0; if (!parser_sources) { parser_sources = cs; } else { cs->cs_next = parser_sources; parser_sources = cs; } return cs; }
static int create_path(pool *p, const char *path) { struct stat st; char *curr_path, *dup_path; pr_fs_clear_cache2(path); if (pr_fsio_stat(path, &st) == 0) { return 0; } dup_path = pstrdup(p, path); curr_path = "/"; while (dup_path && *dup_path) { char *curr_dir; int res; cmd_rec *cmd; pool *sub_pool; pr_signals_handle(); curr_dir = strsep(&dup_path, "/"); curr_path = pdircat(p, curr_path, curr_dir, NULL); /* Dispatch fake C_MKD command, e.g. for mod_quotatab */ sub_pool = pr_pool_create_sz(p, 64); cmd = pr_cmd_alloc(sub_pool, 2, pstrdup(sub_pool, C_MKD), pstrdup(sub_pool, curr_path)); cmd->arg = pstrdup(cmd->pool, curr_path); cmd->cmd_class = CL_DIRS|CL_WRITE; pr_response_clear(&resp_list); pr_response_clear(&resp_err_list); res = pr_cmd_dispatch_phase(cmd, PRE_CMD, 0); if (res < 0) { int xerrno = errno; pr_log_debug(DEBUG3, MOD_COPY_VERSION ": creating directory '%s' blocked by MKD handler: %s", curr_path, strerror(xerrno)); pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0); pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0); pr_response_clear(&resp_err_list); destroy_pool(sub_pool); errno = xerrno; return -1; } res = create_dir(curr_path); if (res < 0) { pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0); pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0); pr_response_clear(&resp_err_list); destroy_pool(sub_pool); return -1; } pr_cmd_dispatch_phase(cmd, POST_CMD, 0); pr_cmd_dispatch_phase(cmd, LOG_CMD, 0); pr_response_clear(&resp_list); destroy_pool(sub_pool); } return 0; }
static int copy_dir(pool *p, const char *src_dir, const char *dst_dir) { DIR *dh = NULL; struct dirent *dent = NULL; int res = 0; pool *iter_pool = NULL; dh = opendir(src_dir); if (dh == NULL) { pr_log_pri(PR_LOG_WARNING, MOD_COPY_VERSION ": error reading directory '%s': %s", src_dir, strerror(errno)); return -1; } while ((dent = readdir(dh)) != NULL) { struct stat st; char *src_path, *dst_path; pr_signals_handle(); /* Skip "." and ".." */ if (strncmp(dent->d_name, ".", 2) == 0 || strncmp(dent->d_name, "..", 3) == 0) { continue; } if (iter_pool != NULL) { destroy_pool(iter_pool); } iter_pool = pr_pool_create_sz(p, 128); src_path = pdircat(iter_pool, src_dir, dent->d_name, NULL); dst_path = pdircat(iter_pool, dst_dir, dent->d_name, NULL); if (pr_fsio_lstat(src_path, &st) < 0) { pr_log_debug(DEBUG3, MOD_COPY_VERSION ": unable to stat '%s' (%s), skipping", src_path, strerror(errno)); continue; } /* Is this path to a directory? */ if (S_ISDIR(st.st_mode)) { if (create_path(iter_pool, dst_path) < 0) { res = -1; break; } if (copy_dir(iter_pool, src_path, dst_path) < 0) { res = -1; break; } continue; /* Is this path to a regular file? */ } else if (S_ISREG(st.st_mode)) { cmd_rec *cmd; /* Dispatch fake COPY command, e.g. for mod_quotatab */ cmd = pr_cmd_alloc(iter_pool, 4, pstrdup(iter_pool, "SITE"), pstrdup(iter_pool, "COPY"), pstrdup(iter_pool, src_path), pstrdup(iter_pool, dst_path)); cmd->arg = pstrcat(iter_pool, "COPY ", src_path, " ", dst_path, NULL); cmd->cmd_class = CL_WRITE; pr_response_clear(&resp_list); pr_response_clear(&resp_err_list); if (pr_cmd_dispatch_phase(cmd, PRE_CMD, 0) < 0) { int xerrno = errno; pr_log_debug(DEBUG3, MOD_COPY_VERSION ": COPY of '%s' to '%s' blocked by COPY handler: %s", src_path, dst_path, strerror(xerrno)); pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0); pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0); pr_response_clear(&resp_err_list); errno = xerrno; res = -1; break; } else { if (pr_fs_copy_file(src_path, dst_path) < 0) { pr_cmd_dispatch_phase(cmd, POST_CMD_ERR, 0); pr_cmd_dispatch_phase(cmd, LOG_CMD_ERR, 0); pr_response_clear(&resp_err_list); res = -1; break; } else { char *abs_path; pr_cmd_dispatch_phase(cmd, POST_CMD, 0); pr_cmd_dispatch_phase(cmd, LOG_CMD, 0); pr_response_clear(&resp_list); /* Write a TransferLog entry as well. */ pr_fs_clear_cache2(dst_path); pr_fsio_stat(dst_path, &st); abs_path = dir_abs_path(p, dst_path, TRUE); if (session.sf_flags & SF_ANON) { xferlog_write(0, session.c->remote_name, st.st_size, abs_path, (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'a', session.anon_user, 'c', "_"); } else { xferlog_write(0, session.c->remote_name, st.st_size, abs_path, (session.sf_flags & SF_ASCII ? 'a' : 'b'), 'd', 'r', session.user, 'c', "_"); } } } continue; /* Is this path a symlink? */ } else if (S_ISLNK(st.st_mode)) { if (copy_symlink(iter_pool, src_path, dst_path) < 0) { res = -1; break; } continue; /* All other file types are skipped */ } else { pr_log_debug(DEBUG3, MOD_COPY_VERSION ": skipping supported file '%s'", src_path); continue; } } if (iter_pool != NULL) { destroy_pool(iter_pool); } closedir(dh); return res; }
int pr_event_register(module *m, const char *event, void (*cb)(const void *, void *), void *user_data) { struct event_handler *evh; struct event_list *evl; pool *evl_pool; if (event == NULL || cb == NULL) { errno = EINVAL; return -1; } if (event_pool == NULL) { event_pool = make_sub_pool(permanent_pool); pr_pool_tag(event_pool, "Event Pool"); } pr_trace_msg(trace_channel, 3, "module '%s' (%p) registering handler for event '%s' (at %p)", m ? m->name : "(none)", m, event, cb); evh = pcalloc(event_pool, sizeof(struct event_handler)); evh->module = m; evh->cb = cb; evh->user_data = user_data; /* Scan the currently registered lists, looking for where to add this * registration. */ for (evl = events; evl; evl = evl->next) { if (strncmp(evl->event, event, evl->event_len + 1) == 0) { struct event_handler *evhi, *evhl; evhi = evl->handlers; if (evhi) { /* Make sure this event handler is added to the START of the list, * in order to preserve module load order handling of events (i.e. * last module loaded, first module handled). The exception to this * rule are core callbacks (i.e. where m == NULL); these will always * be invoked last. * * Before that, though, check for duplicate registration/subscription. */ while (evhi) { pr_signals_handle(); if (evhi->cb == evh->cb) { /* Duplicate callback */ errno = EEXIST; return -1; } evhl = evhi; if (evhi->next == NULL) { break; } evhi = evhi->next; } if (evh->module != NULL) { if (evl->handlers->next != NULL) { evl->handlers->next->prev = evh; } evh->next = evl->handlers; evl->handlers = evh; } else { /* Core event listeners go at the end. */ if (evhl != NULL) { evhl->next = evh; evh->prev = evhl; } else { evl->handlers = evh; } } } else { evl->handlers = evh; } /* All done */ return 0; } } evl_pool = pr_pool_create_sz(event_pool, EVENT_POOL_SZ); pr_pool_tag(evl_pool, "Event listener list pool"); evl = pcalloc(evl_pool, sizeof(struct event_list)); evl->pool = evl_pool; evl->event = pstrdup(evl->pool, event); evl->event_len = strlen(evl->event); evl->handlers = evh; evl->next = events; events = evl; /* Clear any cached data. */ curr_event = NULL; curr_evl = NULL; curr_evh = NULL; return 0; }
int pr_event_register(module *m, const char *event, void (*cb)(const void *, void *), void *user_data) { struct event_handler *evh; struct event_list *evl; pool *evl_pool; if (!event || !cb) { errno = EINVAL; return -1; } if (!event_pool) { event_pool = make_sub_pool(permanent_pool); pr_pool_tag(event_pool, "Event Pool"); } pr_trace_msg(trace_channel, 3, "module '%s' (%p) registering handler for event '%s' (at %p)", m ? m->name : "(none)", m, event, cb); evh = pcalloc(event_pool, sizeof(struct event_handler)); evh->module = m; evh->cb = cb; evh->user_data = user_data; /* Scan the currently registered lists, looking for where to add this * registration. */ for (evl = events; evl; evl = evl->next) { if (strcmp(evl->event, event) == 0) { struct event_handler *evhi = evl->handlers; if (evhi) { /* Make sure this event handler is added to the end of the list, * in order to preserve module load order handling of events. */ while (evhi) { if (evhi->cb == evh->cb) { /* Duplicate callback */ errno = EEXIST; return -1; } if (evhi->next == NULL) break; evhi = evhi->next; } evh->prev = evhi; evhi->next = evh; } else evl->handlers = evh; /* All done */ return 0; } } evl_pool = pr_pool_create_sz(event_pool, EVENT_POOL_SZ); pr_pool_tag(evl_pool, "Event listener list pool"); evl = pcalloc(evl_pool, sizeof(struct event_list)); evl->pool = evl_pool; evl->event = pstrdup(evl->pool, event); evl->handlers = evh; evl->next = events; events = evl; /* Clear any cached data. */ curr_event = NULL; curr_evl = NULL; curr_evh = NULL; return 0; }
struct proxy_conn *proxy_conn_create(pool *p, const char *uri) { int res, use_tls = PROXY_TLS_ENGINE_AUTO; char hostport[512], *proto, *remote_host, *username = NULL, *password = NULL; unsigned int remote_port; struct proxy_conn *pconn; pool *pconn_pool; if (p == NULL || uri == NULL) { errno = EINVAL; return NULL; } res = proxy_uri_parse(p, uri, &proto, &remote_host, &remote_port, &username, &password); if (res < 0) { return NULL; } if (supported_protocol(proto) < 0) { pr_trace_msg(trace_channel, 4, "unsupported protocol '%s' in URI '%.100s'", proto, uri); errno = EPERM; return NULL; } if (strncmp(proto, "ftps", 5) == 0) { /* If the 'ftps' scheme is used, then FTPS is REQUIRED for connections * to this server. */ use_tls = PROXY_TLS_ENGINE_ON; } else if (strncmp(proto, "sftp", 5) == 0) { /* As might be obvious, do not try to use TLS against an SSH2/SFTP * server. */ use_tls = PROXY_TLS_ENGINE_OFF; } memset(hostport, '\0', sizeof(hostport)); snprintf(hostport, sizeof(hostport)-1, "%s:%u", remote_host, remote_port); pconn_pool = pr_pool_create_sz(p, 128); pr_pool_tag(pconn_pool, "proxy connection pool"); pconn = pcalloc(pconn_pool, sizeof(struct proxy_conn)); pconn->pconn_pool = pconn_pool; pconn->pconn_host = pstrdup(pconn_pool, remote_host); pconn->pconn_port = remote_port; pconn->pconn_hostport = pstrdup(pconn_pool, hostport); pconn->pconn_uri = pstrdup(pconn_pool, uri); pconn->pconn_proto = pstrdup(pconn_pool, proto); pconn->pconn_tls = use_tls; if (username != NULL) { pconn->pconn_username = pstrdup(pconn_pool, username); } if (password != NULL) { pconn->pconn_password = pstrdup(pconn_pool, password); } pconn->pconn_addr = pr_netaddr_get_addr(pconn_pool, remote_host, &(pconn->pconn_addrs)); if (pconn->pconn_addr == NULL) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "unable to resolve '%s' from URI '%s'", remote_host, uri); destroy_pool(pconn_pool); errno = EINVAL; return NULL; } if (pr_netaddr_set_port2(pconn->pconn_addr, remote_port) < 0) { (void) pr_log_writefile(proxy_logfd, MOD_PROXY_VERSION, "unable to set port %d from URI '%s': %s", remote_port, uri, strerror(errno)); destroy_pool(pconn_pool); errno = EINVAL; return NULL; } return pconn; }
int pr_netio_write(pr_netio_stream_t *nstrm, char *buf, size_t buflen) { int bwritten = 0, total = 0; pr_buffer_t *pbuf; pool *sub_pool; /* Sanity check */ if (!nstrm) { errno = EINVAL; return -1; } if (nstrm->strm_fd == -1) { errno = (nstrm->strm_errno ? nstrm->strm_errno : EBADF); return -1; } /* Before we send out the data to the client, generate an event * for any listeners which may want to examine this data. To do this, we * need to allocate a pr_buffer_t for sending the buffer data to the * listeners. * * We could just use nstrm->strm_pool, but for a long-lived control * connection, this would amount to a slow memory increase. So instead, * we create a subpool from the stream's pool, and allocate the * pr_buffer_t out of that. Then simply destroy the subpool when done. */ sub_pool = pr_pool_create_sz(nstrm->strm_pool, 64); pbuf = pcalloc(sub_pool, sizeof(pr_buffer_t)); pbuf->buf = buf; pbuf->buflen = buflen; pbuf->current = pbuf->buf; pbuf->remaining = 0; switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: pr_event_generate("core.ctrl-write", pbuf); break; case PR_NETIO_STRM_DATA: pr_event_generate("core.data-write", pbuf); break; case PR_NETIO_STRM_OTHR: pr_event_generate("core.othr-write", pbuf); break; } /* The event listeners may have changed the data to write out. */ buf = pbuf->buf; buflen = pbuf->buflen - pbuf->remaining; destroy_pool(sub_pool); while (buflen) { switch (pr_netio_poll(nstrm)) { case 1: return -2; case -1: return -1; default: /* We have to potentially restart here as well, in case we get EINTR. */ do { pr_signals_handle(); run_schedule(); switch (nstrm->strm_type) { case PR_NETIO_STRM_CTRL: bwritten = ctrl_netio ? (ctrl_netio->write)(nstrm, buf, buflen) : (default_ctrl_netio->write)(nstrm, buf, buflen); break; case PR_NETIO_STRM_DATA: if (XFER_ABORTED) break; bwritten = data_netio ? (data_netio->write)(nstrm, buf, buflen) : (default_data_netio->write)(nstrm, buf, buflen); break; case PR_NETIO_STRM_OTHR: bwritten = othr_netio ? (othr_netio->write)(nstrm, buf, buflen) : (default_othr_netio->write)(nstrm, buf, buflen); break; } } while (bwritten == -1 && errno == EINTR); break; } if (bwritten == -1) { nstrm->strm_errno = errno; return -1; } buf += bwritten; total += bwritten; buflen -= bwritten; } session.total_raw_out += total; return total; }