1 /*
2 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2008, 2009,
3 * 2010, 2011, 2019, 2020
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 #include "common.h"
46
47 static const char rcsid[] =
48 "$Id: sockd_child.c,v 1.454.4.7.6.5 2020/11/22 19:40:49 karls Exp $";
49
50 #define MOTHER (0) /* descriptor mother reads/writes on. */
51 #define CHILD (1) /* descriptor child reads/writes on. */
52
53 static int
54 setchildtype(int type, sockd_child_t ***childv, size_t **childc,
55 void (**function)(void));
56 /*
57 * Sets "childv", "childc" and "function" to the correct value depending
58 * on "type".
59 */
60
61 static ssize_t
62 findchild(pid_t pid, size_t childc, const sockd_child_t *childv);
63 /*
64 * Finds the child with pid "pid" in the array "childv". Searching
65 * Elements in "childv" is given by "childc".
66 * Returns:
67 * On success: the index of the child in "childv".
68 * On failure: -1.
69 */
70
71 static sockd_child_t *
72 addchild(const int type);
73 /*
74 * Adds a new child that can accept objects of type "type" from mother.
75 * Returns:
76 * On success: a pointer to the added child.
77 * On failure: NULL. (resource shortage.)
78 */
79
80
81 static sockd_child_t *monitorv; /* all our monitorchildren. */
82 static size_t monitorc;
83
84 static sockd_child_t *negchildv; /* all our negotiatorchildren */
85 static size_t negchildc;
86
87 static sockd_child_t *reqchildv; /* all our requestchildren */
88 static size_t reqchildc;
89
90 static sockd_child_t *iochildv; /* all our iochildren */
91 static size_t iochildc;
92
93 void
enable_childcreate(void)94 enable_childcreate(void)
95 {
96 const char *function = "enable_childcreate()";
97
98 if (sockscf.child.noaddchild) {
99 static int firsttime = 1;
100
101 if (firsttime)
102 firsttime = 0;
103 else
104 slog(LOG_INFO, "%s: creation of new child processes enabled again",
105 function);
106
107 sockscf.child.noaddchild = 0;
108 }
109
110 sockscf.child.noaddchild_errno = 0;
111 }
112
113 void
disable_childcreate(err,reason)114 disable_childcreate(err, reason)
115 const int err;
116 const char *reason;
117 {
118 const char *function = "disable_childcreate()";
119
120 if (!sockscf.child.noaddchild) {
121 slog(LOG_INFO,
122 "%s: disabling creation of new child processes%s%s (%s)",
123 function,
124 reason == NULL ? "" : ": ",
125 reason == NULL ? "" : reason,
126 strerror(errno));
127
128 sockscf.child.noaddchild = 1;
129 }
130
131 sockscf.child.noaddchild_errno = err;
132 sockscf.child.noaddchild_reason = reason;
133 }
134
135 size_t
childcheck(type)136 childcheck(type)
137 int type;
138 {
139 const char *function = "childcheck()";
140 static time_t lastaddchildfailure_time;
141 const int errno_s = errno;
142 sockd_child_t **childv, *idlechild;
143 size_t child, *childc, minfreeslots, maxslotsperproc, proxyc,
144 minclientshandled;
145 time_t minlifetime;
146 #if BAREFOOTD
147 pid_t hasfreeudpslot = (pid_t)-1;
148 #endif /* BAREFOOTD */
149
150 switch (type) {
151 /*
152 * Special one-child-only processes.
153 */
154 case -PROC_MONITOR:
155 case PROC_MONITOR:
156 childc = &monitorc;
157 childv = &monitorv;
158 minfreeslots = 1;
159 minclientshandled = 1;
160 maxslotsperproc = 1;
161 break;
162
163
164 case -PROC_NEGOTIATE:
165 case PROC_NEGOTIATE:
166 childc = &negchildc;
167 childv = &negchildv;
168 minfreeslots = SOCKD_FREESLOTS_NEGOTIATE;
169 minclientshandled = SOCKD_MIN_CLIENTS_HANDLED_NEGOTIATE;
170 maxslotsperproc = SOCKD_NEGOTIATEMAX;
171 break;
172
173 case -PROC_REQUEST:
174 case PROC_REQUEST:
175 childc = &reqchildc;
176 childv = &reqchildv;
177 minfreeslots = SOCKD_FREESLOTS_REQUEST;
178 minclientshandled = SOCKD_MIN_CLIENTS_HANDLED_REQUEST;
179 maxslotsperproc = SOCKD_REQUESTMAX;
180 break;
181
182 case -PROC_IO:
183 case PROC_IO:
184 childc = &iochildc;
185 childv = &iochildv;
186 minfreeslots = SOCKD_FREESLOTS_IO;
187 minclientshandled = SOCKD_MIN_CLIENTS_HANDLED_IO;
188 maxslotsperproc = SOCKD_IOMAX;
189 break;
190
191 default:
192 SERRX(type);
193 }
194
195 if (sockscf.child.maxrequests != 0)
196 minclientshandled = MIN(minclientshandled, sockscf.child.maxrequests);
197
198 /* minlifetime is the same for all. */
199 if (sockscf.child.maxlifetime != 0)
200 minlifetime = MIN(SOCKD_MIN_LIFETIME_SECONDS, sockscf.child.maxlifetime);
201 else
202 minlifetime = SOCKD_MIN_LIFETIME_SECONDS;
203
204
205 /*
206 * get an estimate over how many (new or in total) clients our children are
207 * able to accept, so we know if we need to create more children, or if we
208 * can remove some.
209 */
210 idlechild = NULL;
211 for (child = proxyc = 0; child < *childc; ++child) {
212 SASSERTX((*childv)[child].freec <= maxslotsperproc);
213
214 if ((*childv)[child].waitingforexit)
215 continue;
216
217 if (child_should_retire(&(*childv)[child])) {
218 slog(LOG_DEBUG,
219 "%s: not counting %s %ld. Should be retired when "
220 "possible. Currently has %lu/%lu slots free.",
221 function,
222 childtype2string((*childv)[child].type),
223 (long)(*childv)[child].pid,
224 (unsigned long)(*childv)[child].freec,
225 (unsigned long)maxfreeslots((*childv)[child].type));
226
227 if ((*childv)[child].freec == maxfreeslots((*childv)[child].type))
228 closechild((*childv)[child].pid, 1);
229
230 continue;
231 }
232
233 #if BAREFOOTD
234 if (type == PROC_IO) {
235 if (!(*childv)[child].hasudpsession)
236 hasfreeudpslot = (*childv)[child].pid;
237 else
238 slog(LOG_DEBUG, "%s: not counting process %lu: no free udp slots",
239 function, (unsigned long)(*childv)[child].pid);
240 }
241 #endif /* BAREFOOTD */
242
243 proxyc += type < 0 ? maxslotsperproc :
244 #if BAREFOOTD
245 /*
246 * Don't know what the next client for this
247 * child will be (udp or tcp), so safer to assume
248 * that if it can not handle any more udp clients,
249 * it has no free slots. Means we will get more
250 * i/o processes than might be required, but
251 * better that than too few.
252 */
253 ((type == PROC_IO
254 && (*childv)[child].hasudpsession) ?
255 0 : (*childv)[child].freec);
256 #else /* !BAREFOOTD */
257
258 (*childv)[child].freec;
259
260 #endif /* !BAREFOOTD */
261
262 if ((*childv)[child].freec == maxslotsperproc) {
263 #if BAREFOOTD
264 if (type == PROC_IO) {
265 if (hasfreeudpslot != (pid_t)-1
266 && hasfreeudpslot != (*childv)[child].pid)
267 ;
268 else {
269 /*
270 * Want to keep this regardless, as we have not seen any
271 * other child with a free udp slot so far, so don't
272 * include it in the idle count where it could possibly be
273 * shut down by maxidle/maxreq code.
274 */
275 hasfreeudpslot = (*childv)[child].pid;
276 continue;
277 }
278 }
279 #endif /* BAREFOOTD */
280
281 /*
282 * all slots in this child are idle. See later if we can remove an
283 * idle child. Shouldn't matter much which, but choose the one that
284 * has handled most clients; if we are using buggy libraries, that
285 * increases the chance of some leaked memory being freed too.
286 *
287 * Ignore children that have only handled a few clients to prevent
288 * removing and then re-creating immediately after as the current
289 * free slots count goes down by one when a slot is freed.
290 * Should work as a cheap form of hysteresis.
291 */
292 if (sockscf.child.noaddchild /* in trouble. Remove what we can. */
293 || (*childv)[child].sentc >= minclientshandled
294 || socks_difftime(time_monotonic(NULL), (*childv)[child].created)
295 >= (time_t)minlifetime) {
296 if (idlechild == NULL || (*childv)[child].sentc > idlechild->sentc)
297 idlechild = &(*childv)[child];
298 }
299 }
300 }
301
302 if (sockscf.child.noaddchild) {
303 if (socks_difftime(time_monotonic(NULL), lastaddchildfailure_time)
304 >= (time_t)MAX_ADDCHILD_SECONDS
305 && socks_difftime(time_monotonic(NULL), sockscf.state.firstdeath_time)
306 >= (time_t)MAX_ADDCHILD_SECONDS)
307 enable_childcreate();
308 }
309
310 if (type >= 0) {
311 /*
312 * Idle child to remove?
313 */
314 if (idlechild != NULL
315 && (proxyc - maxslotsperproc) >= minfreeslots) {
316 slog(LOG_DEBUG,
317 "%s: counted %lu free %s slots. Removing pid %ld which has "
318 "handled %lu client%s during %lds",
319 function,
320 (unsigned long)(proxyc - maxslotsperproc),
321 childtype2string(idlechild->type),
322 (long)(idlechild->pid),
323 (unsigned long)(idlechild->sentc),
324 idlechild->sentc == 1 ? "" : "s",
325 (long)socks_difftime(time_monotonic(NULL), idlechild->created));
326
327 /*
328 * will remove this now, no longer part of free slots pool.
329 */
330 SASSERTX(idlechild->freec == maxslotsperproc);
331 proxyc -= idlechild->freec;
332 closechild(idlechild->pid, 1);
333 }
334
335 /*
336 * Should we create an additional child?
337 */
338 if (!sockscf.child.noaddchild
339 && ((proxyc < minfreeslots)
340 #if BAREFOOTD
341 || (type == PROC_IO && hasfreeudpslot == (pid_t)-1)
342 #endif /* BAREFOOTD */
343 )) {
344 int reservedv[ MAX(FDPASS_MAX, /* max we can receive from children */
345 1) /* need a socket for accept(2). */
346
347 + 1 /* to reopen-sockd.conf */
348
349 + 1 /*
350 * if no syslog socket is open, so
351 * a new sockd.conf is able to open
352 * one if necessary.
353 */
354
355 + 1 /* things we don't know about. */
356 ];
357
358 size_t i, freec;
359
360 /*
361 * It is better to reserve some descriptors for temporary use
362 * than to get errors when receiving from a child and lose clients
363 * that way. Make sure we always have some descriptors available,
364 * and don't try to add a child if we don't.
365 * If we can add a child after reserving the below number of
366 * descriptors, things are ok. If not, it means we have to few
367 * fds available.
368 */
369 for (i = 0, freec = 0; i < ELEMENTS(reservedv); ++i)
370 if ((reservedv[i] = makedummyfd(0, 0)) != -1)
371 ++freec;
372
373 if (freec < ELEMENTS(reservedv)) {
374 swarn("%s: not enough free sockets/file descriptors to add any "
375 "new child. Need at least %lu, but have only %lu",
376 function,
377 (unsigned long)ELEMENTS(reservedv),
378 (unsigned long)freec);
379
380 disable_childcreate(errno,
381 "not enough free sockets/file descriptors");
382
383 /* don't retry until a child exits, or enough time has passed. */
384 time_monotonic(&lastaddchildfailure_time);
385 }
386
387 while (!sockscf.child.noaddchild
388 && ((proxyc < minfreeslots)
389 #if BAREFOOTD
390 || (type == PROC_IO && hasfreeudpslot == (pid_t)-1)
391 #endif /* BAREFOOTD */
392 )) {
393 sockd_child_t *addedchild;
394
395 #if BAREFOOTD
396 if (type == PROC_IO && hasfreeudpslot == (pid_t)-1)
397 slog(LOG_DEBUG, "%s: no free udp slots: need to add more %sren",
398 function, childtype2string(type));
399 else
400 #endif /* BAREFOOTD */
401 slog(LOG_DEBUG,
402 "%s: current # of free %s slots is %lu, configured minimum "
403 "is %lu: need to add more %sren",
404 function,
405 childtype2string(type),
406 (unsigned long)proxyc,
407 (unsigned long)minfreeslots,
408 childtype2string(type));
409
410 if ((addedchild = addchild(type)) != NULL) {
411 slog(LOG_DEBUG, "%s: added child, pid %lu",
412 function, (unsigned long)addedchild->pid);
413
414 proxyc += maxslotsperproc;
415
416 #if BAREFOOTD
417 if (type == PROC_IO)
418 hasfreeudpslot = addedchild->pid;
419 #endif /* BAREFOOTD */
420
421 }
422 else {
423 log_addchild_failed();
424
425 disable_childcreate(errno, NULL);
426
427 /* don't retry until a child exits, or enough time has passed. */
428 time_monotonic(&lastaddchildfailure_time);
429 }
430 }
431
432 closev(ELEMENTS(reservedv), reservedv);
433 }
434 }
435
436 /* if errno was set, it was also logged. Don't drag it with us. */
437 errno = errno_s;
438
439 return proxyc;
440 }
441
442 int
fillset(set,negc,reqc,ioc)443 fillset(set, negc, reqc, ioc)
444 fd_set *set;
445 size_t *negc;
446 size_t *reqc;
447 size_t *ioc;
448 {
449 /* const char *function = "fillset()"; */
450 size_t i;
451 int dbits;
452
453 /*
454 * There is no point in setting data descriptor of child type N unless
455 * child type N+1 is able to accept the data from child N. So find
456 * out if we have slots of the various types available before setting
457 * the descriptor. The same goes for the ack descriptor; we don't
458 * want to think the process has a lot of free slots because we have
459 * read the ack, but are unable to read the data.
460 */
461
462 *negc = childcheck(PROC_NEGOTIATE);
463 *reqc = childcheck(PROC_REQUEST);
464 *ioc = childcheck(PROC_IO);
465
466 FD_ZERO(set);
467 dbits = -1;
468
469 for (i = 0; i < sockscf.internal.addrc; ++i) {
470 #if BAREFOOTD
471 if (sockscf.internal.addrv[i].protocol != SOCKS_TCP)
472 continue; /* udp handled by io children. */
473 #endif /* BAREFOOTD */
474
475 /*
476 * Before we checked whether we had available negotiate slots
477 * before accept(2)'ing a new client, but if we do not have
478 * negotiate slots available, it will look like we have hung
479 * because we are not accepting any new clients.
480 * Also, if we get into the situation where we have no negotiate slots
481 * and are unable to fork new negotiate processes, things are probably
482 * pretty bad, so it might be better to drop new clients
483 * and log a warning about it.
484 */
485
486 SASSERTX(sockscf.internal.addrv[i].s >= 0);
487 FD_SET(sockscf.internal.addrv[i].s, set);
488 dbits = MAX(dbits, sockscf.internal.addrv[i].s);
489 }
490
491 /* negotiator children. */
492 for (i = 0; i < negchildc; ++i) {
493 if (negchildv[i].waitingforexit)
494 continue;
495
496 if (*reqc > 0) {
497 SASSERTX(negchildv[i].s >= 0);
498 FD_SET(negchildv[i].s, set);
499 dbits = MAX(dbits, negchildv[i].s);
500
501 SASSERTX(negchildv[i].ack >= 0);
502 FD_SET(negchildv[i].ack, set);
503 dbits = MAX(dbits, negchildv[i].ack);
504 }
505 }
506
507 /* request children. */
508 for (i = 0; i < reqchildc; ++i) {
509 if (reqchildv[i].waitingforexit)
510 continue;
511
512 if (*ioc > 0) {
513 SASSERTX(reqchildv[i].s >= 0);
514 FD_SET(reqchildv[i].s, set);
515 dbits = MAX(dbits, reqchildv[i].s);
516
517 SASSERTX(reqchildv[i].ack >= 0);
518 FD_SET(reqchildv[i].ack, set);
519 dbits = MAX(dbits, reqchildv[i].ack);
520 }
521 }
522
523 /*
524 * io children are last in chain, unless we are covenant, which may
525 * need to send a client object back from i/o child to a negotiate
526 * child.
527 */
528 for (i = 0; i < iochildc; ++i) {
529 if (iochildv[i].waitingforexit)
530 continue;
531
532 #if COVENANT
533 if (*negc > 0) {
534 SASSERTX(iochildv[i].s >= 0);
535 FD_SET(iochildv[i].s, set);
536 dbits = MAX(dbits, iochildv[i].s);
537 #endif /* COVENANT */
538
539 SASSERTX(iochildv[i].ack >= 0);
540 FD_SET(iochildv[i].ack, set);
541 dbits = MAX(dbits, iochildv[i].ack);
542 #if COVENANT
543 }
544 #endif /* COVENANT */
545
546 }
547
548 return dbits;
549 }
550
551
552 void
clearchildtype(childtype,pipetype,nfds,set)553 clearchildtype(childtype, pipetype, nfds, set)
554 const int childtype;
555 whichpipe_t pipetype;
556 const int nfds;
557 fd_set *set;
558 {
559 const char *function = "clearchildtype()";
560 sockd_child_t **childv;
561 size_t i, *childc;
562
563
564 slog(LOG_DEBUG, "%s: clearing all childs of type %s from set",
565 function, childtype2string(childtype));
566
567 setchildtype(childtype, &childv, &childc, NULL);
568
569 for (i = 0; i < *childc; ++i)
570 clearset(pipetype, &(*childv)[i], set);
571 }
572
573 void
clearset(type,child,set)574 clearset(type, child, set)
575 whichpipe_t type;
576 const sockd_child_t *child;
577 fd_set *set;
578 {
579 #if DEBUG
580 const char *function = "clearset()";
581 char buf[10240];
582 #endif /* DEBUG */
583 int fdtoclear;
584
585 switch (type) {
586 case ACKPIPE:
587 fdtoclear = child->ack;
588 break;
589
590 case DATAPIPE:
591 fdtoclear = child->s;
592 break;
593
594 default:
595 SERRX(type);
596 }
597
598 if (fdtoclear <= 0) {
599 SASSERTX(child->waitingforexit);
600 return;
601 }
602
603 #if DEBUG
604 if (sockscf.option.debug >= DEBUG_DEBUG)
605 slog(LOG_DEBUG, "%s: will clear fd %d from the fd-set containing: %s",
606 function,
607 fdtoclear,
608 fdset2string(sockscf.state.highestfdinuse, set, 1, buf, sizeof(buf)));
609 #endif
610
611 FD_CLR(fdtoclear, set);
612 }
613
614 sockd_child_t *
getset(type,set)615 getset(type, set)
616 whichpipe_t type;
617 fd_set *set;
618 {
619 /* const char *function = "getset()"; */
620 size_t i;
621
622 /*
623 * check negotiator children for match.
624 */
625 for (i = 0; i < negchildc; ++i) {
626 if (negchildv[i].waitingforexit)
627 continue;
628
629 switch (type) {
630 case DATAPIPE:
631 #if BAREFOOTD
632 if (!ALL_UDP_BOUNCED()) { /* have some left to fake. */
633 static fd_set *zero;
634
635 if (zero == NULL) {
636 zero = allocate_maxsize_fdset();
637 FD_ZERO(zero);
638 }
639
640 if (FD_CMP(zero, set) == 0) {
641 slog(LOG_DEBUG,
642 "no fds set in set, but have not yet bounced all "
643 "udp sessions, so faking it for negchild %lu",
644 (unsigned long)negchildv[i].pid);
645
646 return &negchildv[i];
647 }
648 }
649 #endif /* BAREFOOTD */
650
651 if (FD_ISSET(negchildv[i].s, set))
652 return &negchildv[i];
653 break;
654
655 case ACKPIPE:
656 if (FD_ISSET(negchildv[i].ack, set))
657 return &negchildv[i];
658 break;
659 }
660 }
661
662 /*
663 * check request children for match.
664 */
665 for (i = 0; i < reqchildc; ++i) {
666 if (reqchildv[i].waitingforexit)
667 continue;
668
669 switch (type) {
670 case DATAPIPE:
671 if (FD_ISSET(reqchildv[i].s, set))
672 return &reqchildv[i];
673 break;
674
675 case ACKPIPE:
676 if (FD_ISSET(reqchildv[i].ack, set))
677 return &reqchildv[i];
678 break;
679 }
680 }
681
682 /*
683 * check io children for match.
684 */
685 for (i = 0; i < iochildc; ++i) {
686 if (iochildv[i].waitingforexit)
687 continue;
688
689 switch (type) {
690 case DATAPIPE:
691 if (FD_ISSET(iochildv[i].s, set))
692 return &iochildv[i];
693 break;
694
695 case ACKPIPE:
696 if (FD_ISSET(iochildv[i].ack, set))
697 return &iochildv[i];
698 break;
699 }
700 }
701
702 return NULL;
703 }
704
705 void
removechild(pid)706 removechild(pid)
707 const pid_t pid;
708 {
709 const char *function = "removechild()";
710 sockd_child_t **childv;
711 ssize_t child;
712 size_t *childc;
713
714 slog(LOG_DEBUG, "%s: pid = %lu", function, (unsigned long)pid);
715
716 if (pid == 0) { /* remove all children. */
717 int childtypev[] = {PROC_MONITOR, PROC_NEGOTIATE, PROC_REQUEST, PROC_IO};
718 size_t i;
719
720 for (i = 0; i < ELEMENTS(childtypev); ++i) {
721 if (childtypev[i] == PROC_MONITOR
722 && pidismother(sockscf.state.pid) != 1)
723 continue; /* only main mother controls the monitor child. */
724
725 while (1) { /* removechild() will remove it from our child array. */
726 setchildtype(childtypev[i], &childv, &childc, NULL);
727 if (*childc == 0)
728 break;
729
730 SASSERTX((*childv)[0].pid != 0);
731 removechild((*childv)[0].pid);
732 }
733 }
734
735 return;
736 }
737
738 setchildtype(childtype(pid), &childv, &childc, NULL);
739 child = findchild(pid, *childc, *childv);
740 if (child < 0) {
741 SWARNX(child);
742 return;
743 }
744
745 /* shift all following one down */
746 while ((size_t)child < *childc - 1) {
747 (*childv)[child] = (*childv)[child + 1];
748 ++child;
749 }
750 --(*childc);
751
752 /*
753 * Don't bother with realloc(3) when reducing size.
754 */
755 }
756
757 void
closechild(pid,isnormalexit)758 closechild(pid, isnormalexit)
759 pid_t pid;
760 const int isnormalexit;
761 {
762 const char *function = "closechild()";
763 const char cmd = SOCKD_EXITNORMALLY;
764 sockd_child_t **childv;
765 ssize_t child;
766 size_t *childc;
767
768 slog(LOG_DEBUG, "%s: pid = %lu, isnormalexit = %d",
769 function, (unsigned long)pid, isnormalexit);
770
771 if (pid == 0) {
772 int childtypev[] = {PROC_MONITOR, PROC_NEGOTIATE, PROC_REQUEST, PROC_IO};
773 size_t childtypec;
774
775 for (childtypec = 0; childtypec < ELEMENTS(childtypev); ++childtypec) {
776 size_t i;
777
778 if (childtypev[childtypec] == PROC_MONITOR
779 && pidismother(sockscf.state.pid) != 1)
780 continue; /* only main mother controls the monitor child. */
781
782 setchildtype(childtypev[childtypec], &childv, &childc, NULL);
783
784 if (*childc == 0)
785 continue;
786
787 for (i = 0; i < *childc; ++i) {
788 SASSERTX((*childv)[i].pid != 0);
789 closechild((*childv)[i].pid, isnormalexit);
790 }
791 }
792
793 return;
794 }
795
796 setchildtype(childtype(pid), &childv, &childc, NULL);
797 child = findchild(pid, *childc, *childv);
798 if (child < 0) {
799 SWARNX(child);
800 return;
801 }
802
803 if (isnormalexit && (*childv)[child].ack != -1) /* notify child. */
804 if (write((*childv)[child].ack, &cmd, sizeof(cmd)) != sizeof(cmd))
805 swarn("%s: failed to notify %s %ld it should exit normally",
806 function,
807 childtype2string((*childv)[child].type),
808 (long)(*childv)[child].pid);
809
810 if (((*childv)[child].s) != -1) {
811 close((*childv)[child].s);
812 (*childv)[child].s = -1;
813 }
814
815 if (((*childv)[child].ack) != -1) {
816 close((*childv)[child].ack);
817 (*childv)[child].ack = -1;
818 }
819
820 (*childv)[child].waitingforexit = 1;
821 (*childv)[child].exitingnormally = isnormalexit;
822 }
823
824 sockd_child_t *
nextchild(type,protocol)825 nextchild(type, protocol)
826 const int type;
827 const int protocol;
828 {
829 const char *function = "nextchild()";
830 sockd_child_t **childv, *mostbusy;
831 size_t i, *childc;
832 int triedagain = 0;
833
834 tryagain:
835
836 setchildtype(type, &childv, &childc, NULL);
837
838 /*
839 * Try to find the child that is most busy, so that we converge to
840 * filling up slots in existing children and removing idle ones.
841 */
842 mostbusy = NULL;
843
844 for (i = 0; i < *childc; ++i) {
845 if ((*childv)[i].freec > 0) {
846 #if BAREFOOTD
847 if (protocol == SOCKS_UDP && (*childv)[i].hasudpsession) {
848 slog(LOG_DEBUG,
849 "%s: skipping child %ld. Has %lu free slot%s, but also "
850 "has an udp sessions already",
851 function,
852 (long)(*childv)[i].pid,
853 (unsigned long)(*childv)[i].freec,
854 (unsigned long)(*childv)[i].freec == 1 ? "" : "s");
855
856 continue;
857 }
858 #endif /* BAREFOOTD */
859
860 if (child_should_retire(&(*childv)[i]))
861 continue;
862
863 if ((*childv)[i].waitingforexit)
864 continue;
865
866 /*
867 * Child has at least one free slot.
868 * We want to find the child with the fewest free slots, to avoid
869 * processes with only a few clients that can not be shut down by
870 * child.maxidle. Trying to fit as many clients as possible
871 * into each processes allows us to reduce the process count.
872 */
873 if (mostbusy == NULL
874 || (*childv)[i].freec < mostbusy->freec)
875 mostbusy = &(*childv)[i];
876
877 if (mostbusy->freec == 1)
878 break; /* no need to look further, got the busiest we can get. */
879 }
880 }
881
882 if (mostbusy != NULL)
883 return mostbusy;
884
885 slog(LOG_DEBUG, "%s: no free %s slots for protocol %s, triedagain = %d",
886 function,
887 childtype2string(type),
888 protocol2string(protocol),
889 triedagain);
890
891 if (!triedagain) {
892 slog(LOG_DEBUG, "%s: calling childcheck() and trying again", function);
893
894 if (childcheck(type) > 0) {
895 triedagain = 1;
896 goto tryagain;
897 }
898 }
899
900 return NULL;
901 }
902
903 int
childtype(pid)904 childtype(pid)
905 const pid_t pid;
906 {
907
908 if (findchild(pid, monitorc, monitorv) >= 0)
909 return PROC_MONITOR;
910
911 if (findchild(pid, negchildc, negchildv) >= 0)
912 return PROC_NEGOTIATE;
913
914 if (findchild(pid, reqchildc, reqchildv) >= 0)
915 return PROC_REQUEST;
916
917 if (findchild(pid, iochildc, iochildv) >= 0)
918 return PROC_IO;
919
920 if (pidismother(pid))
921 return PROC_MOTHER;
922
923 return PROC_NOTOURS;
924 }
925
926 sockd_child_t *
getchild(pid)927 getchild(pid)
928 pid_t pid;
929 {
930 ssize_t child;
931 size_t *childc;
932 sockd_child_t **childv;
933 int type;
934
935 switch (type = childtype(pid)) {
936 case PROC_MONITOR:
937 case PROC_NEGOTIATE:
938 case PROC_REQUEST:
939 case PROC_IO:
940 break;
941
942 case PROC_MOTHER: /* XXX should have an array for mothers also. */
943 return NULL;
944
945 case PROC_NOTOURS:
946 return NULL;
947
948 default:
949 SERRX(type);
950 }
951
952 setchildtype(type, &childv, &childc, NULL);
953
954 if ((child = findchild(pid, *childc, *childv)) >= 0)
955 return &(*childv)[child];
956
957 SERRX(pid);
958 /* NOTREACHED */
959 }
960
961 int
send_io(s,io)962 send_io(s, io)
963 int s;
964 sockd_io_t *io;
965 {
966 const char *function = "send_io()";
967 struct iovec iov[2];
968 struct msghdr msg;
969 int ioc, fdtosend, length;
970 #if HAVE_GSSAPI
971 gss_buffer_desc gssapistate = { 0, NULL };
972 gss_ctx_id_t original_gssidvalue, *gssid = NULL;
973 char gssapistatemem[MAXGSSAPITOKENLEN];
974 #endif /* HAVE_GSSAPI */
975 CMSG_AALLOC(cmsg, sizeof(int) * FDPASS_MAX);
976
977 SASSERTX(io->allocated == 0);
978
979 log_ruleinfo_shmid(CRULE_OR_HRULE(io), function, NULL);
980
981 if (io->srule.type == object_none) {
982 SASSERTX(io->state.protocol == SOCKS_UDP);
983 SASSERTX(!HAVE_SOCKS_RULES);
984 }
985 else
986 log_ruleinfo_shmid(&io->srule, function, NULL);
987
988 SASSERTX(!(SHMID_ISSET(CRULE_OR_HRULE(io)) && SHMID_ISSET(&io->srule)));
989
990 #if HAVE_SOCKS_RULES
991 SASSERTX(!SHMID_ISSET(CRULE_OR_HRULE(io)));
992
993 #else /* !HAVE_SOCKS_RULES */
994 SASSERTX(!SHMID_ISSET(&io->srule));
995
996 #endif /* !HAVE_SOCKS_RULES */
997
998 SASSERTX(!SHMID_ISATTACHED(CRULE_OR_HRULE(io)));
999 SASSERTX(!SHMID_ISATTACHED(&io->srule));
1000
1001 bzero(iov, sizeof(iov));
1002 length = 0;
1003 ioc = 0;
1004
1005 iov[ioc].iov_base = io;
1006 iov[ioc].iov_len = sizeof(*io);
1007 length += iov[ioc].iov_len;
1008 ++ioc;
1009
1010 fdtosend = 0;
1011 CMSG_ADDOBJECT(io->src.s, cmsg, sizeof(io->src.s) * fdtosend++);
1012
1013 switch (io->state.command) {
1014 case SOCKS_BIND:
1015 CMSG_ADDOBJECT(io->dst.s, cmsg, sizeof(io->dst.s) * fdtosend++);
1016
1017 #if HAVE_GSSAPI
1018 if (io->src.auth.method == AUTHMETHOD_GSSAPI)
1019 gssid = &io->src.auth.mdata.gssapi.state.id;
1020 #endif /* HAVE_GSSAPI */
1021
1022 if (io->state.extension.bind)
1023 CMSG_ADDOBJECT(io->control.s,
1024 cmsg,
1025 sizeof(io->control.s) * fdtosend++);
1026 break;
1027
1028 case SOCKS_BINDREPLY:
1029 CMSG_ADDOBJECT(io->dst.s, cmsg, sizeof(io->dst.s) * fdtosend++);
1030
1031 #if HAVE_GSSAPI
1032 if (io->dst.auth.method == AUTHMETHOD_GSSAPI)
1033 gssid = &io->dst.auth.mdata.gssapi.state.id;
1034 #endif /* HAVE_GSSAPI */
1035
1036 if (io->state.extension.bind)
1037 CMSG_ADDOBJECT(io->control.s, cmsg,
1038 sizeof(io->control.s) * fdtosend++);
1039 break;
1040
1041 case SOCKS_UDPASSOCIATE:
1042 SASSERTX(io->dst.s == -1);
1043
1044 #if HAVE_GSSAPI
1045 if (io->src.auth.method == AUTHMETHOD_GSSAPI)
1046 gssid = &io->src.auth.mdata.gssapi.state.id;
1047 #endif /* HAVE_GSSAPI */
1048
1049 #if !BAREFOOTD /* no control. */
1050 CMSG_ADDOBJECT(io->control.s, cmsg,
1051 sizeof(io->control.s) * fdtosend++);
1052 #endif /* !BAREFOOTD */
1053 break;
1054
1055 case SOCKS_CONNECT:
1056 CMSG_ADDOBJECT(io->dst.s, cmsg, sizeof(io->dst.s) * fdtosend++);
1057
1058 #if HAVE_GSSAPI
1059 if (io->src.auth.method == AUTHMETHOD_GSSAPI)
1060 gssid = &io->src.auth.mdata.gssapi.state.id;
1061 #endif /* HAVE_GSSAPI */
1062 break;
1063
1064 default:
1065 SERRX(io->state.command);
1066 }
1067
1068 #if HAVE_GSSAPI
1069 if (gssid == NULL) {
1070 gssapistate.value = NULL;
1071 gssapistate.length = 0;
1072 }
1073 else {
1074 original_gssidvalue = *gssid;
1075
1076 gssapistate.value = gssapistatemem;
1077 gssapistate.length = sizeof(gssapistatemem);
1078
1079 if (gssapi_export_state(gssid, &gssapistate) != 0)
1080 return -1;
1081
1082 iov[ioc].iov_base = gssapistate.value;
1083 iov[ioc].iov_len = gssapistate.length;
1084 length += gssapistate.length;
1085 ++ioc;
1086
1087 if (sockscf.option.debug >= DEBUG_VERBOSE)
1088 slog(LOG_DEBUG, "%s: gssapistate has length %lu",
1089 function, (long unsigned)gssapistate.length);
1090 }
1091 #endif /* HAVE_GSSAPI */
1092
1093 bzero(&msg, sizeof(msg));
1094 msg.msg_iov = iov;
1095 msg.msg_iovlen = ioc;
1096 msg.msg_name = NULL;
1097
1098 CMSG_SETHDR_SEND(msg, cmsg, sizeof(int) * fdtosend);
1099
1100 if (sockscf.option.debug >= DEBUG_VERBOSE) {
1101 char ctrlbuf[MAXSOCKADDRSTRING * 2 + 64],
1102 srcbuf[sizeof(ctrlbuf)], dstbuf[sizeof(ctrlbuf)];
1103
1104 slog(LOG_DEBUG,
1105 "%s: sending %d descriptors for command %d on fd %d. "
1106 "bw_shmid %lu, mstats_shmid %lu, ss_shmid %lu\n"
1107 "Control: %d (%s)\n"
1108 "Src : %d (%s)\n"
1109 "Dst : %d (%s)",
1110 function,
1111 fdtosend,
1112 io->state.command,
1113 s,
1114 (unsigned long)io->srule.bw_shmid,
1115 (unsigned long)io->srule.mstats_shmid,
1116 (unsigned long)io->srule.ss_shmid,
1117 io->control.s,
1118 socket2string(io->control.s, ctrlbuf, sizeof(ctrlbuf)),
1119 io->src.s,
1120 socket2string(io->src.s, srcbuf, sizeof(srcbuf)),
1121 io->dst.s,
1122 io->dst.s == -1 ?
1123 "N/A" : socket2string(io->dst.s, dstbuf, sizeof(dstbuf)));
1124 }
1125
1126 /*
1127 * if not mother, request child. Since that child only handles one
1128 * client at a time, it's safe to block as long as it takes. Mother
1129 * on the other hand can not block.
1130 */
1131 if (sendmsgn(s, &msg, 0, sockscf.state.type == PROC_MOTHER ? 0 : -1)
1132 != length) {
1133 #if HAVE_GSSAPI
1134 if (gssapistate.value != NULL) {
1135 *gssid = original_gssidvalue;
1136
1137 if (gssapi_import_state(gssid, &gssapistate) != 0)
1138 swarnx("%s: could not re-import gssapi state", function);
1139 }
1140 #endif /* HAVE_GSSAPI */
1141
1142 slog(LOG_DEBUG,
1143 "%s: sending client %s to %s failed: %s",
1144 function,
1145 sockaddr2string(&CONTROLIO(io)->raddr, NULL, 0),
1146 sockscf.state.type == PROC_MOTHER ? "child" : "mother",
1147 strerror(errno));
1148
1149 return -1;
1150 }
1151
1152 return 0;
1153 }
1154
1155 int
send_client(s,_client,buf,buflen)1156 send_client(s, _client, buf, buflen)
1157 int s;
1158 const sockd_client_t *_client;
1159 const char *buf;
1160 const size_t buflen;
1161 {
1162 const char *function = "send_client()";
1163 sockd_client_t client = *_client;
1164 struct iovec iovec[1];
1165 struct msghdr msg;
1166 CMSG_AALLOC(cmsg, sizeof(int));
1167 int fdtosend;
1168
1169 slog(LOG_DEBUG, "%s: buflen = %lu", function, (unsigned long)buflen);
1170
1171 #if COVENANT
1172 if (buflen > 0) {
1173 memcpy(client.clientdata, buf, buflen);
1174 client.clientdatalen = buflen;
1175 }
1176 #endif /* COVENANT */
1177
1178 bzero(iovec, sizeof(iovec));
1179 iovec[0].iov_base = &client;
1180 iovec[0].iov_len = sizeof(client);
1181
1182 fdtosend = 0;
1183 CMSG_ADDOBJECT(client.s, cmsg, sizeof(client.s) * fdtosend++);
1184
1185 bzero(&msg, sizeof(msg));
1186 msg.msg_iov = iovec;
1187 msg.msg_iovlen = ELEMENTS(iovec);
1188 msg.msg_name = NULL;
1189
1190 CMSG_SETHDR_SEND(msg, cmsg, sizeof(int) * fdtosend);
1191
1192 if (sockscf.option.debug >= DEBUG_VERBOSE)
1193 slog(LOG_DEBUG, "%s: sending fd %d (%s) on fd %d ...",
1194 function, client.s, socket2string(client.s, NULL, 0), s);
1195
1196 if (sendmsgn(s, &msg, 0, sockscf.state.type == PROC_MOTHER ? 0 : -1)
1197 != (ssize_t)sizeof(client)) {
1198 slog(LOG_DEBUG, "%s: sending client to mother on fd %d failed: %s",
1199 function, s, strerror(errno));
1200
1201 return -1;
1202 }
1203
1204 return 0;
1205 }
1206
1207 int
send_req(s,req)1208 send_req(s, req)
1209 int s;
1210 sockd_request_t *req;
1211 {
1212 const char *function = "send_req()";
1213 struct iovec iov[2];
1214 struct msghdr msg;
1215 int fdtosend, ioc, length;
1216 #if HAVE_GSSAPI
1217 gss_buffer_desc gssapistate;
1218 char gssapistatemem[MAXGSSAPITOKENLEN];
1219 #endif /* HAVE_GSSAPI */
1220 CMSG_AALLOC(cmsg, sizeof(int));
1221
1222 ioc = 0;
1223 length = 0;
1224
1225 bzero(iov, sizeof(iov));
1226 iov[ioc].iov_base = req;
1227 iov[ioc].iov_len = sizeof(*req);
1228 length += iov[ioc].iov_len;
1229 ++ioc;
1230
1231 #if HAVE_GSSAPI
1232 if (req->sauth.method == AUTHMETHOD_GSSAPI) {
1233 gssapistate.value = gssapistatemem;
1234 gssapistate.length = sizeof(gssapistatemem);
1235
1236 if (gssapi_export_state(&req->sauth.mdata.gssapi.state.id, &gssapistate)
1237 != 0)
1238 return 1;
1239
1240 iov[ioc].iov_base = gssapistate.value;
1241 iov[ioc].iov_len = gssapistate.length;
1242 length += iov[ioc].iov_len;
1243 ++ioc;
1244
1245 if (sockscf.option.debug >= DEBUG_VERBOSE)
1246 slog(LOG_DEBUG, "%s: gssapistate length is %lu",
1247 function, (long unsigned)gssapistate.length);
1248 }
1249 else {
1250 gssapistate.value = NULL;
1251 gssapistate.length = 0;
1252 }
1253 #endif /* HAVE_GSSAPI */
1254
1255 fdtosend = 0;
1256
1257 if (req->s == -1) {
1258 #if BAREFOOTD
1259 SASSERT(req->req.command == SOCKS_UDPASSOCIATE);
1260 #else /* !BAREFOOTD */
1261 SERRX(req->s);
1262 #endif /* !BAREFTOOD */
1263 }
1264 else
1265 CMSG_ADDOBJECT(req->s, cmsg, sizeof(req->s) * fdtosend++);
1266
1267 bzero(&msg, sizeof(msg));
1268 msg.msg_iov = iov;
1269 msg.msg_iovlen = ELEMENTS(iov);
1270 msg.msg_name = NULL;
1271
1272 CMSG_SETHDR_SEND(msg, cmsg, sizeof(int) * fdtosend);
1273
1274 if (sockscf.option.debug >= DEBUG_VERBOSE && req->s != -1)
1275 slog(LOG_DEBUG, "%s: sending fd %d (%s) on fd %d ...",
1276 function, req->s, socket2string(req->s, NULL, 0), s);
1277
1278 if (sendmsgn(s, &msg, 0, sockscf.state.type == PROC_MOTHER ? 0 : -1)
1279 != length) {
1280 if (sockscf.state.type == PROC_MOTHER)
1281 swarn("%s: sending client to child failed", function);
1282 else
1283 slog(sockd_motherexists() ? LOG_WARNING : LOG_DEBUG,
1284 "%s: sending client to mother failed: %s",
1285 function, strerror(errno));
1286
1287 #if HAVE_GSSAPI
1288 if (gssapistate.value != NULL) {
1289 /* re-import so it's still here when/if we retry sending client. */
1290 if (gssapi_import_state(&req->sauth.mdata.gssapi.state.id,
1291 &gssapistate) != 0)
1292 swarnx("%s: could not re-import gssapi state", function);
1293 }
1294 #endif /* HAVE_GSSAPI */
1295
1296 return -1;
1297 }
1298
1299 return 0;
1300 }
1301
1302 void
sigchildbroadcast(sig)1303 sigchildbroadcast(sig)
1304 int sig;
1305 {
1306 const char *function = "sigchildbroadcast()";
1307 int childtypesv[] = { PROC_MONITOR, PROC_NEGOTIATE, PROC_REQUEST, PROC_IO };
1308 size_t *childc, childtypec;
1309 sockd_child_t **childv;
1310
1311 for (childtypec = 0; childtypec < ELEMENTS(childtypesv); ++childtypec) {
1312 size_t i;
1313
1314 if (childtypesv[childtypec] == PROC_MONITOR
1315 && pidismother(sockscf.state.pid) != 1)
1316 continue; /* only main mother controls the monitor child. */
1317
1318 setchildtype(childtypesv[childtypec], &childv, &childc, NULL);
1319
1320 for (i = 0; i < *childc; ++i) {
1321 slog(LOG_DEBUG, "%s: sending signal %d to %s %ld",
1322 function,
1323 sig,
1324 childtype2string(childtypesv[childtypec]),
1325 (long)(*childv)[i].pid);
1326
1327 if (kill((*childv)[i].pid, sig) != 0) {
1328 if ((*childv)[i].waitingforexit)
1329 slog(LOG_DEBUG,
1330 "%s: could not send signal %d to child process %ld: "
1331 "child has exited already",
1332 function, sig, (long)(*childv)[i].pid);
1333 else
1334 swarn("%s: could not send signal %d to child process %ld",
1335 function, sig, (long)(*childv)[i].pid);
1336 }
1337 }
1338 }
1339 }
1340
1341 size_t
maxfreeslots(childtype)1342 maxfreeslots(childtype)
1343 const int childtype;
1344 {
1345
1346 switch (childtype) {
1347 case PROC_MONITOR:
1348 return 1;
1349
1350 case PROC_NEGOTIATE:
1351 return SOCKD_NEGOTIATEMAX;
1352
1353 case PROC_REQUEST:
1354 return SOCKD_REQUESTMAX;
1355
1356 case PROC_IO:
1357 return SOCKD_IOMAX;
1358
1359 default:
1360 SERRX(childtype);
1361 }
1362
1363 return 0; /* NOTREACHED */
1364 }
1365
1366 int
child_should_retire(child)1367 child_should_retire(child)
1368 const sockd_child_t *child;
1369 {
1370 const char *function = "child_should_retire()";
1371
1372 if (sockscf.child.maxrequests != 0
1373 && child->sentc >= sockscf.child.maxrequests) {
1374 slog(LOG_DEBUG,
1375 "%s: %s %ld has served %lu requests, while the max is %lu. "
1376 "It should retire as soon as it has finished serving its %d "
1377 "remaining client%s%s",
1378 function,
1379 childtype2string(child->type),
1380 (long)child->pid,
1381 (unsigned long)child->sentc,
1382 (unsigned long)sockscf.child.maxrequests,
1383 (int)(maxfreeslots(child->type) - child->freec),
1384 maxfreeslots(child->type) - child->freec == 1 ? "" : "s",
1385 maxfreeslots(child->type) - child->freec == 0 ?
1386 ", meaning now" : "");
1387
1388 return 1;
1389 }
1390
1391 if (sockscf.child.maxlifetime != 0) {
1392 time_t tnow;
1393
1394 if (socks_difftime(time_monotonic(&tnow), child->created)
1395 >= (time_t)sockscf.child.maxlifetime) {
1396 slog(LOG_DEBUG,
1397 "%s: %s %d has served for %ld seconds, while the max is %ld. "
1398 "It should retire as soon as it has finished serving its %d "
1399 "remaining client%s%s",
1400 function,
1401 childtype2string(child->type),
1402 (int)child->pid,
1403 socks_difftime(tnow, child->created),
1404 (long)sockscf.child.maxlifetime,
1405 (int)(maxfreeslots(child->type) - child->freec),
1406 maxfreeslots(child->type) - child->freec == 1 ? "" : "s",
1407 maxfreeslots(child->type) - child->freec == 0 ?
1408 ", meaning now" : "");
1409
1410 return 1;
1411 }
1412 }
1413
1414 return 0;
1415 }
1416
1417
1418
1419 void
sockd_print_child_ready_message(freefds)1420 sockd_print_child_ready_message(freefds)
1421 const size_t freefds;
1422 {
1423 const char *function = "sockd_print_child_ready_message()";
1424
1425 slog(LOG_DEBUG,
1426 "%s: I'm %s and ready to serve with %lu free fd%s and %lu free slot%s",
1427 function,
1428 childtype2string(sockscf.state.type),
1429 (unsigned long)freefds, freefds == 1 ? "" : "s",
1430 (unsigned long)maxfreeslots(sockscf.state.type),
1431 maxfreeslots(sockscf.state.type) == 1 ? "" : "s");
1432 }
1433
1434
1435 static sockd_child_t *
addchild(type)1436 addchild(type)
1437 const int type;
1438 {
1439 const char *function = "addchild()";
1440 void (*childfunction)(void);
1441 sigset_t all, oldmask;
1442 sockd_mother_t mother;
1443 sockd_child_t **childv;
1444 pid_t pid;
1445 socklen_t optlen;
1446 size_t *childc;
1447 char *reason;
1448 int min, rcvbuf, sndbuf, rcvbuf_set1, rcvbuf_set2, sndbuf_set1, sndbuf_set2,
1449 p, optname_sndbuf, optname_rcvbuf, ackpipev[2], datapipev[2];
1450
1451 slog(LOG_DEBUG, "%s: type is %s", function, childtype2string(type));
1452
1453 if (sockscf.state.highestfdinuse == 0)
1454 freedescriptors(NULL, &sockscf.state.highestfdinuse);
1455
1456 /*
1457 * create datapipe ...
1458 */
1459 if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, datapipev) != 0) {
1460 swarn("%s: socketpair(AF_LOCAL, SOCK_DGRAM)", function);
1461 return NULL;
1462 }
1463
1464 /* ... and ackpipe. */
1465 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, ackpipev) != 0) {
1466 swarn("%s: socketpair(AF_LOCAL, SOCK_STREAM)", function);
1467
1468 closev(ELEMENTS(datapipev), datapipev);
1469 return NULL;
1470 }
1471
1472 /*
1473 * Need to set the datapipe non-blocking too, even though it's a
1474 * DGRAM-based pipe, or we will block on read/write, because it's
1475 * AF_LOCAL?
1476 */
1477
1478 #if HAVE_VALGRIND_VALGRIND_H
1479 if (RUNNING_ON_VALGRIND)
1480 reason = "pipe between moter and child (probable Valgrind bug)";
1481 else
1482 reason = "pipe between moter and child";
1483 #else /* !HAVE_VALGRIND_VALGRIND_H */
1484 reason = "pipe between moter and child";
1485 #endif /* !HAVE_VALGRIND_VALGRIND_H */
1486
1487 if (setnonblocking(ackpipev[0], reason) == -1
1488 || setnonblocking(ackpipev[1], reason) == -1
1489 || setnonblocking(datapipev[0], reason) == -1
1490 || setnonblocking(datapipev[1], reason) == -1) {
1491 #if HAVE_VALGRIND_VALGRIND_H
1492 if (RUNNING_ON_VALGRIND) {
1493 /*
1494 * Valgrind seems to have some problems with programs that
1495 * increase the max number of open files in some cases.
1496 * Ref http://sourceforge.net/mailarchive/forum.php?thread_name=4F3F7A23.8020808%40gentoo.org&forum_name=valgrind-users
1497 */
1498
1499 if (fdisopen(datapipev[0]))
1500 close(datapipev[0]);
1501 else
1502 swarn("%s: probable valgrind bug triggered", function);
1503
1504 if (fdisopen(datapipev[1]))
1505 close(datapipev[1]);
1506 else
1507 slog(LOG_NOTICE, "%s: probable valgrind bug triggered", function);
1508
1509 if (fdisopen(ackpipev[0]))
1510 close(ackpipev[0]);
1511 else
1512 slog(LOG_NOTICE, "%s: probable valgrind bug triggered", function);
1513
1514 if (fdisopen(ackpipev[1]))
1515 close(ackpipev[1]);
1516 else
1517 slog(LOG_NOTICE, "%s: probable valgrind bug triggered", function);
1518
1519 return NULL;
1520 }
1521 #endif /* HAVE_VALGRIND_VALGRIND_H */
1522
1523 closev(ELEMENTS(datapipev), datapipev);
1524 closev(ELEMENTS(ackpipev), ackpipev);
1525
1526 return NULL;
1527 }
1528
1529 /*
1530 * Try to set socket buffers to a optimal size depending on the size of
1531 * the data that passes over the pipes. Could fine tune this further by
1532 * differentiating between snd/rcv-sizes for mother/child, but not
1533 * bothering with that at the moment.
1534 */
1535 switch (setchildtype(type, &childv, &childc, &childfunction)) {
1536 case PROC_MONITOR:
1537 /* only exit message is expected, so set to some small size. */
1538 sndbuf = sizeof(SOCKD_EXITNORMALLY);
1539 rcvbuf = sizeof(SOCKD_EXITNORMALLY);
1540 break;
1541
1542 case PROC_NEGOTIATE:
1543 /*
1544 * A negotiator child receives a sockd_client_t struct,
1545 * and sends back a sockd_request_t struct.
1546 */
1547 rcvbuf = (MAX(sizeof(sockd_client_t), sizeof(sockd_request_t))
1548 + sizeof(struct msghdr)
1549 + CMSG_SPACE(sizeof(int)) * FDPASS_MAX);
1550
1551 rcvbuf += SENDMSG_PADBYTES;
1552
1553 #if HAVE_GSSAPI
1554 rcvbuf += (MAX_GSS_STATE + sizeof(struct iovec));
1555 #endif /* HAVE_GSSAPI */
1556
1557 sndbuf = rcvbuf * SOCKD_NEGOTIATEMAX;
1558 break;
1559
1560 case PROC_REQUEST:
1561 /*
1562 * A request child receives a sockd_request_t structure,
1563 * it sends back a sockd_io_t structure.
1564 */
1565 rcvbuf = (MAX(sizeof(sockd_request_t), sizeof(sockd_io_t))
1566 + sizeof(struct msghdr)
1567 + CMSG_SPACE(sizeof(int)) * FDPASS_MAX);
1568
1569 rcvbuf += SENDMSG_PADBYTES;
1570
1571 #if HAVE_GSSAPI
1572 rcvbuf += (MAX_GSS_STATE + sizeof(struct iovec));
1573 #endif /* HAVE_GSSAPI */
1574
1575 sndbuf = rcvbuf * SOCKD_REQUESTMAX;
1576 break;
1577
1578 case PROC_IO:
1579 /*
1580 * A io child receives a sockd_io_t structure,
1581 * it sends back only an ack-byte.
1582 * XXX that is not true in COVENANT's case.
1583 */
1584 rcvbuf = (sizeof(sockd_io_t)
1585 + sizeof(struct msghdr)
1586 + CMSG_SPACE(sizeof(int)) * FDPASS_MAX);
1587
1588 rcvbuf += SENDMSG_PADBYTES;
1589
1590 #if HAVE_GSSAPI
1591 rcvbuf += (MAX_GSS_STATE + sizeof(struct iovec));
1592 #endif /* HAVE_GSSAPI */
1593
1594 sndbuf = rcvbuf * SOCKD_IOMAX;
1595 break;
1596
1597 default:
1598 SERRX(type);
1599 }
1600
1601 min = rcvbuf;
1602
1603 if (HAVE_PIPEBUFFER_SEND_BASED)
1604 ; /* as expected. */
1605 else if (HAVE_PIPEBUFFER_RECV_BASED) {
1606 /*
1607 * reverse of our assumption that how much we can write to the pipe
1608 * depends on the pipe's sndbuf. On this platform it instead depends
1609 * on the pipe's rcvbuf.
1610 */
1611 const size_t tmp = sndbuf;
1612 sndbuf = rcvbuf;
1613 rcvbuf = tmp;
1614 }
1615 else if (HAVE_PIPEBUFFER_UNKNOWN) { /* wastes a lot of memory. */
1616 rcvbuf = MAX(sndbuf, rcvbuf);
1617 sndbuf = MAX(sndbuf, rcvbuf);
1618 }
1619
1620 #ifdef SO_RCVBUFFORCE
1621 if (sockscf.state.haveprivs) {
1622 optname_rcvbuf = SO_RCVBUFFORCE;
1623 sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_ON);
1624 }
1625 else
1626 #endif /* !SO_RCVBUFFORCE */
1627 optname_rcvbuf = SO_RCVBUF;
1628
1629 p = rcvbuf;
1630 do {
1631 if (setsockopt(datapipev[MOTHER],
1632 SOL_SOCKET,
1633 optname_rcvbuf,
1634 &p,
1635 sizeof(p)) != 0
1636 || setsockopt(datapipev[CHILD],
1637 SOL_SOCKET,
1638 optname_rcvbuf,
1639 &p,
1640 sizeof(p)) != 0) {
1641 slog(LOG_DEBUG, "%s: could not set SO_RCVBUF to %d: %s",
1642 function, p, strerror(errno));
1643
1644 p -= min;
1645 }
1646 else
1647 break;
1648 } while (p > min);
1649
1650 #ifdef SO_RCVBUFFORCE
1651 if (sockscf.state.haveprivs)
1652 sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_OFF);
1653 #endif /* !SO_RCVBUFFORCE */
1654
1655 optlen = sizeof(rcvbuf_set1);
1656 if (getsockopt(datapipev[MOTHER],
1657 SOL_SOCKET,
1658 SO_RCVBUF,
1659 &rcvbuf_set1,
1660 &optlen) != 0
1661 || getsockopt(datapipev[CHILD],
1662 SOL_SOCKET,
1663 SO_RCVBUF,
1664 &rcvbuf_set2,
1665 &optlen) != 0) {
1666 swarn("%s: could not get size of SO_RCVBUF", function);
1667
1668 closev(ELEMENTS(datapipev), datapipev);
1669 closev(ELEMENTS(ackpipev), ackpipev);
1670
1671 return NULL;
1672 }
1673
1674 #ifdef SO_SNDBUFFORCE
1675 if (sockscf.state.haveprivs) {
1676 optname_sndbuf = SO_SNDBUFFORCE;
1677 sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_ON);
1678 }
1679 else
1680 #endif /* !SO_SNDBUFFORCE */
1681 optname_sndbuf = SO_SNDBUF;
1682
1683 p = sndbuf;
1684 do {
1685 if (setsockopt(datapipev[MOTHER],
1686 SOL_SOCKET,
1687 optname_sndbuf,
1688 &p,
1689 sizeof(p)) != 0
1690 || setsockopt(datapipev[CHILD],
1691 SOL_SOCKET,
1692 optname_sndbuf,
1693 &p,
1694 sizeof(p)) != 0) {
1695
1696 slog(LOG_DEBUG, "%s: could not set SO_SNDBUF to %d: %s",
1697 function, p, strerror(errno));
1698
1699 p -= min;
1700 }
1701 else
1702 break;
1703 } while (p > min);
1704
1705 #ifdef SO_SNDBUFFORCE
1706 if (sockscf.state.haveprivs)
1707 sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_OFF);
1708 #endif /* !SO_SNDBUFFORCE */
1709
1710 optlen = sizeof(sndbuf_set1);
1711 if (getsockopt(datapipev[MOTHER],
1712 SOL_SOCKET,
1713 SO_SNDBUF,
1714 &sndbuf_set1,
1715 &optlen) != 0
1716 || getsockopt(datapipev[CHILD],
1717 SOL_SOCKET,
1718 SO_SNDBUF,
1719 &sndbuf_set2,
1720 &optlen) != 0) {
1721 swarn("%s: could not get size of SO_SNDBUF", function);
1722
1723 closev(ELEMENTS(datapipev), datapipev);
1724 closev(ELEMENTS(ackpipev), ackpipev);
1725
1726 return NULL;
1727 }
1728
1729
1730 if (rcvbuf_set1 < rcvbuf || rcvbuf_set2 < rcvbuf
1731 || sndbuf_set1 < sndbuf || sndbuf_set2 < sndbuf) {
1732 const int isfatal = (rcvbuf_set1 < min || rcvbuf_set2 < min
1733 || sndbuf_set1 < min || sndbuf_set2 < min);
1734 char *value;
1735 int loggedalready;
1736
1737 switch (type) {
1738 case PROC_NEGOTIATE: {
1739 static int local_loggedalready;
1740
1741 loggedalready = local_loggedalready;
1742 local_loggedalready = 1;
1743
1744 value = "SOCKD_NEGOTIATEMAX";
1745 break;
1746 }
1747
1748 case PROC_REQUEST: {
1749 static int local_loggedalready;
1750
1751 loggedalready = local_loggedalready;
1752 local_loggedalready = 1;
1753
1754 value = "SOCKD_REQUESTMAX";
1755 break;
1756 }
1757
1758 case PROC_IO: {
1759 static int local_loggedalready;
1760
1761 loggedalready = local_loggedalready;
1762 local_loggedalready = 1;
1763
1764 value = "SOCKD_IOMAX";
1765 break;
1766 }
1767
1768 case PROC_MONITOR: {
1769 /*
1770 * Very strange. Our requested size should be minimal.
1771 */
1772 static int local_loggedalready;
1773
1774 loggedalready = local_loggedalready;
1775 local_loggedalready = 1;
1776
1777 value = "N/A";
1778 break;
1779 }
1780
1781 default:
1782 SERRX(type);
1783 }
1784
1785 /*
1786 * Ideally we should shrink the size of the objects we IPC around.
1787 * Keep this message to remind ourselves.
1788 */
1789 #if PRERELEASE
1790 slog(isfatal ? LOG_WARNING : (loggedalready ? LOG_DEBUG : LOG_NOTICE),
1791 #else /* !PRERELEASE */
1792 slog(isfatal ? LOG_WARNING : (loggedalready ? LOG_DEBUG : LOG_DEBUG),
1793 #endif /* !PRERELEASE */
1794
1795 "%s: kernel did not honour requested size concerning send/receive "
1796 "buffers for IPC between mother and child processes. "
1797 "Requested send size: %d, returned: %d and %d. "
1798 "Requested receive size: %d, returned: %d and %d. "
1799 "This probably means %s's %s was at compile-time set to a value "
1800 "too large for the current kernel settings. "
1801 "To avoid this warning you will need to either increase the "
1802 "kernel's max-size socket buffers somehow, or decrease the %s "
1803 "value in %s and recompile. "
1804 "%s",
1805 function,
1806 sndbuf, sndbuf_set1, sndbuf_set2,
1807 rcvbuf, rcvbuf_set1, rcvbuf_set2,
1808 PRODUCT,
1809 value,
1810 value,
1811 PRODUCT,
1812 isfatal ? "" : "We will continue with the smaller buffersize, as "
1813 "if our internal maxvalue was reduced, but "
1814 "performance might be degraded");
1815
1816 if (isfatal) {
1817 closev(ELEMENTS(datapipev), datapipev);
1818 closev(ELEMENTS(ackpipev), ackpipev);
1819
1820 return NULL;
1821 }
1822 }
1823
1824 /*
1825 * All set to create the new child. Update highestfdinuse now.
1826 * Never mind that it will not be exactly the same in child and
1827 * mother. The important thing is that the value saved is not lower
1828 * than what the value really is.
1829 */
1830 sockscf.state.highestfdinuse = MAX(sockscf.state.highestfdinuse,
1831 MAX(datapipev[0], datapipev[1]));
1832
1833 sockscf.state.highestfdinuse = MAX(sockscf.state.highestfdinuse,
1834 MAX(ackpipev[0], ackpipev[1]));
1835
1836 slog(LOG_DEBUG, "%s: highest fd in use at the moment: %d",
1837 function, sockscf.state.highestfdinuse);
1838
1839 /*
1840 * Temporarily block signals to avoid mixing up signals to us
1841 * and to child created as well as any races between child receiving
1842 * signal and child having finished setting up signalhandlers.
1843 */
1844 (void)sigfillset(&all);
1845 if (sigprocmask(SIG_SETMASK, &all, &oldmask) != 0)
1846 swarn("%s: sigprocmask(SIG_SETMASK)", function);
1847
1848 switch ((pid = fork())) {
1849 case -1:
1850 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
1851 swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
1852
1853 swarn("%s: fork()", function);
1854
1855 closev(ELEMENTS(datapipev), datapipev);
1856 closev(ELEMENTS(ackpipev), ackpipev);
1857
1858 return NULL;
1859
1860 case 0: {
1861 struct sigaction sigact;
1862 size_t i, maxfd;
1863
1864 #if HAVE_PROFILING && HAVE_MONCONTROL /* XXX is this only needed on Linux? */
1865 moncontrol(1);
1866 #endif /* HAVE_PROFILING && HAVE_MONCONTROL */
1867
1868 bzero(&sigact, sizeof(sigact));
1869
1870 /*
1871 * signals mother has set up but which we need ignore at this
1872 * point, lest we accidentally run mothers signal handler if the
1873 * child does not install it's own signal handler for the
1874 * particular signal.
1875 * Later on, the child sets up its own signal handlers.
1876 */
1877 #if HAVE_BSDAUTH
1878 /*
1879 * For BSD authentication on OpenBSD, libc forks sub process,
1880 * so SIG_DFL is needed for waitpid() to work.
1881 */
1882 sigact.sa_handler = SIG_DFL;
1883 #else /* !HAVE_BSDAUTH */
1884 sigact.sa_handler = SIG_IGN;
1885 #endif /* !HAVE_BSDAUTH */
1886
1887 if (sigaction(SIGCHLD, &sigact, NULL) != 0)
1888 swarn("%s: sigaction(SIGCHLD)", function);
1889
1890 sigact.sa_handler = SIG_IGN;
1891
1892 #if HAVE_SIGNAL_SIGINFO
1893 if (sigaction(SIGINFO, &sigact, NULL) != 0)
1894 swarn("%s: sigaction(SIGINFO)", function);
1895 #endif /* HAVE_SIGNAL_SIGINFO */
1896
1897 if (sigaction(SIGUSR1, &sigact, NULL) != 0)
1898 swarn("%s: sigaction(SIGUSR1)", function);
1899
1900 /*
1901 * Next install a SIGHUP handler. Same for all children and
1902 * different from the one mother uses.
1903 */
1904 sigact.sa_flags = SA_RESTART | SA_NOCLDSTOP | SA_SIGINFO;
1905
1906 sigact.sa_sigaction = sighup_child;
1907 if (sigaction(SIGHUP, &sigact, NULL) != 0)
1908 serr("%s: could not install signalhandler for SIGHUP", function);
1909
1910 mother.s = datapipev[CHILD];
1911 mother.ack = ackpipev[CHILD];
1912 sockscf.state.type = type;
1913
1914 newprocinit();
1915 postconfigloadinit(); /* may be something special for this process. */
1916
1917 #if 0
1918 slog(LOG_DEBUG, "sleeping...");
1919 sleep(20);
1920 #endif
1921
1922 /*
1923 * It would be nice to be able to lose all root privileges here
1924 * but unfortunately we can't. All children may need it for
1925 * re-opening logfiles or sockd.conf on SIGHUP. In addition:
1926 *
1927 * monitor children:
1928 * - Nothing known.
1929 *
1930 * negotiation children:
1931 * - could need privileges to check password.
1932 *
1933 * request children:
1934 * - could need privileges to bind port.
1935 * - could need privileges to check password.
1936 *
1937 * io children:
1938 * - could need privileges to create a raw socket to listen
1939 * for icmp errors.
1940 * - could need privileges to bind port if using the
1941 * redirect() module.
1942 *
1943 * Also may need it to write to the logfiles.
1944 * If we have privilege-support, give up what we can though.
1945 */
1946
1947 switch (type) {
1948 case PROC_MONITOR:
1949 break;
1950
1951 case PROC_NEGOTIATE:
1952 #if HAVE_LIBWRAP
1953 #if SOCKD_NEGOTIATEMAX > 1
1954 resident = 1;
1955 #endif /* SOCKD_NEGOTIATEMAX > 1 */
1956 #endif /* HAVE_LIBWRAP */
1957
1958 #if HAVE_PRIVILEGES
1959 if (sockscf.state.haveprivs) {
1960 /* don't need this privilege so permanently loose it. */
1961 priv_delset(sockscf.privileges.privileged, PRIV_NET_PRIVADDR);
1962
1963 if (setppriv(PRIV_SET,
1964 PRIV_PERMITTED,
1965 sockscf.privileges.privileged) != 0)
1966 swarn("%s: setppriv() failed to relinquish "
1967 "PRIV_NET_PRIVADDR",
1968 function);
1969 }
1970 #endif /* HAVE_PRIVILEGES */
1971
1972 break;
1973
1974 case PROC_REQUEST:
1975 #if HAVE_LIBWRAP
1976 #if SOCKD_REQUESTMAX > 1
1977 resident = 1;
1978 #endif /* SOCKD_REQUESTMAX > 1 */
1979 #endif /* HAVE_LIBWRAP */
1980 break;
1981
1982 case PROC_IO:
1983 #if HAVE_LIBWRAP
1984 #if SOCKD_IOMAX > 1
1985 resident = 1;
1986 #endif /* SOCKD_IOMAX > 1 */
1987 #endif /* HAVE_LIBWRAP */
1988 break;
1989
1990 default:
1991 SERRX(type);
1992 }
1993
1994 /*
1995 * delete all fd's we got from parent, with a few exceptions.
1996 */
1997
1998 maxfd = (size_t)sockscf.state.highestfdinuse;
1999 SASSERTX(maxfd != 0);
2000
2001 for (i = 0; i <= maxfd; ++i) {
2002 /*
2003 * exceptions.
2004 */
2005
2006 if (i == (size_t)mother.s || i == (size_t)mother.ack)
2007 continue;
2008
2009 if (descriptorisreserved((int)i))
2010 continue;
2011
2012 (void)close((int)i);
2013 }
2014
2015 /*
2016 * Needs to be called again after closing, since if using syslog we
2017 * don't know what descriptor that uses, so it will have been closed
2018 * in the above close(2) loop.
2019 *
2020 * This must happen as the first thing after the above loop as
2021 * newprocinit() will close the old syslog descriptor, if any,
2022 * before opening a new one. If we have started to use the
2023 * descriptor for something else already (e.g. due to dup(2)),
2024 * newprocinit(), will still close the old descriptor, even
2025 * though it's no longer a syslog descriptor.
2026 */
2027 newprocinit();
2028
2029 /*
2030 * This is minor optimization to make things faster for select(2)
2031 * by avoiding having two increasingly high-numbered descriptors
2032 * to check for, with most of the other descriptors in the lower-end.
2033 */
2034
2035 datapipev[0] = mother.s;
2036 datapipev[1] = mother.ack;
2037
2038 if ((mother.s = dup(mother.s)) == -1
2039 || (mother.ack = dup(mother.ack)) == -1)
2040 serr("%s: failed to dup(2) pipe to mother", function);
2041
2042 close(datapipev[0]);
2043 close(datapipev[1]);
2044
2045 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
2046 swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
2047
2048 /*
2049 * Ok, all set for this process.
2050 */
2051
2052 slog(LOG_DEBUG, "%s: I am a new %s with data-pipe %d and ack-pipe %d",
2053 function, childtype2string(type), mother.s, mother.ack);
2054
2055 sockscf.state.mother = mother;
2056 time_monotonic(&sockscf.stat.boot);
2057
2058 errno = 0;
2059 childfunction();
2060 /* NOTREACHED */
2061 break;
2062 }
2063
2064 default: {
2065 sockd_child_t *p;
2066
2067 if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
2068 swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
2069
2070 if ((p = realloc(*childv, sizeof(**childv) * (*childc + 1))) == NULL) {
2071 swarn("%s: %s", function, NOMEM);
2072
2073 closev(ELEMENTS(datapipev), datapipev);
2074 closev(ELEMENTS(ackpipev), ackpipev);
2075
2076 return NULL;
2077 }
2078 *childv = p;
2079
2080 bzero(&((*childv)[*childc]), sizeof((*childv)[*childc]));
2081
2082 time_monotonic(&(*childv)[*childc].created);
2083 (*childv)[*childc].type = type;
2084 (*childv)[*childc].pid = pid;
2085 (*childv)[*childc].s = datapipev[MOTHER];
2086 (*childv)[*childc].ack = ackpipev[MOTHER];
2087
2088 close(datapipev[CHILD]);
2089 close(ackpipev[CHILD]);
2090
2091 slog(LOG_DEBUG,
2092 "%s: created new %s with pid %ld, data-pipe %d and ack-pipe %d. "
2093 "Minimum rcvbuf: %d, set: %d and %d. "
2094 "Minimum sndbuf: %d, set: %d and %d",
2095 function,
2096 childtype2string((*childv)[*childc].type),
2097 (long)(*childv)[*childc].pid,
2098 (*childv)[*childc].s,
2099 (*childv)[*childc].ack,
2100 rcvbuf, rcvbuf_set1, rcvbuf_set2,
2101 sndbuf, sndbuf_set1, sndbuf_set2);
2102
2103 switch ((*childv)[*childc].type) {
2104 case PROC_MONITOR:
2105 /*
2106 * Doesn't really have slots, so just set 1. Will remain
2107 * at one for the entire lifespans, as there are no slots.
2108 */
2109 (*childv)[*childc].freec = 1;
2110 break;
2111
2112 case PROC_NEGOTIATE:
2113 (*childv)[*childc].freec = SOCKD_NEGOTIATEMAX;
2114 break;
2115
2116 case PROC_REQUEST:
2117 (*childv)[*childc].freec = SOCKD_REQUESTMAX;
2118 break;
2119
2120 case PROC_IO:
2121 (*childv)[*childc].freec = SOCKD_IOMAX;
2122 break;
2123
2124 default:
2125 SERRX((*childv)[*childc].type);
2126 }
2127 }
2128 }
2129
2130 return &(*childv)[(*childc)++];
2131 }
2132
2133
2134 static int
setchildtype(type,childv,childc,function)2135 setchildtype(type, childv, childc, function)
2136 int type;
2137 sockd_child_t ***childv;
2138 size_t **childc;
2139 void (**function)(void);
2140 {
2141 size_t *c;
2142 sockd_child_t **v;
2143 void (*f)(void);
2144
2145 switch (type) {
2146 case PROC_MONITOR:
2147 c = &monitorc;
2148 v = &monitorv;
2149 f = &run_monitor;
2150 break;
2151
2152 case PROC_NEGOTIATE:
2153 c = &negchildc;
2154 v = &negchildv;
2155 f = &run_negotiate;
2156 break;
2157
2158 case PROC_IO:
2159 c = &iochildc;
2160 v = &iochildv;
2161 f = &run_io;
2162 break;
2163
2164 case PROC_REQUEST:
2165 c = &reqchildc;
2166 v = &reqchildv;
2167 f = &run_request;
2168 break;
2169
2170 default:
2171 SERRX(type);
2172 }
2173
2174 if (childv != NULL)
2175 *childv = v;
2176
2177 if (childc != NULL)
2178 *childc = c;
2179
2180 if (function != NULL)
2181 *function = f;
2182
2183 SASSERTX(c != NULL);
2184 SASSERTX(v != NULL);
2185 SASSERTX(f != NULL);
2186
2187 return type;
2188 }
2189
2190 static ssize_t
findchild(pid,childc,childv)2191 findchild(pid, childc, childv)
2192 pid_t pid;
2193 size_t childc;
2194 const sockd_child_t *childv;
2195 {
2196 static size_t i;
2197
2198 if (i < childc && childv[i].pid == pid)
2199 return i;
2200
2201 for (i = 0; i < childc; ++i)
2202 if (childv[i].pid == pid)
2203 return i;
2204
2205 return -1;
2206 }
2207
2208
2209 /* ARGSUSED */
2210 void
sighup_child(sig,si,sc)2211 sighup_child(sig, si, sc)
2212 int sig;
2213 siginfo_t *si;
2214 void *sc;
2215 {
2216 const char *function = "sighup_child()";
2217 const int errno_s = errno;
2218 struct config *shmemconfig, config;
2219 ptrdiff_t offset;
2220 #if DIAGNOSTIC
2221 size_t i;
2222 #endif /* DIAGNOSTIC */
2223
2224 SIGNAL_PROLOGUE(sig, si, errno_s);
2225
2226 /*
2227 * we are not main mother. Can we assume the signal is from mother?
2228 * If not, ignore it.
2229 * Some systems don't set si_pid correctly, so check if the value is set
2230 * first.
2231 */
2232 if (si->si_pid != 0 /* some systems don't fill this in. */
2233 && !pidismother(si->si_pid)) {
2234 swarnx("%s: received SIGHUP from pid %ld, but only expecting it from "
2235 "mother (pid %ld). Ignored",
2236 function, (long)si->si_pid, (long)getppid());
2237
2238 return;
2239 }
2240
2241 if (sockscf.shmeminfo->configsize == 0) {
2242 swarnx("%s: Strange. Received a SIGHUP signal, but the size of "
2243 "mother's shmemconfig is zero, which does not make sense. "
2244 "Ignoring it",
2245 function);
2246 return;
2247 }
2248
2249 slog(LOG_INFO, "%s: received SIGHUP: reloading config", function);
2250
2251 socks_lock(sockscf.shmemconfigfd, 0, 0, 0, 1);
2252
2253 #if 1
2254 shmemconfig = sockd_mmap(NULL,
2255 sockscf.shmeminfo->configsize,
2256 /*
2257 * Need PROT_WRITE also as we may need to adjust
2258 * the pointer addresses before accessing.
2259 */
2260 PROT_READ | PROT_WRITE,
2261 MAP_PRIVATE,
2262 sockscf.shmemconfigfd,
2263 0);
2264
2265 #else /* just for testing */
2266 shmemconfig = mmap((void *)((uintptr_t)sockscf.shmeminfo->config
2267 + sockscf.state.pagesize),
2268 sockscf.shmeminfo->configsize,
2269 /*
2270 * Need PROT_WRITE also as we update
2271 * the pointer addresses as we go.
2272 */
2273 PROT_READ | PROT_WRITE,
2274 MAP_PRIVATE | MAP_FIXED,
2275 sockscf.shmemconfigfd,
2276 0);
2277 #endif /* just for testing. */
2278
2279 if (shmemconfig == MAP_FAILED) {
2280 swarn("%s: could not mmap(2) %lu bytes of memory for config reload",
2281 function, (unsigned long)sockscf.shmeminfo->configsize);
2282
2283 socks_unlock(sockscf.shmemconfigfd, 0, 0);
2284 return;
2285 }
2286
2287 offset = (uintptr_t)shmemconfig - (uintptr_t)sockscf.shmeminfo->config;
2288
2289 slog(LOG_DEBUG,
2290 "%s: mmap(2)-ed %lu bytes of memory at offset %p. "
2291 "Mothers offset is at %p, %ld bytes away",
2292 function,
2293 (unsigned long)sockscf.shmeminfo->configsize,
2294 shmemconfig,
2295 sockscf.shmeminfo->config,
2296 (long)offset);
2297
2298 /*
2299 * shallow copy what we can.
2300 */
2301
2302 config = *shmemconfig;
2303
2304 if (pointer_copy(shmemconfig, offset, &config, NULL, 0) != 0) {
2305 swarnx("%s: could not update pointers in config-object after reload",
2306 function);
2307
2308 if (munmap(shmemconfig, sockscf.shmeminfo->configsize) != 0)
2309 swarn("%s: munmap(%p, %lu) failed",
2310 function,
2311 shmemconfig,
2312 (unsigned long)sockscf.shmeminfo->configsize);
2313
2314 socks_unlock(sockscf.shmemconfigfd, 0, 0);
2315 return;
2316 }
2317
2318
2319 #if DIAGNOSTIC
2320 slog(LOG_DEBUG, "%s: updated config, doing compare test ...", function);
2321 i = compareconfigs(shmemconfig, &config);
2322 #endif /* DIAGNOSTIC */
2323
2324 if (munmap(shmemconfig, sockscf.shmeminfo->configsize) != 0)
2325 swarn("%s: munmap(%p, %lu) failed",
2326 function,
2327 shmemconfig,
2328 (unsigned long)sockscf.shmeminfo->configsize);
2329
2330 #if DIAGNOSTIC
2331 if (i == 0) {
2332 swarnx("%s: created config not identical to config in shmem", function);
2333 return;
2334 }
2335 else
2336 slog(LOG_DEBUG,
2337 "%s: created config identical to shmem config. %lu bytes compared",
2338 function, (unsigned long)i);
2339 #endif /* DIAGNOSTIC */
2340
2341 socks_unlock(sockscf.shmemconfigfd, 0, 0);
2342
2343 SASSERTX(!pidismainmother(sockscf.state.pid));
2344
2345 SASSERTX(config.state.type == sockscf.state.type);
2346
2347 resetconfig(&sockscf, 0); /* reset old before loading new. */
2348
2349 SASSERTX(config.state.type == sockscf.state.type);
2350
2351 /*
2352 * needs to be handled specially.
2353 */
2354
2355 sockd_freelogobject(&sockscf.errlog, 1);
2356 sockd_reopenlogfiles(&config.errlog, 0);
2357
2358 sockd_freelogobject(&sockscf.log, 1);
2359 sockd_reopenlogfiles(&config.log, 0);
2360
2361 sockscf = config;
2362
2363 #if DIAGNOSTIC
2364 /*
2365 * compareconfig() will dereference pointers. If there's something left
2366 * pointing to the shmem by mistake, things will hopefully crash now.
2367 */
2368 SASSERTX(compareconfigs(&sockscf, &config) != 0);
2369 #endif /* DIAGNOSTIC */
2370
2371 postconfigloadinit();
2372
2373 if (pidismother(sockscf.state.pid))
2374 sigchildbroadcast(sig); /* each mother process has its own children. */
2375
2376 resetprivileges();
2377
2378 time_monotonic(&sockscf.stat.configload);
2379
2380 SIGNAL_EPILOGUE(sig, si, errno_s);
2381 }
2382