/* Sentinel values: * * cmd_type = 0 * cmd_group = NULL * cmd_class = -1 */ int pr_stash_remove_cmd(const char *cmd_name, module *m, unsigned char cmd_type, const char *cmd_group, int cmd_class) { int count = 0, prev_idx, symtab_idx = 0; size_t cmd_namelen = 0; unsigned int hash; cmdtable *tab = NULL; if (cmd_name == NULL) { errno = EINVAL; return -1; } /* Don't forget to include one for the terminating NUL. */ cmd_namelen = strlen(cmd_name) + 1; hash = sym_type_hash(PR_SYM_CMD, cmd_name, cmd_namelen); symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE; prev_idx = -1; tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, NULL, &prev_idx, &hash); while (tab) { cmdtable *cmd_sym; pr_signals_handle(); /* Note: this works because of a hack: the symbol lookup functions set a * static pointer, cmd_curr_sym, to point to the struct stash just looked * up. cmd_curr_sym will not be NULL if pr_stash_get_symbol2() returns * non-NULL. */ cmd_sym = cmd_curr_sym->ptr.sym_cmd; if ((m == NULL || cmd_curr_sym->sym_module == m) && (cmd_type == 0 || cmd_sym->cmd_type == cmd_type) && (cmd_group == NULL || (cmd_group != NULL && cmd_sym->group != NULL && strcmp(cmd_sym->group, cmd_group) == 0)) && (cmd_class == -1 || cmd_sym->cmd_class == cmd_class)) { xaset_remove(cmd_symbol_table[symtab_idx], (xasetmember_t *) cmd_curr_sym); destroy_pool(cmd_curr_sym->sym_pool); cmd_curr_sym = NULL; tab = NULL; count++; } tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, tab, &prev_idx, &hash); } return count; }
static struct group *p_getgrnam(const char *name) { struct group *gr = NULL; p_setgrent(); while ((gr = p_getgrent()) != NULL) { pr_signals_handle(); if (strcmp(name, gr->gr_name) == 0) break; } return gr; }
unsigned char command_exists(char *name) { int idx = -1; unsigned int hash = 0; cmdtable *cmdtab; cmdtab = pr_stash_get_symbol2(PR_SYM_CMD, name, NULL, &idx, &hash); while (cmdtab && cmdtab->cmd_type != CMD) { pr_signals_handle(); cmdtab = pr_stash_get_symbol2(PR_SYM_CMD, name, cmdtab, &idx, &hash); } return (cmdtab ? TRUE : FALSE); }
static struct passwd *p_getpwuid(uid_t uid) { struct passwd *pw = NULL; p_setpwent(); while ((pw = p_getpwent()) != NULL) { pr_signals_handle(); if (pw->pw_uid == uid) break; } return pw; }
static struct group *p_getgrgid(gid_t gid) { struct group *gr = NULL; p_setgrent(); while ((gr = p_getgrent()) != NULL) { pr_signals_handle(); if (gr->gr_gid == gid) break; } return gr; }
int pr_netio_lingering_abort(pr_netio_stream_t *nstrm, long linger) { int res; if (nstrm == NULL) { errno = EINVAL; return -1; } /* Send an appropriate response code down the stream asychronously. */ pr_response_send_async(R_426, _("Transfer aborted. Data connection closed.")); pr_netio_shutdown(nstrm, 1); if (nstrm->strm_fd >= 0) { fd_set rs; struct timeval tv; /* Wait for just a little while for the shutdown to take effect. */ tv.tv_sec = 0L; tv.tv_usec = 300000L; while (TRUE) { run_schedule(); FD_ZERO(&rs); FD_SET(nstrm->strm_fd, &rs); res = select(nstrm->strm_fd+1, &rs, NULL, NULL, &tv); if (res == -1) { if (errno == EINTR) { pr_signals_handle(); /* Linger some more. */ tv.tv_sec = 0L; tv.tv_usec = 300000L; continue; } else { nstrm->strm_errno = errno; return -1; } } break; } } /* Now continue with a normal lingering close. */ return netio_lingering_close(nstrm, linger, NETIO_LINGERING_CLOSE_FL_NO_SHUTDOWN); }
conn_t *pr_ipbind_accept_conn(fd_set *readfds, int *listenfd) { conn_t **listeners = listener_list->elts; register unsigned int i = 0; if (readfds == NULL || listenfd == NULL) { errno = EINVAL; return NULL; } for (i = 0; i < listener_list->nelts; i++) { conn_t *listener = listeners[i]; pr_signals_handle(); if (FD_ISSET(listener->listen_fd, readfds) && listener->mode == CM_LISTEN) { int fd = pr_inet_accept_nowait(listener->pool, listener); if (fd == -1) { int xerrno = errno; /* Handle errors gracefully. If we're here, then * ipbind->ib_server->listen contains either error information, or * we just got caught in a blocking condition. */ if (listener->mode == CM_ERROR) { /* Ignore ECONNABORTED, as they tend to be health checks/probes by * e.g. load balancers and other naive TCP clients. */ if (listener->xerrno != ECONNABORTED) { pr_log_pri(PR_LOG_ERR, "error: unable to accept an incoming " "connection: %s", strerror(listener->xerrno)); } listener->xerrno = 0; listener->mode = CM_LISTEN; errno = xerrno; return NULL; } } *listenfd = fd; return listener; } } errno = ENOENT; return NULL; }
/* Very similar to the {block,unblock}_signals() function, this masks most * of the same signals -- except for TERM. This allows a throttling process * to be killed by the admin. */ static void xfer_rate_sigmask(int block) { static sigset_t sig_set; if (block) { sigemptyset(&sig_set); sigaddset(&sig_set, SIGCHLD); sigaddset(&sig_set, SIGUSR1); sigaddset(&sig_set, SIGINT); sigaddset(&sig_set, SIGQUIT); #ifdef SIGIO sigaddset(&sig_set, SIGIO); #endif /* SIGIO */ #ifdef SIGBUS sigaddset(&sig_set, SIGBUS); #endif /* SIGBUS */ sigaddset(&sig_set, SIGHUP); while (sigprocmask(SIG_BLOCK, &sig_set, NULL) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } break; } } else { while (sigprocmask(SIG_UNBLOCK, &sig_set, NULL) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } break; } } }
static int read_scoreboard_header(pr_scoreboard_header_t *sch) { int res = 0; /* No interruptions, please. */ pr_signals_block(); /* NOTE: reading a struct from a file using read(2) -- bad (in general). */ while ((res = read(scoreboard_fd, sch, sizeof(pr_scoreboard_header_t))) != sizeof(pr_scoreboard_header_t)) { int rd_errno = errno; if (res == 0) { pr_signals_unblock(); errno = EIO; return -1; } if (errno == EINTR) { pr_signals_handle(); continue; } pr_signals_unblock(); errno = rd_errno; return -1; } pr_signals_unblock(); /* Note: these errors will most likely occur only for inetd-run daemons. * Standalone daemons erase the scoreboard on startup. */ if (sch->sch_magic != PR_SCOREBOARD_MAGIC) { pr_close_scoreboard(); return PR_SCORE_ERR_BAD_MAGIC; } if (sch->sch_version < PR_SCOREBOARD_VERSION) { pr_close_scoreboard(); return PR_SCORE_ERR_OLDER_VERSION; } if (sch->sch_version > PR_SCOREBOARD_VERSION) { pr_close_scoreboard(); return PR_SCORE_ERR_NEWER_VERSION; } return 0; }
static struct passwd *p_getpwnam(const char *name) { struct passwd *pw = NULL; p_setpwent(); while ((pw = p_getpwent()) != NULL) { pr_signals_handle(); if (strcmp(name, pw->pw_name) == 0) { break; } } return pw; }
static int utf8_convert(iconv_t conv, const char *inbuf, size_t *inbuflen, char *outbuf, size_t *outbuflen) { # ifdef HAVE_ICONV /* Reset the state machine before each conversion. */ (void) iconv(conv, NULL, NULL, NULL, NULL); while (*inbuflen > 0) { size_t nconv; pr_signals_handle(); /* Solaris/FreeBSD's iconv(3) takes a const char ** for the input buffer, * whereas Linux/Mac OSX iconv(3) use char ** for the input buffer. */ #if defined(LINUX) || defined(DARWIN6) || defined(DARWIN7) || \ defined(DARWIN8) || defined(DARWIN9) || defined(DARWIN10) || \ defined(DARWIN11) nconv = iconv(conv, (char **) &inbuf, inbuflen, &outbuf, outbuflen); #else nconv = iconv(conv, &inbuf, inbuflen, &outbuf, outbuflen); #endif if (nconv == (size_t) -1) { /* Note: an errno of EILSEQ here can indicate badly encoded strings OR * (more likely) that the source character set used in the iconv_open(3) * call for this iconv_t descriptor does not accurately describe the * character encoding of the given string. E.g. a filename may use * the ISO8859-1 character set, but iconv_open(3) was called using * US-ASCII. */ return -1; } /* XXX We should let the loop condition work, rather than breaking out * of the loop here. */ break; } return 0; # else errno = ENOSYS; return -1; # endif /* HAVE_ICONV */ }
int pr_ipbind_add_binds(server_rec *serv) { int res = 0; config_rec *c = NULL; conn_t *listen_conn = NULL; const pr_netaddr_t *addr = NULL; if (serv == NULL) { errno = EINVAL; return -1; } c = find_config(serv->conf, CONF_PARAM, "_bind_", FALSE); while (c != NULL) { listen_conn = NULL; pr_signals_handle(); addr = pr_netaddr_get_addr(serv->pool, c->argv[0], NULL); if (addr == NULL) { pr_log_pri(PR_LOG_WARNING, "notice: unable to determine IP address of '%s'", (char *) c->argv[0]); c = find_config_next(c, c->next, CONF_PARAM, "_bind_", FALSE); continue; } /* If the SocketBindTight directive is in effect, create a separate * listen socket for this address, and add it to the binding list. */ if (SocketBindTight && serv->ServerPort) { listen_conn = pr_ipbind_get_listening_conn(serv, addr, serv->ServerPort); if (listen_conn == NULL) { return -1; } PR_CREATE_IPBIND(serv, addr, serv->ServerPort); PR_OPEN_IPBIND(addr, serv->ServerPort, listen_conn, FALSE, FALSE, TRUE); } else { PR_CREATE_IPBIND(serv, addr, serv->ServerPort); PR_OPEN_IPBIND(addr, serv->ServerPort, serv->listen, FALSE, FALSE, TRUE); } c = find_config_next(c, c->next, CONF_PARAM, "_bind_", FALSE); } return 0; }
int snmp_mib_get_idx(oid_t *mib_oid, unsigned int mib_oidlen, int *lacks_instance_id) { register unsigned int i; int mib_idx = -1; if (lacks_instance_id != NULL) { *lacks_instance_id = FALSE; } for (i = 1; snmp_mibs[i].mib_oidlen != 0; i++) { pr_signals_handle(); /* Skip any disabled MIBs. */ if (snmp_mibs[i].mib_enabled == FALSE) { continue; } if (snmp_mibs[i].mib_oidlen == mib_oidlen) { if (memcmp(snmp_mibs[i].mib_oid, mib_oid, mib_oidlen * sizeof(oid_t)) == 0) { mib_idx = i; break; } } /* Check for the case where the given OID might be missing the final * ".0" instance identifier. This is done to support the slightly * more user-friendly NO_SUCH_INSTANCE exception for SNMPv2/SNMPv3 * responses. */ if (lacks_instance_id != NULL) { if (snmp_mibs[i].mib_oidlen == (mib_oidlen + 1)) { if (memcmp(snmp_mibs[i].mib_oid, mib_oid, mib_oidlen * sizeof(oid_t)) == 0) { *lacks_instance_id = TRUE; break; } } } } if (mib_idx < 0) { errno = ENOENT; } return mib_idx; }
int pr_auth_banned_by_ftpusers(xaset_t *ctx, const char *user) { int res = FALSE; unsigned char *use_ftp_users; use_ftp_users = get_param_ptr(ctx, "UseFtpUsers", FALSE); if (use_ftp_users == NULL || *use_ftp_users == TRUE) { FILE *fh = NULL; char buf[256]; PRIVS_ROOT fh = fopen(PR_FTPUSERS_PATH, "r"); PRIVS_RELINQUISH if (fh == NULL) return res; memset(buf, '\0', sizeof(buf)); while (fgets(buf, sizeof(buf)-1, fh)) { char *ptr; pr_signals_handle(); buf[sizeof(buf)-1] = '\0'; CHOP(buf); ptr = buf; while (isspace((int) *ptr) && *ptr) { ptr++; } if (!*ptr || *ptr == '#') { continue; } if (strcmp(ptr, user) == 0 ) { res = TRUE; break; } memset(buf, '\0', sizeof(buf)); } fclose(fh); }
static int wlock_entry(void) { entry_lock.l_type = F_WRLCK; entry_lock.l_whence = SEEK_CUR; entry_lock.l_len = sizeof(pr_scoreboard_entry_t); while (fcntl(scoreboard_fd, F_SETLKW, &entry_lock) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } else return -1; } return 0; }
int pr_stash_remove_conf(const char *directive_name, module *m) { int count = 0, prev_idx, symtab_idx = 0; size_t directive_namelen = 0; unsigned int hash; conftable *tab = NULL; if (directive_name == NULL) { errno = EINVAL; return -1; } /* Don't forget to include one for the terminating NUL. */ directive_namelen = strlen(directive_name) + 1; hash = sym_type_hash(PR_SYM_CONF, directive_name, directive_namelen); symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE; prev_idx = -1; tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, NULL, &prev_idx, &hash); while (tab) { pr_signals_handle(); /* Note: this works because of a hack: the symbol lookup functions set a * static pointer, conf_curr_sym, to point to the struct stash just looked * up. conf_curr_sym will not be NULL if pr_stash_get_symbol2() returns * non-NULL. */ if (m == NULL || conf_curr_sym->sym_module == m) { xaset_remove(conf_symbol_table[symtab_idx], (xasetmember_t *) conf_curr_sym); destroy_pool(conf_curr_sym->sym_pool); conf_curr_sym = NULL; tab = NULL; count++; } tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, tab, &prev_idx, &hash); } return count; }
static struct passwd *af_getpwuid(uid_t uid) { struct passwd *pwd = NULL; if (af_setpwent() < 0) { return NULL; } while ((pwd = af_getpwent()) != NULL) { pr_signals_handle(); if (pwd->pw_uid == uid) { /* Found the requested UID */ break; } } return pwd; }
static struct passwd *af_getpwnam(const char *name) { struct passwd *pwd = NULL; if (af_setpwent() < 0) { return NULL; } while ((pwd = af_getpwent()) != NULL) { pr_signals_handle(); if (strcmp(name, pwd->pw_name) == 0) { /* Found the requested user */ break; } } return pwd; }
static struct group *af_getgrgid(gid_t gid) { struct group *grp = NULL; if (af_setgrent() < 0) { return NULL; } while ((grp = af_getgrent()) != NULL) { pr_signals_handle(); if (grp->gr_gid == gid) { /* Found the requested GID */ break; } } return grp; }
static struct group *af_getgrnam(const char *name) { struct group *grp = NULL; if (af_setgrent() < 0) { return NULL; } while ((grp = af_getgrent()) != NULL) { pr_signals_handle(); if (strcmp(name, grp->gr_name) == 0) { /* Found the requested group */ break; } } return grp; }
static char *get_meta_arg(pool *p, unsigned char *m, size_t *arglen) { char buf[PR_TUNABLE_PATH_MAX+1], *ptr; size_t len; ptr = buf; len = 0; while (*m != LOGFMT_META_ARG_END) { pr_signals_handle(); *ptr++ = (char) *m++; len++; } *ptr = '\0'; *arglen = len; return pstrdup(p, buf); }
/* Use a hash function to hash the given lookup key to a slot in the * sd_entries list. This hash, module the number of entries, is the initial * iteration start point. This will hopefully avoid having to do many linear * scans for the add/get/delete operations. * * Use Perl's hashing algorithm. */ static unsigned int shmcache_hash(unsigned char *sess_id, unsigned int sess_id_len) { unsigned int i = 0; size_t sz = sess_id_len; while (sz--) { const unsigned char *k = sess_id; unsigned int c = *k; k++; /* Always handle signals in potentially long-running while loops. */ pr_signals_handle(); i = (i * 33) + c; } return i; }
/* Use Perl's hashing algorithm by default. * * Here's a good article about this hashing algorithm, and about hashing * functions in general: * * http://www.perl.com/pub/2002/10/01/hashes.html */ static unsigned int key_hash(const void *key, size_t keysz) { unsigned int i = 0; size_t sz = !keysz ? strlen((const char *) key) : keysz; while (sz--) { const char *k = key; unsigned int c; c = k[sz]; /* Always handle signals in potentially long-running while loops. */ pr_signals_handle(); i = (i * 33) + c; } return i; }
static int core_netio_poll_cb(pr_netio_stream_t *nstrm) { int res; fd_set rfds, *rfdsp, wfds, *wfdsp; struct timeval tval; FD_ZERO(&rfds); rfdsp = NULL; FD_ZERO(&wfds); wfdsp = NULL; if (nstrm->strm_mode == PR_NETIO_IO_RD) { if (nstrm->strm_fd >= 0) { FD_SET(nstrm->strm_fd, &rfds); rfdsp = &rfds; } } else { if (nstrm->strm_fd >= 0) { FD_SET(nstrm->strm_fd, &wfds); wfdsp = &wfds; } } tval.tv_sec = ((nstrm->strm_flags & PR_NETIO_SESS_INTR) ? nstrm->strm_interval: 60); tval.tv_usec = 0; res = select(nstrm->strm_fd + 1, rfdsp, wfdsp, NULL, &tval); while (res < 0) { int xerrno = errno; /* Watch for EAGAIN, and handle it by delaying temporarily. */ if (xerrno == EAGAIN) { errno = EINTR; pr_signals_handle(); continue; } errno = nstrm->strm_errno = xerrno; break; } return res; }
pr_scoreboard_entry_t *pr_scoreboard_read_entry(void) { static pr_scoreboard_entry_t scan_entry; int res = 0; if (scoreboard_fd < 0) { errno = EINVAL; return NULL; } /* Make sure the scoreboard file is read-locked. */ if (!scoreboard_read_locked) { /* Do not proceed if we cannot lock the scoreboard. */ if (rlock_scoreboard() < 0) return NULL; } memset(&scan_entry, '\0', sizeof(scan_entry)); /* NOTE: use readv(2)? */ while (TRUE) { while ((res = read(scoreboard_fd, &scan_entry, sizeof(scan_entry))) <= 0) { if (res < 0 && errno == EINTR) { pr_signals_handle(); continue; } else { unlock_scoreboard(); return NULL; } } if (scan_entry.sce_pid) { unlock_scoreboard(); return &scan_entry; } else continue; } unlock_scoreboard(); return NULL; }
MODRET authfile_getgrnam(cmd_rec *cmd) { struct group *grp = NULL; const char *name = cmd->argv[0]; if (af_setgrent() < 0) { return PR_DECLINED(cmd); } while ((grp = af_getgrent()) != NULL) { pr_signals_handle(); if (strcmp(name, grp->gr_name) == 0) { /* Found the name requested */ break; } } return grp ? mod_create_data(cmd, grp) : PR_DECLINED(cmd); }
void run_schedule(void) { sched_t *s, *snext; if (scheds == NULL || scheds->xas_list == NULL) { return; } for (s = (sched_t *) scheds->xas_list; s; s = snext) { snext = s->next; pr_signals_handle(); if (s->nloops-- <= 0) { s->cb(s->arg1, s->arg2, s->arg3, s->arg4); xaset_remove(scheds, (xasetmember_t *) s); destroy_pool(s->pool); } } }
char *pr_str_strip_end(char *s, char *ch) { size_t len; if (s == NULL || ch == NULL) { errno = EINVAL; return NULL; } len = strlen(s); while (len && strchr(ch, *(s+len - 1))) { pr_signals_handle(); *(s+len - 1) = '\0'; len--; } return s; }
static int wlock_scoreboard(void) { struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = 0; lock.l_start = 0; lock.l_len = 0; while (fcntl(scoreboard_fd, F_SETLKW, &lock) < 0) { if (errno == EINTR) { pr_signals_handle(); continue; } else return -1; } scoreboard_write_locked = TRUE; return 0; }
MODRET authfile_getpwnam(cmd_rec *cmd) { struct passwd *pwd = NULL; const char *name = cmd->argv[0]; if (af_setpwent() < 0) { return PR_DECLINED(cmd); } /* Ugly -- we iterate through the file. Time-consuming. */ while ((pwd = af_getpwent()) != NULL) { pr_signals_handle(); if (strcmp(name, pwd->pw_name) == 0) { /* Found the requested name */ break; } } return pwd ? mod_create_data(cmd, pwd) : PR_DECLINED(cmd); }