1 /*
2  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2008,
3  *               2009, 2010, 2011, 2012, 2013, 2014, 2019
4  *      Inferno Nettverk A/S, Norway.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. The above copyright notice, this list of conditions and the following
10  *    disclaimer must appear in all copies of the software, derivative works
11  *    or modified versions, and any portions thereof, aswell as in all
12  *    supporting documentation.
13  * 2. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by
16  *      Inferno Nettverk A/S, Norway.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Inferno Nettverk A/S requests users of this software to return to
32  *
33  *  Software Distribution Coordinator  or  sdc@inet.no
34  *  Inferno Nettverk A/S
35  *  Oslo Research Park
36  *  Gaustadall�en 21
37  *  NO-0349 Oslo
38  *  Norway
39  *
40  * any improvements or extensions that they make and grant Inferno Nettverk A/S
41  * the rights to redistribute these changes.
42  *
43  */
44 
45 static const char rcsid[] =
46 "$Id: sockd_util.c,v 1.263.4.3.6.2 2020/11/11 16:12:03 karls Exp $";
47 
48 #include "common.h"
49 
50 int
selectmethod(methodv,methodc,offeredv,offeredc)51 selectmethod(methodv, methodc, offeredv, offeredc)
52    const int *methodv;
53    const size_t methodc;
54    const unsigned char *offeredv;
55    const size_t offeredc;
56 {
57    const unsigned char *methodokv;
58    size_t i, methodokc;
59    int intmethodv[MAXMETHODS];
60 
61    if (offeredc == 0)
62       return AUTHMETHOD_NOACCEPT;
63 
64    charmethod2intmethod(offeredc, offeredv, intmethodv);
65 
66    for (i = 0; i < methodc; ++i) {
67       if (methodv[i] > AUTHMETHOD_NOACCEPT) {
68          /*
69           * non-socks method.  Can select any of the standard methods
70           * that can provide the necessary information.
71           */
72          const unsigned char rfc931methodv[] = { AUTHMETHOD_NONE,
73                                                  AUTHMETHOD_UNAME,
74 #if HAVE_GSSAPI
75                                                  AUTHMETHOD_GSSAPI
76 #endif /* HAVE_GSSAPI */
77                                                };
78 
79          const unsigned char pam_any_methodv[] = {   AUTHMETHOD_UNAME,
80                                                      AUTHMETHOD_NONE,
81 #if HAVE_GSSAPI
82                                                      AUTHMETHOD_GSSAPI,
83 #endif /* HAVE_GSSAPI */
84                                             };
85 
86          const unsigned char pam_address_methodv[] = {   AUTHMETHOD_UNAME,
87                                                          AUTHMETHOD_NONE,
88 #if HAVE_GSSAPI
89                                                          AUTHMETHOD_GSSAPI,
90 #endif /* HAVE_GSSAPI */
91                                             };
92 
93          const unsigned char pam_password_methodv[] = {   AUTHMETHOD_UNAME };
94 
95          const unsigned char bsdmethodv[] = {    AUTHMETHOD_UNAME,
96 #if HAVE_GSSAPI
97                                                  AUTHMETHOD_GSSAPI,
98 #endif /* HAVE_GSSAPI */
99                                             };
100 
101 #if HAVE_LDAP
102          const unsigned char ldapmethodv[] = {    AUTHMETHOD_UNAME,
103 #if HAVE_GSSAPI
104                                                  AUTHMETHOD_GSSAPI,
105 #endif /* HAVE_GSSAPI */
106                                             };
107 #endif /* HAVE_LDAP */
108 
109          size_t ii;
110 
111          /* find the correct array to use for selecting the method. */
112          switch (methodv[i]) {
113             case AUTHMETHOD_RFC931:
114                methodokc = ELEMENTS(rfc931methodv);
115                methodokv = rfc931methodv;
116                break;
117 
118             case AUTHMETHOD_PAM_ANY:
119                methodokc = ELEMENTS(pam_any_methodv);
120                methodokv = pam_any_methodv;
121                break;
122 
123             case AUTHMETHOD_PAM_ADDRESS:
124                methodokc = ELEMENTS(pam_address_methodv);
125                methodokv = pam_address_methodv;
126                break;
127 
128             case AUTHMETHOD_PAM_USERNAME:
129                methodokc = ELEMENTS(pam_password_methodv);
130                methodokv = pam_password_methodv;
131                break;
132 
133             case AUTHMETHOD_BSDAUTH:
134                methodokc = ELEMENTS(bsdmethodv);
135                methodokv = bsdmethodv;
136                break;
137 
138 #if HAVE_LDAP
139             case AUTHMETHOD_LDAPAUTH:
140                methodokc = ELEMENTS(ldapmethodv);
141                methodokv = ldapmethodv;
142                break;
143 #endif /* HAVE_LDAP */
144 
145             default:
146                SERRX(methodv[i]);
147          }
148 
149          for (ii = 0; ii < methodokc; ++ii)
150             if (methodisset(methodokv[ii], intmethodv, offeredc))
151                return methodokv[ii];
152 
153          continue;
154       }
155 
156       if (memchr(offeredv, (unsigned char)methodv[i], offeredc) != NULL)
157          return methodv[i];
158    }
159 
160    return AUTHMETHOD_NOACCEPT;
161 }
162 
163 int
pidismother(pid)164 pidismother(pid)
165    pid_t pid;
166 {
167    size_t i;
168 
169    if (sockscf.state.motherpidv == NULL)
170       return 1; /* so early we haven't forked yet. */
171 
172    for (i = 0; i < sockscf.option.serverc; ++i)
173       if (sockscf.state.motherpidv[i] == pid)
174          return i + 1;
175 
176    return 0;
177 }
178 
179 int
pidismainmother(pid)180 pidismainmother(pid)
181    pid_t pid;
182 {
183 
184    return pidismother(pid) == 1;
185 }
186 
187 int
descriptorisreserved(d)188 descriptorisreserved(d)
189    int d;
190 {
191    size_t i;
192 
193    if (d == sockscf.hostfd
194    ||  d == sockscf.shmemfd
195    ||  d == sockscf.loglock
196 
197 #if HAVE_LDAP
198    ||  d == sockscf.ldapfd
199 #endif /* HAVE_LDAP */
200 
201    ||  d == sockscf.shmemconfigfd
202    || FD_IS_RESERVED_EXTERNAL(d))
203       return 1;
204 
205    /* don't close log files. */
206    if (socks_logmatch(d, &sockscf.log)
207    ||  socks_logmatch(d, &sockscf.errlog))
208       return 1;
209 
210    for (i = 0; i < ELEMENTS(sockscf.state.reservedfdv); ++i)
211       if (d == sockscf.state.reservedfdv[i])
212          return 1;
213 
214    return 0;
215 }
216 
217 void
sigserverbroadcast(sig)218 sigserverbroadcast(sig)
219    int sig;
220 {
221    const char *function = "sigserverbroadcast()";
222    size_t i;
223 
224    if (sockscf.state.motherpidv == NULL)
225       return; /* so early we haven't forked yet. */
226 
227    for (i = 1; i < sockscf.option.serverc; ++i)
228       if (sockscf.state.motherpidv[i] != 0) {
229          slog(LOG_DEBUG, "%s: sending signal %d to mother %lu",
230               function, sig, (unsigned long)(sockscf.state.motherpidv[i]));
231 
232          if (kill(sockscf.state.motherpidv[i], sig) != 0)
233             swarn("%s: could not send signal %d to mother process %lu",
234                   function,
235                   sig,
236                   (unsigned long)sockscf.state.motherpidv[i]);
237    }
238 }
239 
240 void
sockd_pushsignal(sig,siginfo)241 sockd_pushsignal(sig, siginfo)
242    const int sig;
243    const siginfo_t *siginfo;
244 {
245    const char *function = "sockd_pushsignal()";
246    sigset_t all, oldmask;
247    size_t i, alreadythere;
248 
249    SASSERTX(sig > 0);
250 
251    (void)sigfillset(&all);
252    if (sigprocmask(SIG_SETMASK, &all, &oldmask) != 0) {
253       const char *msgv[]
254       = { function,
255           ": sigprocmask(SIG_SETMASK) failed with errno ",
256           ltoa(errno, NULL, 0),
257           NULL
258         };
259 
260       signalslog(LOG_WARNING, msgv);
261    }
262 
263    /* go through currently pending signals.  If already there, don't add. */
264    for (i = alreadythere = 0; i < (size_t)sockscf.state.signalc; ++i)
265       if (sockscf.state.signalv[i].signal == sig) {
266          alreadythere = 1;
267          break;
268       }
269 
270    if (!alreadythere) {
271       if (i < ELEMENTS(sockscf.state.signalv)) {
272          sockscf.state.signalv[sockscf.state.signalc].signal = sig;
273 
274          if (siginfo != NULL)
275             sockscf.state.signalv[sockscf.state.signalc].siginfo = *siginfo;
276          else /* Solaris ...  */
277             bzero(&sockscf.state.signalv[sockscf.state.signalc].siginfo,
278                   sizeof(sockscf.state.signalv[sockscf.state.signalc].siginfo));
279 
280          ++sockscf.state.signalc;
281 
282          if (1) {
283             char sigbuf[32], pidbuf[32], numbuf[32];
284             const char *msgv[]
285             = { function,
286                 ": pushed signal ",
287                 ltoa(sig, sigbuf, sizeof(sigbuf)),
288                 " from pid ",
289                 ltoa(sockscf.state.signalv[sockscf.state.signalc - 1]
290                      .siginfo.si_pid,
291                      pidbuf,
292                      sizeof(pidbuf)),
293                 ".  Number of signals on the stack is now ",
294                 ltoa(sockscf.state.signalc, numbuf, sizeof(numbuf)),
295                 NULL
296               };
297 
298             signalslog(LOG_DEBUG, msgv);
299          }
300       }
301       else
302          SWARNX(i);
303    }
304 
305    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0) {
306       const char *msgv[]
307       = { function,
308           ": sigprocmask(SIG_SETMASK) restoration failed with errno ",
309           ltoa(errno, NULL, 0),
310           NULL
311         };
312 
313       signalslog(LOG_WARNING, msgv);
314    }
315 }
316 
317 int
sockd_popsignal(siginfo_t * siginfo)318 sockd_popsignal(siginfo_t *siginfo)
319 {
320    const char *function = "sockd_popsignal()";
321    sigset_t all, oldmask;
322    int sig;
323 
324    (void)sigfillset(&all);
325    if (sigprocmask(SIG_SETMASK, &all, &oldmask) != 0)
326       swarn("%s: sigprocmask(SIG_SETMASK)", function);
327 
328    SASSERTX(sockscf.state.signalc > 0);
329 
330    sig      = sockscf.state.signalv[0].signal;
331    *siginfo = sockscf.state.signalv[0].siginfo;
332 
333    memmove(sockscf.state.signalv,
334            &sockscf.state.signalv[1],
335            sizeof(*sockscf.state.signalv) * (--sockscf.state.signalc));
336 
337    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
338       swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
339 
340    return sig;
341 }
342 
343 int
sockd_handledsignals()344 sockd_handledsignals()
345 {
346    const char *function = "sockd_handledsignals()";
347    const int errno_s = errno;
348    struct sigaction oact;
349    int i, rc = 0;
350 
351    if (sockscf.state.signalc == 0)
352       return 0;
353 
354    if (sockscf.option.debug >= DEBUG_VERBOSE)
355       for (i = 0, rc = 0; i < sockscf.state.signalc; ++i)
356          slog(LOG_DEBUG, "%s: signal #%d on the stack is signal %d",
357               function, i + 1, (int)sockscf.state.signalv[i].signal);
358 
359    while (sockscf.state.signalc) {
360       siginfo_t siginfo;
361       const int signal = sockd_popsignal(&siginfo);
362 
363       slog(LOG_DEBUG,
364             "%s: signals left on the stack after popping signal %d: %d",
365             function, signal, sockscf.state.signalc);
366 
367       if (sigaction(signal, NULL, &oact) != 0)
368          SERR(0);
369 
370 
371       if (oact.sa_handler != SIG_IGN && oact.sa_handler != SIG_DFL) {
372          oact.sa_sigaction(-signal, &siginfo, NULL);
373          ++rc;
374       }
375       else
376          /*
377           * can happen when a child temporarily changes the
378           * signal disposition while starting up.
379           */
380          slog(LOG_DEBUG, "%s: no handler for signal %d at the moment",
381               function, signal);
382    }
383 
384    errno = errno_s;
385    return rc;
386 }
387 
388 int
freedescriptors(message,hfd)389 freedescriptors(message, hfd)
390    const char *message;
391    int *hfd;
392 {
393    const int errno_s = errno;
394    int i, freefds, tmp_hfd, max;
395 
396    if (sockscf.state.highestfdinuse != 0 && hfd == NULL)
397       /* not asked to recalculate, so assume previous result is still valid. */
398       max = sockscf.state.highestfdinuse;
399   else
400       max = sockscf.state.maxopenfiles;
401 
402    if (hfd == NULL) {
403       tmp_hfd = 0;
404       hfd     = &tmp_hfd;
405    }
406 
407    for (i = freefds = 0; i < max; ++i)
408       if (fdisopen((int)i))
409          *hfd = MAX(i, *hfd);
410       else
411          ++freefds;
412 
413    freefds += (sockscf.state.maxopenfiles - max);
414 
415    if (message != NULL)
416       slog(LOG_DEBUG, "freedescriptors(%s): free : %d/%ld, highest in use: %d",
417            message, freefds, (long)sockscf.state.maxopenfiles, *hfd);
418 
419    errno = errno_s;
420    return freefds;
421 }
422 
423 int
sockd_motherexists(void)424 sockd_motherexists(void)
425 {
426    const pid_t pid = getppid();
427    size_t i;
428 
429    if (sockscf.state.motherpidv == NULL)
430       return 1; /* so early we haven't forked yet.  We must be mother then. */
431 
432    /*
433     * A simple getppid(2) unfortunately no longer works on all platforms.
434     * E.g. Solaris apparently, annoyingly enough, returns the pid of the
435     * zone scheduler process, and not initd. :-(
436     * So go through the list of all motherpids to see if getppid() matches
437     * any of them and use that to decide if mother still exists.
438     */
439    for (i = 0; i < sockscf.option.serverc; ++i)
440       if (sockscf.state.motherpidv[i] == pid)
441          return 1;
442 
443    return 0;
444 }
445 
446 void
sockdexit(code)447 sockdexit(code)
448    const int code;
449 {
450    const char *function = "sockdexit()";
451    struct sigaction sigact;
452    static int exiting;
453 
454    if (exiting) /* this must have gotten really screwed up. */
455       abort();
456    else
457       exiting = 1;
458 
459    /*
460     * we are terminating; don't want to receive SIGTERM or SIGCHLD now.
461     */
462    bzero(&sigact, sizeof(sigact));
463    sigact.sa_handler = SIG_IGN;
464    if (sigaction(SIGTERM, &sigact, NULL) != 0
465    ||  sigaction(SIGCHLD, &sigact, NULL) != 0)
466       swarn("%s: sigaction()", function);
467 
468    slog(LOG_DEBUG, "%s: insignal = %d", function, (int)sockscf.state.insignal);
469 
470    if (sockscf.state.type == PROC_MOTHER) {
471       struct rusage rusage;
472 
473       closechild(0, 1); /* tell them we are shutting down orderly now. */
474 
475 #if HAVE_ENABLED_PIDFILE
476       if (sockscf.option.pidfilewritten
477       && pidismainmother(sockscf.state.pid)) {
478          sockd_priv(SOCKD_PRIV_FILE_WRITE, PRIV_ON);
479 
480          if (truncate(sockscf.option.pidfile, 0) != 0)
481             swarn("%s: truncate(%s)", function, sockscf.option.pidfile);
482 
483          sockd_priv(SOCKD_PRIV_FILE_WRITE, PRIV_OFF);
484       }
485 #endif /* HAVE_ENABLED_PIDFILE */
486 
487       if (getrusage(RUSAGE_SELF, &rusage) == 0)
488          log_rusage(PROC_MOTHER,  0, &rusage);
489 
490       log_rusage(PROC_MONITOR,   0, &sockscf.state.rusage_monitor);
491       log_rusage(PROC_NEGOTIATE, 0, &sockscf.state.rusage_negotiate);
492       log_rusage(PROC_REQUEST,   0, &sockscf.state.rusage_request);
493       log_rusage(PROC_IO,        0, &sockscf.state.rusage_io);
494    }
495    else {
496       if (sockscf.state.insignal)
497          slog(LOG_DEBUG, "%s: shutting down on signal %d",
498               childtype2string(sockscf.state.type), sockscf.state.insignal);
499       else
500          slog(LOG_DEBUG, "%s: shutting down",
501               childtype2string(sockscf.state.type));
502    }
503 
504 #if HAVE_PROFILING
505    if (chdir(SOCKS_PROFILEDIR) != 0) {
506       if (sockscf.state.type == PROC_MOTHER)
507          slog(LOG_ERR,
508               "%s: profiling is enabled, but could not chdir(2) to it (%s).  "
509               "If you wish profiling output to be saved, create a directory "
510               "named \"%s\" in the same as directory as you start %s",
511               function, strerror(errno), SOCKS_PROFILEDIR, PRODUCT);
512    }
513    else {
514       char dir[80];
515 
516       snprintf(dir, sizeof(dir), "%s.%ld",
517               childtype2string(sockscf.state.type), (long)getpid());
518 
519       if (mkdir(dir, S_IRWXU) != 0)
520          swarn("%s: mkdir(%s)", function, dir);
521       else
522          if (chdir(dir) != 0)
523             swarn("%s: chdir(%s)", function, dir);
524    }
525 #endif /* HAVE_PROFILING */
526 
527    if (sockscf.state.type == PROC_MOTHER) {
528       if (pidismainmother(sockscf.state.pid)) {
529          sigserverbroadcast(SIGTERM); /* signal other mothers too. */
530 
531          /*
532           * mainly for removing old shared memory stuff and temporary files.
533           * Do this last to reduce the chance of a child trying to use a
534           * shmemfile we have already removed.
535           */
536          resetconfig(&sockscf, 1);
537       }
538 
539       if (sockscf.state.insignal)
540          slog(LOG_ALERT, "%s[%d/%lu]: shutting down on signal %d",
541               childtype2string(sockscf.state.type),
542               pidismother(sockscf.state.pid),
543               (unsigned long)sockscf.option.serverc,
544               sockscf.state.insignal);
545       else
546          slog(LOG_ALERT, "%s[%d/%lu]: shutting down",
547               childtype2string(sockscf.state.type),
548               pidismother(sockscf.state.pid),
549               (unsigned long)sockscf.option.serverc);
550 
551       exit(code);
552    }
553 
554    /*
555     * Else; we are a child.
556     */
557 
558 #if HAVE_PROFILING
559    exit(code);
560 #else
561    fflush(NULL);
562    _exit(code);
563 #endif /* HAVE_PROFILING */
564 }
565