void serr(const char *fmt, ...) { if (fmt != NULL) { va_list ap; ssize_t bufused; char buf[2048]; va_start(ap, fmt); bufused = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (bufused >= (ssize_t)sizeof(buf)) { bufused = sizeof(buf) - 1; buf[bufused] = NUL; } SASSERTX(buf[bufused] == NUL); if (errno != 0) snprintf(&buf[bufused], sizeof(buf) - bufused, ": %s", strerror(errno)); slog(LOG_ERR, "%s", buf); } #if SOCKS_CLIENT exit(EXIT_FAILURE); #else sockdexit(EXIT_FAILURE); #endif /* SOCKS_CLIENT */ }
void mother_envsetup(void) { const char *function = "mother_envsetup()"; const int exitsignalv[] = { SIGINT, SIGQUIT, SIGBUS, SIGSEGV, SIGTERM, SIGILL, SIGFPE #ifdef SIGSYS , SIGSYS #endif /* SIGSYS */ }; const size_t pipetomotherfds = 2; /* fds needed for pipe to mother. */ const size_t exitsignalc = ELEMENTS(exitsignalv); const int ignoresignalv[] = { SIGPIPE }; const size_t ignoresignalc = ELEMENTS(ignoresignalv); struct sigaction sigact; struct rlimit rlimit; #ifdef RLIMIT_NPROC struct rlimit maxproc; #endif /* RLIMIT_NPROC */ rlim_t maxopenfd, minfd_neg, minfd_req, minfd_io, minfd; size_t i, fdreserved; for (fdreserved = 0; fdreserved < ELEMENTS(sockscf.state.reservedfdv); ++fdreserved) if ((sockscf.state.reservedfdv[fdreserved] = makedummyfd(0, 0)) == -1) serr("%s: could not reserve fd #%lu for later use", function, (unsigned long)fdreserved + 1); /* * close any descriptor we don't need, both in case of chroot(2) * and for needing every descriptor we can get. */ /* assume syslog uses one */ fdreserved += sockscf.log.type & LOGTYPE_SYSLOG ? 0 : 1; /* * shmem-segments we may need to attach to temporarily in relation * to doing rulespermit() and similar for a client. */ fdreserved += 1 /* bw fd */ + 1 /* session fd */ + 1; /* monitor fd */ for (i = 0, maxopenfd = getmaxofiles(softlimit); (rlim_t)i < maxopenfd; ++i) { size_t j; if (descriptorisreserved((int)i)) { ++fdreserved; continue; } /* sockets we listen on. */ for (j = 0; j < sockscf.internal.addrc; ++j) { if ((int)i == sockscf.internal.addrv[j].s) break; } if (j < sockscf.internal.addrc) /* listening on this socket. */ continue; close((int)i); } errno = 0; newprocinit(); /* just in case the above closed a syslog(3) fd. */ /* * Check system limits against what we need. * Enough descriptors for each child process? + 2 for the pipes from * the child to mother. */ minfd_neg = (SOCKD_NEGOTIATEMAX * 1) + pipetomotherfds + fdreserved; minfd_req = (SOCKD_REQUESTMAX * FDPASS_MAX) + pipetomotherfds + fdreserved; minfd_io = (SOCKD_IOMAX * FDPASS_MAX) + pipetomotherfds + fdreserved; /* i/o process stays attached to bw and monitor shmem all the time. */ minfd_io += SOCKD_IOMAX * (1 + 1); #if BAREFOOTD minfd_io += MIN(10, MIN_UDPCLIENTS); #endif slog(LOG_DEBUG, "%s: minfd_negotiate: %lu, minfd_request: %lu, minfd_io: %lu", function, (unsigned long)minfd_neg, (unsigned long)minfd_req, (unsigned long)minfd_io); /* * need to know max number of open files so we can allocate correctly * sized fd_sets. Also, try to set both it and the max number of * processes to the hard limit. */ sockscf.state.maxopenfiles = getmaxofiles(hardlimit); slog(LOG_DEBUG, "hard limit for max number of open files is %lu, soft limit is %lu", (unsigned long)sockscf.state.maxopenfiles, (unsigned long)getmaxofiles(softlimit)); if (sockscf.state.maxopenfiles == RLIM_INFINITY) { sockscf.state.maxopenfiles = getmaxofiles(softlimit); SASSERTX(sockscf.state.maxopenfiles != RLIM_INFINITY); } minfd = MAX(minfd_neg, MAX(minfd_req, minfd_io)); if (sockscf.state.maxopenfiles < minfd) { slog(LOG_INFO, "have only %lu file descriptors available, but need at least %lu " "according to the configuration. Trying to increase it ...", (unsigned long)sockscf.state.maxopenfiles, (unsigned long)minfd); sockscf.state.maxopenfiles = minfd; } rlimit.rlim_cur = rlimit.rlim_max = sockscf.state.maxopenfiles; if (setrlimit(RLIMIT_OFILE, &rlimit) == 0) slog(LOG_DEBUG, "max number of file descriptors is now %lu", (unsigned long)sockscf.state.maxopenfiles); else { const char *problem; sockscf.state.maxopenfiles = getmaxofiles(hardlimit); if (sockscf.state.maxopenfiles < minfd_neg) problem = "SOCKD_NEGOTIATEMAX"; else if (sockscf.state.maxopenfiles < minfd_req) problem = "SOCKD_REQUESTMAX"; else if (sockscf.state.maxopenfiles < minfd_io) problem = "SOCKD_IOMAX"; else SERRX(sockscf.state.maxopenfiles); serrx("%s: failed to increase the max number of open file descriptors " "for ourselves via setrlimit(RLIMIT_OFILE) to %lu: %s. " "Increase the kernel/shell's max open files limit, or reduce " "the %s value in %s's include/config.h, or we will be unable to " "start up", function, (unsigned long)rlimit.rlim_max, strerror(errno), problem, PRODUCT); } #ifdef RLIMIT_NPROC if (getrlimit(RLIMIT_NPROC, &maxproc) != 0) swarn("getrlimit(RLIMIT_NPROC) failed"); else { maxproc.rlim_cur = maxproc.rlim_max; if (setrlimit(RLIMIT_NPROC, &maxproc) != 0) swarn("setrlimit(RLIMIT_NPROC, { %lu, %lu }) failed", (unsigned long)rlimit.rlim_cur, (unsigned long)rlimit.rlim_max); } #endif /* !RLIMIT_NPROC */ /* * set up signal handlers. */ bzero(&sigact, sizeof(sigact)); sigact.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO; sigact.sa_sigaction = siginfo; #if HAVE_SIGNAL_SIGINFO if (sigaction(SIGINFO, &sigact, NULL) != 0) serr("sigaction(SIGINFO)"); #endif /* HAVE_SIGNAL_SIGINFO */ /* * same handler, for systems without SIGINFO, as well as systems with * broken ("more secure") signal semantics. */ if (sigaction(SIGUSR1, &sigact, NULL) != 0) serr("sigaction(SIGUSR1)"); sigact.sa_sigaction = sighup; if (sigaction(SIGHUP, &sigact, NULL) != 0) serr("sigaction(SIGHUP)"); sigact.sa_sigaction = sigchld; if (sigaction(SIGCHLD, &sigact, NULL) != 0) serr("sigaction(SIGCHLD)"); sigact.sa_sigaction = sigterm; for (i = 0; (size_t)i < exitsignalc; ++i) if (sigaction(exitsignalv[i], &sigact, NULL) != 0) serr("sigaction(%d)", exitsignalv[i]); sigact.sa_handler = SIG_IGN; for (i = 0; (size_t)i < ignoresignalc; ++i) if (sigaction(ignoresignalv[i], &sigact, NULL) != 0) serr("sigaction(%d)", ignoresignalv[i]); sigact.sa_flags = SA_SIGINFO; /* want to be interrupted. */ sigact.sa_sigaction = sigalrm; if (sigaction(SIGALRM, &sigact, NULL) != 0) serr("sigaction(SIGALRM)"); if (sockscf.option.daemon) { if (daemon(1, 0) != 0) serr("daemon()"); newprocinit(); /* for daemon(). */ close(STDIN_FILENO); /* leave stdout/stderr, but close stdin. */ *sockscf.state.motherpidv = getpid(); /* we are the main mother. */ } if (HAVE_ENABLED_PIDFILE) { FILE *fp; sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_ON); if ((fp = fopen(sockscf.option.pidfile, "w")) == NULL) { swarn("open(%s)", sockscf.option.pidfile); errno = 0; } sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_OFF); if (fp != NULL) { if (fprintf(fp, "%lu\n", (unsigned long)sockscf.state.pid) == EOF) swarn("failed writing pid to pidfile %s", sockscf.option.pidfile); else sockscf.option.pidfilewritten = 1; fclose(fp); } } enable_childcreate(); freedescriptors(NULL, &sockscf.state.highestfdinuse); }