static struct mypasswd *mypwenter(const struct passwd * pwd) { struct mypasswd *mypwd; /* * Initialize on the fly. */ if (mypwcache_name == 0) { mypwcache_name = htable_create(0); mypwcache_uid = binhash_create(0); } mypwd = (struct mypasswd *) mymalloc(sizeof(*mypwd)); mypwd->refcount = 0; mypwd->pw_name = mystrdup(pwd->pw_name); mypwd->pw_passwd = mystrdup(pwd->pw_passwd); mypwd->pw_uid = pwd->pw_uid; mypwd->pw_gid = pwd->pw_gid; mypwd->pw_gecos = mystrdup(pwd->pw_gecos); mypwd->pw_dir = mystrdup(pwd->pw_dir); mypwd->pw_shell = mystrdup(*pwd->pw_shell ? pwd->pw_shell : _PATH_BSHELL); /* * Avoid mypwcache_uid memory leak when multiple names have the same UID. * This makes the lookup result dependent on program history. But, it was * already history-dependent before we added this extra check. */ htable_enter(mypwcache_name, mypwd->pw_name, (char *) mypwd); if (binhash_locate(mypwcache_uid, (char *) &mypwd->pw_uid, sizeof(mypwd->pw_uid)) == 0) binhash_enter(mypwcache_uid, (char *) &mypwd->pw_uid, sizeof(mypwd->pw_uid), (char *) mypwd); return (mypwd); }
/* * Locate or allocate connection cache entry. */ static void dict_ldap_conn_find(DICT_LDAP *dict_ldap) { VSTRING *keybuf = vstring_alloc(10); char *key; int len; #ifdef LDAP_API_FEATURE_X_OPENLDAP int sslon = dict_ldap->start_tls || dict_ldap->ldap_ssl; #endif LDAP_CONN *conn; #define ADDSTR(vp, s) vstring_memcat((vp), (s), strlen((s))+1) #define ADDINT(vp, i) vstring_sprintf_append((vp), "%lu", (unsigned long)(i)) ADDSTR(keybuf, dict_ldap->server_host); ADDINT(keybuf, dict_ldap->server_port); ADDINT(keybuf, dict_ldap->bind); ADDSTR(keybuf, dict_ldap->bind ? dict_ldap->bind_dn : ""); ADDSTR(keybuf, dict_ldap->bind ? dict_ldap->bind_pw : ""); ADDINT(keybuf, dict_ldap->dereference); ADDINT(keybuf, dict_ldap->chase_referrals); ADDINT(keybuf, dict_ldap->debuglevel); ADDINT(keybuf, dict_ldap->version); #ifdef LDAP_API_FEATURE_X_OPENLDAP ADDINT(keybuf, dict_ldap->ldap_ssl); ADDINT(keybuf, dict_ldap->start_tls); ADDINT(keybuf, sslon ? dict_ldap->tls_require_cert : 0); ADDSTR(keybuf, sslon ? dict_ldap->tls_ca_cert_file : ""); ADDSTR(keybuf, sslon ? dict_ldap->tls_ca_cert_dir : ""); ADDSTR(keybuf, sslon ? dict_ldap->tls_cert : ""); ADDSTR(keybuf, sslon ? dict_ldap->tls_key : ""); ADDSTR(keybuf, sslon ? dict_ldap->tls_random_file : ""); ADDSTR(keybuf, sslon ? dict_ldap->tls_cipher_suite : ""); #endif key = vstring_str(keybuf); len = VSTRING_LEN(keybuf); if (conn_hash == 0) conn_hash = binhash_create(0); if ((dict_ldap->ht = binhash_locate(conn_hash, key, len)) == 0) { conn = (LDAP_CONN *) mymalloc(sizeof(LDAP_CONN)); conn->conn_ld = 0; conn->conn_refcount = 0; dict_ldap->ht = binhash_enter(conn_hash, key, len, (char *) conn); } ++DICT_LDAP_CONN(dict_ldap)->conn_refcount; vstring_free(keybuf); }
void master_spawn(MASTER_SERV *serv) { const char *myname = "master_spawn"; MASTER_PROC *proc; MASTER_PID pid; int n; static unsigned master_generation = 0; static VSTRING *env_gen = 0; if (master_child_table == 0) master_child_table = binhash_create(0); if (env_gen == 0) env_gen = vstring_alloc(100); /* * Sanity checks. The master_avail module is supposed to know what it is * doing. */ if (!MASTER_LIMIT_OK(serv->max_proc, serv->total_proc)) msg_panic("%s: at process limit %d", myname, serv->total_proc); if (serv->avail_proc > 0) msg_panic("%s: processes available: %d", myname, serv->avail_proc); if (serv->flags & MASTER_FLAG_THROTTLE) msg_panic("%s: throttled service: %s", myname, serv->path); /* * Create a child process and connect parent and child via the status * pipe. */ master_generation += 1; switch (pid = fork()) { /* * Error. We're out of some essential resource. Best recourse is to * try again later. */ case -1: msg_warn("%s: fork: %m -- throttling", myname); master_throttle(serv); return; /* * Child process. Redirect child stdin/stdout to the parent-child * connection and run the requested command. Leave child stderr * alone. Disable exit handlers: they should be executed by the * parent only. * * When we reach the process limit on a public internet service, we * create stress-mode processes until the process count stays below * the limit for some amount of time. See master_avail_listen(). */ case 0: msg_cleanup((void (*) (void)) 0); /* disable exit handler */ closelog(); /* avoid filedes leak */ if (master_flow_pipe[0] <= MASTER_FLOW_READ) msg_fatal("%s: flow pipe read descriptor <= %d", myname, MASTER_FLOW_READ); if (DUP2(master_flow_pipe[0], MASTER_FLOW_READ) < 0) msg_fatal("%s: dup2: %m", myname); if (close(master_flow_pipe[0]) < 0) msg_fatal("close %d: %m", master_flow_pipe[0]); if (master_flow_pipe[1] <= MASTER_FLOW_WRITE) msg_fatal("%s: flow pipe read descriptor <= %d", myname, MASTER_FLOW_WRITE); if (DUP2(master_flow_pipe[1], MASTER_FLOW_WRITE) < 0) msg_fatal("%s: dup2: %m", myname); if (close(master_flow_pipe[1]) < 0) msg_fatal("close %d: %m", master_flow_pipe[1]); close(serv->status_fd[0]); /* status channel */ if (serv->status_fd[1] <= MASTER_STATUS_FD) msg_fatal("%s: status file descriptor collision", myname); if (DUP2(serv->status_fd[1], MASTER_STATUS_FD) < 0) msg_fatal("%s: dup2 status_fd: %m", myname); (void) close(serv->status_fd[1]); for (n = 0; n < serv->listen_fd_count; n++) { if (serv->listen_fd[n] <= MASTER_LISTEN_FD + n) msg_fatal("%s: listen file descriptor collision", myname); if (DUP2(serv->listen_fd[n], MASTER_LISTEN_FD + n) < 0) msg_fatal("%s: dup2 listen_fd %d: %m", myname, serv->listen_fd[n]); (void) close(serv->listen_fd[n]); } vstring_sprintf(env_gen, "%s=%o", MASTER_GEN_NAME, master_generation); if (putenv(vstring_str(env_gen)) < 0) msg_fatal("%s: putenv: %m", myname); if (serv->stress_param_val && serv->stress_expire_time > event_time()) serv->stress_param_val[0] = CONFIG_BOOL_YES[0]; execvp(serv->path, serv->args->argv); msg_fatal("%s: exec %s: %m", myname, serv->path); /* NOTREACHED */ /* * Parent. Fill in a process member data structure and set up links * between child and process. Say this process has become available. * If this service has a wakeup timer that is turned on only when the * service is actually used, turn on the wakeup timer. */ default: if (msg_verbose) msg_info("spawn command %s; pid %d", serv->path, pid); proc = (MASTER_PROC *) mymalloc(sizeof(MASTER_PROC)); proc->serv = serv; proc->pid = pid; proc->gen = master_generation; proc->use_count = 0; proc->avail = 0; binhash_enter(master_child_table, (void *) &pid, sizeof(pid), (void *) proc); serv->total_proc++; master_avail_more(serv, proc); if (serv->flags & MASTER_FLAG_CONDWAKE) { serv->flags &= ~MASTER_FLAG_CONDWAKE; master_wakeup_init(serv); if (msg_verbose) msg_info("start conditional timer for %s", serv->name); } return; } }