1 /*
2  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
3  *               2009, 2010, 2011, 2012, 2013, 2014, 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 #include "vis_compat.h"
48 
49 static const char rcsid[] =
50 "$Id: util.c,v 1.416.4.5.6.5 2020/11/11 17:02:26 karls Exp $";
51 
52 const char *
strcheck(string)53 strcheck(string)
54    const char *string;
55 {
56    return string == NULL ? NOMEM : string;
57 }
58 
59 unsigned int
sockscode(version,code)60 sockscode(version, code)
61    const int version;
62    const int code;
63 {
64 
65    SASSERTX(code >= 0);
66 
67    switch (version) {
68       case PROXY_SOCKS_V4:
69       case PROXY_SOCKS_V4REPLY_VERSION:
70          switch (code) {
71             case SOCKS_SUCCESS:
72                return SOCKSV4_SUCCESS;
73 
74             default:
75                return SOCKSV4_FAIL; /* v4 is not very specific. */
76          }
77          /* NOTREACHED */
78 
79       case PROXY_SOCKS_V5:
80          return (unsigned char)code; /* current codes are all V5. */
81 
82       case PROXY_HTTP_10:
83       case PROXY_HTTP_11:
84          switch (code) {
85             case SOCKS_SUCCESS:
86                return HTTP_SUCCESS;
87 
88             case SOCKS_FAILURE:
89                return HTTP_FAILURE;
90 
91             case SOCKS_NOTALLOWED:
92                return HTTP_NOTALLOWED;
93 
94             case SOCKS_NETUNREACH:
95             case SOCKS_HOSTUNREACH:
96             case SOCKS_CONNREFUSED:
97                return HTTP_HOSTUNREACH;
98 
99             default:
100                return HTTP_FAILURE;
101          }
102          /* NOTREACHED */
103 
104       case PROXY_UPNP:
105          switch (code) {
106             case SOCKS_SUCCESS:
107                return UPNP_SUCCESS;
108 
109             case SOCKS_FAILURE:
110                return UPNP_FAILURE;
111 
112             default:
113                return UPNP_FAILURE;
114          }
115          /* NOTREACHED */
116 
117 
118       default:
119          SERRX(version);
120    }
121 
122    /* NOTREACHED */
123 }
124 
125 unsigned int
errno2reply(errnum,version)126 errno2reply(errnum, version)
127    int errnum;
128    int version;
129 {
130 
131    switch (errnum) {
132       case ENETDOWN:
133       case ENETUNREACH:
134          return sockscode(version, SOCKS_NETUNREACH);
135 
136       case EHOSTDOWN:
137       case EHOSTUNREACH:
138          return sockscode(version, SOCKS_HOSTUNREACH);
139 
140       case ECONNREFUSED:
141       case ECONNRESET:
142          return sockscode(version, SOCKS_CONNREFUSED);
143 
144       case ETIMEDOUT:
145          return sockscode(version, SOCKS_TTLEXPIRED);
146    }
147 
148    return sockscode(version, SOCKS_FAILURE);
149 }
150 
151 struct sockaddr_storage *
int_sockshost2sockaddr2(host,addr,addrlen,gaierr,emsg,emsglen)152 int_sockshost2sockaddr2(host, addr, addrlen, gaierr, emsg, emsglen)
153    const sockshost_t *host;
154    struct sockaddr_storage *addr;
155    size_t addrlen;
156    int *gaierr;
157    char *emsg;
158    size_t emsglen;
159 {
160    const char *function = "int_sockshost2sockaddr2()";
161    char emsgmem[1024 + MAXHOSTNAMELEN * 4];
162 
163    if (emsg == NULL || emsglen == 0) {
164       emsg    = emsgmem;
165       emsglen = sizeof(emsgmem);
166    }
167 
168    *emsg   = NUL;
169    *gaierr = 0;
170 
171    if (addr == NULL) {
172       static struct sockaddr_storage addrmem;
173 
174       addr    = &addrmem;
175       addrlen = sizeof(addrmem);
176    }
177 
178    bzero(addr, addrlen);
179 
180    switch (host->atype) {
181       case SOCKS_ADDR_IPV4:
182       case SOCKS_ADDR_IPV6: {
183          struct sockaddr_storage ss;
184 
185          bzero(&ss, sizeof(ss));
186 
187          if (host->atype == SOCKS_ADDR_IPV4) {
188             SET_SOCKADDR(&ss, AF_INET);
189             TOIN(&ss)->sin_addr = host->addr.ipv4;
190          }
191          else {
192             SET_SOCKADDR(&ss, AF_INET6);
193             TOIN6(&ss)->sin6_addr     = host->addr.ipv6.ip;
194             TOIN6(&ss)->sin6_scope_id = host->addr.ipv6.scopeid;
195          }
196 
197          sockaddrcpy(addr, &ss, salen(ss.ss_family));
198          SET_SOCKADDRPORT(addr, host->port);
199          break;
200       }
201 
202       case SOCKS_ADDR_DOMAIN: {
203          struct addrinfo hints, *res;
204          dnsinfo_t resmem;
205 
206          bzero(&hints, sizeof(hints));
207 
208          set_hints_ai_family(&hints.ai_family);
209 
210          *gaierr = cgetaddrinfo(host->addr.domain, NULL, &hints, &res, &resmem);
211 
212          if (*gaierr == 0) {
213             if (res->ai_addrlen <= addrlen) {
214                sockaddrcpy(addr, TOSS(res->ai_addr), addrlen);
215                SET_SOCKADDRPORT(addr, host->port);
216             }
217             else {
218                snprintf(emsg, emsglen,
219                         "strange dns reply.  res->ai_addrlen (%lu) > "
220                         "addrlen (%lu)",
221                         (unsigned long)res->ai_addrlen,
222                         (unsigned long)addrlen);
223 
224                swarnx("%s: %s", function, emsg);
225                addr->ss_family = AF_UNSPEC;
226             }
227          }
228          else {
229             char visbuf[MAXHOSTNAMELEN * 4];
230 
231             snprintf(emsg, emsglen,
232                      "could not resolve hostname \"%s\": %s",
233                      str2vis(host->addr.domain,
234                              strlen(host->addr.domain),
235                              visbuf,
236                              sizeof(visbuf)),
237                      gai_strerror(*gaierr));
238 
239             slog(LOG_NEGOTIATE, "%s: %s", function, emsg);
240             addr->ss_family = AF_UNSPEC;
241          }
242 
243          break;
244       }
245 
246       case SOCKS_ADDR_IFNAME: {
247          struct sockaddr_storage a, m;
248 
249          if (ifname2sockaddr(host->addr.ifname, 0, &a, &m) != NULL) {
250             sockaddrcpy(addr, &a, addrlen);
251             SET_SOCKADDRPORT(addr, host->port);
252          }
253          else {
254             snprintf(emsg, emsglen,
255                      "could not resolve %s to IP-address",
256                      sockshost2string2(host, ADDRINFO_ATYPE, NULL, 0));
257 
258             slog(LOG_NEGOTIATE, "%s: %s", function, emsg);
259 
260             addr->ss_family = AF_UNSPEC;
261          }
262 
263          break;
264       }
265 
266       case SOCKS_ADDR_URL:
267          urlstring2sockaddr(host->addr.urlname, addr, gaierr, emsg, emsglen);
268          break;
269 
270       default:
271          SERRX(host->atype);
272    }
273 
274    SASSERTX(addr->ss_family == AF_UNSPEC
275    ||       addr->ss_family == AF_INET
276    ||       addr->ss_family == AF_INET6);
277 
278    return addr;
279 }
280 
281 struct sockaddr_storage *
int_sockshost2sockaddr(host,addr,addrlen)282 int_sockshost2sockaddr(host, addr, addrlen)
283    const sockshost_t *host;
284    struct sockaddr_storage *addr;
285    size_t addrlen;
286 {
287    int p;
288 
289    return int_sockshost2sockaddr2(host, addr, addrlen, &p, NULL, 0);
290 }
291 
292 
293 sockshost_t *
sockaddr2sockshost(addr,host)294 sockaddr2sockshost(addr, host)
295    const struct sockaddr_storage *addr;
296    sockshost_t *host;
297 {
298 
299    if (host == NULL) {
300       static sockshost_t _host;
301 
302       host = &_host;
303    }
304 
305    switch (addr->ss_family) {
306       case AF_INET:
307          host->atype     = SOCKS_ADDR_IPV4;
308          host->addr.ipv4 = TOCIN(addr)->sin_addr;
309          host->port      = TOCIN(addr)->sin_port;
310          break;
311 
312       case AF_INET6:
313          host->atype             = SOCKS_ADDR_IPV6;
314          host->addr.ipv6.ip      = TOCIN6(addr)->sin6_addr;
315          host->addr.ipv6.scopeid = TOCIN6(addr)->sin6_scope_id;
316          host->port              = TOCIN6(addr)->sin6_port;
317          break;
318 
319       default:
320          SERRX(addr->ss_family);
321    }
322 
323    return host;
324 }
325 
326 int
sockaddr2hostname(sa,hostname,hostnamelen)327 sockaddr2hostname(sa, hostname, hostnamelen)
328    const struct sockaddr_storage *sa;
329    char *hostname;
330    const size_t hostnamelen;
331 {
332    const char *function = "sockaddr2hostname()";
333    char vbuf[MAXHOSTNAMELEN * 4];
334    int rc;
335 
336    rc = getnameinfo(TOCSA(sa),
337                     salen(sa->ss_family),
338                     hostname,
339                     hostnamelen,
340                     NULL,
341                     0,
342                     NI_NAMEREQD);
343 
344    if (rc != 0) {
345       slog(LOG_DEBUG, "%s: getnameinfo(%s) failed: %s",
346            function,
347            sockaddr2string2(sa, 0, NULL, 0),
348            gai_strerror(rc));
349 
350       return rc;
351    }
352 
353    slog(LOG_DEBUG, "%s: %s resolved to \"%s\"",
354         function,
355         sockaddr2string2(sa, 0, NULL, 0),
356         str2vis(hostname, strlen(hostname), vbuf, sizeof(vbuf)));
357 
358    return rc;
359 }
360 
361 
362 struct sockaddr_storage *
int_ruleaddr2sockaddr2(address,sa,len,protocol,gaierr,emsg,emsglen)363 int_ruleaddr2sockaddr2(address, sa, len, protocol, gaierr, emsg, emsglen)
364    const ruleaddr_t *address;
365    struct sockaddr_storage *sa;
366    size_t len;
367    const int protocol;
368    int *gaierr;
369    char *emsg;
370    const size_t emsglen;
371 {
372    sockshost_t host;
373 
374    if (sa == NULL) {
375       static struct sockaddr_storage samem;
376 
377       sa  = &samem;
378       len = sizeof(samem);
379    }
380 
381    ruleaddr2sockshost(address, &host, protocol);
382    return int_sockshost2sockaddr2(&host, sa, len, gaierr, emsg, emsglen);
383 }
384 
385 struct sockaddr_storage *
int_ruleaddr2sockaddr(address,sa,len,protocol)386 int_ruleaddr2sockaddr(address, sa, len, protocol)
387    const ruleaddr_t *address;
388    struct sockaddr_storage *sa;
389    size_t len;
390    const int protocol;
391 {
392    int gaierr;
393 
394    return int_ruleaddr2sockaddr2(address, sa, len, protocol, &gaierr, NULL, 0);
395 }
396 
397 sockshost_t *
ruleaddr2sockshost(address,host,protocol)398 ruleaddr2sockshost(address, host, protocol)
399    const ruleaddr_t *address;
400    sockshost_t *host;
401    int protocol;
402 {
403    const char *function = "ruleaddr2sockshost()";
404 
405    if (host == NULL) {
406       static sockshost_t hostmem;
407 
408       host = &hostmem;
409    }
410 
411    switch (host->atype = address->atype) {
412       case SOCKS_ADDR_IPV4:
413          host->addr.ipv4 = address->addr.ipv4.ip;
414          break;
415 
416       case SOCKS_ADDR_IPV6:
417          host->addr.ipv6.ip      = address->addr.ipv6.ip;
418          host->addr.ipv6.scopeid = address->addr.ipv6.scopeid;
419          break;
420 
421       case SOCKS_ADDR_DOMAIN:
422          STRCPY_ASSERTSIZE(host->addr.domain, address->addr.domain);
423          break;
424 
425       case SOCKS_ADDR_IFNAME: {
426          struct sockaddr_storage addr, p;
427 
428          if (ifname2sockaddr(address->addr.ifname, 0, &addr, &p) == NULL){
429             swarnx("%s: cannot find interface named %s with IP configured.  "
430                    "Using address %d instead",
431                    function, address->addr.ifname, INADDR_ANY);
432 
433             host->atype            = SOCKS_ADDR_IPV4;
434             host->addr.ipv4.s_addr = htonl(INADDR_ANY);
435          }
436          else {
437             switch (addr.ss_family) {
438                case AF_INET:
439                   host->addr.ipv4 = TOIN(&addr)->sin_addr;
440                   break;
441 
442                case AF_INET6:
443                   host->addr.ipv6.ip      = TOIN6(&addr)->sin6_addr;
444                   host->addr.ipv6.scopeid = TOIN6(&addr)->sin6_scope_id;
445                   break;
446 
447                default:
448                   SERRX(addr.ss_family);
449 
450             }
451 
452             host->atype = safamily2atype(addr.ss_family);
453          }
454 
455          break;
456       }
457 
458       default:
459          SERRX(address->atype);
460    }
461 
462    switch (protocol) {
463       case SOCKS_TCP:
464          host->port = address->port.tcp;
465          break;
466 
467       case SOCKS_UDP:
468          host->port = address->port.udp;
469          break;
470 
471       default:
472          SERRX(protocol);
473    }
474 
475    return host;
476 }
477 
478 ruleaddr_t *
sockshost2ruleaddr(host,addr)479 sockshost2ruleaddr(host, addr)
480    const sockshost_t *host;
481    ruleaddr_t *addr;
482 {
483 
484    if (addr == NULL) {
485       static ruleaddr_t addrmem;
486 
487       addr = &addrmem;
488    }
489 
490    switch (addr->atype = host->atype) {
491       case SOCKS_ADDR_IPV4:
492          addr->addr.ipv4.ip            = host->addr.ipv4;
493          addr->addr.ipv4.mask.s_addr   = htonl(IPV4_FULLNETMASK);
494          break;
495 
496       case SOCKS_ADDR_IPV6:
497          addr->addr.ipv6.ip        = host->addr.ipv6.ip;
498          addr->addr.ipv6.maskbits  = IPV6_NETMASKBITS;
499          addr->addr.ipv6.scopeid   = host->addr.ipv6.scopeid;
500          break;
501 
502       case SOCKS_ADDR_DOMAIN:
503          STRCPY_ASSERTSIZE(addr->addr.domain, host->addr.domain);
504          break;
505 
506       default:
507          SERRX(host->atype);
508    }
509 
510 
511    if (host->port == htons(0)) {
512       addr->operator   = none;
513       addr->port.tcp   = addr->port.udp = addr->portend = htons(0);
514    }
515    else {
516       addr->operator  = eq;
517       addr->port.tcp  = host->port;
518       addr->port.udp  = host->port;
519       addr->portend   = host->port;
520    }
521 
522    return addr;
523 }
524 
525 ruleaddr_t *
sockaddr2ruleaddr(addr,ruleaddr)526 sockaddr2ruleaddr(addr, ruleaddr)
527    const struct sockaddr_storage *addr;
528    ruleaddr_t *ruleaddr;
529 {
530    sockshost_t host;
531 
532    sockaddr2sockshost(addr, &host);
533    sockshost2ruleaddr(&host, ruleaddr);
534 
535    return ruleaddr;
536 }
537 
538 struct sockaddr_storage *
int_hostname2sockaddr(name,index,addr,addrlen)539 int_hostname2sockaddr(name, index, addr, addrlen)
540    const char *name;
541    size_t index;
542    struct sockaddr_storage *addr;
543    size_t addrlen;
544 {
545    int rc;
546 
547    return int_hostname2sockaddr2(name, index, addr, addrlen, &rc, NULL, 0);
548 }
549 
550 
551 struct sockaddr_storage *
int_hostname2sockaddr2(name,index,addr,addrlen,gaierr,emsg,emsglen)552 int_hostname2sockaddr2(name, index, addr, addrlen, gaierr, emsg, emsglen)
553    const char *name;
554    size_t index;
555    struct sockaddr_storage *addr;
556    size_t addrlen;
557    int *gaierr;
558    char *emsg;
559    size_t emsglen;
560 {
561    const char *function = "int_hostname2sockaddr()";
562    struct addrinfo *ai, hints;
563    dnsinfo_t aimem;
564    size_t i;
565    char emsgmem[1024 + MAXHOSTNAMELEN * 4];
566 
567    if (emsg == NULL || emsglen == 0) {
568       emsg    = emsgmem;
569       emsglen = sizeof(emsgmem);
570    }
571 
572    *emsg   = NUL;
573    *gaierr = 0;
574 
575    bzero(addr, addrlen);
576    SET_SOCKADDR(addr, AF_UNSPEC);
577 
578    bzero(&hints, sizeof(hints));
579    if ((*gaierr = cgetaddrinfo(name, NULL, &hints, &ai, &aimem)) != 0) {
580       char visbuf[MAXHOSTNAMELEN * 4];
581 
582       snprintf(emsg, emsglen, "could not resolve hostname \"%s\": %s",
583                str2vis(name, strlen(name), visbuf, sizeof(visbuf)),
584                gai_strerror(*gaierr));
585 
586       slog(LOG_DEBUG, "%s: could not resolve hostname \"%s\": %s",
587            function, visbuf, gai_strerror(*gaierr));
588 
589       return NULL;
590    }
591 
592    i = 0;
593    do {
594       SASSERTX(ai->ai_addr != NULL);
595 
596       if (i == index) {
597          sockaddrcpy(addr, TOSS(ai->ai_addr), addrlen);
598          return addr;
599       }
600 
601       ++i;
602       ai = ai->ai_next;
603    } while (ai != NULL);
604 
605    return NULL;
606 }
607 
608 
609 struct sockaddr_storage *
int_ifname2sockaddr(ifname,index,addr,addrlen,mask,masklen)610 int_ifname2sockaddr(ifname, index, addr, addrlen, mask, masklen)
611    const char *ifname;
612    size_t index;
613    struct sockaddr_storage *addr;
614    size_t addrlen;
615    struct sockaddr_storage *mask;
616    size_t masklen;
617 {
618    const char *function = "int_ifname2sockaddr()";
619    struct ifaddrs ifa, *ifap = &ifa, *iface;
620    size_t i, realindex;
621    int foundifname, foundaddr;
622 
623    if (getifaddrs(&ifap) != 0) {
624       swarn("%s: getifaddrs() failed", function);
625       return NULL;
626    }
627 
628    for (iface = ifap, i = 0, realindex = 0, foundifname = foundaddr = 0;
629    i <= index && iface != NULL;
630    iface = iface->ifa_next, ++realindex) {
631       if (strcmp(iface->ifa_name, ifname) != 0)
632          continue;
633 
634       foundifname = 1;
635 
636       if (iface->ifa_addr == NULL) {
637          slog(LOG_DEBUG,
638               "%s: interface %s missing address on index %lu ... skipping",
639               function, iface->ifa_name, (unsigned long)realindex);
640 
641          continue;
642       }
643 
644       if (iface->ifa_netmask == NULL) {
645          slog(LOG_DEBUG,
646               "%s: interface %s missing netmask for address %s, skipping",
647               function,
648               iface->ifa_name,
649               sockaddr2string(TOSS(iface->ifa_addr), NULL, 0));
650 
651          continue;
652       }
653 
654       if (iface->ifa_addr->sa_family != AF_INET
655       &&  iface->ifa_addr->sa_family != AF_INET6) {
656          slog(LOG_DEBUG,
657               "%s: interface %s has neither AF_INET nor AF_INET6 configured "
658               "at index %lu, skipping",
659               function, iface->ifa_name, (unsigned long)index);
660 
661          continue;
662       }
663 
664       /*
665        * this address-index looks usable.  Does it match the requested
666        * index?
667        */
668       if (i != index) {
669          ++i;        /* we only count usable indexes. */
670          continue;
671       }
672 
673       foundaddr = 1;
674 
675       sockaddrcpy(addr, TOSS(iface->ifa_addr), addrlen);
676 
677       if (mask != NULL)
678          sockaddrcpy(mask, TOSS(iface->ifa_netmask), masklen);
679 
680       break;
681    }
682 
683    freeifaddrs(ifap);
684 
685    if (!foundifname) {
686       slog(LOG_DEBUG, "%s: no interface with the name \"%s\" found",
687            function, ifname);
688 
689       return NULL;
690    }
691 
692    if (!foundaddr) {
693       if (index == 0) {
694          char visbuf[MAXIFNAMELEN * 4];
695 
696          swarnx("%s: interface \"%s\" has no usable IP-addresses configured",
697                 function,
698                 str2vis(ifname, strlen(ifname), visbuf, sizeof(visbuf)));
699 
700       }
701 
702       return NULL;
703    }
704 
705    return addr;
706 }
707 
708 const char *
sockaddr2ifname(addr,ifname,iflen)709 sockaddr2ifname(addr, ifname, iflen)
710    struct sockaddr_storage *addr;
711    char *ifname;
712    size_t iflen;
713 {
714    const char *function = "sockaddr2ifname()";
715    struct ifaddrs ifa, *ifap = &ifa, *iface;
716    size_t nocompare;
717 
718    if (ifname == NULL || iflen == 0) {
719       static char ifname_mem[MAXIFNAMELEN];
720 
721       ifname = ifname_mem;
722       iflen  = sizeof(ifname_mem);
723    }
724 
725    /*
726     * port is irrelevant as far as an interface-address is concerned,
727     * so make a copy of the address and zero it before we start
728     * comparing.
729     */
730    nocompare = ADDRINFO_PORT;
731 
732    if (addr->ss_family == AF_INET6
733    &&  TOIN6(addr)->sin6_scope_id == 0)
734       /*
735        * no particular scope requested, match all.
736        */
737       nocompare |= ADDRINFO_SCOPEID;
738 
739    if (getifaddrs(&ifap) != 0)
740       return NULL;
741 
742    for (iface = ifap; iface != NULL; iface = iface->ifa_next) {
743       if (iface->ifa_addr != NULL
744       &&  sockaddrareeq(TOSS(iface->ifa_addr), addr, nocompare)) {
745          strncpy(ifname, iface->ifa_name, iflen - 1);
746          ifname[iflen - 1] = NUL;
747 
748          slog(LOG_DEBUG, "%s: address %s belongs to interface %s (af: %s)",
749               function,
750               sockaddr2string(addr, NULL, 0),
751               ifname,
752               safamily2string(iface->ifa_addr->sa_family));
753 
754          freeifaddrs(ifap);
755          return ifname;
756       }
757       else
758          slog(LOG_DEBUG,
759               "%s: address %s does not belong to interface %s (af: %s)",
760               function,
761               sockaddr2string(addr, NULL, 0),
762               iface->ifa_name,
763               iface->ifa_addr == NULL ?
764                   "<no address>" : safamily2string(iface->ifa_addr->sa_family));
765    }
766 
767    freeifaddrs(ifap);
768    return NULL;
769 }
770 
771 int
sockshostareeq(a,b)772 sockshostareeq(a, b)
773    const sockshost_t *a;
774    const sockshost_t *b;
775 {
776 
777    if (a->atype != b->atype)
778       return 0;
779 
780    if (a->port != b->port)
781       return 0;
782 
783    switch (a->atype) {
784       case SOCKS_ADDR_IPV4:
785          if (memcmp(&a->addr.ipv4, &b->addr.ipv4, sizeof(a->addr.ipv4)) != 0)
786             return 0;
787          break;
788 
789       case SOCKS_ADDR_IPV6:
790          if (memcmp(&a->addr.ipv6, &b->addr.ipv6, sizeof(a->addr.ipv6)) != 0)
791             return 0;
792          break;
793 
794       case SOCKS_ADDR_DOMAIN:
795          if (strcmp(a->addr.domain, b->addr.domain) != 0)
796             return 0;
797          break;
798 
799       default:
800          SERRX(a->atype);
801    }
802 
803    return 1;
804 }
805 
806 int
fdsetop(highestfd,op,a,b,result)807 fdsetop(highestfd, op, a, b, result)
808    int highestfd;
809    int op;
810    const fd_set *a;
811    const fd_set *b;
812    fd_set *result;
813 {
814    int i, bits;
815 
816    bits = -1;
817    switch (op) {
818       case '&':
819          FD_ZERO(result);
820          for (i = 0; i <= highestfd; ++i)
821             if (FD_ISSET(i, a) && FD_ISSET(i, b)) {
822                FD_SET(i, result);
823                bits = MAX(i, bits);
824             }
825 
826          break;
827 
828       case '^':
829          FD_ZERO(result);
830          for (i = 0; i <= highestfd; ++i)
831             if (FD_ISSET(i, a) != FD_ISSET(i, b)) {
832                FD_SET(i, result);
833                bits = MAX(i, bits);
834             }
835             else
836                FD_CLR(i, result);
837 
838          break;
839 
840       case '|':
841          /*
842           * no FD_ZERO() required.  Allows caller to call us without using
843           * a temporary object for result if he wants to do result = a | b.
844           */
845          for (i = 0; i <= highestfd; ++i)
846             if (FD_ISSET(i, a) || FD_ISSET(i, b)) {
847                FD_SET(i, result);
848                bits = MAX(i, bits);
849             }
850          break;
851 
852       default:
853          SERRX(op);
854    }
855 
856    return bits;
857 }
858 
859 int
methodisset(method,methodv,methodc)860 methodisset(method, methodv, methodc)
861    int method;
862    const int *methodv;
863    size_t methodc;
864 {
865    const char *function = "methodisset()";
866    size_t i;
867 
868    if (sockscf.option.debug)
869       slog(LOG_DEBUG,
870            "%s: checking if method %s is set in the list (%lu) \"%s\"",
871            function,
872            method2string(method),
873            (unsigned long)methodc,
874            methods2string(methodc, methodv, NULL, 0));
875 
876    for (i = 0; i < methodc; ++i)
877       if (methodv[i] == method)
878          return 1;
879 
880    return 0;
881 }
882 
883 char *
str2vis(string,len,visstring,vislen)884 str2vis(string, len, visstring, vislen)
885    const char *string;
886    size_t len;
887    char *visstring;
888    size_t vislen;
889 {
890    const int visflag = VIS_SP | VIS_TAB | VIS_NL | VIS_CSTYLE | VIS_OCTAL;
891 
892    if (visstring == NULL) {
893       SERRX(0); /* should never be used. */
894 
895       /* see vis(3) for "* 4" */
896       if ((visstring = malloc((sizeof(*visstring) * len * 4) + 1)) == NULL)
897          return NULL;
898 
899       vislen = len * 4 + 1;
900    }
901 
902    len = MIN(len, (vislen / 4) - 1);
903    strvisx(visstring, string, len, visflag);
904 
905    return visstring;
906 }
907 
908 int
socks_mklock(template,newname,newnamelen)909 socks_mklock(template, newname, newnamelen)
910    const char *template;
911    char *newname;
912    const size_t newnamelen;
913 {
914    const char *function = "socks_mklock()";
915    static char newtemplate[PATH_MAX];
916    size_t len;
917    char *prefix;
918    int s, flag;
919 
920    if ((prefix = socks_getenv(ENV_TMPDIR, dontcare)) != NULL)
921       if (*prefix == NUL)
922          prefix = NULL;
923 
924    if (prefix == NULL)
925       prefix = "/tmp";
926 
927    len = strlen(prefix) + strlen("/") + strlen(template) + 1;
928    if (len > sizeof(newtemplate))
929       serr("%s: the combination of \"%s\" and \"%s\""
930            "is longer than the system max path length of %lu",
931            function, prefix, template, (unsigned long)sizeof(newtemplate));
932 
933    if (newnamelen != 0 && len > newnamelen)
934       serr("%s: the combination of \"%s\" and \"%s\""
935            "is longer than the passed maxlength length of %lu",
936            function, prefix, template, (unsigned long)newnamelen);
937 
938    if (*prefix != NUL)
939       snprintf(newtemplate, len, "%s/%s", prefix, template);
940    else
941       snprintf(newtemplate, len, "%s", template);
942 
943    if (sockscf.option.debug >= DEBUG_VERBOSE)
944       slog(LOG_DEBUG, "%s: newtemplate = \"%s\", prefix = \"%s\" "
945            "uid = %d, euid = %d, gid = %d, egid = %d",
946            function, newtemplate, prefix,
947            (int)getuid(), (int)geteuid(), (int)getgid(), (int)getegid());
948 
949    if (strstr(newtemplate, "XXXXXX") != NULL) {
950       const mode_t oldumask = umask(S_IWGRP | S_IWOTH);
951 
952       if ((s = mkstemp(newtemplate)) == -1)
953          swarn("%s: mkstemp(%s) using euid/egid %d/%d failed",
954                function, newtemplate, (int)geteuid(), (int)getegid());
955 
956       (void)umask(oldumask);
957 
958 #if HAVE_SOLARIS_BUGS
959       if (s == -1 && *newtemplate == NUL) {
960           /*
961            * Solaris 5.11 sometimes loses the template on failure. :-/
962            */
963          if (*prefix != NUL)
964             snprintf(newtemplate, len, "%s/%s", prefix, template);
965          else
966             snprintf(newtemplate, len, "%s", template);
967       }
968 #endif /* HAVE_SOLARIS_BUGS */
969    }
970    else {
971       s = open(newtemplate, O_RDWR | O_CREAT | O_EXCL, 0600);
972       swarn("%s: open(%s)", function, newtemplate);
973    }
974 
975    if (s == -1) {
976       if (*prefix == NUL) {
977          slog(LOG_DEBUG, "%s: failed to create \"%s\" (%s) and TMPDIR is not "
978                          "set.  Trying again with TMPDIR set to \"/tmp\"",
979                          function, newtemplate, strerror(errno));
980 
981          if (setenv("TMPDIR", "/tmp", 1) != 0)
982             serr("%s: could not setenv(\"TMPDIR\", \"/tmp\")", function);
983 
984          SASSERT(socks_getenv(ENV_TMPDIR, dontcare) != NULL);
985 
986          return socks_mklock(template, newname, newnamelen);
987       }
988 
989       return -1;
990    }
991    else
992       if (sockscf.option.debug >= DEBUG_VERBOSE)
993          slog(LOG_DEBUG, "%s: created file %s", function, newtemplate);
994 
995    if (newnamelen == 0) {
996       if (unlink(newtemplate) == -1) {
997          swarn("%s: unlink(%s)", function, newtemplate);
998          close(s);
999 
1000          return -1;
1001       }
1002    }
1003    else
1004       strcpy(newname, newtemplate);
1005 
1006    if ((flag = fcntl(s, F_GETFD, 0))       == -1
1007    || fcntl(s, F_SETFD, flag | FD_CLOEXEC) == -1)
1008       swarn("%s: fcntl(F_GETFD/F_SETFD)", function);
1009 
1010    return s;
1011 }
1012 
1013 int
socks_lock(d,offset,len,exclusive,wait)1014 socks_lock(d, offset, len, exclusive, wait)
1015    const int d;
1016    const off_t offset;
1017    const off_t len;
1018    const int exclusive;
1019    const int wait;
1020 {
1021    const char *function = "socks_lock()";
1022    struct flock lock;
1023    int rc;
1024 
1025 /*   slog(LOG_DEBUG, "%s: %d", function, d);  */
1026 
1027    if (d == -1)
1028       return 0;
1029 
1030    lock.l_start  = offset;
1031    lock.l_len    = len;
1032    lock.l_whence = SEEK_SET;
1033    lock.l_type   = exclusive ? F_WRLCK : F_RDLCK;
1034 
1035 #if DIAGNOSTIC && 0
1036 {
1037    struct flock diaginfo = lock;
1038 
1039    if (d != sockscf.loglock && fcntl(d, F_GETLK, &diaginfo) != -1)
1040       if (diaginfo.l_type != F_UNLCK)
1041          slog(LOG_DEBUG, "%s: lock %d is currently held by pid %ld",
1042               function, d, (long)diaginfo.l_pid);
1043 }
1044 #endif /* DIAGNOSTIC && 0*/
1045 
1046    do
1047       rc = fcntl(d, wait ? F_SETLKW : F_SETLK, &lock);
1048    while (rc == -1 && wait && (ERRNOISTMP(errno) || errno == EACCES));
1049 
1050    if (rc == -1) {
1051       if (!sockscf.state.inited
1052       &&  sockscf.loglock == d
1053       &&  sockscf.loglock == 0) { /* have not yet inited lockfile. */
1054          sockscf.loglock = -1;
1055          return 0;
1056       }
1057 
1058       SASSERT(ERRNOISTMP(errno) || errno == EACCES);
1059       SASSERT(!wait);
1060    }
1061 
1062    return rc;
1063 }
1064 
1065 void
socks_unlock(d,offset,len)1066 socks_unlock(d, offset, len)
1067    int d;
1068    const off_t offset;
1069    const off_t len;
1070 {
1071 /*   const char *function = "socks_unlock()";  */
1072    struct flock lock;
1073 
1074 /*   slog(LOG_DEBUG, "%s: %d", function, d);  */
1075 
1076    if (d == -1)
1077       return;
1078 
1079    lock.l_start  = offset;
1080    lock.l_len    = len;
1081    lock.l_type   = F_UNLCK;
1082    lock.l_whence = SEEK_SET;
1083 
1084    if (fcntl(d, F_SETLK, &lock) == -1)
1085       SERR(errno);
1086 }
1087 
1088 int
fdisopen(fd)1089 fdisopen(fd)
1090    const int fd;
1091 {
1092    const int errno_s = errno;
1093    const int rc = fcntl(fd, F_GETFD, 0);
1094 
1095    errno = errno_s;
1096    return rc != -1;
1097 }
1098 
1099 int
fdisblocking(fd)1100 fdisblocking(fd)
1101    const int fd;
1102 {
1103    const char *function = "fdisblocking()";
1104    int p;
1105 
1106    if ((p = fcntl(fd, F_GETFL, 0)) == -1) {
1107       swarn("%s: fcntl(F_GETFL)", function);
1108       return 1;
1109    }
1110 
1111    return !(p & O_NONBLOCK);
1112 }
1113 
1114 void
closev(ic,iv)1115 closev(ic, iv)
1116    size_t ic;
1117    int *iv;
1118 {
1119    size_t i;
1120 
1121    for (i = 0; i < ic; ++i)
1122       if (iv[i] >= 0)
1123          if (close(iv[i]) != 0)
1124             SWARN(iv[i]);
1125 }
1126 
1127 /*
1128  * Posted by Kien Ha (Kien_Ha@Mitel.COM) in comp.lang.c once upon a
1129  * time.
1130 */
1131 int
bitcount(number)1132 bitcount(number)
1133    unsigned long number;
1134 {
1135    int bitsset;
1136 
1137    for (bitsset = 0; number > 0; number >>= 1)
1138       if (number & 1)
1139          ++bitsset;
1140 
1141    return bitsset;
1142 }
1143 
1144 int
bitcount_in6addr(in6addr)1145 bitcount_in6addr(in6addr)
1146    const struct in6_addr *in6addr;
1147 {
1148    size_t i;
1149    int bitsset;
1150 
1151    for (i = 0, bitsset = 0; i < ELEMENTS(in6addr->s6_addr); ++i)
1152       bitsset += bitcount((unsigned long)in6addr->s6_addr[i]);
1153 
1154    return bitsset;
1155 }
1156 
1157 
1158 fd_set *
allocate_maxsize_fdset(void)1159 allocate_maxsize_fdset(void)
1160 {
1161    const char *function = "allocate_maxsize_fdset()";
1162    fd_set *set;
1163 
1164 #if SOCKS_CLIENT
1165    sockscf.state.maxopenfiles = getmaxofiles(hardlimit);
1166    if (sockscf.state.maxopenfiles == (rlim_t)RLIM_INFINITY)
1167       /*
1168        * In the client the softlimit can vary at any time, so this is not
1169        * 100%, but see no other practical solution at the moment.
1170        */
1171       sockscf.state.maxopenfiles = getmaxofiles(softlimit);
1172 #endif /* !SOCKS_CLIENT */
1173 
1174    SASSERTX(sockscf.state.maxopenfiles < (rlim_t)RLIM_INFINITY);
1175    SASSERTX(sockscf.state.maxopenfiles > 0);
1176 
1177    if ((set = malloc(MAX(sizeof(fd_set), SOCKD_FD_SIZE()))) == NULL)
1178       serr("%s: malloc() of %lu bytes for fd_set failed",
1179            function, (unsigned long)MAX(sizeof(fd_set), SOCKD_FD_SIZE()));
1180 
1181 #if DEBUG
1182    if (sockscf.option.debug >= DEBUG_VERBOSE)
1183       slog(LOG_DEBUG, "%s: allocated %lu bytes",
1184            function, (unsigned long)SOCKD_FD_SIZE());
1185 #endif /* DEBUG */
1186 
1187    return set;
1188 }
1189 
1190 rlim_t
getmaxofiles(limittype_t type)1191 getmaxofiles(limittype_t type)
1192 {
1193    const char *function = "getmaxofiles()";
1194    struct rlimit rlimit;
1195    rlim_t limit;
1196 
1197    if (getrlimit(RLIMIT_OFILE, &rlimit) != 0)
1198          serr("%s: getrlimit(RLIMIT_OFILE)", function);
1199 
1200    if (type == softlimit)
1201       limit = rlimit.rlim_cur;
1202    else if (type == hardlimit)
1203 #if HAVE_DARWIN /* documented os x bug.  What on earth are they thinking? */
1204       limit = MIN(rlimit.rlim_max, OPEN_MAX);
1205 #else /* !HAVE_DARWIN */
1206       limit = rlimit.rlim_max;
1207 #endif /* !HAVE_DARWIN */
1208    else
1209       SERRX(type);
1210       /* NOTREACHED */
1211 
1212 #if !SOCKS_CLIENT && FD_SETSIZE_LIMITS_SELECT
1213    /*
1214     * we don't mess with the clients limits.  Not our business whether
1215     * select(2) will work or not if a fd has a index that would overflow
1216     * FD_SETSIZE.
1217     */
1218    if (limit >= FD_SETSIZE) {
1219       static int logged;
1220 
1221       if (!logged) {
1222          slog(LOG_INFO,
1223               "%s: max open file limit is %lu, but we need to shrink it "
1224               "down to below FD_SETSIZE (%lu) for select(2) to work",
1225               function, (unsigned long)limit, (unsigned long)FD_SETSIZE);
1226 
1227          logged = 1;
1228       }
1229 
1230       limit = FD_SETSIZE - 1;
1231    }
1232 #endif /* !SOCKS_CLIENT && FD_SETSIZE_LIMITS_SELECT */
1233 
1234    if (type == softlimit && limit == (rlim_t)RLIM_INFINITY) {
1235       static int logged;
1236       const rlim_t reduced = 65356;
1237 
1238       if (!logged) {
1239          slog(LOG_INFO,
1240               "%s: maxopenfiles is RLIM_INFINITY (%lu), reducing to %lu",
1241               function, (unsigned long)RLIM_INFINITY, (unsigned long)reduced);
1242 
1243          logged = 1;
1244       }
1245 
1246       limit = reduced;
1247    }
1248 
1249    return limit;
1250 }
1251 
1252 void
socks_sigblock(sig,oldset)1253 socks_sigblock(sig, oldset)
1254    const int sig;
1255    sigset_t *oldset;
1256 {
1257    const char *function = "socks_sigblock()";
1258    sigset_t newmask;
1259 
1260    if (sig == -1)
1261       (void)sigfillset(&newmask);
1262    else {
1263       (void)sigemptyset(&newmask);
1264       (void)sigaddset(&newmask, sig);
1265    }
1266 
1267    if (sigprocmask(SIG_BLOCK, &newmask, oldset) != 0)
1268       swarn("%s: sigprocmask()", function);
1269 }
1270 
1271 void
socks_sigunblock(oldset)1272 socks_sigunblock(oldset)
1273    const sigset_t *oldset;
1274 {
1275    const char *function = "socks_sigunblock()";
1276 
1277    if (sigprocmask(SIG_SETMASK, oldset, NULL) != 0)
1278       swarn("%s: sigprocmask()", function);
1279 }
1280 
1281 int
socks_msghaserrors(prefix,msg)1282 socks_msghaserrors(prefix, msg)
1283    const char *prefix;
1284    const struct msghdr *msg;
1285 {
1286    if (msg->msg_flags & MSG_TRUNC) {
1287       swarnx("%s: msg is truncated ... message discarded", prefix);
1288 
1289       if (CMSG_TOTLEN(*msg) > 0)
1290          swarnx("%s: XXX should close received descriptors", prefix);
1291 
1292       return 1;
1293    }
1294 
1295    if (msg->msg_flags & MSG_CTRUNC) {
1296       swarnx("%s: cmsg was truncated ... message discarded", prefix);
1297       return 1;
1298    }
1299 
1300    return 0;
1301 }
1302 
1303 void
seconds2days(seconds,days,hours,minutes)1304 seconds2days(seconds, days, hours, minutes)
1305    unsigned long *seconds;
1306    unsigned long *days;
1307    unsigned long *hours;
1308    unsigned long *minutes;
1309 {
1310 
1311    if (*seconds >= 3600 * 24) {
1312       *days     = *seconds / (3600 * 24);
1313       *seconds -= (time_t)(*days * 3600 * 24);
1314    }
1315    else
1316       *days = 0;
1317 
1318    if (*seconds >= 3600) {
1319       *hours    = *seconds / 3600;
1320       *seconds -= (time_t)(*hours * 3600);
1321    }
1322    else
1323       *hours = 0;
1324 
1325    if (*seconds >= 60) {
1326       *minutes  = *seconds / 60;
1327       *seconds -= (time_t)(*minutes * 60);
1328    }
1329    else
1330       *minutes = 0;
1331 
1332 #if DIAGNOSTIC
1333    SASSERTX(*seconds < 60);
1334    SASSERTX(*minutes < 60);
1335    SASSERTX(*hours   < 24);
1336 #endif /* DIAGNOSTIC */
1337 
1338 }
1339 
1340 struct sockaddr_storage *
int_urlstring2sockaddr(string,saddr,saddrlen,gaierr,emsg,emsglen)1341 int_urlstring2sockaddr(string, saddr, saddrlen, gaierr, emsg, emsglen)
1342    const char *string;
1343    struct sockaddr_storage *saddr;
1344    size_t saddrlen;
1345    int *gaierr;
1346    char *emsg;
1347    size_t emsglen;
1348 {
1349    const char *function = "int_urlstring2sockaddr()";
1350    const char *httpprefix = "http://";
1351    char buf[1024], vbuf[sizeof(buf) * 4], vstring[sizeof(vbuf)],
1352         emsgmem[1024], *port, *s;
1353    long portnumber;
1354    int haveportsep;
1355 
1356    *gaierr = 0;
1357 
1358    bzero(saddr, saddrlen);
1359    SET_SOCKADDR(saddr, AF_UNSPEC);
1360 
1361    if (emsg == NULL) {
1362       emsg    = emsgmem;
1363       emsglen = sizeof(emsgmem);
1364    }
1365 
1366    slog(LOG_DEBUG, "%s: string to parse is \"%s\"",
1367         function, str2vis(string, strlen(string), vstring, sizeof(vstring)));
1368 
1369    if (strstr(string, httpprefix) == NULL) {
1370       snprintf(emsg, emsglen,
1371                "could not find http prefix (%s) in http address \"%s\"",
1372                httpprefix, vstring);
1373 
1374       slog(LOG_DEBUG, "%s: %s", function, emsg);
1375       return NULL;
1376    }
1377 
1378    string += strlen(httpprefix);
1379 
1380    snprintf(buf, sizeof(buf), "%s", string);
1381 
1382    if ((s = strchr(buf, ':')) == NULL) {
1383       slog(LOG_DEBUG, "%s: could not find port separator in \"%s\"",
1384            function, vstring);
1385 
1386       haveportsep = 0;
1387    }
1388    else {
1389       haveportsep = 1;
1390       *s = NUL;
1391    }
1392 
1393    if (*buf == NUL) {
1394       snprintf(emsg, emsglen,
1395                "could not find address string in \"%s\"", vstring);
1396 
1397       slog(LOG_DEBUG, "%s: %s", function, emsg);
1398       return NULL;
1399    }
1400 
1401    slog(LOG_DEBUG, "%s: pre-portnumber string (%s): \"%s\"",
1402         function,
1403         haveportsep ? "portnumber comes later" : "no portnumber given",
1404         str2vis(buf, strlen(buf), vbuf, sizeof(vbuf)));
1405 
1406    if (socks_inet_pton(saddr->ss_family, buf, &(TOIN(saddr)->sin_addr), NULL)
1407    != 1) {
1408       struct hostent *hostent;
1409       char *ep;
1410 
1411       errno = 0;
1412       (void)strtol(buf, &ep, 10);
1413 
1414       if (*ep == NUL || errno == ERANGE) {
1415          /* only digits, but inet_pton() failed. */
1416          snprintf(emsg, emsglen,
1417                  "\"%s\" does not appear to be a valid IP address",
1418                  str2vis(buf, strlen(buf), vbuf, sizeof(vbuf)));
1419 
1420          slog(LOG_DEBUG, "%s: %s", function, emsg);
1421          return NULL;
1422       }
1423 
1424       if ((hostent = gethostbyname(buf)) == NULL
1425       ||   hostent->h_addr               == NULL) {
1426          snprintf(emsg, emsglen, "could not resolve hostname \"%s\"",
1427                   str2vis(buf, strlen(buf), vbuf, sizeof(vbuf)));
1428 
1429          slog(LOG_DEBUG, "%s: %s", function, emsg);
1430          return NULL;
1431       }
1432 
1433       SET_SOCKADDR(saddr, (uint8_t)hostent->h_addrtype);
1434       memcpy(&TOIN(saddr)->sin_addr,
1435              hostent->h_addr_list[0],
1436              (size_t)hostent->h_length);
1437    }
1438 
1439 
1440    if (haveportsep) {
1441       if ((port = strchr(string, ':')) == NULL) {
1442          snprintf(emsg, emsglen,
1443                  "could not find start of port number in \"%s\"",
1444                  str2vis(string, strlen(string), vbuf, sizeof(vbuf)));
1445 
1446          return NULL;
1447       }
1448       ++port; /* skip ':' */
1449 
1450       if ((portnumber = string2portnumber(port, emsg, emsglen)) == -1)
1451          return NULL;
1452    }
1453    else
1454       portnumber = SOCKD_HTTP_PORT;
1455 
1456    TOIN(saddr)->sin_port = htons((in_port_t)portnumber);
1457 
1458    slog(LOG_DEBUG, "%s: returning addr %s",
1459         function, sockaddr2string(saddr, NULL, 0));
1460 
1461    return saddr;
1462 }
1463 
1464 #undef snprintf
1465 size_t
snprintfn(char * str,size_t size,const char * format,...)1466 snprintfn(char *str, size_t size, const char *format, ...)
1467 {
1468    const int errno_s = errno;
1469    va_list ap;
1470    ssize_t rc;
1471 
1472    if (size <= 0 || str == NULL)
1473       return 0;
1474 
1475    va_start(ap, format);
1476    rc = vsnprintf(str, size, format, ap);
1477    va_end(ap);
1478 
1479    errno = errno_s; /* don't want snprintf(3) to change errno. */
1480 
1481    if (rc <= 0) {
1482       *str = NUL;
1483       rc   = 0;
1484    }
1485    else if (rc >= (ssize_t)size) {
1486       rc = (ssize_t)(size - 1);
1487       str[rc] = NUL; /* we never return non-terminated strings. */
1488    }
1489 
1490    if (size > 0)
1491       SASSERTX(str[rc] == NUL);
1492 
1493    return (size_t)rc;
1494 }
1495 
1496 /*
1497  * NOTE: close() macro undefined; closen() function needs to be at the
1498  * end of the file.
1499  */
1500 int
closen(d)1501 closen(d)
1502    int d;
1503 {
1504    int rc;
1505 
1506 #undef close  /* we redefine close() to closen() for convenience. */
1507    while ((rc = close(d)) == -1 && errno == EINTR)
1508       ; /* LINTED empty */
1509 
1510    if (rc == -1 && errno != EBADF) {
1511       /*
1512        * Some people don't understand one should not introduce random
1513        * extra return codes into standard system calls without thinking
1514        * about it carefully first.
1515        * E.g. FreeBSD seems to think it's perfectly ok to let close(2)
1516        * close the socket, yet return -1 and set errno to ECONNRESET.
1517        * Never mind this breaks all sort of applications who keep track
1518        * of their fd's well enough to consider a failure from close(2)
1519        * an indication of something being wrong in their code, rather
1520        * than a TCP connection being reset.
1521        */
1522       errno = 0;
1523       rc    = 0;
1524    }
1525 
1526    return rc;
1527 }
1528 
1529 int
linkednamesareeq(a,b)1530 linkednamesareeq(a, b)
1531    const linkedname_t *a;
1532    const linkedname_t *b;
1533 {
1534 
1535    /*
1536     * Check that they have the same contents and in the same order.
1537     */
1538    while (1) {
1539       if (a == b)
1540          return 1;
1541 
1542       if (a == NULL || b == NULL)
1543          return 0;
1544 
1545       if (strcmp(a->name, b->name) != 0)
1546          return 0;
1547 
1548       a = a->next;
1549       b = b->next;
1550    }
1551 
1552    /* NOTREACHED */
1553    SERRX(0);
1554 }
1555