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