1 /*
2 * Copyright (c) 2013, 2014, 2019, 2020
3 * Inferno Nettverk A/S, Norway. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. The above copyright notice, this list of conditions and the following
9 * disclaimer must appear in all copies of the software, derivative works
10 * or modified versions, and any portions thereof, aswell as in all
11 * supporting documentation.
12 * 2. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by
15 * Inferno Nettverk A/S, Norway.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * Inferno Nettverk A/S requests users of this software to return to
31 *
32 * Software Distribution Coordinator or sdc@inet.no
33 * Inferno Nettverk A/S
34 * Oslo Research Park
35 * Gaustadall�en 21
36 * NO-0349 Oslo
37 * Norway
38 *
39 * any improvements or extensions that they make and grant Inferno Nettverk A/S
40 * the rights to redistribute these changes.
41 *
42 */
43
44 #include "common.h"
45
46 static const char rcsid[] =
47 "$Id: mother_util.c,v 1.22.4.8.6.3 2020/11/11 16:11:59 karls Exp $";
48
49 /*
50 * signal handler functions. Upon reception of signal, "sig" is the real
51 * signal value (> 0). We then set a flag indicating we got a signal,
52 * but we don't do anything and return immediately. Later we are called
53 * again, with "sig" having the value -(sig), to indicate we are not
54 * executing in the signal handler and it's safe to do whatever we
55 * need to do.
56 */
57 static void sigterm(int sig, siginfo_t *si, void *sc);
58 static void siginfo(int sig, siginfo_t *si, void *sc);
59 static void sigchld(int sig, siginfo_t *si, void *sc);
60 static void sigalrm(int sig, siginfo_t *si, void *sc);
61 static void sighup(int sig, siginfo_t *si, void *sc);
62
63 static void unexpecteddeath(void);
64 /*
65 * Should be called after any unexpected child death / child removal.
66 * May disable creation of further children for a while and log a warning
67 * if appropriate, or the enable creation of further children.
68 */
69
70 void
mother_preconfigload(void)71 mother_preconfigload(void)
72 {
73
74 }
75
76 void
mother_postconfigload(void)77 mother_postconfigload(void)
78 {
79 const char *function = "mother_postconfigload()";
80
81 if (pidismainmother(sockscf.state.pid))
82 shmem_idupdate(&sockscf); /* only main mother does this. */
83 }
84
85 void
mother_envsetup(argc,argv)86 mother_envsetup(argc, argv)
87 int argc;
88 char *argv[];
89 {
90 const char *function = "mother_envsetup()";
91 const int exitsignalv[] = {
92 SIGINT, SIGQUIT, SIGBUS, SIGSEGV, SIGTERM, SIGILL, SIGFPE
93 #ifdef SIGSYS
94 , SIGSYS
95 #endif /* SIGSYS */
96 };
97 const size_t pipetomotherfds = 2; /* fds needed for pipe to mother. */
98 const size_t exitsignalc = ELEMENTS(exitsignalv);
99 const int ignoresignalv[] = {
100 SIGPIPE
101 };
102 const size_t ignoresignalc = ELEMENTS(ignoresignalv);
103 struct sigaction sigact;
104 struct rlimit rlimit;
105 #ifdef RLIMIT_NPROC
106 struct rlimit maxproc;
107 #endif /* RLIMIT_NPROC */
108 rlim_t maxopenfd, minfd_neg, minfd_req, minfd_io, minfd;
109 size_t i, fdreserved;
110
111 for (fdreserved = 0;
112 fdreserved < ELEMENTS(sockscf.state.reservedfdv);
113 ++fdreserved) {
114 if (sockscf.state.reservedfdv[fdreserved] == -1) {
115 if ((sockscf.state.reservedfdv[fdreserved] = makedummyfd(0, 0)) == -1)
116 serr("%s: could not reserve fd #%lu for later use",
117 function, (unsigned long)fdreserved + 1);
118 }
119 }
120
121 /*
122 * close any descriptor we don't need, both in case of chroot(2)
123 * and for needing every descriptor we can get.
124 */
125
126 /* assume syslog uses one */
127 fdreserved += sockscf.log.type & LOGTYPE_SYSLOG ? 0 : 1;
128
129 /*
130 * shmem-segments we may need to attach to temporarily in relation
131 * to doing rulespermit() and similar for a client.
132 */
133 fdreserved += 1 /* bw fd */
134 + 1 /* session fd */
135 + 1; /* monitor fd */
136
137 for (i = 0, maxopenfd = getmaxofiles(softlimit); (rlim_t)i < maxopenfd; ++i){
138 size_t j;
139
140 if (descriptorisreserved((int)i)) {
141 ++fdreserved;
142 continue;
143 }
144
145 /* sockets we listen on. */
146 for (j = 0; j < sockscf.internal.addrc; ++j) {
147 if ((int)i == sockscf.internal.addrv[j].s)
148 break;
149 }
150
151 if (j < sockscf.internal.addrc) /* listening on this socket. */
152 continue;
153
154 close((int)i);
155 }
156
157 errno = 0;
158 newprocinit(); /* just in case the above closed a syslog(3) fd. */
159
160 /*
161 * Check system limits against what we need.
162 * Enough descriptors for each child process? + 2 for the pipes from
163 * the child to mother.
164 */
165
166 minfd_neg = (SOCKD_NEGOTIATEMAX * 1) + pipetomotherfds + fdreserved;
167
168 minfd_req = (SOCKD_REQUESTMAX * FDPASS_MAX) + pipetomotherfds + fdreserved;
169
170 minfd_io = (SOCKD_IOMAX * FDPASS_MAX) + pipetomotherfds + fdreserved;
171
172 /* i/o process stays attached to bw and monitor shmem all the time. */
173 minfd_io += SOCKD_IOMAX * (1 + 1);
174
175 #if BAREFOOTD
176 minfd_io += MIN(10, MIN_UDPCLIENTS);
177 #endif
178
179 slog(LOG_DEBUG,
180 "%s: minfd_negotiate: %lu, minfd_request: %lu, minfd_io: %lu",
181 function,
182 (unsigned long)minfd_neg,
183 (unsigned long)minfd_req,
184 (unsigned long)minfd_io);
185 /*
186 * need to know max number of open files so we can allocate correctly
187 * sized fd_sets. Also, try to set both it and the max number of
188 * processes to the hard limit.
189 */
190
191 sockscf.state.maxopenfiles = getmaxofiles(hardlimit);
192
193 slog(LOG_DEBUG,
194 "hard limit for max number of open files is %lu, soft limit is %lu",
195 (unsigned long)sockscf.state.maxopenfiles,
196 (unsigned long)getmaxofiles(softlimit));
197
198 if (sockscf.state.maxopenfiles == RLIM_INFINITY) {
199 sockscf.state.maxopenfiles = getmaxofiles(softlimit);
200 SASSERTX(sockscf.state.maxopenfiles != RLIM_INFINITY);
201 }
202
203 minfd = MAX(minfd_neg, MAX(minfd_req, minfd_io));
204
205 if (sockscf.state.maxopenfiles < minfd) {
206 slog(LOG_INFO,
207 "have only %lu file descriptors available, but need at least %lu "
208 "according to the configuration. Trying to increase it ...",
209 (unsigned long)sockscf.state.maxopenfiles,
210 (unsigned long)minfd);
211
212 sockscf.state.maxopenfiles = minfd;
213 }
214
215 rlimit.rlim_cur = rlimit.rlim_max = sockscf.state.maxopenfiles;
216
217 if (setrlimit(RLIMIT_OFILE, &rlimit) == 0)
218 slog(LOG_DEBUG, "max number of file descriptors is now %lu",
219 (unsigned long)sockscf.state.maxopenfiles);
220 else {
221 const char *problem;
222
223 sockscf.state.maxopenfiles = getmaxofiles(hardlimit);
224
225 if (sockscf.state.maxopenfiles < minfd_neg)
226 problem = "SOCKD_NEGOTIATEMAX";
227 else if (sockscf.state.maxopenfiles < minfd_req)
228 problem = "SOCKD_REQUESTMAX";
229 else if (sockscf.state.maxopenfiles < minfd_io)
230 problem = "SOCKD_IOMAX";
231 else
232 SERRX(sockscf.state.maxopenfiles);
233
234 serrx("%s: failed to increase the max number of open file descriptors "
235 "for ourselves via setrlimit(RLIMIT_OFILE) to %lu: %s. "
236 "Increase the kernel/shell's max open files limit, or reduce "
237 "the %s value in %s's include/config.h, or we will be unable to "
238 "start up",
239 function,
240 (unsigned long)rlimit.rlim_max,
241 strerror(errno),
242 problem,
243 PRODUCT);
244 }
245
246 #ifdef RLIMIT_NPROC
247 if (getrlimit(RLIMIT_NPROC, &maxproc) != 0)
248 swarn("getrlimit(RLIMIT_NPROC) failed");
249 else {
250 maxproc.rlim_cur = maxproc.rlim_max;
251
252 if (setrlimit(RLIMIT_NPROC, &maxproc) != 0)
253 swarn("setrlimit(RLIMIT_NPROC, { %lu, %lu }) failed",
254 (unsigned long)rlimit.rlim_cur,
255 (unsigned long)rlimit.rlim_max);
256 }
257 #endif /* !RLIMIT_NPROC */
258
259
260 /*
261 * set up signal handlers.
262 */
263
264 bzero(&sigact, sizeof(sigact));
265 sigact.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO;
266
267 sigact.sa_sigaction = siginfo;
268 #if HAVE_SIGNAL_SIGINFO
269 if (sigaction(SIGINFO, &sigact, NULL) != 0)
270 serr("sigaction(SIGINFO)");
271 #endif /* HAVE_SIGNAL_SIGINFO */
272
273 /*
274 * same handler, for systems without SIGINFO, as well as systems with
275 * broken ("more secure") signal semantics.
276 */
277 if (sigaction(SIGUSR1, &sigact, NULL) != 0)
278 serr("sigaction(SIGUSR1)");
279
280 sigact.sa_sigaction = sighup;
281 if (sigaction(SIGHUP, &sigact, NULL) != 0)
282 serr("sigaction(SIGHUP)");
283
284 sigact.sa_sigaction = sigchld;
285 if (sigaction(SIGCHLD, &sigact, NULL) != 0)
286 serr("sigaction(SIGCHLD)");
287
288 sigact.sa_sigaction = sigterm;
289 for (i = 0; (size_t)i < exitsignalc; ++i)
290 if (sigaction(exitsignalv[i], &sigact, NULL) != 0)
291 serr("sigaction(%d)", exitsignalv[i]);
292
293 sigact.sa_handler = SIG_IGN;
294 for (i = 0; (size_t)i < ignoresignalc; ++i)
295 if (sigaction(ignoresignalv[i], &sigact, NULL) != 0)
296 serr("sigaction(%d)", ignoresignalv[i]);
297
298 sigact.sa_flags = SA_SIGINFO; /* want to be interrupted. */
299 sigact.sa_sigaction = sigalrm;
300 if (sigaction(SIGALRM, &sigact, NULL) != 0)
301 serr("sigaction(SIGALRM)");
302
303 if (sockscf.option.daemon) {
304 if (daemon(1, 0) != 0)
305 serr("daemon()");
306
307 /*
308 * leave stdout/stderr, but close stdin.
309 * Note that this needs to be done before newprocinit() (which
310 * sets up syslog-thing), as it may happen that the syslog socket
311 * is 0, and we don't want to close that.
312 */
313 close(STDIN_FILENO);
314 newprocinit(); /* for daemon(). */
315
316 *sockscf.state.motherpidv = getpid(); /* we are the main mother. */
317 }
318
319 if (HAVE_ENABLED_PIDFILE) {
320 const mode_t openmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
321 const int openflags = O_WRONLY | O_CREAT;
322 FILE *fp;
323 int fd;
324
325 sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_ON);
326 if ((fd = open(sockscf.option.pidfile, openflags, openmode)) == -1) {
327 swarn("could not open pidfile %s for writing", sockscf.option.pidfile);
328 errno = 0;
329 }
330 sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_OFF);
331
332 if (fd != -1) {
333 fp = fdopen(fd, "w");
334
335 if (fp != NULL) {
336 if (fprintf(fp, "%lu\n", (unsigned long)sockscf.state.pid) == EOF)
337 swarn("failed writing pid to pidfile %s",
338 sockscf.option.pidfile);
339 else
340 sockscf.option.pidfilewritten = 1;
341
342 fclose(fp);
343 }
344
345 close(fd);
346 }
347
348 }
349
350 enable_childcreate();
351
352 freedescriptors(NULL, &sockscf.state.highestfdinuse);
353 }
354
355 char *
mother_getlimitinfo(void)356 mother_getlimitinfo(void)
357 {
358 const char *function = "mother_getlimitinfo()";
359 static char buf[2048];
360 const int fds_per_proc = 2; /* two pipes */
361 const char *limiter, *prefix = "max clients calculation will not be done";
362 struct rlimit maxfd, maxproc;
363 char maxprocstr[64], maxfdstr[64];
364 unsigned long negc_proc, negc_fd, reqc_proc, reqc_fd, ioc_proc, ioc_fd,
365 negc_limit, reqc_limit, ioc_limit,
366 proc_free, proc_used, procs, fds_free;
367
368 if (getrlimit(RLIMIT_NOFILE, &maxfd) != 0) {
369 swarn("%s: getrlimit(RLIMIT_NOFILE) failed", function);
370 return "";
371 }
372
373 #ifdef RLIMIT_NPROC
374 if (getrlimit(RLIMIT_NPROC, &maxproc) != 0) {
375 swarn("%s: %s: getrlimit(RLIMIT_NPROC) failed", function, prefix);
376 return "";
377 }
378 #else /* !RLIMIT_NPROC */
379 if ((maxproc.rlim_cur = (rlim_t)sysconf(_SC_CHILD_MAX)) == (rlim_t)-1) {
380 swarn("%s: %s: sysconf(_SC_CHILD_MAX) failed", function, prefix);
381 return "";
382 }
383
384 maxproc.rlim_max = maxproc.rlim_cur;
385 #endif /* !RLIMIT_NPROC */
386
387 if (maxfd.rlim_cur == RLIM_INFINITY
388 && maxproc.rlim_cur == RLIM_INFINITY)
389 return "no applicable environment resource limits configured";
390
391 proc_used = sockscf.option.serverc
392 + childcheck(-PROC_NEGOTIATE) / SOCKD_NEGOTIATEMAX
393 + childcheck(-PROC_REQUEST) / SOCKD_REQUESTMAX
394 + childcheck(-PROC_IO) / SOCKD_IOMAX;
395 proc_free = maxproc.rlim_cur - proc_used;
396
397 if (maxproc.rlim_cur == RLIM_INFINITY)
398 snprintf(maxprocstr, sizeof(maxprocstr), "no limit");
399 else
400 snprintf(maxprocstr, sizeof(maxprocstr),
401 "%lu (%lu free)",
402 (unsigned long)maxproc.rlim_cur, proc_free);
403
404 fds_free = freedescriptors(NULL, NULL) - FDPASS_MAX;
405 if (maxfd.rlim_cur == RLIM_INFINITY)
406 snprintf(maxfdstr, sizeof(maxfdstr), "no limit");
407 else
408 snprintf(maxfdstr, sizeof(maxfdstr),
409 "%lu (%lu free)", (unsigned long)maxfd.rlim_cur, fds_free);
410
411 /*
412 * Calculate the max number of new clients we can handle based on both
413 * the process resource limit and the fd limit.
414 */
415
416 /*
417 * Process-based limit, disregarding any other limits.
418 * Each process can handle SOCKD_{NEGOTIATE,REQUEST,IO}MAX clients.
419 * We can create a max number of proc_free additional processes, so
420 * the number of additional clients we can handle is the number
421 * of additional clients multiplied by the number of clients each
422 * process can handle.
423 */
424 negc_proc = proc_free * SOCKD_NEGOTIATEMAX;
425 reqc_proc = proc_free * SOCKD_REQUESTMAX;
426 ioc_proc = proc_free * SOCKD_IOMAX;
427
428 /*
429 * FD-based limit, disregarding any other limits.
430 * With the fds we have, we can create a given number of additional
431 * processes (procs).
432 * Each process needs fds_per_proc, and an additional
433 * SOCKD_{NEGOTIATE,REQUEST,IO}MAX * <number of fds per client in this
434 * phase> fds to handle the max number of clients, meaning we can handle
435 * the following number of additional clients:
436 */
437 procs = fds_free / fds_per_proc;
438 negc_fd = MIN(((fds_free - fds_per_proc) / 1), SOCKD_NEGOTIATEMAX)
439 * procs;
440 reqc_fd = MIN(((fds_free - fds_per_proc) / FDPASS_MAX), SOCKD_REQUESTMAX)
441 * procs;
442 ioc_fd = MIN(((fds_free - fds_per_proc) / FDPASS_MAX), SOCKD_IOMAX)
443 * procs;
444
445 /*
446 * Different process-types could be limited by different things, but
447 * ignore that here.
448 */
449 if (negc_proc < negc_fd
450 || reqc_proc < reqc_fd
451 || ioc_proc < ioc_fd) {
452 limiter = "process";
453
454 negc_limit = negc_proc;
455 reqc_limit = reqc_proc;
456 ioc_limit = ioc_proc;
457 }
458 else {
459 limiter = "open file";
460
461 negc_limit = negc_fd;
462 reqc_limit = reqc_fd;
463 ioc_limit = ioc_fd;
464 }
465
466 snprintf(buf, sizeof(buf), "max limits: processes: %s, files: %s, "
467 "%s-slots: %lu, %s-slots: %lu, %s-slots: %lu "
468 "(max clients limited by %s limit)",
469 maxprocstr,
470 maxfdstr,
471 childtype2string(PROC_NEGOTIATE),
472 negc_limit,
473 childtype2string(PROC_REQUEST),
474 reqc_limit,
475 childtype2string(PROC_IO),
476 ioc_limit,
477 limiter);
478
479 return buf;
480 }
481
482 void
log_rusage(childtype,pid,rusage)483 log_rusage(childtype, pid, rusage)
484 const int childtype;
485 const pid_t pid;
486 const struct rusage *rusage;
487 {
488 char prefix[256];
489
490 if (pid == 0)
491 snprintf(prefix, sizeof(prefix),
492 "sum of resource usage for all %s processes",
493 childtype2string(childtype));
494 else
495 snprintf(prefix, sizeof(prefix),
496 "resource usage for %s-child %lu",
497 childtype2string(childtype),
498 (unsigned long)pid);
499
500
501 slog(LOG_DEBUG,
502 "%s\n"
503 " ru_utime : %ld.%06lds\n"
504 " ru_stime : %ld.%06lds\n"
505 " ru_minflt : %ld\n"
506 " ru_majflt : %ld\n"
507 " ru_nswap : %ld\n"
508 " ru_inblock : %ld\n"
509 " ru_oublock : %ld\n"
510 " ru_msgsnd : %ld\n"
511 " ru_msgrcv : %ld\n"
512 " ru_nsignals: %ld\n"
513 " ru_nvcsw : %ld\n"
514 " ru_nivcsw : %ld\n",
515 prefix,
516 (long)rusage->ru_utime.tv_sec, (long)rusage->ru_utime.tv_usec,
517 (long)rusage->ru_stime.tv_sec, (long)rusage->ru_stime.tv_usec,
518 rusage->ru_minflt,
519 rusage->ru_majflt,
520 rusage->ru_nswap,
521 rusage->ru_inblock,
522 rusage->ru_oublock,
523 rusage->ru_msgsnd,
524 rusage->ru_msgrcv,
525 rusage->ru_nsignals,
526 rusage->ru_nvcsw,
527 rusage->ru_nivcsw);
528 }
529
530
531
532 static void
unexpecteddeath(void)533 unexpecteddeath(void)
534 {
535 const char *function = "unexpecteddeath()";
536 const size_t maxdeaths = 10;
537
538
539 ++sockscf.state.unexpected_deaths;
540 time_monotonic(&sockscf.state.lastdeath_time);
541
542 if (sockscf.state.unexpected_deaths == 1)
543 sockscf.state.firstdeath_time = sockscf.state.lastdeath_time;
544
545 if (sockscf.state.unexpected_deaths < maxdeaths)
546 return;
547
548 if (sockscf.state.unexpected_deaths == maxdeaths) { /* log once only. */
549 slog(LOG_ERR,
550 "%s: %lu child deaths in %ld seconds. Not something we are "
551 "expecting so possibly something is wrong. Locking childcount "
552 "for a while (%ld seconds), hoping things will stabilize",
553 function,
554 (unsigned long)sockscf.state.unexpected_deaths,
555 (long)socks_difftime(sockscf.state.lastdeath_time,
556 sockscf.state.firstdeath_time),
557 (long)MAX_ADDCHILD_SECONDS);
558
559 disable_childcreate(0, "large amount of processes suddenly died");
560 alarm(MAX_ADDCHILD_SECONDS);
561 }
562 }
563
564 /* ARGSUSED */
565 static void
sigalrm(sig,si,sc)566 sigalrm(sig, si, sc)
567 int sig;
568 siginfo_t *si;
569 void *sc;
570 {
571 const char *function = "sigalrm()";
572 const int errno_s = errno;
573
574 SIGNAL_PROLOGUE(sig, si, errno_s);
575
576 enable_childcreate();
577
578 SIGNAL_EPILOGUE(sig, si, errno_s);
579 }
580
581 /* ARGSUSED */
582 static void
sigterm(sig,si,sc)583 sigterm(sig, si, sc)
584 int sig;
585 siginfo_t *si;
586 void *sc;
587 {
588 const char *function = "sigterm()";
589 const int errno_s = errno;
590
591 if (sig > 0) {
592 if (SIGNALISOK(sig))
593 SIGNAL_PROLOGUE(sig, si, errno_s);
594 else {
595 /*
596 * A bad signal, something has crashed. Can't count
597 * on it being possible to continue from here, have
598 * to exit now.
599 */
600 const char *msgv[] = { function,
601 ": terminating on unexpected signal ",
602 ltoa(sig, NULL, 0),
603 NULL
604 };
605 sigset_t clearmask;
606
607 sockscf.state.insignal = sig;
608
609 signalslog(LOG_WARNING, msgv);
610
611 #if HAVE_LIVEDEBUG
612 if (!sockscf.option.debug)
613 socks_flushrb();
614 #endif /* HAVE_LIVEDEBUG */
615
616 /*
617 * Reinstall default signal handler for this signal and raise it
618 * again, assuming we will terminate and get a coredump if that is
619 * the default behavior.
620 */
621 if (signal(sig, SIG_DFL) == SIG_ERR) {
622 const char *msgv[]
623 = { function,
624 ": failed to reinstall original handler for signal %d",
625 ltoa(sig, NULL, 0),
626 NULL
627 };
628
629 signalslog(LOG_WARNING, msgv);
630 }
631
632 bzero(&clearmask, sizeof(clearmask));
633 (void)sigprocmask(SIG_SETMASK, &clearmask, NULL);
634 raise(sig);
635
636 return; /* need to exit this signal handler so the default can run. */
637 }
638 }
639 else
640 sig = -sig;
641
642 slog(LOG_INFO, "%s: exiting on signal %d", function, sig);
643
644 SIGNAL_EPILOGUE(sig, si, errno_s);
645
646 sockdexit(EXIT_SUCCESS);
647 }
648
649 /* ARGSUSED */
650 static void
siginfo(sig,si,sc)651 siginfo(sig, si, sc)
652 int sig;
653 siginfo_t *si;
654 void *sc;
655 {
656 const char *function = "siginfo()";
657 const int errno_s = errno;
658 unsigned long days, hours, minutes, seconds,
659 free_negc, free_reqc, free_ioc,
660 max_negc, max_reqc, max_ioc;
661 size_t clients;
662
663 SIGNAL_PROLOGUE(sig, si, errno_s);
664
665 clients = 0;
666 clients += (max_negc = childcheck(-PROC_NEGOTIATE));
667 clients += (max_reqc = childcheck(-PROC_REQUEST));
668 clients += (max_ioc = childcheck(-PROC_IO));
669
670 clients -= (free_negc = childcheck(PROC_NEGOTIATE));
671 clients -= (free_reqc = childcheck(PROC_REQUEST));
672 clients -= (free_ioc = childcheck(PROC_IO));
673
674 seconds = (unsigned long)socks_difftime(time_monotonic(NULL),
675 sockscf.stat.boot);
676 seconds2days(&seconds, &days, &hours, &minutes);
677
678 slog(LOG_INFO, "%s v%s up %lu day%s, %lu:%.2lu, a: %lu, h: %lu c: %lu",
679 PRODUCT,
680 VERSION,
681 days,
682 days == 1 ? "" : "s",
683 hours,
684 minutes,
685 (unsigned long)sockscf.stat.accepted,
686 (unsigned long)sockscf.stat.negotiate.sendt,
687 (unsigned long)clients);
688
689 slog(LOG_INFO, "negotiators (%lu): a: %lu, h: %lu, c: %lu, f: %lu",
690 max_negc / SOCKD_NEGOTIATEMAX,
691 (unsigned long)sockscf.stat.negotiate.sendt,
692 (unsigned long)sockscf.stat.negotiate.received,
693 max_negc - free_negc,
694 free_negc);
695
696 slog(LOG_INFO, "requesters (%lu): a: %lu, h: %lu, c: %lu, f: %lu",
697 max_reqc / SOCKD_REQUESTMAX,
698 (unsigned long)sockscf.stat.request.sendt,
699 (unsigned long)sockscf.stat.request.received,
700 max_reqc - free_reqc,
701 free_reqc);
702
703 slog(LOG_INFO, "iorelayers (%lu): a: %lu, h: %lu, c: %lu, f: %lu",
704 max_ioc / SOCKD_IOMAX,
705 (unsigned long)sockscf.stat.io.sendt,
706 (unsigned long)sockscf.stat.io.received,
707 max_ioc - free_ioc,
708 free_ioc);
709
710 slog(LOG_INFO, "%s", mother_getlimitinfo());
711
712 /*
713 * Regarding kill(2), the OpenBSD manpage says this:
714 *
715 * """
716 * Setuid and setgid processes are dealt with slightly differently.
717 * For the non-root user, to prevent attacks against such processes,
718 * some signal deliveries are not permitted and return the error
719 * EPERM. The following signals are allowed through to this class
720 * of processes: SIGKILL, SIGINT, SIGTERM, SIGSTOP, SIGTTIN, SIGTTOU,
721 * SIGTSTP, SIGHUP, SIGUSR1, SIGUSR2.
722 * """
723 *
724 * The practical effect of this seems to be that if we use different
725 * userids, we, when running with the euid of something other than root,
726 * may not be able to send the SIGINFO signal to our own children. :-/
727 * Simlar problem exists for FreeBSD.
728 *
729 * To workaround the problem, send SIGUSR1 to the children instead of
730 * SIGINFO, as SIGUSR1 has always been treated the same way as SIGINFO
731 * by Dante due to some platforms not having the SIGINFO signal.
732 */
733 #ifdef SIGINFO
734 if (sig == SIGINFO)
735 sig = SIGUSR1;
736 #endif
737
738 if (pidismainmother(sockscf.state.pid)) /* main mother */
739 sigserverbroadcast(sig);
740
741 sigchildbroadcast(sig);
742
743 SIGNAL_EPILOGUE(sig, si, errno_s);
744 }
745
746 /* ARGSUSED */
747 static void
sighup(sig,si,sc)748 sighup(sig, si, sc)
749 int sig;
750 siginfo_t *si;
751 void *sc;
752 {
753 const char *function = "sighup()";
754 const int errno_s = errno;
755 struct config *newshmemconfig;
756 internaladdress_t oldinternal;
757 size_t i, pointersize;
758 int rc;
759
760 SIGNAL_PROLOGUE(sig, si, errno_s);
761
762 slog(LOG_INFO, "SIGHUP [: reloading config");
763
764 /*
765 * Copy the current addresses on the internal interfaces so that after
766 * we have read in the new configuration, we can compare the old list
767 * against the new to know which addresses/sockets are longer in use,
768 * and stop listening on them.
769 *
770 * We can not simply clear them before reading in the new config
771 * and then start listening on them (again) after we in read the new
772 * config, as that would mean we could lose clients in the time-gap
773 * between unbinding and rebinding the addresses.
774 *
775 * This is mainly for barefootd, where adding/removing bounce-to
776 * addresses is probably not uncommon. In the case of barefootd,
777 * we additionally have udp addresses we listen on constantly that
778 * we need to handle in a similar way.
779 *
780 * We also have a slight problem with udp rules, as we need to
781 * know if the rule existed before the reload. If it did,
782 * we will fail when we try to bind on the internal side,
783 * and also waste time trying to set up bouncing for the same
784 * udp addresses several times. More importantly, we will not
785 * know whether the error is expected, or if we should tell the
786 * user he is trying to use an address already in use by
787 * somebody else.
788 * The same problem occurs if we have multiple rules with the
789 * same "to:" address, which can make sense provided "from:"
790 * differs. We then have multiple acls for the same "to:" address,
791 * but of course only one "to:" address/socket.
792 *
793 * Our solution for this is to also save the unique udp addresses we
794 * need to listen to, and compare against them upon config reload.
795 * If one of the udp address is the same as before, we consider the
796 * session to be "bounced" already, and if one of the addresses
797 * present on the old list is not present on the new list, we know
798 * we have an old session/socket to terminate.
799 */
800
801 oldinternal.addrc = sockscf.internal.addrc;
802 if ((oldinternal.addrv = malloc(sizeof(*oldinternal.addrv)
803 * oldinternal.addrc)) == NULL) {
804 swarn("%s: failed to allocate memory for saving state before "
805 "configuration reload",
806 function);
807
808 return;
809 }
810
811 for (i = 0; i < oldinternal.addrc; ++i)
812 oldinternal.addrv[i] = sockscf.internal.addrv[i];
813
814 resetconfig(&sockscf, 0);
815 genericinit();
816 checkconfig();
817
818 showconfig(&sockscf);
819
820 #if DIAGNOSTIC
821 if (sockscf.monitor != NULL)
822 SASSERTX(sockscf.monitor->mstats == NULL);
823
824 if (sockscf.crule != NULL)
825 SASSERTX(!SHMID_ISATTACHED(sockscf.crule));
826
827 if (sockscf.srule != NULL)
828 SASSERTX(!SHMID_ISATTACHED(sockscf.srule));
829 #endif /* DIAGNOSTIC */
830
831 for (i = 0; i < oldinternal.addrc; ++i) {
832 ssize_t p;
833
834 p = addrindex_on_listenlist(sockscf.internal.addrc,
835 sockscf.internal.addrv,
836 &oldinternal.addrv[i].addr,
837 oldinternal.addrv[i].protocol);
838
839 if (p >= 0) {
840 /*
841 * this socket/session should continue to exist.
842 */
843 sockscf.internal.addrv[p].s = oldinternal.addrv[i].s;
844 continue;
845 }
846
847 /*
848 * this socket should be removed.
849 */
850
851 if (oldinternal.addrv[i].protocol == SOCKS_TCP) {
852 close(oldinternal.addrv[i].s);
853 continue;
854 }
855
856 #if BAREFOOTD
857 /* else; udp. */
858 slog(LOG_DEBUG, "%s: child should remove udp session for %s",
859 function,
860 sockaddr2string(&oldinternal.addrv[i].addr, NULL, 0));
861 #endif /* BAREFOOTD */
862 }
863
864 #if BAREFOOTD
865 if (!ALL_UDP_BOUNCED()) {
866 /*
867 * Go through all rules and see if the current udp addresses
868 * to bind matches any of the old ones so we know which addresses
869 * are new and need to be bounced. Those already bounced we should
870 * ignore.
871 */
872 rule_t *rule;
873
874 /*
875 * Assume there are no new addresses to bounce initially.
876 */
877 sockscf.state.alludpbounced = 1;
878
879 for (rule = sockscf.crule; rule != NULL; rule = rule->next) {
880 sockshost_t hosttobind;
881 struct sockaddr_storage addrtobind;
882
883 if (!rule->state.protocol.udp)
884 continue;
885
886 switch (rule->dst.atype) {
887 case SOCKS_ADDR_IPV4:
888 case SOCKS_ADDR_IPV6:
889 ruleaddr2sockshost(&rule->dst, &hosttobind, SOCKS_UDP);
890 sockshost2sockaddr(&hosttobind, &addrtobind);
891
892 if (addrindex_on_listenlist(oldinternal.addrc,
893 oldinternal.addrv,
894 &addrtobind,
895 SOCKS_UDP) != -1) {
896 slog(LOG_DEBUG,
897 "%s: marking address %s in rule %lu as bounced; "
898 "previously bounced",
899 function,
900 sockaddr2string(&addrtobind, NULL, 0),
901 (unsigned long)rule->number);
902
903 rule->bounced = 1;
904 }
905 break;
906
907 case SOCKS_ADDR_DOMAIN: {
908 size_t i;
909
910 i = 0;
911 while (hostname2sockaddr(rule->dst.addr.domain,
912 i++,
913 &addrtobind) != NULL) {
914 if (addrindex_on_listenlist(oldinternal.addrc,
915 oldinternal.addrv,
916 &addrtobind,
917 SOCKS_UDP) != -1) {
918 slog(LOG_DEBUG,
919 "%s: marking address %s in rule %lu "
920 "as bounced; previously bounced",
921 function,
922 sockaddr2string(&addrtobind, NULL, 0),
923 (unsigned long)rule->number);
924
925 rule->bounced = 1;
926 break;
927 }
928 }
929
930 break;
931 }
932
933 case SOCKS_ADDR_IFNAME: {
934 struct sockaddr_storage mask;
935 size_t i;
936
937 i = 0;
938 while (ifname2sockaddr(rule->dst.addr.ifname,
939 i++,
940 &addrtobind,
941 &mask) != NULL) {
942 if (addrindex_on_listenlist(oldinternal.addrc,
943 oldinternal.addrv,
944 &addrtobind,
945 SOCKS_UDP) != -1) {
946 slog(LOG_DEBUG,
947 "%s: marking address %s in rule %lu "
948 "as bounced; previously bounced",
949 function,
950 sockaddr2string(&addrtobind, NULL, 0),
951 (unsigned long)rule->number);
952
953 rule->bounced = 1;
954 break;
955 }
956 }
957 break;
958 }
959
960 default:
961 SERRX(rule->dst.atype);
962 }
963
964 if (!rule->bounced)
965 sockscf.state.alludpbounced = 0;
966 }
967 }
968 #endif /* BAREFOOTD */
969
970 free(oldinternal.addrv);
971
972 /* may have added addresses in new config, rebind if necessary. */
973 if (bindinternal(SOCKS_TCP) != 0)
974 serr("%s: failed to bind internal addresses", function);
975
976 /*
977 * Now comes the tricky part: copy the config to shared memory and forward
978 * the SIGHUP to our children so they know to copy the config we put in
979 * shared memory to their own local memory.
980 *
981 * The procedure works like this:
982 * 1) We lock shmemconfigfd, copy the config to shmem (mapped by the
983 * file referenced by shmemconfigfd), and unlock shmemconfigfd.
984 *
985 * 2) We then forward the children the SIGHUP.
986 *
987 * 3) When the children receive the SIGHUP, they lock shmemconfigfd,
988 * copy the config, and unlock shmemconfigfd.
989 *
990 * The only reason for locking shmemconfig is so we do not update it (due
991 * to another SIGHUP) while the children try to read it (children lock it
992 * read-only, we lock it it read-write).
993 */
994
995 socks_lock(sockscf.shmemconfigfd, 0, 0, 1, 1);
996
997 pointersize = pointer_size(&sockscf);
998
999 slog(LOG_DEBUG,
1000 "%s: current config is of size %lu + %lu (%lu). Trying to mmap(2) ...",
1001 function,
1002 (unsigned long)sizeof(sockscf),
1003 (unsigned long)pointersize,
1004 (unsigned long)(sizeof(sockscf) + pointersize));
1005
1006 if ((newshmemconfig = sockd_mmap(NULL,
1007 sizeof(sockscf) + pointersize,
1008 PROT_READ | PROT_WRITE,
1009 MAP_SHARED,
1010 sockscf.shmemconfigfd,
1011 1)) == MAP_FAILED) {
1012 swarn("%s: could not create shared memory segment of size %lu",
1013 function, (unsigned long)(sizeof(sockscf) + pointersize));
1014
1015 socks_unlock(sockscf.shmemconfigfd, 0, 0);
1016 return;
1017 }
1018
1019 /*
1020 * First shallow copy what we can.
1021 */
1022 *newshmemconfig = sockscf;
1023
1024 /*
1025 * Then the more complicated deep copy.
1026 */
1027 if (pointer_copy(&sockscf,
1028 0,
1029 newshmemconfig,
1030 (void *)((uintptr_t)newshmemconfig + sizeof(sockscf)),
1031 pointersize) != 0) {
1032
1033 swarn("%s: could not copy pointers to shared memory", function);
1034
1035 munmap(newshmemconfig, sizeof(sockscf) + pointersize);
1036
1037 socks_unlock(sockscf.shmemconfigfd, 0, 0);
1038
1039 return;
1040 }
1041
1042 /*
1043 * Successfully mapped new config and everything looks ok. Now remove
1044 * the old mapping, if any.
1045 */
1046 if (sockscf.shmeminfo->config != NULL) {
1047 rc = munmap(sockscf.shmeminfo->config, sockscf.shmeminfo->configsize);
1048 SASSERTX(rc == 0);
1049 }
1050
1051 sockscf.shmeminfo->config = newshmemconfig;
1052 sockscf.shmeminfo->configsize = sizeof(sockscf) + pointersize;
1053
1054 socks_unlock(sockscf.shmemconfigfd, 0, 0);
1055
1056 slog(LOG_DEBUG,
1057 "%s: updated config in shmem. Total size %lu. Doing compare test ...",
1058 function, (unsigned long)sockscf.shmeminfo->configsize);
1059
1060 if ((i = compareconfigs(&sockscf, sockscf.shmeminfo->config)) == 0) {
1061 swarnx("%s: config in shmem not identical to running config", function);
1062 return;
1063 }
1064 else
1065 slog(LOG_DEBUG,
1066 "%s: shmem config identical to running config. %lu bytes compared",
1067 function, (unsigned long)i);
1068
1069 /*
1070 * Not necessarily necessary, but the config-change could imply we
1071 * should no longer use (and thus resolve for) ipv4 or ipv6 addresses.
1072 * Also, might be we have cached something the admin no longer wants us to
1073 * cache. Safest to invalidate the cache too at this point.
1074 */
1075 hostcacheinvalidate();
1076
1077 #if HAVE_LDAP
1078
1079 /*
1080 * LDAP cache entries depend on rule configuration so old cached entries
1081 * might no longer be valid after a SIGHUP. Need to invalidate cache
1082 * at this point.
1083 */
1084 ldapcacheinvalid();
1085
1086 #endif /* HAVE_LDAP */
1087
1088 time_monotonic(&sockscf.stat.configload);
1089
1090 slog(LOG_INFO,
1091 "SIGHUP ]: config reloaded. Broadcasting to children to do the same");
1092
1093 sigserverbroadcast(sig);
1094 sigchildbroadcast(sig);
1095
1096 resetprivileges();
1097
1098 SIGNAL_EPILOGUE(sig, si, errno_s);
1099 }
1100
1101
1102
1103 /* ARGSUSED */
1104 static void
sigchld(sig,si,sc)1105 sigchld(sig, si, sc)
1106 int sig;
1107 siginfo_t *si;
1108 void *sc;
1109 {
1110 const char *function = "sigchld()";
1111 const int errno_s = errno;
1112 time_t tnow;
1113 pid_t pid;
1114 int status;
1115
1116 SIGNAL_PROLOGUE(sig, si, errno_s);
1117
1118 if (socks_difftime(time_monotonic(&tnow), sockscf.state.firstdeath_time)
1119 >= (time_t)MAX_ADDCHILD_SECONDS) { /* enough time has passed; reset. */
1120 sockscf.state.unexpected_deaths = 0;
1121 sockscf.state.firstdeath_time = 0;
1122 sockscf.state.lastdeath_time = 0;
1123
1124 enable_childcreate();
1125 }
1126
1127 while (1) {
1128 struct rusage thisrusage;
1129 sockd_child_t *child;
1130 int isunexpected, proctype;
1131
1132 /*
1133 * On Solaris wait4(2) expects WAIT_ANY to be 0, not -1 as it is
1134 * on other systems. Using -1 ends up calling waitid(2) as
1135 * waitid(P_PGID, 1, ...
1136 * Not what we want, so use wait3(2) instead, as it does not have
1137 * that bug.
1138 */
1139 if ((pid = wait3(&status, WNOHANG, &thisrusage)) == -1
1140 && ERRNOISTMP(errno))
1141 continue;
1142
1143 if (pid <= 0)
1144 break;
1145
1146 slog(LOG_DEBUG, "%s: process %ld exited", function, (long)pid);
1147
1148 if (pidismother(pid)) {
1149 sockscf.state.motherpidv[pidismother(pid) - 1] = 0;
1150 isunexpected = 1;
1151 proctype = PROC_MOTHER;
1152 }
1153 else {
1154 /*
1155 * Must be a regular childprocess.
1156 * XXX merge motherprocesses into getchild() code.
1157 */
1158 struct rusage *rusage, sum;
1159
1160 if ((child = getchild(pid)) == NULL) {
1161 /*
1162 * Note that this might be a pid from our former self also
1163 * if we failed on an internal error, fork(2)-ed process to
1164 * get the coredump and continue. When the fork(2)-ed process
1165 * exits after generating the coredump, we will receive it's
1166 * SIGCHLD, but no account of it. To avoid that, hopefully
1167 * never happening, problem generating a recursive error, let
1168 * this be a swarnx(), and not a SWARNX().
1169 */
1170
1171 swarnx("%s: unknown child pid %lu exited",
1172 function, (unsigned long)pid);
1173
1174 continue;
1175 }
1176
1177 if (child->exitingnormally)
1178 isunexpected = 0;
1179 else
1180 isunexpected = 1;
1181
1182 proctype = child->type;
1183 switch (child->type) {
1184 case PROC_MONITOR:
1185 rusage = &sockscf.state.rusage_monitor;
1186 break;
1187
1188 case PROC_NEGOTIATE:
1189 rusage = &sockscf.state.rusage_negotiate;
1190 break;
1191
1192 case PROC_REQUEST:
1193 rusage = &sockscf.state.rusage_request;
1194 break;
1195
1196 case PROC_IO:
1197 rusage = &sockscf.state.rusage_io;
1198 break;
1199
1200 default:
1201 SERRX(child->type);
1202 }
1203
1204 sum = *rusage;
1205
1206 timeradd(&rusage->ru_utime, &thisrusage.ru_utime, &sum.ru_utime);
1207 timeradd(&rusage->ru_stime, &thisrusage.ru_stime, &sum.ru_stime);
1208 sum.ru_minflt += thisrusage.ru_minflt;
1209 sum.ru_majflt += thisrusage.ru_majflt;
1210 sum.ru_nswap += thisrusage.ru_nswap;
1211 sum.ru_inblock += thisrusage.ru_inblock;
1212 sum.ru_oublock += thisrusage.ru_oublock;
1213 sum.ru_msgsnd += thisrusage.ru_msgsnd;
1214 sum.ru_msgrcv += thisrusage.ru_msgrcv;
1215 sum.ru_nsignals += thisrusage.ru_nsignals;
1216 sum.ru_nvcsw += thisrusage.ru_nvcsw;
1217 sum.ru_nivcsw += thisrusage.ru_nivcsw;
1218
1219 *rusage = sum;
1220
1221 slog(LOG_DEBUG, "%s: %s-child %lu exiting after %lds and %lu client%s",
1222 function,
1223 childtype2string(proctype),
1224 (unsigned long)pid,
1225 (long)socks_difftime(tnow, child->created),
1226 (unsigned long)child->sentc,
1227 (unsigned long)child->sentc == 1 ? "" : "s");
1228
1229 log_rusage(child->type, pid, &thisrusage);
1230
1231 removechild(pid);
1232 }
1233
1234 if (isunexpected) {
1235 swarnx("%s: %s %lu exited unexpectedly %s %s",
1236 function,
1237 childtype2string(proctype),
1238 (unsigned long)pid,
1239 WIFSIGNALED(status) ? "on signal" : "",
1240 WIFSIGNALED(status) ? signal2string(WTERMSIG(status)) : "");
1241
1242 unexpecteddeath();
1243 }
1244 }
1245
1246 SIGNAL_EPILOGUE(sig, si, errno_s);
1247 }
1248