Пример #1
0
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 */
}
Пример #2
0
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);
}