1 /*
2  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3  *               2008, 2009, 2010, 2011, 2012, 2013, 2014, 2019, 2020, 2021
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: serverconfig.c,v 1.567.4.12.6.14 2021/03/24 23:06:07 karls Exp $";
49 
50 static int
51 safamily_isenabled(const sa_family_t family, const char *addrstr,
52                    const interfaceside_t side);
53 /*
54  * Returns true if the address family "family" is enabled on the
55  * interface-side "side".  "addrstr" is a printable representation of
56  * the address we tried to add.
57  *
58  * Returns false if the address family "family" is not enabled.
59  */
60 
61 static int addexternaladdr(const struct ruleaddr_t *ra);
62 /*
63  * Returns 0 if the address "ra" was addedd to the list of external addresses.
64  *
65  * Returns -1 if the address "ra" was not added for a non-fatal reason,
66  * after loging a message if apropriate.
67  */
68 
69 static int addinternaladdr(const char *ifname,
70                            const struct sockaddr_storage *sa,
71                            const int protocol);
72 /*
73  * Returns 0 if the address "ra" was addedd to the list of internal addresses.
74  *
75  * Returns -1 if the address "ra" was not added for a non-fatal reason,
76  * after loging a message if apropriate.
77  */
78 
79 
80 static void
81 add_more_old_shmem(struct config *config, const size_t memc,
82                    const oldshmeminfo_t memv[]);
83 /*
84  * Adds "memv" to the list of old shmem entries stored in "config".
85  */
86 
87 struct config sockscf;        /* current config.   */
88 
89 void
addinternal(addr,protocol)90 addinternal(addr, protocol)
91    const ruleaddr_t *addr;
92    const int protocol;
93 {
94    const char *function = "addinternal()";
95    struct sockaddr_storage sa;
96    char ifname[MAXIFNAMELEN];
97    int changesupported;
98 
99    if (sockscf.option.serverc == 1
100    ||  sockscf.state.inited   == 0
101    ||  protocol               == SOCKS_UDP)
102       changesupported = 1;
103    else
104       changesupported = 0;
105 
106    slog(LOG_DEBUG, "%s: (%s, %s).  Change supported: %d",
107         function,
108         ruleaddr2string(addr,
109                         ADDRINFO_PORT | ADDRINFO_ATYPE,
110                         NULL,
111                         0),
112         protocol2string(protocol),
113         changesupported);
114 
115    switch (addr->atype) {
116        case SOCKS_ADDR_IPV4:
117        case SOCKS_ADDR_IPV6:
118          if (addr->atype == SOCKS_ADDR_IPV4)
119             SASSERTX(addr->addr.ipv4.mask.s_addr == htonl(IPV4_FULLNETMASK));
120          else if (addr->atype == SOCKS_ADDR_IPV6)
121             SASSERTX(addr->addr.ipv6.maskbits    == IPV6_NETMASKBITS);
122 
123          ruleaddr2sockaddr(addr, &sa, protocol);
124 
125          if (!PORTISBOUND(&sa))
126             yyerrorx("%s: address %s does not specify a portnumber to bind",
127                      function, sockaddr2string(&sa, NULL, 0));
128 
129          if (addrindex_on_listenlist(sockscf.internal.addrc,
130                                      sockscf.internal.addrv,
131                                      &sa,
132                                      protocol) == -1) {
133             if (!changesupported) {
134                yywarnx("cannot change internal addresses once running.  "
135                        "%s looks like a new address and will be ignored",
136                        sockaddr2string(&sa, NULL, 0));
137 
138                break;
139             }
140          }
141          else {
142             /*
143              * Already here, but do make sure to update globalstate to reflect
144              * it too.
145              */
146             add_internal_safamily(sa.ss_family);
147             break;
148          }
149 
150          if (sa.ss_family == AF_INET
151          &&  TOIN(&sa)->sin_addr.s_addr == htonl(INADDR_ANY))
152             STRCPY_ASSERTSIZE(ifname, "<any IPv4-interface>");
153          else if (sa.ss_family == AF_INET6
154          &&  memcmp(&TOIN6(&sa)->sin6_addr,
155                     &in6addr_any,
156                     sizeof(in6addr_any)) == 0)
157             STRCPY_ASSERTSIZE(ifname, "<any IPv6-interface>");
158          else if (sockaddr2ifname(&sa, ifname, sizeof(ifname)) == NULL) {
159             /*
160              * Probably config-error, but could be a bug in sockaddr2ifname(),
161              * so don't error out yet.  Will know for sure when we try to bind
162              * the address later.
163              */
164             strncpy(ifname, "<unknown>", sizeof(ifname) - 1);
165             ifname[sizeof(ifname) - 1] = NUL;
166 
167             yywarn("%s: could not find address %s on any network interface",
168                    function, sockaddr2string2(&sa, 0, NULL, 0));
169          }
170 
171          addinternaladdr(ifname, &sa, protocol);
172          break;
173 
174       case SOCKS_ADDR_DOMAIN: {
175          size_t i;
176          char emsg[1024];
177          int gaierr;
178 
179          for (i = 0;
180               hostname2sockaddr2(addr->addr.domain,
181                                  i,
182                                  &sa,
183                                  &gaierr,
184                                  emsg,
185                                  sizeof(emsg)) != NULL;
186               ++i) {
187             SET_SOCKADDRPORT(&sa,
188                              protocol == SOCKS_TCP ?
189                                        addr->port.tcp : addr->port.udp);
190 
191             if (addrindex_on_listenlist(sockscf.internal.addrc,
192                                         sockscf.internal.addrv,
193                                         &sa,
194                                         protocol) == -1) {
195                if (!changesupported) {
196                   swarnx("cannot change internal addresses once running "
197                          "and %s looks like a new address.  Ignored",
198                          sockaddr2string(&sa, NULL, 0));
199 
200                   continue;
201                }
202             }
203             else {
204                /*
205                 * Already here, but do make sure to update globalstate to
206                 * reflect it too.
207                 */
208                add_internal_safamily(sa.ss_family);
209                continue;
210             }
211 
212             if (sockaddr2ifname(&sa, ifname, sizeof(ifname)) == NULL) {
213                /*
214                 * Probably config-error, but could be bug in our
215                 * sockaddr2ifname().
216                 * Will know for sure when we try to bind the address later,
217                 * so don't error out quite yet.
218                 */
219 
220                yywarn("%s: could not find address %s (resolved from %s) on "
221                       "any network interface",
222                       function,
223                       sockaddr2string(&sa, NULL, 0),
224                       addr->addr.domain);
225 
226                STRCPY_ASSERTSIZE(ifname, "<unknown>");
227             }
228 
229             addinternaladdr(ifname, &sa, protocol);
230          }
231 
232          if (i == 0)
233             yyerrorx("%s", emsg);
234 
235          break;
236       }
237 
238       case SOCKS_ADDR_IFNAME: {
239          struct ifaddrs *ifap, *iface;
240          int isvalidif;
241 
242          ifap = NULL;
243 
244          if (getifaddrs(&ifap) != 0)
245             serr("getifaddrs()");
246 
247          SASSERTX(ifap != NULL);
248 
249          for (isvalidif = 0, iface = ifap;
250          iface != NULL;
251          iface = iface->ifa_next) {
252             if (iface->ifa_addr == NULL)
253                continue;
254 
255             if (!safamily_issupported(iface->ifa_addr->sa_family))
256                continue;
257 
258             if (strcmp(iface->ifa_name, addr->addr.ifname) != 0)
259                continue;
260 
261             isvalidif = 1;
262 
263             sockaddrcpy(&sa, TOSS(iface->ifa_addr), sizeof(sa));
264 
265             SET_SOCKADDRPORT(&sa, protocol == SOCKS_TCP ?
266                                        addr->port.tcp : addr->port.udp);
267 
268             if (addrindex_on_listenlist(sockscf.internal.addrc,
269                                         sockscf.internal.addrv,
270                                         &sa,
271                                         protocol) == -1) {
272                if (!changesupported) {
273                   swarnx("cannot change internal addresses once running, "
274                          "and %s, expanded from the ifname \"%s\" looks "
275                          "like a new address.  Ignored",
276                          sockaddr2string(&sa, NULL, 0),
277                          addr->addr.ifname);
278 
279                   continue;
280                }
281             }
282             else {
283                /*
284                 * Already here, but do make sure to update globalstate to
285                 * reflect it too.
286                 */
287                add_internal_safamily(sa.ss_family);
288                continue;
289             }
290 
291             addinternaladdr(addr->addr.ifname, &sa, protocol);
292          }
293 
294          freeifaddrs(ifap);
295 
296          if (!isvalidif)
297             swarnx("cannot find interface/address for %s", addr->addr.ifname);
298 
299          break;
300       }
301 
302       default:
303          SERRX(addr->atype);
304    }
305 }
306 
307 void
addexternal(addr)308 addexternal(addr)
309    const ruleaddr_t *addr;
310 {
311    const char *function = "addexternal()";
312    ruleaddr_t ra;
313    int added_ipv4 = 0, added_ipv6 = 0, added_ipv6_gs = 0;
314 
315    SASSERTX(ntohs(addr->port.tcp) == 0);
316    SASSERTX(ntohs(addr->port.udp) == 0);
317 
318    switch (addr->atype) {
319       case SOCKS_ADDR_DOMAIN: {
320          /*
321           * XXX this is not good.  It is be better to not resolve this now,
322           * but resolve it when using.  Since we have a hostcache, that
323           * should not add too much expense.  Sending servers a SIGHUP
324           * when local addresses change is quite common though, so
325           * assume it's good enough for now.
326           */
327          struct sockaddr_storage sa;
328          size_t i;
329          char emsg[1024];
330          int gaierr;
331 
332          for (i = 0;
333          hostname2sockaddr2(addr->addr.domain,
334                             i,
335                             &sa,
336                             &gaierr,
337                             emsg,
338                             sizeof(emsg)) != NULL;
339           ++i) {
340             SET_SOCKADDRPORT(&sa, addr->port.tcp);
341 
342             sockaddr2ruleaddr(&sa, &ra);
343 
344             if (addexternaladdr(&ra) == 0) {
345                switch (sa.ss_family) {
346                   case AF_INET:
347                      added_ipv4 = 1;
348                      break;
349 
350                   case AF_INET6:
351                      added_ipv6 = 1;
352 
353                      if (!IN6_IS_ADDR_LINKLOCAL(&TOIN6(&sa)->sin6_addr))
354                         added_ipv6_gs = 1;
355 
356                      break;
357 
358                   default:
359                      SERRX(sa.ss_family);
360                }
361             }
362          }
363 
364          if (i == 0)
365             yyerrorx("%s", emsg);
366 
367          break;
368       }
369 
370       case SOCKS_ADDR_IPV4:
371          if (addr->addr.ipv4.ip.s_addr == htonl(INADDR_ANY))
372             yyerrorx("external address (%s) to connect out from cannot "
373                      "be a wildcard address",
374                      ruleaddr2string(addr, 0, NULL, 0));
375 
376          ra                       = *addr;
377          ra.addr.ipv4.mask.s_addr = htonl(IPV4_FULLNETMASK);
378 
379          if (addexternaladdr(&ra) == 0)
380             added_ipv4 = 1;
381 
382          break;
383 
384       case SOCKS_ADDR_IPV6:
385          if (memcmp(&addr->addr.ipv6.ip, &in6addr_any, sizeof(in6addr_any))
386          == 0)
387             yyerrorx("external address (%s) cannot be a wildcard address",
388                      ruleaddr2string(addr, 0, NULL, 0));
389 
390          ra                    = *addr;
391          ra.addr.ipv6.maskbits = IPV6_NETMASKBITS;
392 
393          if (addexternaladdr(&ra) == 0) {
394             added_ipv6 = 1;
395 
396             if (!IN6_IS_ADDR_LINKLOCAL(&ra.addr.ipv6.ip))
397                added_ipv6_gs = 1;
398          }
399 
400          break;
401 
402       case SOCKS_ADDR_IFNAME: {
403          /*
404           * Would be nice if this could be cached, e.g. by monitoring a
405           * routing socket for changes.  Have no code for that however.
406           */
407          struct sockaddr_storage sa, t;
408          size_t i;
409 
410          /*
411           * We add the interface, not the addresses.  But we want to
412           * know whether the addresses, at least currently, resolve
413           * to ipv4 or ipv6 so we can resolve hostnames appropriately.
414           * E.g., no need to resolve hostname to ipv6 address if we do
415           * not have ipv6 on the external interface.
416           */
417          for (i = 0;
418          ifname2sockaddr(addr->addr.ifname, i, &sa, &t) != NULL;
419          ++i) {
420             const int enabled
421             = safamily_isenabled(sa.ss_family,
422                                  sockaddr2string(&sa, NULL, 0),
423                                  EXTERNALIF);
424 
425             slog(LOG_DEBUG, "%s: ifname %s resolved to address %s.  %s",
426                  function,
427                  addr->addr.ifname,
428                  sockaddr2string2(&sa, ADDRINFO_ATYPE, NULL, 0),
429                  enabled ? "enabled" : "not enabled due to address family");
430 
431             if (!enabled)
432                continue;
433 
434             switch (sa.ss_family) {
435                case AF_INET:
436                   added_ipv4 = 1;
437                   break;
438 
439                case AF_INET6:
440                   added_ipv6 = 1;
441 
442                   if (!IN6_IS_ADDR_LINKLOCAL(&TOIN6(&sa)->sin6_addr))
443                      added_ipv6_gs = 1;
444 
445                   break;
446 
447                default:
448                   SERRX(sa.ss_family);
449             }
450          }
451 
452          /*
453           * Not resolving but adding the ifname itself.
454           */
455          (void)addexternaladdr(addr);
456 
457          break;
458       }
459 
460       default:
461          SERRX(addr->atype);
462    }
463 
464    if (added_ipv4)
465       add_external_safamily(AF_INET, 1);
466 
467    if (added_ipv6)
468       add_external_safamily(AF_INET6, added_ipv6_gs);
469 }
470 
471 void
resetconfig(config,exiting)472 resetconfig(config, exiting)
473    struct config *config;
474    const int exiting;
475 {
476    const char *function = "resetconfig()";
477    const int ismainmother = pidismainmother(config->state.pid);
478    rule_t *rulev[] = { config->crule, config->hrule, config->srule };
479    monitor_t *monitor;
480    size_t oldc, i;
481 
482    slog(LOG_DEBUG, "%s: exiting? %s, ismainmother? %s",
483         function,
484         exiting ?       "yes" : "no",
485         ismainmother?   "yes" : "no");
486 
487    if (!exiting) {
488 #if !HAVE_NO_RESOLVESTUFF
489       _res.options = config->initial.res_options;
490 #endif /* !HAVE_NO_RESOLVSTUFF */
491    }
492 
493    switch (sockscf.state.type) {
494       case PROC_MOTHER:
495          mother_preconfigload();
496          break;
497 
498       case PROC_MONITOR:
499          monitor_preconfigload();
500          break;
501 
502       case PROC_NEGOTIATE:
503          negotiate_preconfigload();
504          break;
505 
506       case PROC_REQUEST:
507          request_preconfigload();
508          break;
509 
510       case PROC_IO:
511          io_preconfigload();
512          break;
513    }
514 
515    /*
516     * config->initial: nothing to do here.
517     */
518 
519    /*
520     * Internal interface.
521     */
522 
523    if (config->option.serverc == 1 || !ismainmother) {
524       /*
525        * We only support changing these as long as we only have one mother
526        * process.
527        * If we are not the main mother, we do need to free the memory as
528        * usual however, so it will not be leaked when we realloc based on
529        * the config in shmem that main mother has now installed and from
530        * which we will update.
531        */
532 
533       free(config->internal.addrv);
534       config->internal.addrv = NULL;
535       config->internal.addrc = 0;
536 
537       bzero(&config->internal.protocol, sizeof(config->internal.protocol));
538    }
539 
540    bzero(&config->internal.log, sizeof(config->internal.log));
541 
542    /*
543     * External interface.
544     */
545 
546    /* external addresses can always be changed. */
547    free(config->external.addrv);
548    config->external.addrv = NULL;
549    config->external.addrc = 0;
550 
551    config->external.rotation = ROTATION_NOTSET;
552    bzero(&config->external.log, sizeof(config->external.log));
553    bzero(&config->external.protocol, sizeof(config->external.protocol));
554 
555    /* can always be changed from config. */
556    bzero(&config->cpu, sizeof(config->cpu));
557 
558    for (i = 0; i < ELEMENTS(rulev); ++i) {
559       rule_t *rule, prevrule, *next;
560       int haveprevrule;
561 
562       haveprevrule = 0;
563       rule         = rulev[i];
564 
565       while (rule != NULL) {
566          /*
567           * Free normal process-local memory.
568           */
569          int rule_is_autoexpanded;
570 
571 #if !HAVE_SOCKS_RULES
572          if (rule->type == object_srule) {
573             /*
574              * All pointers are pointers to the same memory in the clientrule,
575              * so it has already been freed and only the rule itself remains
576              * to be freed.
577              */
578             next = rule->next;
579             free(rule);
580             rule = next;
581 
582             continue;
583          }
584 #endif /* !HAVE_SOCKS_RULES */
585 
586          if (haveprevrule
587          &&  prevrule.type   == rule->type
588          &&  prevrule.number == rule->number) {
589             slog(LOG_DEBUG,
590                  "%s: another %s with same rule-number (%lu).  "
591                  "Must be expanded from the same \"to\"-address",
592                  function,
593                  objecttype2string(rule->type),
594                  (unsigned long)rule->number);
595 
596             rule_is_autoexpanded = 1;
597             SASSERTX(BAREFOOTD);
598          }
599          else
600             rule_is_autoexpanded = 0;
601 
602          if (!rule_is_autoexpanded)
603             /*
604              * We don't bother allocating identical memory for auto-expanded
605              * rules, so only need to free it if it is not auto-expanded.
606              */
607             freelinkedname(rule->user);
608          rule->user = NULL;
609 
610          if (!rule_is_autoexpanded)
611             freelinkedname(rule->group);
612          rule->group = NULL;
613 
614          if (!rule_is_autoexpanded)
615             free(rule->socketoptionv);
616          rule->socketoptionv = NULL;
617          rule->socketoptionc = 0;
618 
619          if (ismainmother) {
620             /*
621              * Next go through the shmem in this rule.  It's possible
622              * we have children that are still using, or about to use,
623              * these segments, so don't delete them now, but save
624              * them for later.  Only upon exit we delete them all.
625              *
626              * This means we may have a lot of unneeded shmem segments
627              * laying around, but since they are just files, rather
628              * than the, on some systems very scarce, sysv-style shmem
629              * segments, that should not be any problem.  It allows
630              * us to ignore a lot of nasty locking issues.
631              */
632             size_t moreoldshmemc = 0;
633             oldshmeminfo_t moreoldshmemv[   1 /* bw             */
634                                           + 1 /* session        */
635                                           + 1 /* session state. */
636                                         ];
637 
638             if (rule_is_autoexpanded) {
639                SASSERTX(BAREFOOTD);
640                SHMEM_CLEAR(rule, SHMEM_ALL, 1);
641             }
642             else {
643                if (rule->bw_shmid != 0) {
644                   moreoldshmemv[moreoldshmemc].id   = rule->bw_shmid;
645                   moreoldshmemv[moreoldshmemc].key  = key_unset;
646                   moreoldshmemv[moreoldshmemc].type = SHMEM_BW;
647 
648                   ++moreoldshmemc;
649                }
650 
651                if (rule->ss_shmid != 0) {
652                   /*
653                    * session-module supports statekeys too, so need to save that
654                    * too.
655                    */
656                   if (sockd_shmat(rule, SHMEM_SS) == 0) {
657                      moreoldshmemv[moreoldshmemc].id   = rule->ss_shmid;
658                      moreoldshmemv[moreoldshmemc].key  = rule->ss->keystate.key;
659                      moreoldshmemv[moreoldshmemc].type = SHMEM_SS;
660 
661                      ++moreoldshmemc;
662 
663                      sockd_shmdt(rule, SHMEM_SS);
664                   }
665                }
666 
667                if (moreoldshmemc > 0)
668                   add_more_old_shmem(config, moreoldshmemc, moreoldshmemv);
669             }
670          }
671 
672          prevrule = *rule;
673          haveprevrule = 1;
674 
675          next     = rule->next;
676          free(rule);
677          rule     = next;
678       }
679    }
680 
681    config->crule = config->hrule = config->srule = NULL;
682 
683    /* routeoptions, read from config file. */
684    bzero(&config->routeoptions, sizeof(config->routeoptions));
685 
686    /* free routes. */
687    freeroutelist(config->route);
688    config->route = NULL;
689 
690    /* and monitors. */
691    monitor = sockscf.monitor;
692    while (monitor != NULL) {
693       monitor_t *next = monitor->next;
694 
695       if (ismainmother && monitor->mstats_shmid != 0) {
696          oldshmeminfo_t moreoldshmemv[   1 /* just the monitor shmid. */ ];
697 
698          moreoldshmemv[0].id    = monitor->mstats_shmid;
699          moreoldshmemv[0].key   = key_unset;
700          moreoldshmemv[0].type  = SHMEM_MONITOR;
701 
702          add_more_old_shmem(config, ELEMENTS(moreoldshmemv), moreoldshmemv);
703       }
704 
705       free(monitor);
706       monitor = next;
707    }
708    config->monitor = NULL;
709 
710    /* monitoroptions.  Reset on each reload. */
711    bzero(&config->monitorspec, sizeof(config->monitorspec));
712 
713    free(config->socketoptionv);
714    config->socketoptionv = NULL;
715    config->socketoptionc = 0;
716 
717    /* compat, read from config file. */
718    bzero(&config->compat, sizeof(config->compat));
719 
720    /* extensions, read from config file. */
721    bzero(&config->extension, sizeof(config->extension));
722 
723    /*
724     * log, errlog; handled specially when parsing.
725     */
726 
727    /*
728     * option; some only settable at commandline, some only read from config
729     * file.  Those only read from config file will be reset to default in
730     * optioninit().
731     */
732 
733    /* resolveprotocol, read from config file. */
734    bzero(&config->resolveprotocol, sizeof(config->resolveprotocol));
735 
736    /*
737     * socketconfig, read from config file, but also has defaults set by
738     * optioninit(), so don't need to touch it.
739     */
740 
741    /* srchost, read from config file. */
742    bzero(&config->srchost, sizeof(config->srchost));
743 
744    /* stat: not touch.  Accumulated continously. */
745 
746    /*
747     * state; keep most of it, with the following exceptions:
748     */
749    /* don't want to have too much code for tracking this, so regen this now. */
750    config->state.highestfdinuse = 0;
751 
752    /* timeout, read from config file. */
753    bzero(&config->timeout, sizeof(config->timeout));
754 
755 #if HAVE_SOLARIS_PRIVS
756    /* uid; is special.  Needs clearing, but must reopen config-file first. */
757 #endif /* HAVE_SOLARIS_PRIVS */
758 
759    /* (child)state: not touched. */
760 
761 
762    /*
763     * various method settings.  All read from config file.
764     */
765 
766    bzero(config->cmethodv, sizeof(config->cmethodv));
767    config->cmethodc = 0;
768 
769    bzero(config->smethodv, sizeof(config->smethodv));
770    config->smethodc = 0;
771 
772    /* udpconnectdst.  No need to touch.  Reset to default on reload. */
773 
774 #if HAVE_LIBWRAP
775    if (config->hosts_allow_original != NULL
776    && hosts_allow_table             != config->hosts_allow_original) {
777       free(hosts_allow_table);
778       hosts_allow_table = config->hosts_allow_original;
779    }
780 
781    if (config->hosts_deny_original != NULL
782    && hosts_deny_table             != config->hosts_deny_original) {
783       free(hosts_deny_table);
784       hosts_deny_table = config->hosts_deny_original;
785    }
786 #endif /* HAVE_LIBWRAP */
787 
788    if (exiting && ismainmother && config->oldshmemc > 0) {
789       /*
790        * Go through the list of saved segments and delete them.
791        * Any (io) children using them should already have them open,
792        * and nobody not already using them should need to attach to them
793        * after we exit.  The exception is clients using the session module,
794        * where we do not keep attached to the segment, but who need to attach
795        * to it when removing the client.  Unfortunately failure to attach
796        * to a shmem segment is normally a serious error and logged as thus,
797        * but if mother has removed the segment, then obviously the other
798        * processes can not attach to it again.
799        *
800        * There is some code to only debug log failure to attach to the
801        * shmem segments (or rather, failure to open the file) if mother
802        * does not exist (presumably having deleted the files before exiting),
803        * rather than warn.  It depends on mother having exited before the
804        * child process tries to remove the client though, which may not
805        * be the case even though we do a little work to increase the odds.
806        * Worst case is that we end up with some useless warnings though,
807        * so not worth going overboard with it.
808        */
809 
810       SASSERTX(ismainmother);
811       SASSERTX(sockscf.state.type == PROC_MOTHER);
812 
813       /*
814        * Lock to increase the chance of us having time to exit before
815        * any children try to attach/detach (they will be blocked waiting for
816        * the lock).  Don't unlock ourselves, but let the kernel release the
817        * lock when we exit, further reducing gap between us exiting and
818        * a child process being able to detect it.
819        */
820       socks_lock(config->shmemfd, 0, 0, 1, 1);
821 
822       slog(LOG_DEBUG, "%s: %ld old shmem entr%s saved.  Deleting now",
823                       function, (unsigned long)config->oldshmemc,
824                       config->oldshmemc == 1 ? "y" : "ies");
825 
826       for (oldc = 0; oldc < config->oldshmemc; ++oldc) {
827          char fname[PATH_MAX];
828 
829          snprintf(fname, sizeof(fname), "%s",
830                   sockd_getshmemname(config->oldshmemv[oldc].id, key_unset));
831 
832          slog(LOG_DEBUG,
833               "%s: deleting shmem segment shmid %lu in file %s at index #%lu",
834               function,
835               (unsigned long)config->oldshmemv[oldc].id,
836               fname,
837               (unsigned long)oldc);
838 
839          if (unlink(fname) != 0)
840             swarn("%s: failed to unlink shmem segment %ld in file %s",
841                   function, config->oldshmemv[oldc].id, fname);
842 
843          if (config->oldshmemv[oldc].key != key_unset) {
844             snprintf(fname, sizeof(fname), "%s",
845                      sockd_getshmemname(config->oldshmemv[oldc].id,
846                                         config->oldshmemv[oldc].key));
847 
848             slog(LOG_DEBUG,
849                  "%s: deleting shmem segment shmid %lu/key %lu in file %s",
850                  function,
851                  (unsigned long)config->oldshmemv[oldc].id,
852                  (unsigned long)config->oldshmemv[oldc].key,
853                  fname);
854 
855             if (unlink(fname) != 0)
856                swarn("%s: failed to unlink shmem segment %ld.%d in file %s",
857                      function,
858                      config->oldshmemv[oldc].id,
859                      (int)config->oldshmemv[oldc].key,
860                      fname);
861          }
862       }
863    }
864 }
865 
866 void
freeroutelist(routehead)867 freeroutelist(routehead)
868    route_t *routehead;
869 {
870 
871    while (routehead != NULL) {
872       route_t *next = routehead->next;
873 
874       free(routehead->socketoptionv);
875       free(routehead);
876       routehead = next;
877    }
878 }
879 
880 int
addrisbindable(addr)881 addrisbindable(addr)
882    const ruleaddr_t *addr;
883 {
884    const char *function = "addrisbindable()";
885    struct sockaddr_storage saddr;
886    int rc, s;
887 
888    switch (addr->atype) {
889       case SOCKS_ADDR_IPV4:
890       case SOCKS_ADDR_IPV6:
891          sockshost2sockaddr(ruleaddr2sockshost(addr, NULL, SOCKS_TCP), &saddr);
892          break;
893 
894       case SOCKS_ADDR_IFNAME: {
895          struct sockaddr_storage mask;
896 
897          if (ifname2sockaddr(addr->addr.ifname, 0, &saddr, &mask) == NULL) {
898             swarn("%s: cannot find interface named %s with ip configured",
899                   function, addr->addr.ifname);
900 
901             return 0;
902          }
903 
904          break;
905       }
906 
907       case SOCKS_ADDR_DOMAIN: {
908          sockshost_t host;
909 
910          sockshost2sockaddr(ruleaddr2sockshost(addr, &host, SOCKS_TCP), &saddr);
911          if (!IPADDRISBOUND(&saddr)) {
912             swarnx("%s can not resolve host %s: %s",
913                   function,
914                   sockshost2string(&host, NULL, 0),
915                   hstrerror(h_errno));
916 
917             return 0;
918          }
919 
920          break;
921       }
922 
923       default:
924          SERRX(addr->atype);
925    }
926 
927    if ((s = socket(saddr.ss_family, SOCK_STREAM, 0)) == -1) {
928       swarn("%s: socket(SOCK_STREAM)", function);
929       return 0;
930    }
931 
932    rc = socks_bind(s, &saddr, 0);
933    close(s);
934 
935    if (rc != 0)
936       swarn("%s: cannot bind address: %s (from address specification %s)",
937             function,
938             sockaddr2string(&saddr, NULL, 0),
939             ruleaddr2string(addr, 0, NULL, 0));
940 
941    return rc == 0;
942 }
943 
944 int
isreplycommandonly(command)945 isreplycommandonly(command)
946    const command_t *command;
947 {
948 
949    if ((command->bindreply || command->udpreply)
950    && !(command->connect || command->bind || command->udpassociate))
951       return 1;
952    else
953       return 0;
954 }
955 
956 int
hasreplycommands(command)957 hasreplycommands(command)
958    const command_t *command;
959 {
960 
961    if (command->bindreply || command->udpreply)
962       return 1;
963    else
964       return 0;
965 }
966 
967 
968 ssize_t
addrindex_on_listenlist(listc,listv,_addr,protocol)969 addrindex_on_listenlist(listc, listv, _addr, protocol)
970    const size_t listc;
971    const listenaddress_t *listv;
972    const struct sockaddr_storage *_addr;
973    const int protocol;
974 {
975    size_t i;
976 
977    for (i = 0; i < listc; ++i) {
978       struct sockaddr_storage addr = *(const struct sockaddr_storage *)_addr;
979 
980       if (listv[i].protocol != protocol)
981          continue;
982 
983       if (GET_SOCKADDRPORT(&addr) == htons(0)) /* match any internal port. */
984          SET_SOCKADDRPORT(&addr, GET_SOCKADDRPORT(&listv[i].addr));
985 
986       if (sockaddrareeq(&addr, &listv[i].addr, 0))
987          return (ssize_t)i;
988    }
989 
990    return (ssize_t)-1;
991 }
992 
993 ssize_t
addrindex_on_externallist(external,_addr)994 addrindex_on_externallist(external, _addr)
995    const externaladdress_t *external;
996    const struct sockaddr_storage *_addr;
997 {
998    const char *function = "addrindex_on_externallist()";
999    struct sockaddr_storage sa, addr;
1000    size_t i;
1001 
1002    /*
1003     * Not interested in comparing portnumber.
1004     */
1005    sockaddrcpy(&addr, _addr, sizeof(addr));
1006    SET_SOCKADDRPORT(&addr, htons(0));
1007 
1008    slog(LOG_DEBUG,
1009         "%s: checking if address %s is a configured external address",
1010         function, sockaddr2string(&addr, NULL, 0));
1011 
1012    for (i = 0; i < external->addrc; ++i) {
1013       slog(LOG_DEBUG, "%s: external address #%lu: %s",
1014            function,
1015            (unsigned long)i,
1016            ruleaddr2string(&external->addrv[i], ADDRINFO_ATYPE, NULL, 0));
1017 
1018       switch (external->addrv[i].atype) {
1019          case SOCKS_ADDR_IPV4:
1020          case SOCKS_ADDR_IPV6: {
1021             sockshost_t host;
1022 
1023             sockshost2sockaddr(ruleaddr2sockshost(&external->addrv[i],
1024                                                   &host,
1025                                                   SOCKS_TCP),
1026                                &sa);
1027 #if DIAGNOSTIC
1028             SASSERTX(safamily_isenabled(sa.ss_family,
1029                                         sockaddr2string(&sa, NULL, 0),
1030                                         EXTERNALIF));
1031 #endif /* DIAGNOSTIC */
1032 
1033             if (sockaddrareeq(&addr, &sa, 0))
1034                return (ssize_t)i;
1035 
1036             break;
1037          }
1038          case SOCKS_ADDR_DOMAIN: {
1039             char emsg[1024];
1040             int gaierr;
1041             size_t ii;
1042 
1043             ii = 0;
1044             while (hostname2sockaddr2(external->addrv[i].addr.domain,
1045                                       ii++,
1046                                       &sa,
1047                                       &gaierr,
1048                                       emsg,
1049                                       sizeof(emsg)) != NULL) {
1050                slog(LOG_DEBUG, "%s: checking resolved address %s ...",
1051                     function, sockaddr2string(&sa, NULL, 0));
1052 
1053                if (!safamily_isenabled(sa.ss_family,
1054                                        sockaddr2string(&sa, NULL, 0),
1055                                        EXTERNALIF))
1056                   continue;
1057 
1058                if (sockaddrareeq(&addr, &sa, 0))
1059                   return (ssize_t)i;
1060             }
1061 
1062             if (ii == 0)
1063                swarnx("%s: problem with address on external interface: %s",
1064                       function, emsg);
1065 
1066             break;
1067          }
1068 
1069          case SOCKS_ADDR_IFNAME: {
1070             struct sockaddr_storage mask;
1071             size_t ii;
1072 
1073             ii = 0;
1074             while (ifname2sockaddr(external->addrv[i].addr.ifname,
1075                                    ii++,
1076                                    &sa,
1077                                    &mask) != NULL) {
1078                if (!safamily_isenabled(sa.ss_family,
1079                                        sockaddr2string(&sa, NULL, 0),
1080                                        EXTERNALIF))
1081                   continue;
1082 
1083                if (sockaddrareeq(&addr, &sa, 0))
1084                   return (ssize_t)i;
1085             }
1086 
1087             break;
1088          }
1089 
1090          default:
1091             SERRX(external->addrv[i].atype);
1092       }
1093    }
1094 
1095    return (ssize_t)-1;
1096 }
1097 
1098 void
checkconfig(void)1099 checkconfig(void)
1100 {
1101    const char *function = "checkconfig()";
1102 
1103 #if HAVE_PAM
1104    char *pamservicename = NULL;
1105 #endif /* HAVE_PAM */
1106 
1107 #if HAVE_BSDAUTH
1108    char *bsdauthstylename = NULL;
1109 #endif /* HAVE_BSDAUTH */
1110 
1111 #if HAVE_LDAP
1112 
1113    ldapauthentication_t ldapauthentication =
1114    { .ldapurl    = NULL,
1115 /*     .ldapbasedn = NULL, */
1116      .domain     = { NUL },
1117      .keytab     = { NUL },
1118      .filter     = { NUL },
1119      .certfile   = { NUL },
1120      .certpath   = { NUL },
1121      .debug      = LDAP_UNSET_DEBUG_VALUE,
1122      .auto_off   = -1,
1123      .ssl        = -1,
1124      .certcheck  = -1,
1125      .port       = -1,
1126      .portssl    = -1,
1127    };
1128 
1129    /*
1130     * XXX need same for ldap_t?
1131     */
1132 
1133    int ldom = -1, lfil = -1;
1134 
1135 #endif /* HAVE_LDAP */
1136 
1137 #if HAVE_GSSAPI
1138 
1139    char *gssapiservicename = NULL, *gssapikeytab = NULL;
1140 
1141 #endif /* HAVE_GSSAPI */
1142 
1143 
1144    rule_t *rulebasev[]   =  { sockscf.crule,
1145                               sockscf.hrule,
1146                               sockscf.srule
1147                             };
1148    size_t i, basec;
1149    int usinglibwrap = 0;
1150 
1151    for (i = 0; i < sockscf.cmethodc; ++i) {
1152       SASSERTX(sockscf.cmethodv[i] >= AUTHMETHOD_NONE);
1153       SASSERTX(sockscf.cmethodv[i] <= AUTHMETHOD_MAX);
1154 
1155       SASSERTX(methodisvalid(sockscf.cmethodv[i], object_crule));
1156 
1157       if (sockscf.cmethodv[i] == AUTHMETHOD_RFC931)
1158          usinglibwrap = 1;
1159    }
1160 
1161 #if HAVE_SOCKS_RULES
1162    if (sockscf.smethodc == 0)
1163       swarnx("%s: no socks authentication methods enabled.  This means all "
1164              "socks requests will be blocked after negotiation.  "
1165              "Perhaps this is not intended?",
1166              function);
1167    else {
1168       for (i = 0; i < sockscf.smethodc; ++i) {
1169          SASSERTX(sockscf.smethodv[i] >= AUTHMETHOD_NONE);
1170          SASSERTX(sockscf.smethodv[i] <= AUTHMETHOD_MAX);
1171 
1172          if (sockscf.smethodv[i] == AUTHMETHOD_RFC931)
1173             usinglibwrap = 1;
1174 
1175          if (sockscf.smethodv[i] == AUTHMETHOD_NONE
1176          &&  i + 1               < sockscf.smethodc)
1177             yywarnx("authentication method \"%s\" is configured in the "
1178                     "global socksmethod list, but since authentication "
1179                     "methods are selected by the priority given, we will "
1180                     "never try to match any of the subsequent authentication "
1181                     "methods.  I.e., no match will ever be attempted on the "
1182                     "next method, method \"%s\"",
1183                     method2string(sockscf.smethodv[i]),
1184                     method2string(sockscf.smethodv[i + 1]));
1185 
1186       }
1187    }
1188 #endif /* HAVE_SOCKS_RULES */
1189 
1190    /*
1191     * Check rules, including if some rule-specific settings vary across
1192     * rules.
1193     *
1194     * If they don't vary we can optimize things when running and set the
1195     * corresponding variable in the global sockscf object to the constant
1196     * value.
1197     * If they vary, we set the corresponding global variable in sockscf to
1198     * NULL/NUL to indicate we don't have a constant value for this
1199     * variable/setting.
1200     */
1201    basec = 0;
1202    while (basec < ELEMENTS(rulebasev)) {
1203       rule_t *rule = rulebasev[basec++];
1204 
1205       if (rule == NULL)
1206          continue;
1207 
1208       for (; rule != NULL; rule = rule->next) {
1209          size_t methodc;
1210          int *methodv;
1211 
1212          slog(LOG_DEBUG, "%s: %s %u",
1213               function, objecttype2string(rule->type), (unsigned)rule->number);
1214 
1215 #if HAVE_LIBWRAP
1216 
1217          if (*rule->libwrap != NUL)
1218             usinglibwrap = 1;
1219 
1220 #endif /* HAVE_LIBWRAP */
1221 
1222          /*
1223           * What methods do we need to check?  clientmethods for
1224           * client-rules, socksmethods for socks-rules.
1225           */
1226          switch (rule->type) {
1227             case object_crule:
1228 
1229 #if HAVE_SOCKS_HOSTID
1230 
1231             case object_hrule:
1232 
1233 #endif /* HAVE_SOCKS_HOSTID */
1234 
1235                methodc = rule->state.cmethodc;
1236                methodv = rule->state.cmethodv;
1237                break;
1238 
1239             case object_srule:
1240                methodc = rule->state.smethodc;
1241                methodv = rule->state.smethodv;
1242                break;
1243 
1244             default:
1245                SERRX(rule->type);
1246          }
1247 
1248          for (i = 0; i < methodc; ++i) {
1249             switch (methodv[i]) {
1250 
1251 #if HAVE_PAM
1252                case AUTHMETHOD_PAM_ANY:
1253                case AUTHMETHOD_PAM_ADDRESS:
1254                case AUTHMETHOD_PAM_USERNAME:
1255                   if (*sockscf.state.pamservicename == NUL)
1256                      break; /* already found to vary. */
1257 
1258                   if (pamservicename == NULL) /* first pam rule. */
1259                      pamservicename = rule->state.pamservicename;
1260                   else if (strcmp(pamservicename, rule->state.pamservicename)
1261                   != 0) {
1262                      slog(LOG_DEBUG, "%s: pam.servicename varies, %s ne %s",
1263                           function,
1264                           pamservicename,
1265                           rule->state.pamservicename);
1266 
1267                      *sockscf.state.pamservicename = NUL;
1268                   }
1269 
1270                   break;
1271 
1272 #endif /* HAVE_PAM */
1273 
1274 #if HAVE_BSDAUTH
1275 
1276                case AUTHMETHOD_BSDAUTH:
1277                   if (*sockscf.state.bsdauthstylename == NUL)
1278                      break; /* already found to vary. */
1279 
1280                   if (bsdauthstylename == NULL) /* first bsdauth rule. */
1281                      bsdauthstylename = rule->state.bsdauthstylename;
1282                   else if (strcmp(bsdauthstylename,
1283                                   rule->state.bsdauthstylename) != 0) {
1284                      slog(LOG_DEBUG,
1285                           "%s: bsdauth.stylename varies, %s ne %s",
1286                           function,
1287                           bsdauthstylename,
1288                           rule->state.bsdauthstylename);
1289 
1290                      *sockscf.state.bsdauthstylename = NUL;
1291                   }
1292 
1293                   break;
1294 
1295 #endif /* HAVE_BSDAUTH */
1296 
1297 #if HAVE_LDAP
1298 
1299                   case AUTHMETHOD_LDAPAUTH:
1300                      if (sockscf.state.ldapauthentication.ldapurl == NULL)
1301                         ; /* varies. */
1302                      else {
1303                         if (ldapauthentication.ldapurl == NULL)
1304                            ldapauthentication.ldapurl
1305                            = rule->state.ldapauthentication.ldapurl;
1306                         else if (!linkednamesareeq(ldapauthentication.ldapurl,
1307                                       rule->state.ldapauthentication.ldapurl)) {
1308                            slog(LOG_DEBUG,
1309                                 "%s: ldapauthentication.ldapurl varies",
1310                                 function);
1311 
1312                            sockscf.state.ldapauthentication.ldapurl = NULL;
1313                         }
1314                      }
1315 
1316                      if (*sockscf.state.ldapauthentication.certfile == NUL)
1317                         ; /* varies. */
1318                      else {
1319                         if (*ldapauthentication.certfile == NUL)
1320                            STRCPY_ASSERTSIZE(ldapauthentication.certfile,
1321                                        rule->state.ldapauthentication.certfile);
1322                         else if (strcmp(ldapauthentication.certfile,
1323                                         rule->state.ldapauthentication.certfile)
1324                                  != 0) {
1325                            slog(LOG_DEBUG,
1326                                 "%s: ldapauthentication.certfile varies, "
1327                                 "%s ne %s",
1328                                 function,
1329                                 ldapauthentication.certfile,
1330                                 rule->state.ldapauthentication.certfile);
1331 
1332                            *sockscf.state.ldapauthentication.certfile = NUL;
1333                         }
1334                      }
1335 
1336                      if (*sockscf.state.ldapauthentication.certpath == NUL)
1337                         ; /* varies. */
1338                      else {
1339                         if (*ldapauthentication.certpath == NUL)
1340                            STRCPY_ASSERTSIZE(ldapauthentication.certpath,
1341                                        rule->state.ldapauthentication.certpath);
1342                         else if (strcmp(ldapauthentication.certpath,
1343                                         rule->state.ldapauthentication.certpath)
1344                         != 0) {
1345                            slog(LOG_DEBUG,
1346                                 "%s: ldapauthentication.certpath varies, "
1347                                 "%s ne %s",
1348                                 function,
1349                                 ldapauthentication.certpath,
1350                                 rule->state.ldapauthentication.certpath);
1351 
1352                            *sockscf.state.ldapauthentication.certpath = NUL;
1353                         }
1354                      }
1355 
1356                      if (*sockscf.state.ldapauthentication.keytab == NUL)
1357                         ; /* varies. */
1358                      else {
1359                         if (*ldapauthentication.keytab == NUL)
1360                            STRCPY_ASSERTSIZE(ldapauthentication.keytab,
1361                                          rule->state.ldapauthentication.keytab);
1362                         else if (strcmp(ldapauthentication.keytab,
1363                                         rule->state.ldapauthentication.keytab)
1364                                  != 0) {
1365                            slog(LOG_DEBUG,
1366                                 "%s: ldapauthentication.keytab varies, "
1367                                 "%s ne %s",
1368                                 function,
1369                                 ldapauthentication.keytab,
1370                                 rule->state.ldapauthentication.keytab);
1371 
1372                            *sockscf.state.ldapauthentication.keytab = NUL;
1373                         }
1374                      }
1375 
1376                      if (ldom != 0
1377                      &&  *rule->state.ldapauthentication.domain != NUL) {
1378                         if (*ldapauthentication.domain == NUL)
1379                            STRCPY_ASSERTSIZE(ldapauthentication.domain,
1380                                          rule->state.ldapauthentication.domain);
1381                         else if (strcmp(ldapauthentication.domain,
1382                                         rule->state.ldapauthentication.domain)
1383                                  != 0) {
1384                            slog(LOG_DEBUG,
1385                                 "%s: ldapauthentication.domain varies, "
1386                                 "%s ne %s",
1387                                 function,
1388                                 ldapauthentication.domain,
1389                                 rule->state.ldapauthentication.domain);
1390 
1391                            ldom = 0;
1392                         }
1393                      }
1394 
1395                      if (lfil != 0
1396                      &&  *rule->state.ldapauthentication.filter != NUL) {
1397                         if (*ldapauthentication.filter == NUL)
1398                            STRCPY_ASSERTSIZE(ldapauthentication.filter,
1399                                          rule->state.ldapauthentication.filter);
1400                         else if (strcmp(ldapauthentication.filter,
1401                                         rule->state.ldapauthentication.filter)
1402                                  != 0) {
1403                            slog(LOG_DEBUG,
1404                                 "%s: ldapauthentication.filter varies, "
1405                                 "%s ne %s",
1406                                 function,
1407                                 ldapauthentication.filter,
1408                                 rule->state.ldapauthentication.filter);
1409 
1410                            lfil = 0;
1411                         }
1412                      }
1413 
1414                      if (sockscf.state.ldapauthentication.debug
1415                      != LDAP_UNSET_DEBUG_VALUE) {
1416                         if (ldapauthentication.debug == LDAP_UNSET_DEBUG_VALUE)
1417                            ldapauthentication.debug
1418                            = rule->state.ldapauthentication.debug;
1419                         else if (ldapauthentication.debug
1420                         != rule->state.ldapauthentication.debug) {
1421                            slog(LOG_DEBUG,
1422                                 "%s: ldapauthentication.debug varies, %d ne %d",
1423                                 function,
1424                                 (int)ldapauthentication.debug,
1425                                 (int)rule->state.ldapauthentication.debug);
1426 
1427                            sockscf.state.ldapauthentication.debug
1428                            = LDAP_UNSET_DEBUG_VALUE;
1429                         }
1430                      }
1431 
1432                      if (sockscf.state.ldapauthentication.auto_off != -1) {
1433                         if (ldapauthentication.auto_off == -1)
1434                            ldapauthentication.auto_off
1435                            = rule->state.ldapauthentication.auto_off;
1436                         else if (ldapauthentication.auto_off
1437                         != rule->state.ldapauthentication.auto_off) {
1438                            slog(LOG_DEBUG,
1439                                 "%s: ldapauthentication.auto_off varies, "
1440                                 "%d ne %d",
1441                                 function,
1442                                 (int)ldapauthentication.auto_off,
1443                                 (int)rule->state.ldapauthentication.auto_off);
1444 
1445                            sockscf.state.ldapauthentication.auto_off = -1;
1446                         }
1447                      }
1448 
1449                      if (sockscf.state.ldapauthentication.ssl != -1) {
1450                         if (ldapauthentication.ssl == -1)
1451                            ldapauthentication.ssl
1452                            = rule->state.ldapauthentication.ssl ;
1453                        else if (ldapauthentication.ssl
1454                        != rule->state.ldapauthentication.ssl) {
1455                           slog(LOG_DEBUG,
1456                                "%s: ldapauthentication.ssl varies, %d ne %d",
1457                                function,
1458                                (int)ldapauthentication.ssl ,
1459                                (int)rule->state.ldapauthentication.ssl);
1460 
1461                            sockscf.state.ldapauthentication.ssl = -1;
1462                         }
1463                      }
1464 
1465                      if (sockscf.state.ldapauthentication.certcheck != -1) {
1466                         if (ldapauthentication.certcheck == -1)
1467                            ldapauthentication.certcheck
1468                            = rule->state.ldapauthentication.certcheck;
1469                         else if (ldapauthentication.certcheck
1470                         != rule->state.ldapauthentication.certcheck) {
1471                            slog(LOG_DEBUG,
1472                                 "%s: ldapauthentication.certcheck varies, "
1473                                 "%d ne %d",
1474                                 function,
1475                                 (int)ldapauthentication.certcheck,
1476                                 (int)rule->state.ldapauthentication.certcheck);
1477 
1478                            sockscf.state.ldapauthentication.certcheck = -1;
1479                         }
1480                      }
1481 
1482                      if (sockscf.state.ldapauthentication.port != -1) {
1483                         if (ldapauthentication.port == -1)
1484                            ldapauthentication.port
1485                            = rule->state.ldapauthentication.port;
1486                         else if (ldapauthentication.port
1487                         != rule->state.ldapauthentication.port) {
1488                            slog(LOG_DEBUG,
1489                                 "%s: ldapauthentication.port varies, %d ne %d",
1490                                 function,
1491                                 ldapauthentication.port,
1492                                 rule->state.ldapauthentication.port);
1493 
1494                            sockscf.state.ldapauthentication.port = -1;
1495                         }
1496                      }
1497 
1498                      if (sockscf.state.ldapauthentication.portssl != -1) {
1499                         if (ldapauthentication.portssl == -1)
1500                            ldapauthentication.portssl
1501                            = rule->state.ldapauthentication.portssl;
1502                         else if (ldapauthentication.portssl
1503                         != rule->state.ldapauthentication.portssl) {
1504                            slog(LOG_DEBUG,
1505                                 "%s: ldapauthentication.portssl varies, "
1506                                 "%d ne %d",
1507                                 function,
1508                                 ldapauthentication.portssl,
1509                                 rule->state.ldapauthentication.portssl);
1510 
1511                            sockscf.state.ldapauthentication.portssl = -1;
1512                         }
1513                      }
1514 
1515                      break;
1516 
1517 #endif /* HAVE_LDAP */
1518 
1519 #if HAVE_GSSAPI
1520                case AUTHMETHOD_GSSAPI:
1521                   if (*sockscf.state.gssapiservicename != NUL) {
1522                      if (gssapiservicename == NULL) /* first gssapi rule. */
1523                         gssapiservicename = rule->state.gssapiservicename;
1524                      else if (strcmp(gssapiservicename,
1525                               rule->state.gssapiservicename) != 0) {
1526                         slog(LOG_DEBUG,
1527                              "%s: gssapi.servicename varies, %s ne %s",
1528                              function,
1529                              gssapiservicename,
1530                              rule->state.gssapiservicename);
1531 
1532                         *sockscf.state.gssapiservicename = NUL;
1533                      }
1534                   }
1535                   /* else; already found to vary. */
1536 
1537                   if (*sockscf.state.gssapikeytab != NUL) {
1538                      if (gssapikeytab == NULL) /* first gssapi rule. */
1539                         gssapikeytab = rule->state.gssapikeytab;
1540                      else if (strcmp(gssapikeytab, rule->state.gssapikeytab)
1541                      != 0) {
1542                         slog(LOG_DEBUG, "%s: gssapi.keytab varies, %s ne %s",
1543                              function,
1544                              gssapikeytab,
1545                              rule->state.gssapikeytab);
1546 
1547                         *sockscf.state.gssapikeytab = NUL;
1548                      }
1549                   }
1550                   /* else; already found to vary. */
1551 
1552                   break;
1553 #endif /* HAVE_GSSAPI */
1554 
1555                default:
1556                   break;
1557             }
1558          }
1559 
1560 #if BAREFOOTD
1561          if (rule->type == object_crule) {
1562             if (rule->state.protocol.tcp)
1563                /*
1564                 * Add all "to:" addresses to the list of internal interfaces;
1565                 * barefootd doesn't use a separate "internal:" keyword for it.
1566                 */
1567                 addinternal(&rule->dst, SOCKS_TCP);
1568 
1569             if (rule->state.protocol.udp)
1570                sockscf.state.alludpbounced = 0;
1571          }
1572 #endif /* BAREFOOTD */
1573 
1574       }
1575    }
1576 
1577    /*
1578     * Check that the main configured privileges work.
1579     */
1580    sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_ON);
1581    sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_OFF);
1582 
1583    sockd_priv(SOCKD_PRIV_UNPRIVILEGED, PRIV_ON);
1584    sockd_priv(SOCKD_PRIV_UNPRIVILEGED, PRIV_OFF);
1585 
1586    sockd_priv(SOCKD_PRIV_LIBWRAP, PRIV_ON);
1587    sockd_priv(SOCKD_PRIV_LIBWRAP, PRIV_OFF);
1588 
1589 #if !HAVE_PRIVILEGES
1590    SASSERTX(sockscf.state.euid == geteuid());
1591    SASSERTX(sockscf.state.egid == getegid());
1592 
1593    if (sockscf.uid.unprivileged_uid == 0)
1594       swarnx("%s: setting the unprivileged uid to %d is not recommended "
1595              "for security reasons",
1596              function, sockscf.uid.unprivileged_uid);
1597 
1598 #if HAVE_LIBWRAP
1599    if (usinglibwrap && sockscf.uid.libwrap_uid == 0)
1600       swarnx("%s: setting the libwrap uid to %d is almost never needed, and "
1601              "is not recommended for security reasons",
1602              function, sockscf.uid.libwrap_uid);
1603 #endif /* HAVE_LIBWRAP */
1604 #endif /* !HAVE_PRIVILEGES */
1605 
1606 #if HAVE_PAM
1607    if (*sockscf.state.pamservicename != NUL
1608    &&  pamservicename                != NULL) {
1609       /*
1610        * pamservicename does not vary, but is not necessarily the
1611        * the same as sockscf.state.pamservicename (default).
1612        * If it is not, set sockscf.state.pamservicename to
1613        * what the user used in one or more of the rules, since
1614        * it is the same in all rules, i.e. making it that value
1615        * we use to make passworddbisunique() work as expected.
1616        *
1617        * Likewise for bsdauth, gssapi, etc.
1618       */
1619 
1620       if (strcmp(pamservicename, sockscf.state.pamservicename) != 0)
1621          STRCPY_CHECKLEN(sockscf.state.pamservicename,
1622                          pamservicename,
1623                          sizeof(sockscf.state.pamservicename) - 1,
1624                          yyerrorx);
1625    }
1626 #endif /* HAVE_PAM */
1627 
1628 #if HAVE_BSDAUTH
1629    if (*sockscf.state.bsdauthstylename != NUL
1630    &&  bsdauthstylename                != NULL) {
1631       if (strcmp(bsdauthstylename, sockscf.state.bsdauthstylename) != 0)
1632          STRCPY_CHECKLEN(sockscf.state.bsdauthstylename,
1633                          bsdauthstylename,
1634                          sizeof(sockscf.state.bsdauthstylename) - 1,
1635                          yyerrorx);
1636    }
1637 #endif /* HAVE_BSDAUTH */
1638 
1639 # if HAVE_LDAP
1640 
1641    if (sockscf.state.ldapauthentication.ldapurl != NULL
1642    &&  ldapauthentication.ldapurl               != NULL)
1643        sockscf.state.ldapauthentication.ldapurl = ldapauthentication.ldapurl;
1644 
1645    if (*sockscf.state.ldapauthentication.certfile != NUL
1646    &&  *ldapauthentication.certfile               != NUL)
1647       if (strcmp(ldapauthentication.certfile,
1648                  sockscf.state.ldapauthentication.certfile) != 0)
1649          STRCPY_CHECKLEN(sockscf.state.ldapauthentication.certfile,
1650                          ldapauthentication.certfile,
1651                          sizeof(sockscf.state.ldapauthentication.certfile) - 1,
1652                          yyerrorx);
1653 
1654    if (*sockscf.state.ldapauthentication.certpath != NUL
1655    &&  *ldapauthentication.certpath               != NUL)
1656       if (strcmp(ldapauthentication.certpath,
1657                  sockscf.state.ldapauthentication.certpath) != 0)
1658          STRCPY_CHECKLEN(sockscf.state.ldapauthentication.certpath,
1659                          ldapauthentication.certpath,
1660                          sizeof(sockscf.state.ldapauthentication.certpath) - 1,
1661                          yyerrorx);
1662 
1663    if (*sockscf.state.ldapauthentication.keytab != NUL
1664    &&  *ldapauthentication.keytab               != NUL)
1665       if (strcmp(ldapauthentication.keytab,
1666                  sockscf.state.ldapauthentication.keytab) != 0)
1667          STRCPY_CHECKLEN(sockscf.state.ldapauthentication.keytab,
1668                          ldapauthentication.keytab,
1669                          sizeof(sockscf.state.ldapauthentication.keytab) - 1,
1670                          yyerrorx);
1671 
1672    if (ldom             == -1
1673    &&  *ldapauthentication.domain != NUL)
1674       if (strcmp(ldapauthentication.domain,
1675                  sockscf.state.ldapauthentication.domain) != 0)
1676          STRCPY_CHECKLEN(sockscf.state.ldapauthentication.domain,
1677                          ldapauthentication.domain,
1678                          sizeof(sockscf.state.ldapauthentication.domain) - 1,
1679                          yyerrorx);
1680 
1681    if (lfil              == -1
1682    &&  *ldapauthentication.filter  != NUL)
1683       if (strcmp(ldapauthentication.filter,
1684                  sockscf.state.ldapauthentication.filter) != 0)
1685          STRCPY_CHECKLEN(sockscf.state.ldapauthentication.filter,
1686                          ldapauthentication.filter,
1687                          sizeof(sockscf.state.ldapauthentication.filter) - 1,
1688                          yyerrorx);
1689 
1690    if (sockscf.state.ldapauthentication.debug != LDAP_UNSET_DEBUG_VALUE
1691    &&  ldapauthentication.debug               != LDAP_UNSET_DEBUG_VALUE)
1692       sockscf.state.ldapauthentication.debug = ldapauthentication.debug;
1693 
1694    if (sockscf.state.ldapauthentication.auto_off != -1
1695     && ldapauthentication.auto_off               != -1)
1696       sockscf.state.ldapauthentication.auto_off = ldapauthentication.auto_off;
1697 
1698    if (sockscf.state.ldapauthentication.ssl != -1
1699    &&  ldapauthentication.ssl               != -1)
1700       sockscf.state.ldapauthentication.ssl = ldapauthentication.ssl;
1701 
1702    if (sockscf.state.ldapauthentication.certcheck != -1
1703    &&  ldapauthentication.certcheck               != -1)
1704       sockscf.state.ldapauthentication.certcheck = ldapauthentication.certcheck;
1705 
1706    if (sockscf.state.ldapauthentication.port != -1
1707    &&  ldapauthentication.port               != -1)
1708       sockscf.state.ldapauthentication.port = ldapauthentication.port;
1709 
1710    if (sockscf.state.ldapauthentication.portssl != -1
1711    &&  ldapauthentication.portssl               != -1)
1712       sockscf.state.ldapauthentication.portssl = ldapauthentication.portssl;
1713 
1714 #endif /* HAVE_LDAP */
1715 
1716 #if HAVE_GSSAPI
1717    if (*sockscf.state.gssapiservicename != NUL
1718    &&  gssapiservicename                != NULL) {
1719       if (strcmp(gssapiservicename, sockscf.state.gssapiservicename) != 0)
1720          STRCPY_CHECKLEN(sockscf.state.gssapiservicename,
1721                          gssapiservicename,
1722                          sizeof(sockscf.state.gssapiservicename) - 1,
1723                          yyerrorx);
1724    }
1725 
1726    if (*sockscf.state.gssapikeytab != NUL
1727    &&  gssapikeytab                != NULL) {
1728       if (strcmp(gssapikeytab, sockscf.state.gssapikeytab) != 0)
1729          STRCPY_CHECKLEN(sockscf.state.gssapikeytab,
1730                          gssapikeytab,
1731                          sizeof(sockscf.state.gssapikeytab) - 1,
1732                          yyerrorx);
1733    }
1734 #endif /* HAVE_GSSAPI */
1735 
1736    /*
1737     * Go through all rules again and set default values for
1738     * authentication-methods based on the global method-lines, if none set.
1739     */
1740 #if BAREFOOTD
1741    if (sockscf.internal.addrc == 0 && ALL_UDP_BOUNCED())
1742       serrx("%s: no client-rules to accept clients on specified", function);
1743 
1744 #else /* !BAREFOOTD */
1745    if (sockscf.internal.addrc == 0)
1746       serrx("%s: no internal address given for server to listen for clients on",
1747             function);
1748 #endif /* !BAREFOOTD */
1749 
1750 
1751    if (sockscf.external.addrc == 0)
1752       serrx("%s: no external address specified for server to use when "
1753             "forwarding data on behalf of clients",
1754             function);
1755 
1756    if (sockscf.external.rotation == ROTATION_NONE) {
1757       size_t ipv4c = 0, ipv6c = 0;
1758 
1759       for (i = 0; i < sockscf.external.addrc; ++i) {
1760          switch (sockscf.external.addrv[i].atype) {
1761             case SOCKS_ADDR_IPV4:
1762                ++ipv4c;
1763                break;
1764 
1765             case SOCKS_ADDR_IPV6:
1766                ++ipv6c;
1767                break;
1768 
1769             case SOCKS_ADDR_IFNAME:
1770             case SOCKS_ADDR_DOMAIN:
1771                break;
1772 
1773             default:
1774                SERRX(sockscf.external.addrv[i].atype);
1775          }
1776       }
1777 
1778       if (ipv4c > 1 || ipv6c > 1)
1779          swarnx("%s: more than one external address has been specified, but "
1780                 "as long as external.rotation has the default value %s "
1781                 "only the first address specified will be used",
1782                 function, rotation2string(sockscf.external.rotation));
1783    }
1784 
1785    if (sockscf.external.rotation == ROTATION_SAMESAME
1786    &&  sockscf.external.addrc    == 1)
1787       swarnx("%s: rotation for external addresses is set to same-same, but "
1788              "the number of external addresses is only one, so this does "
1789              "not make sense",
1790              function);
1791 
1792    if (sockscf.routeoptions.maxfail == 0 && sockscf.routeoptions.badexpire != 0)
1793       swarnx("%s: it does not make sense to set \"route.badexpire\" "
1794              "when \"route.maxfail\" is set to zero",
1795              function);
1796 
1797 #if COVENANT
1798    if (*sockscf.realmname == NUL)
1799       STRCPY_ASSERTSIZE(sockscf.realmname, DEFAULT_REALMNAME);
1800 #endif /* COVENANT */
1801 
1802 #if HAVE_SCHED_SETAFFINITY
1803 {
1804    const cpusetting_t *cpuv[] = { &sockscf.cpu.mother,
1805                                   &sockscf.cpu.monitor,
1806                                   &sockscf.cpu.negotiate,
1807                                   &sockscf.cpu.request,
1808                                   &sockscf.cpu.io };
1809 
1810    const int proctypev[]      = { PROC_MOTHER,
1811                                   PROC_MONITOR,
1812                                   PROC_NEGOTIATE,
1813                                   PROC_REQUEST,
1814                                   PROC_IO };
1815    size_t i;
1816 
1817    for (i = 0; i < ELEMENTS(cpuv); ++i)
1818    if (cpuv[i]->affinity_isset && !sockd_cpuset_isok(&cpuv[i]->mask))
1819       serrx("%s: invalid cpu mask configured for %s process: %s",
1820             function,
1821             childtype2string(proctypev[i]),
1822             cpuset2string(&cpuv[i]->mask, NULL, 0));
1823 }
1824 #endif /* HAVE_SCHED_SETAFFINITY */
1825 
1826    for (i = 0; i < sockscf.external.addrc; ++i)
1827       if (!addrisbindable(&sockscf.external.addrv[i]))
1828          serrx("%s: cannot bind external address #%ld: %s",
1829                function,
1830                (long)i,
1831                ruleaddr2string(&sockscf.external.addrv[i], 0, NULL, 0));
1832 }
1833 
1834 void
add_external_safamily(safamily,globalscope)1835 add_external_safamily(safamily, globalscope)
1836    const sa_family_t safamily;
1837    const int globalscope;
1838 {
1839    switch (safamily) {
1840       case AF_INET:
1841          sockscf.external.protocol.hasipv4 = 1;
1842          break;
1843 
1844       case AF_INET6:
1845          sockscf.external.protocol.hasipv6 = 1;
1846 
1847          if (globalscope)
1848             sockscf.external.protocol.hasipv6_globalscope = 1;
1849 
1850          break;
1851 
1852       default:
1853          SERRX(safamily);
1854    }
1855 }
1856 
1857 
1858 int
external_has_safamily(safamily)1859 external_has_safamily(safamily)
1860    const sa_family_t safamily;
1861 {
1862    const char *function = "external_has_safamily()";
1863 
1864    SASSERTX(sockscf.shmeminfo != NULL);
1865 
1866 #if 0
1867    slog(LOG_DEBUG, "%s: hasipv4: %d, hasipv6: %d, hasipv6_globalscope: %d",
1868         function,
1869         sockscf.shmeminfo->state.external_hasipv4,
1870         sockscf.shmeminfo->state.external_hasipv6,
1871         sockscf.shmeminfo->state.external_hasipv6_globalscope);
1872 #endif
1873 
1874    switch (safamily) {
1875       case AF_INET:
1876          return sockscf.external.protocol.hasipv4;
1877 
1878       case AF_INET6:
1879          return sockscf.external.protocol.hasipv6;
1880 
1881       default:
1882          SERRX(safamily);
1883    }
1884 }
1885 
1886 void
add_internal_safamily(safamily)1887 add_internal_safamily(safamily)
1888    const sa_family_t safamily;
1889 {
1890    switch (safamily) {
1891       case AF_INET:
1892          sockscf.internal.protocol.hasipv4 = 1;
1893          break;
1894 
1895       case AF_INET6:
1896          sockscf.internal.protocol.hasipv6 = 1;
1897          break;
1898 
1899       default:
1900          SERRX(safamily);
1901    }
1902 }
1903 
1904 
1905 int
internal_has_safamily(safamily)1906 internal_has_safamily(safamily)
1907    const sa_family_t safamily;
1908 {
1909    const char *function = "internal_has_safamily()";
1910 
1911    SASSERTX(sockscf.shmeminfo != NULL);
1912 
1913 #if 0
1914    slog(LOG_DEBUG, "%s: hasipv4: %d, hasipv6: %d",
1915         function,
1916         sockscf.internal.protocol.hasipv4,
1917         sockscf.internal.protocol.hasipv6);
1918 #endif
1919 
1920    switch (safamily) {
1921       case AF_INET:
1922          return sockscf.internal.protocol.hasipv4;
1923 
1924       case AF_INET6:
1925          return sockscf.internal.protocol.hasipv6;
1926 
1927       default:
1928          SERRX(safamily);
1929    }
1930 }
1931 
1932 int
external_has_only_safamily(safamily)1933 external_has_only_safamily(safamily)
1934    const sa_family_t safamily;
1935 {
1936 
1937    switch (safamily) {
1938       case AF_INET:
1939          return   (external_has_safamily(AF_INET)
1940                && !external_has_safamily(AF_INET6));
1941 
1942       case AF_INET6:
1943          return   (external_has_safamily(AF_INET6)
1944                && !external_has_safamily(AF_INET));
1945 
1946       default:
1947          SERRX(safamily);
1948    }
1949 }
1950 
1951 
1952 int
external_has_global_safamily(safamily)1953 external_has_global_safamily(safamily)
1954    const sa_family_t safamily;
1955 {
1956 
1957    SASSERTX(sockscf.shmeminfo != NULL);
1958 
1959    switch (safamily) {
1960       case AF_INET: /* don't care about scope for IPv4. */
1961          return sockscf.external.protocol.hasipv4;
1962 
1963       case AF_INET6:
1964          return sockscf.external.protocol.hasipv6_globalscope;
1965 
1966       default:
1967          SERRX(safamily);
1968    }
1969 }
1970 
1971 
1972 
1973 
1974 static void
add_more_old_shmem(config,memc,memv)1975 add_more_old_shmem(config, memc, memv)
1976    struct config *config;
1977    const size_t memc;
1978    const oldshmeminfo_t memv[];
1979 {
1980    const char *function = "add_more_old_shmem()";
1981    void *old;
1982    size_t i;
1983 
1984    if ((old = realloc(config->oldshmemv,
1985                       sizeof(*config->oldshmemv) * (config->oldshmemc + memc)))
1986    == NULL) {
1987       swarn("%s: could not allocate %lu bytes of memory to "
1988             "hold old shmids for later removal",
1989             function,
1990             (unsigned long)(sizeof(*config->oldshmemv)
1991                             * (config->oldshmemc + memc)));
1992       return;
1993    }
1994    config->oldshmemv = old;
1995 
1996    for (i = 0; i < memc; ++i) {
1997       const char *type;
1998 
1999       switch (memv[i].type) {
2000          case SHMEM_BW:
2001             type = "bw";
2002             break;
2003 
2004          case SHMEM_MONITOR:
2005             type = "monitor";
2006             break;
2007 
2008          case SHMEM_SS:
2009             type = "session";
2010             break;
2011 
2012          default:
2013             SERRX(memv[i].type);
2014       }
2015 
2016       slog(LOG_DEBUG,
2017            "%s: saving old shmem-object of type %lu (%s), with "
2018            "shmid %lu/key %lu, at index #%lu, for removal upon exit",
2019            function,
2020            (unsigned long)memv[i].type,
2021            type,
2022            (unsigned long)memv[i].id,
2023            (unsigned long)memv[i].key,
2024            (unsigned long)i);
2025 
2026       config->oldshmemv[config->oldshmemc++] = memv[i];
2027    }
2028 }
2029 
2030 static int
safamily_isenabled(safamily,addrstr,side)2031 safamily_isenabled(safamily, addrstr, side)
2032    const sa_family_t safamily;
2033    const char *addrstr;
2034    const interfaceside_t side;
2035 {
2036    const char *function = "safamily_isenabled()";
2037    interfaceprotocol_t *interface;
2038    int isenabled;
2039 
2040    switch (side) {
2041       case INTERNALIF:
2042          interface = &sockscf.internal.protocol;
2043          break;
2044 
2045       case EXTERNALIF:
2046          interface = &sockscf.external.protocol;
2047          break;
2048 
2049       default:
2050          SERRX(side);
2051    }
2052 
2053    isenabled = 0;
2054    switch (safamily) {
2055       case AF_INET:
2056          if (interface->ipv4)
2057             isenabled = 1;
2058          break;
2059 
2060       case AF_INET6:
2061          if (interface->ipv6)
2062             isenabled = 1;
2063          break;
2064 
2065       default:
2066          SERRX(safamily);
2067    }
2068 
2069    if (!isenabled)
2070       slog(LOG_DEBUG,
2071            "%s: address family %s option is not enabled on the %s-side "
2072            "interface. Can not use address \"%s\"",
2073            function,
2074            safamily2string(safamily),
2075            interfaceside2string(side),
2076            addrstr);
2077 
2078    return isenabled;
2079 }
2080 
2081 static int
addexternaladdr(ra)2082 addexternaladdr(ra)
2083    const struct ruleaddr_t *ra;
2084 {
2085    void *old;
2086 
2087    switch (ra->atype) {
2088       case SOCKS_ADDR_IPV4:
2089       case SOCKS_ADDR_IPV6:
2090          if (!safamily_isenabled(atype2safamily(ra->atype),
2091                                  ruleaddr2string(ra, ADDRINFO_ATYPE, NULL, 0),
2092                                  EXTERNALIF))
2093             return -1;
2094          break;
2095 
2096       default:
2097          /*
2098           * Will be resolved when needed.
2099           */
2100          break;
2101    }
2102 
2103    old = realloc(sockscf.external.addrv,
2104                 sizeof(*sockscf.external.addrv) * (sockscf.external.addrc + 1));
2105 
2106    if (old == NULL)
2107       yyerror(NOMEM);
2108 
2109    sockscf.external.addrv = old;
2110 
2111    sockscf.external.addrv[sockscf.external.addrc++] = *ra;
2112    return 0;
2113 }
2114 
2115 
2116 static int
addinternaladdr(ifname,sa,protocol)2117 addinternaladdr(ifname, sa, protocol)
2118    const char *ifname;
2119    const struct sockaddr_storage *sa;
2120    const int protocol;
2121 {
2122    const char *function = "addinternaladdr()";
2123    void *old;
2124 
2125    if (!safamily_isenabled(sa->ss_family,
2126                            sockaddr2string2(sa, ADDRINFO_ATYPE, NULL, 0),
2127                            INTERNALIF) != 0)
2128       return -1;
2129 
2130    slog(LOG_DEBUG, "%s: adding address %s on nic %s to the internal list",
2131         function, sockaddr2string(sa, NULL, 0), ifname);
2132 
2133    old = realloc(sockscf.internal.addrv,
2134                 sizeof(*sockscf.internal.addrv) * (sockscf.internal.addrc + 1));
2135 
2136    if (old == NULL)
2137       yyerror(NOMEM);
2138 
2139    sockscf.internal.addrv = old;
2140 
2141 #if 0
2142    bzero(&sockscf.internal.addrv[sockscf.internal.addrc],
2143          sizeof(sockscf.internal.addrv[sockscf.internal.addrc]));
2144 #endif
2145    sockaddrcpy(&sockscf.internal.addrv[sockscf.internal.addrc].addr,
2146                sa,
2147                sizeof(sockscf.internal.addrv[sockscf.internal.addrc].addr));
2148 
2149    sockscf.internal.addrv[sockscf.internal.addrc].protocol = protocol;
2150    sockscf.internal.addrv[sockscf.internal.addrc].s        = -1;
2151 
2152    ++sockscf.internal.addrc;
2153 
2154    add_internal_safamily(sa->ss_family);
2155 
2156    return 0;
2157 }
2158