1 /*
2  * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2005, 2008, 2009, 2010,
3  *               2011, 2012, 2013, 2014
4  *      Inferno Nettverk A/S, Norway.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. The above copyright notice, this list of conditions and the following
10  *    disclaimer must appear in all copies of the software, derivative works
11  *    or modified versions, and any portions thereof, aswell as in all
12  *    supporting documentation.
13  * 2. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by
16  *      Inferno Nettverk A/S, Norway.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Inferno Nettverk A/S requests users of this software to return to
32  *
33  *  Software Distribution Coordinator  or  sdc@inet.no
34  *  Inferno Nettverk A/S
35  *  Oslo Research Park
36  *  Gaustadall�en 21
37  *  NO-0349 Oslo
38  *  Norway
39  *
40  * any improvements or extensions that they make and grant Inferno Nettverk A/S
41  * the rights to redistribute these changes.
42  *
43  */
44 
45 static const char rcsid[] =
46 "$Id: log.c,v 1.373.4.8.6.1 2021/02/16 22:32:41 michaels Exp $";
47 
48 #include "common.h"
49 #include "config_parse.h"
50 
51 #if HAVE_EXECINFO_H && HAVE_BACKTRACE
52 #include <execinfo.h>
53 #endif /* HAVE_EXECINFO_H && HAVE_BACKTRACE */
54 
55 #if DEBUG && PRERELEASE
56 #undef SOCKS_IGNORE_SIGNALSAFETY
57 #define SOCKS_IGNORE_SIGNALSAFETY 1
58 #endif /* DEBUG && PRERELEASE*/
59 
60 #if SOCKS_CLIENT
61 #define SRCDSTLEN     (1024)
62 #else /* !SOCKS_CLIENT */
63 #define SRCDSTLEN     (MAX_IOLOGADDR + sizeof(" -> ") + MAX_IOLOGADDR)
64 #endif /* !SOCKS_CLIENT */
65 
66 #define DATALEN       (2048)  /* payload data or message */
67 #define REGULARBUFLEN (  SRCDSTLEN                                             \
68                        + (DATALEN * 4) /* x 4 for strivs(3) */                 \
69                        + 1024          /* whatever. */)
70 
71 struct syslogfacility {
72    const char name[MAXFACILITYNAMELEN];
73    const int  value;
74 };
75 
76 
77 /*
78  * if possible (enough space) and necessary, add a newline to the
79  * NUL-terminated buf (of size buflen, of which buflen has been used so far),
80  * and increment bufused if so.
81  */
82 #define ADDNL(bufused, buf, buflen)                                            \
83 do {                                                                           \
84    SASSERTX((buf)[(*bufused) - 1] == NUL);                                     \
85    if ((buf)[(*bufused) - 2] != '\n') {                                        \
86       if ((*bufused) + 1 <= (buflen)) {                                        \
87          buf[(*bufused) - 1] = '\n';                                           \
88          buf[(*bufused)++]   = NUL;                                            \
89       }                                                                        \
90       else                                                                     \
91          buf[(*bufused) - 2] = '\n'; /* truncated.  */                         \
92    }                                                                           \
93    SASSERTX((buf)[(*bufused) - 1] == NUL);                                     \
94 } while (0 /* CONSTCOND */)
95 
96 static const struct syslogfacility *
97 syslogfacility(const char *name);
98 /*
99  * Returns the syslog facility value having the name "name".
100  * Returns NULL if there is no such facility.
101  */
102 
103 
104 static void
105 dolog(const int priority, const char *buf,
106       const size_t logprefixlen, const size_t messagelen);
107 /*
108  * Does the actual logging of the formated logmessage for slog()/vslog().
109  *
110  * The last character in "buf", before the NUL, must be a newline.
111  *
112  * "prefixlen" is the length of the logprefix at the start of "buf", and
113  * is not used if logging to syslog.
114  *
115  * "messagelen" gives the length of the message that follows after the
116  * logprefix.
117  */
118 
119 static int
120 openlogfile(const char *logfile, int *wecreated);
121 /*
122  * Calls open(2) with the correct flags for a logfile named "logfile",
123  * as well as sets any fd flags we want.
124  *
125  * If "created" is true upon return, it means the openlog() created
126  * the logfile.  Otherwise, no logfile was created, either because it
127  * already existed, or because the function failed.
128  *
129  * Returns the fd associated with the open logfile.
130  */
131 
132 static size_t
133 getlogprefix(const int priority, char *buf, size_t buflen);
134 /*
135  * Writes a logprefix, similar to that used by syslog, which should be used
136  * if logging a message with level "priority" at the current time.
137  * Should not be used if logging via syslog.
138  *
139  * The prefix is written to "buf", which should be of at least size "buflen".
140  * Returns the length of the prefix, *NOT* including the terminating NUL.
141  */
142 
143 
144 #if HAVE_LIVEDEBUG
145 
146 /*
147  * Apart from messages where payload data is included we never expect
148  * the message to log being very large.  Since we don't normally care
149  * much about the payload data, it's better to lose some/most of it and
150  * have room for more relevant data instead.
151  */
152 #define SOCKS_RINGBUF_MAXLINELEN (1024)
153 
154 #ifndef SOCKS_RINGBUFLEN
155 #define SOCKS_RINGBUFLEN   (SOCKS_RINGBUF_MAXLINELEN * 100)
156 #endif /* SOCKS_RINGBUFLEN */
157 
158 
159 static int dont_add_to_rb;
160 static void
161 socks_addtorb(const char *str, const size_t strlen);
162 /*
163  * Adds the NUL-terminated string "str", of length "strlen" (including NUL)
164  * to the ringbuffer.
165  */
166 
167 #if SOCKS_CLIENT
168 static void atexit_flushrb(void);
169 #endif /* SOCKS_CLIENT */
170 
171 static char ringbuffer[SOCKS_RINGBUFLEN];
172 static size_t ringbuf_curroff;
173 #endif /* HAVE_LIVEDEBUG */
174 
175 #if !SOCKS_CLIENT
176 
177 #define DO_BUILD(srcdst_str, dst_too)                                          \
178 do {                                                                           \
179    char srcstr[MAX_IOLOGADDR];                                                 \
180                                                                                \
181    build_addrstr_src(GET_HOSTIDV(src),                                         \
182                      GET_HOSTIDC(src),                                         \
183                      src != NULL && src->peer_isset ?                          \
184                         &src->peer : NULL,                                     \
185                      tosrc_proxy != NULL && tosrc_proxy->peer_isset ?          \
186                         &tosrc_proxy->peer : NULL,                             \
187                      tosrc_proxy != NULL && tosrc_proxy->local_isset ?         \
188                         &tosrc_proxy->local : NULL,                            \
189                      src != NULL && src->local_isset ?                         \
190                         &src->local : NULL,                                    \
191                      src != NULL && src->auth_isset ?                          \
192                         &src->auth : NULL,                                     \
193                      tosrc_proxy != NULL && tosrc_proxy->auth_isset ?          \
194                         &tosrc_proxy->auth  : NULL,                            \
195                      (dst_too) ? srcstr         : srcdst_str,                  \
196                      (dst_too) ? sizeof(srcstr) : sizeof(srcdst_str));         \
197                                                                                \
198    if (dst_too) {                                                              \
199       char dststr[MAX_IOLOGADDR];                                              \
200                                                                                \
201       build_addrstr_dst(dst != NULL && dst->local_isset ?                      \
202                            &dst->local : NULL,                                 \
203                         todst_proxy != NULL && todst_proxy->local_isset ?      \
204                            &todst_proxy->local : NULL,                         \
205                         todst_proxy != NULL && todst_proxy->peer_isset  ?      \
206                            &todst_proxy->peer  : NULL,                         \
207                         dst != NULL && dst->peer_isset ?                       \
208                            &dst->peer : NULL,                                  \
209                         dst != NULL && dst->auth_isset ?                       \
210                            &dst->auth : NULL,                                  \
211                         todst_proxy != NULL && todst_proxy->auth_isset ?       \
212                            &todst_proxy->auth  : NULL,                         \
213                         GET_HOSTIDV(dst),                                      \
214                         GET_HOSTIDC(dst),                                      \
215                         dststr,                                                \
216                         sizeof(dststr));                                       \
217                                                                                \
218       snprintf(srcdst_str, sizeof(srcdst_str), "%s -> %s", srcstr, dststr);    \
219    }                                                                           \
220 } while (/* CONSTCOND */ 0)
221 
222 
223 iologaddr_t *
init_iologaddr(addr,local_type,local,peer_type,peer,auth,hostidv,hostidc)224 init_iologaddr(addr, local_type, local, peer_type, peer, auth, hostidv, hostidc)
225    iologaddr_t *addr;
226    const objecttype_t local_type;
227    const void *local;
228    const objecttype_t peer_type;
229    const void *peer;
230    const authmethod_t *auth;
231    const struct in_addr *hostidv;
232    const unsigned int hostidc;
233 {
234 
235    if (local == NULL || local_type == object_none)
236       addr->local_isset = 0;
237    else {
238       switch (local_type) {
239          case object_sockaddr:
240             sockaddr2sockshost(local, &addr->local);
241             break;
242 
243          case object_sockshost:
244             addr->local = *(const sockshost_t *)local;
245             break;
246 
247          default:
248             SERRX(local_type);
249       }
250 
251       addr->local_isset = 1;
252    }
253 
254    if (peer == NULL || peer_type == object_none)
255       addr->peer_isset  = 0;
256    else {
257       switch (peer_type) {
258          case object_sockaddr:
259             sockaddr2sockshost(peer, &addr->peer);
260             break;
261 
262          case object_sockshost:
263             addr->peer = *(const sockshost_t *)peer;
264             break;
265 
266          default:
267             SERRX(peer_type);
268       }
269 
270       addr->peer_isset = 1;
271    }
272 
273    if (auth == NULL)
274       addr->auth_isset = 0;
275    else {
276       addr->auth       = *auth;
277       addr->auth_isset = 1;
278    }
279 
280 #if HAVE_SOCKS_HOSTID
281    if (hostidv == NULL || hostidc == 0)
282       addr->hostidc = 0;
283    else {
284       memcpy(addr->hostidv, hostidv, sizeof(*hostidv) * hostidc);
285       addr->hostidc = hostidc;
286    }
287 #endif /* HAVE_SOCKS_HOSTID */
288 
289    return addr;
290 }
291 
292 void
iolog(rule,state,op,src,dst,tosrc_proxy,todst_proxy,data,datalen)293 iolog(rule, state, op, src, dst, tosrc_proxy, todst_proxy, data, datalen)
294    const rule_t *rule;
295    const connectionstate_t *state;
296    const operation_t op;
297    const iologaddr_t *src;
298    const iologaddr_t *dst;
299    const iologaddr_t *tosrc_proxy;
300    const iologaddr_t *todst_proxy;
301    const char *data;
302    size_t datalen;
303 {
304    const char *function = "iolog()";
305    const char *tcpinfoprefix = "\nTCP_INFO:\n";
306    const char *verdict;
307    const int dologtcpinfo = (rule->log.tcpinfo && state->tcpinfo != NULL) ?
308                                  1 : 0;
309    const int dologdstinfo = (dst == NULL) ? 0 : 1;
310    size_t buflen;
311    char srcdst_str[SRCDSTLEN], rulecommand[256],
312         *buf, *bigbuf, regbuf[REGULARBUFLEN];
313 
314    if (rule->log.data && datalen > DATALEN) {
315       const size_t bigbufsize =   (size_t)datalen * 4 /* x 4 for strvis(3) */
316                                 + sizeof(regbuf);
317 
318       slog(LOG_DEBUG,
319            "%s: a datalen of %ld is too large to fit in the stack-allocated "
320            "buffer.  Allocating %lu bytes of memory dynamically",
321            function, (unsigned long)datalen, (unsigned long)bigbufsize);
322 
323       if ((bigbuf = malloc(bigbufsize)) != NULL) {
324          buf    = bigbuf;
325          buflen = bigbufsize;
326       }
327       else {
328          swarn("%s: failed to allocate %lu bytes of memory",
329                function, (unsigned long)bigbufsize);
330 
331          buf    = regbuf;
332          buflen = sizeof(regbuf);
333       }
334    }
335    else {
336       buflen = sizeof(regbuf);
337       buf    = regbuf;
338       bigbuf = NULL;
339    }
340 
341 /*
342  * If the datastring we are passed starts with a newline, don't include an
343  * extra ':' to separate it from the addressinfo.  We do not need to worry
344  * about the payload data starting with a newline, as we strvis(3) it before
345  * passing it here, so it should not start with a newline when we get it.
346  */
347 #define DATASEPARATOR(data)                                                    \
348 (((data) == NULL || *(data) == NUL || *(data) == '\n') ? "" : ": ")
349 
350 #define DATASTRING(data)                                                       \
351 (((data) == NULL || *(data) == NUL) ? "" : data)
352 
353    verdict = NULL;
354    switch (op) {
355       case OPERATION_ACCEPT:
356       case OPERATION_HOSTID:
357       case OPERATION_CONNECT:
358          if (rule->log.connect) {
359             DO_BUILD(srcdst_str, dologdstinfo);
360             snprintf(buf, buflen,
361                     "[: %s%s%s",
362                      srcdst_str,
363                      DATASEPARATOR(data),
364                      DATASTRING(data));
365          }
366          else {
367             free(bigbuf);
368             return;
369          }
370 
371          break;
372 
373       case OPERATION_BLOCK:
374       case OPERATION_TMPBLOCK:
375          if (rule->log.connect || rule->log.disconnect
376          ||  rule->log.data    || rule->log.iooperation) {
377             DO_BUILD(srcdst_str, dologdstinfo);
378             snprintf(buf, buflen,
379                      "%c: %s%s%s",
380                      op == OPERATION_BLOCK ? ']' : '-',
381                      srcdst_str,
382                      DATASEPARATOR(data),
383                      DATASTRING(data));
384          }
385          else {
386             free(bigbuf);
387             return;
388          }
389 
390          verdict = verdict2string(VERDICT_BLOCK);
391          break;
392 
393       case OPERATION_DISCONNECT:
394          if (rule->log.disconnect) {
395             DO_BUILD(srcdst_str, dologdstinfo);
396             snprintf(buf, buflen,
397                      "]: %s%s%s",
398                      srcdst_str,
399                      DATASEPARATOR(data),
400                      DATASTRING(data));
401          }
402          else {
403             free(bigbuf);
404             return;
405          }
406 
407          break;
408 
409       case OPERATION_ERROR:
410       case OPERATION_TMPERROR:
411          if (rule->log.error || rule->log.disconnect) {
412             DO_BUILD(srcdst_str, dologdstinfo);
413             snprintf(buf, buflen,
414                      "%c: %s%s%s",
415                      op == OPERATION_ERROR ? ']' : '-',
416                      srcdst_str,
417                      DATASEPARATOR((data == NULL || *data == NUL) ?
418                                           strerror(errno) : data),
419                      (data == NULL || *data == NUL) ? strerror(errno) : data);
420          }
421          else {
422             free(bigbuf);
423             return;
424          }
425 
426          verdict = verdict2string(VERDICT_BLOCK);
427          break;
428 
429       case OPERATION_IO:
430          if (rule->log.data || rule->log.iooperation) {
431             if (rule->log.data && datalen != 0) {
432                size_t lastbyteused;
433 
434                DO_BUILD(srcdst_str, dologdstinfo);
435                lastbyteused = snprintf(buf, buflen,
436                                        "-: %s (%lu): ",
437                                        srcdst_str, (unsigned long)datalen);
438                str2vis(data,
439                        datalen,
440                        &buf[lastbyteused],
441                        buflen - lastbyteused);
442             }
443             else {
444                DO_BUILD(srcdst_str, dologdstinfo);
445                snprintf(buf, buflen,
446                         "-: %s (%lu)", srcdst_str, (unsigned long)datalen);
447             }
448          }
449          else {
450             free(bigbuf);
451             return;
452          }
453 
454          break;
455 
456       default:
457          SERRX(op);
458    }
459 
460    snprintf(rulecommand, sizeof(rulecommand), "%s(%lu): %s/%s",
461             verdict == NULL ? verdict2string(rule->verdict) : verdict,
462             (unsigned long)rule->number,
463             protocol2string(state->protocol),
464             command2string(state->command));
465 
466    slog(LOG_INFO, "%s %s%s%s",
467         rulecommand,
468         buf,
469         dologtcpinfo ? tcpinfoprefix  : "",
470         dologtcpinfo ? state->tcpinfo : "");
471 
472    free(bigbuf);
473 }
474 
475 void
sockd_freelogobject(logobject,closetoo)476 sockd_freelogobject(logobject, closetoo)
477    logtype_t *logobject;
478    const int closetoo;
479 {
480    const char *function = "sockd_freelogobject()";
481    sigset_t all, oldmask;
482    size_t i;
483 
484    (void)sigfillset(&all);
485    if (sigprocmask(SIG_SETMASK, &all, &oldmask) != 0)
486       swarn("%s: sigprocmask(SIG_SETMASK)", function);
487 
488   for (i = 0; i < logobject->filenoc; ++i) {
489       if (closetoo && !FD_IS_RESERVED_EXTERNAL(logobject->filenov[i]))
490          close(logobject->filenov[i]);
491 
492       free(logobject->fnamev[i]);
493    }
494 
495    free(logobject->fnamev);
496    free(logobject->filenov);
497    free(logobject->createdv);
498 
499    bzero(logobject, sizeof(*logobject));
500 
501    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
502       swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
503 }
504 
505 int
loglevel_errno(e,side)506 loglevel_errno(e, side)
507    const int e;
508    const interfaceside_t side;
509 {
510    const logspecial_t *log;
511    static interfaceside_t last_side;
512    static int last_loglevel = -1, last_errno;
513    size_t i, ii;
514 
515    CTASSERT(LOG_EMERG == 0);
516    CTASSERT(LOG_DEBUG == 7);
517 
518    if (last_loglevel != -1 && last_errno == e && last_side == side)
519       return last_loglevel;
520 
521    if (side == INTERNALIF)
522       log = &sockscf.internal.log;
523    else {
524       SASSERTX(side == EXTERNALIF);
525       log = &sockscf.external.log;
526    }
527 
528    /*
529     * Go through all loglevels and see if we find a match for 'e'.
530     * Presumably there will not be too many errnovalues set, so
531     * this should be fast enough.  The other obvious alternative,
532     * index by errnovalue, would unfortunately depend on us never
533     * running on a system with large errnovalues, which we have no
534     * control over.  The loglevels on the other side are defined by
535     * rfc.
536     */
537    for (i = 0; i < ELEMENTS(log->errno_loglevelv); ++i)
538       for (ii = 0; ii < log->errno_loglevelc[i]; ++ii)
539          if (log->errno_loglevelv[i][ii] == e) {
540             last_side     = side;
541             last_errno    = errno;
542             last_loglevel = i;
543 
544             return i;
545          }
546 
547    return LOG_DEBUG;
548 }
549 
550 int
loglevel_gaierr(e,side)551 loglevel_gaierr(e, side)
552    const int e;
553    const interfaceside_t side;
554 {
555    const char *function = "loglevel_gaierr()";
556    static interfaceside_t last_side;
557    static int last_loglevel = -1, last_gaierr;
558    const logspecial_t *log;
559    size_t i, ii;
560 
561    CTASSERT(LOG_EMERG == 0);
562    CTASSERT(LOG_DEBUG == 7);
563 
564    slog(LOG_DEBUG, "%s: error %d, side %s",
565         function, e, side == EXTERNALIF ? "external" : "internal");
566 
567    if (last_loglevel != -1 && last_gaierr == e && last_side == side)
568       return last_loglevel;
569 
570    if (side == INTERNALIF)
571       log = &sockscf.internal.log;
572    else {
573       SASSERTX(side == EXTERNALIF);
574       log = &sockscf.external.log;
575    }
576 
577    for (i = 0; i < ELEMENTS(log->gaierr_loglevelv); ++i) {
578       for (ii = 0; ii < log->gaierr_loglevelc[i]; ++ii)
579          if (log->gaierr_loglevelv[i][ii] == e) {
580             last_loglevel = i;
581             last_gaierr   = e;
582             last_side     = side;
583             return i;
584          }
585    }
586 
587    return LOG_DEBUG;
588 }
589 
590 #endif /* !SOCKS_CLIENT */
591 
592 void
newprocinit(void)593 newprocinit(void)
594 {
595 
596 #if SOCKS_CLIENT
597    return;
598 #else /* !SOCKS_CLIENT */
599    const char *function = "newprocinit()";
600 
601    if ((sockscf.log.type    & LOGTYPE_SYSLOG)
602    ||  (sockscf.errlog.type & LOGTYPE_SYSLOG)
603    ||  HAVE_LIBWRAP /* libwrap may also log to syslog. */) {
604       closelog();
605 
606       /*
607        * LOG_NDELAY so we don't end up in a situation where we
608        * have no free descriptors and haven't yet syslog-ed anything.
609        */
610       openlog(__progname,
611               LOG_NDELAY | LOG_PID
612 #ifdef LOG_NOWAIT
613               | LOG_NOWAIT
614 #endif /* LOG_NOWAIT */
615               , 0);
616 
617       errno = 0; /* syslog() stuff might set errno on some platforms. */
618    }
619 
620    /*
621     * not using this for client, since if e.g. the client forks, we'd
622     * end up printing the wrong pid.
623     */
624    sockscf.state.pid = getpid();
625 
626    srandom((unsigned int)sockscf.state.pid);
627 
628    /* don't want children to inherit mother's signal queue. */
629    sockscf.state.signalc = 0;
630 #endif /* !SOCKS_CLIENT */
631 }
632 
633 int
socks_addlogfile(logcf,logfile)634 socks_addlogfile(logcf, logfile)
635    logtype_t *logcf;
636    const char *logfile;
637 {
638    const char *function = "socks_addlogfile()";
639    const char *syslogname = "syslog";
640    void *p1, *p2, *p3;
641    sigset_t all, oldmask;
642    char *fname;
643    int fd, logfilewascreated;
644 
645    if (strncmp(logfile, syslogname, strlen(syslogname)) == 0
646    && ( logfile[strlen(syslogname)] == NUL
647      || logfile[strlen(syslogname)] == '/')) {
648       const char *sl;
649 
650       logcf->type |= LOGTYPE_SYSLOG;
651 
652       if (*(sl = &(logfile[strlen(syslogname)])) == '/') { /* facility. */
653          const struct syslogfacility *facility;
654 
655          ++sl;
656          if ((facility = syslogfacility(sl)) == NULL) {
657             yywarnx("unknown syslog facility \"%s\"", sl);
658             return -1;
659          }
660 
661          logcf->facility = facility->value;
662          STRCPY_ASSERTSIZE(logcf->facilityname, facility->name);
663       }
664       else {   /* use default. */
665          logcf->facility = LOG_DAEMON;
666          STRCPY_ASSERTSIZE(logcf->facilityname, "daemon");
667       }
668 
669       if (!sockscf.state.inited)
670          newprocinit(); /* to setup syslog correctly asap. */
671 
672       return 0;
673    }
674 
675    /* else: filename. */
676    logcf->type |= LOGTYPE_FILE;
677    if ((fd = openlogfile(logfile, &logfilewascreated)) == -1)
678       return -1;
679 
680    /*
681     * Don't want to receive signals, which could lead to us accessing the
682     * logobject, at this point.
683     */
684 
685    (void)sigfillset(&all);
686    if (sigprocmask(SIG_SETMASK, &all, &oldmask) != 0)
687       swarn("%s: sigprocmask(SIG_SETMASK)", function);
688 
689    if ((fname = strdup(logfile)) == NULL) {
690       yywarn("%s: could not allocate %lu bytes of memory for logfile \"%s\"",
691              function, (unsigned long)strlen(logfile), logfile);
692 
693       if (fd != fileno(stdout) && fd != fileno(stderr))
694          close(fd);
695 
696       if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
697          swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
698 
699       return -1;
700    }
701 
702    p1 = p2 = p3 = NULL;
703 
704    p1 = realloc(logcf->filenov, sizeof(*logcf->filenov) * (logcf->filenoc + 1));
705    p2 = realloc(logcf->fnamev,  sizeof(*logcf->fnamev)  * (logcf->filenoc + 1));
706    p3 = realloc(logcf->createdv,
707                                sizeof(*logcf->createdv) * (logcf->filenoc + 1));
708 
709 
710    if (p1 != NULL)
711       logcf->filenov  = p1;
712 
713    if (p2 != NULL)
714       logcf->fnamev   = p2;
715 
716    if (p3 != NULL)
717       logcf->createdv = p3;
718 
719 
720    if (p1 == NULL || p2 == NULL || p3 == NULL) {
721       yywarn("%s: failed to allocate memory for log filenames", function);
722 
723       free(fname);
724 
725       /*
726        * Don't bother free(3)'ing what we actually managed to realloc(3).
727        * Only means some of the elements in logcf now have a little more
728        * memory available than strictly needed.
729        */
730 
731       if (fd != fileno(stdout) && fd != fileno(stderr))
732          close(fd);
733 
734       if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
735          swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
736 
737       return -1;
738    }
739 
740    logcf->filenov[logcf->filenoc]  = fd;
741    logcf->fnamev[logcf->filenoc]   = fname;
742    logcf->createdv[logcf->filenoc] = logfilewascreated;
743    ++logcf->filenoc;
744 
745    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
746       swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
747 
748    return 0;
749 }
750 
751 #if !SOCKS_CLIENT
752 
753 int
sockd_reopenlogfiles(log,docloseold)754 sockd_reopenlogfiles(log, docloseold)
755    logtype_t *log;
756    const int docloseold;
757 {
758    const char *function = "sockd_reopenlogfiles()";
759    sigset_t all, oldmask;
760    size_t i;
761    int p;
762 
763    (void)sigfillset(&all);
764    if (sigprocmask(SIG_SETMASK, &all, &oldmask) != 0)
765       swarn("%s: sigprocmask(SIG_SETMASK)", function);
766 
767    for (i = 0; i < log->filenoc; ++i) {
768       if (docloseold) {
769          if (close(log->filenov[i]) != 0)
770             swarn("%s: could not close logfile \"%s\" using fd %d",
771                   function, log->fnamev[i], log->filenov[i]);
772       }
773 
774       /*
775        * When reopening we don't care if we created the logfile or not,
776        * as it is only used for the first startup, when we may create
777        * logfiles before we've inited our userids properly, in case we
778        * may need to change the logfile owner after userids are inited.
779        */
780       if ((log->filenov[i] = openlogfile(log->fnamev[i], &p)) == -1) {
781          swarn("%s: could not reopen logfile \"%s\"", function, log->fnamev[i]);
782 
783          if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
784             swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
785 
786          return -1;
787       }
788    }
789 
790    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) != 0)
791       swarn("%s: sigprocmask(SIG_SETMASK, &oldmask, NULL)", function);
792 
793    return 0;
794 }
795 #endif /* !SOCKS_CLIENT */
796 
797 void
slog(int priority,const char * message,...)798 slog(int priority, const char *message, ...)
799 {
800    va_list ap, apcopy;
801 
802    /*
803     * not all systems may have va_copy().  Idea from a news post by
804     * Chris Torek.
805     */
806    va_start(ap, message);
807    va_start(apcopy, message);
808 
809    vslog(priority, message, ap, apcopy);
810 
811    va_end(apcopy);
812    va_end(ap);
813 }
814 
815 void
vslog(priority,message,ap,apcopy)816 vslog(priority, message, ap, apcopy)
817    int priority;
818    const char *message;
819    va_list ap;
820    va_list apcopy;
821 {
822    const char *function = "vslog()";
823    const int errno_s = errno;
824    ssize_t p;
825    size_t datalen /* no NUL */, prefixlen /* no NUL */, buflen,
826           loglen, oldloglen;
827    char *buf, *bigbuf, regbuf[REGULARBUFLEN];
828 
829    buf    = regbuf;
830    buflen = sizeof(regbuf);
831    bigbuf = NULL;
832 
833 #if !SOCKS_IGNORE_SIGNALSAFETY
834    if (sockscf.state.insignal
835    /* && priority > LOG_WARNING */) /* > pri means < serious */
836       /*
837        * Note that this can be the case even if insignal is not set.
838        * This can happen in the client if the application has
839        * installed a signal handler, and that signal handler ends
840        * up making calls that involve us.
841        */
842       return;
843 #endif /* !SOCKS_IGNORE_SIGNALSAFETY */
844 
845    if (priority == LOG_DEBUG && !sockscf.option.debug) {
846 #if HAVE_LIVEDEBUG
847       const int insignal = sockscf.state.insignal;
848 
849 #if SOCKS_CLIENT
850       static int atexit_registered;
851 
852       if (!atexit_registered) {
853          if (atexit(atexit_flushrb) != 0)
854             swarn("%s: atexit() failed to register atexit function", function);
855          else
856             atexit_registered = 1;
857       }
858 #endif /* SOCKS_CLIENT */
859 
860       if (!dont_add_to_rb) {
861          /*
862           * don't have getlogprefix() bother with calling localtime(3);  too
863           * slow.
864           */
865           ssize_t maxtoprint;
866 
867          sockscf.state.insignal = 1;
868          prefixlen = getlogprefix(priority, buf, buflen);
869          sockscf.state.insignal = insignal;
870 
871          maxtoprint = MIN(buflen - prefixlen, SOCKS_RINGBUF_MAXLINELEN);
872          SASSERTX(maxtoprint >= 0);
873 
874          p = vsnprintf(&buf[prefixlen],
875                        (size_t)maxtoprint,
876                        message,
877                        ap);
878 
879          if (p <= 0) { /* well, that's strange. */
880             errno = errno_s;
881             return;
882          }
883 
884          if (p >= maxtoprint) {
885             buf[(prefixlen + maxtoprint) - 1] = NUL;
886             p = maxtoprint - 1;
887          }
888 
889          datalen = (size_t)p;
890 
891          SASSERTX(buf[prefixlen + datalen] == NUL);
892 
893          if (prefixlen + datalen < buflen)
894             loglen = prefixlen + datalen + 1 /* + 1: NUL terminator */;
895          else /* truncated, but never mind when debug-logging to ringbuffer. */
896             loglen = buflen;
897 
898 #if DIAGNOSTIC
899          SASSERTX(loglen == strlen(buf) + 1);
900 #endif /* DIAGNOSTIC */
901 
902          SASSERTX(loglen >= 2);
903          SASSERTX(buf[loglen - 1] == NUL);
904 
905          ADDNL(&loglen, buf, buflen);
906 
907          SASSERTX(buf[loglen - 1] == NUL);
908          socks_addtorb(buf, loglen);
909       }
910 #endif /* HAVE_LIVEDEBUG */
911 
912       errno = errno_s;
913       return;
914    }
915 
916    prefixlen = getlogprefix(priority, buf, buflen);
917    SASSERTX(prefixlen < buflen);
918 
919    p = vsnprintf(&buf[prefixlen], buflen -prefixlen, message, ap);
920    if (p <= 0) { /* well, that's strange. */
921       errno = errno_s;
922       return;
923    }
924 
925    datalen = p;
926 
927    if (prefixlen + datalen >= buflen && !sockscf.state.insignal) {
928       /*
929        * not enough room in our regular buffer (and not in signal,
930        * so can malloc(3)).
931        */
932       const size_t toalloc = datalen + prefixlen + sizeof("\n");
933 
934       if ((bigbuf = malloc(toalloc)) != NULL) {
935          memcpy(bigbuf, buf, prefixlen);
936          buf    = bigbuf;
937          buflen = toalloc;
938 
939          p = vsnprintf(&buf[prefixlen], buflen - prefixlen, message, apcopy);
940          if (p <= 0) { /* well, that's strange. */
941             free(bigbuf);
942             errno = errno_s;
943 
944             return;
945          }
946 
947          datalen = p;
948       }
949    }
950 
951    /* check again, after possible malloc(3)/vsnprintf(3). */
952    if (prefixlen + datalen >= buflen) {
953       /* still not enough room.  Must truncate. */
954       datalen         = buflen - prefixlen - 1;
955       buf[buflen - 1] = NUL;
956    }
957 
958    loglen = prefixlen + datalen + 1 /* NUL */;
959    SASSERTX(loglen <= buflen);
960    SASSERTX(buf[loglen - 1] == NUL);
961 
962 #if DIAGNOSTIC
963    SASSERTX(loglen == strlen(buf) + 1);
964 #endif /* DIAGNOSTIC */
965 
966    oldloglen = loglen;
967    ADDNL(&loglen, buf, buflen);
968    if (loglen != oldloglen) {
969       SASSERTX(loglen = oldloglen + 1); /* newline added. */
970       ++datalen;
971    }
972 
973    SASSERTX(loglen <= buflen);
974    SASSERTX(buf[loglen - 1] == NUL);
975 
976 #if DIAGNOSTIC
977    SASSERTX(loglen == strlen(buf) + 1);
978 #endif /* DIAGNOSTIC */
979 
980    dolog(priority, buf, prefixlen, datalen);
981 
982    free(bigbuf);
983    errno = errno_s;
984 }
985 
986 void
signalslog(priority,msgv)987 signalslog(priority, msgv)
988    const int priority;
989    const char *msgv[];
990 {
991    const char *function = "signalslog()";
992    const int errno_s = errno;
993    size_t bufused, msglen, prefixlen, i;
994 #if HAVE_LIVEDEBUG
995    char buf[SOCKS_RINGBUFLEN];
996 
997 #else /* !HAVE_LIVEDEBUG */
998    char buf[REGULARBUFLEN];
999 
1000 #endif /* !HAVE_LIVEDEBUG */
1001 
1002    prefixlen = bufused = getlogprefix(priority, buf, sizeof(buf));
1003 
1004    if (msgv == NULL)
1005       return;
1006 
1007    for (i = 0; msgv[i] != NULL; ++i) {
1008       msglen = MIN(strlen(msgv[i]), sizeof(buf) - bufused - 1);
1009       memcpy(&buf[bufused], msgv[i], msglen);
1010       bufused += msglen;
1011    }
1012 
1013    SASSERTX(bufused < sizeof(buf));
1014    buf[bufused++] = NUL;
1015 
1016    ADDNL(&bufused, buf, sizeof(buf));
1017 
1018    SASSERTX(buf[bufused - 1] == NUL);
1019    SASSERTX(buf[bufused - 2] == '\n');
1020 
1021    msglen = bufused - 1 /* don't count NUL */ - prefixlen;
1022 
1023    if (priority == LOG_DEBUG && !sockscf.option.debug) {
1024 #if HAVE_LIVEDEBUG
1025       if (!dont_add_to_rb)
1026          socks_addtorb(buf, bufused);
1027 #endif /* HAVE_LIVEDEBUG */
1028 
1029       errno = errno_s;
1030       return;
1031    }
1032 
1033    dolog(priority, buf, prefixlen, msglen);
1034 
1035 #if HAVE_LIVEDEBUG /* always save to ring buffer too. */
1036    if (!dont_add_to_rb)
1037       socks_addtorb(buf, bufused);
1038 #endif /* HAVE_LIVEDEBUG */
1039 
1040    errno = errno_s;
1041 }
1042 
1043 
1044 static void
dolog(priority,buf,prefixlen,messagelen)1045 dolog(priority, buf, prefixlen, messagelen)
1046    const int priority;
1047    const char *buf;
1048    const size_t prefixlen;
1049    const size_t messagelen;
1050 {
1051    int needlock = 0, logged = 0;
1052 
1053    /*
1054     * syslog first ...
1055     */
1056    if ((sockscf.errlog.type & LOGTYPE_SYSLOG)
1057    ||  (sockscf.log.type    & LOGTYPE_SYSLOG)) {
1058       if (priority <= LOG_WARNING) { /* lower pri value means more serious */
1059          if (sockscf.errlog.type & LOGTYPE_SYSLOG) {
1060             /*
1061              * Unfortunately it's not safe to call syslog(3) from a signal
1062              * handler.  Do make an exception for the most serious warnings
1063              * however.
1064              */
1065             if (!sockscf.state.insignal || priority <= LOG_CRIT) {
1066                syslog(priority | sockscf.errlog.facility,
1067                       "%s: %s", loglevel2string(priority), &buf[prefixlen]);
1068 
1069                logged = 1;
1070             }
1071          }
1072       }
1073 
1074       if (sockscf.log.type & LOGTYPE_SYSLOG) {
1075          if (!sockscf.state.insignal || priority <= LOG_CRIT) {
1076             syslog(priority | sockscf.log.facility,
1077                    "%s: %s", loglevel2string(priority), &buf[prefixlen]);
1078 
1079             logged = 1;
1080          }
1081       }
1082 
1083 #if SOCKS_CLIENT
1084       /*
1085        * We don't have control over what sockets the application is using,
1086        * and some applications may try to close all open fds, including the
1087        * socket used by syslog.  If that happens, the syslog(3) call will
1088        * probably fail, which is not critical.  A critical problem is however
1089        * that some libc-libraries (e.g., glibc-2.26 and up) will in that
1090        * case close(2) the syslog-socket they previously opened, but
1091        * that socket may now be in use by the application.  The latter problem
1092        * will make things go bad as the application will for some unknown
1093        * reason suddenly lose it's fd, or even worse, the fd may now be
1094        * connected to syslog after the libc-library decides to recreate the
1095        * syslog-socket.
1096        *
1097        * To avoid that problem we call closelog(3) after every syslog(3)
1098        * call, to make the syslog library code close any fd in use for
1099        * syslog(3)-ing.  Next time we then call syslog(3) (including the
1100        * first time we call syslog(3)), the syslog code should create a new
1101        * syslog-socket, syslog what we want, and then we call closelog(3)
1102        * again.  The effect should be that the syslog-socket only exists
1103        * during the time we need to log something, which should avoid any
1104        * conflicts with the application code.
1105        *
1106        * It is obviously not very optimal creating a new socket every time
1107        * we syslog(3), but since this is only a problem for the client (in
1108        * the Dante server, we have better control over sockets in use), the
1109        * overhead is deemed acceptable.
1110        */
1111 
1112       closelog();
1113 
1114 #endif /* SOCKS_CLIENT */
1115    }
1116 
1117    /*
1118     * ... and then logging to file.
1119     */
1120 
1121 
1122 #if 0
1123    if ((sockscf.log.type & LOGTYPE_FILE)
1124    ||  (priority <= LOG_WARNING && (sockscf.errlog.type & LOGTYPE_FILE))
1125    ||  HAVE_LIVEDEBUG) {
1126       if (sockscf.loglock != -1) {
1127          needlock = 1;
1128          socks_lock(sockscf.loglock, 0, 0, 1, 1);
1129       }
1130    }
1131 #else /* the file is opened with O_APPEND - no locking should be required. */
1132    needlock = 0;
1133 #endif
1134 
1135    /* error-related logging first ...  */
1136    if (priority <= LOG_WARNING) { /* lower pri value means more serious */
1137       if (sockscf.errlog.type & LOGTYPE_FILE) {
1138          size_t i;
1139 
1140          for (i = 0; i < sockscf.errlog.filenoc; ++i) {
1141             while (write(sockscf.errlog.filenov[i], buf, prefixlen + messagelen)
1142             == -1 && errno == EINTR)
1143                ;
1144 
1145             logged = 1;
1146          }
1147       }
1148    }
1149 
1150    /* ... and then normal logging. */
1151    if (sockscf.log.type & LOGTYPE_FILE) {
1152       size_t i;
1153 
1154       for (i = 0; i < sockscf.log.filenoc; ++i) {
1155          size_t retries = 0;
1156 
1157          while (write(sockscf.log.filenov[i], buf, prefixlen + messagelen) == -1
1158          && errno     == EINTR
1159          && retries++ <  10)
1160             ;
1161 
1162          logged = 1;
1163       }
1164    }
1165 
1166    if (needlock)
1167       socks_unlock(sockscf.loglock, 0, 0);
1168 
1169    /*
1170     * If we need to log something serious but have not inited logfiles
1171     * yet, take the risk of logging it to stderr.
1172     */
1173    if (!logged) {
1174       if (!sockscf.state.inited && priority <= LOG_WARNING) {
1175 #if SOCKS_CLIENT
1176 
1177          if (isatty(fileno(stderr))) /* don't take the risk otherwise. */
1178             (void)write(fileno(stderr), buf, prefixlen + messagelen);
1179 
1180 #else /* server */
1181 
1182          (void)write(fileno(stderr), buf, prefixlen + messagelen);
1183 
1184 #endif /* server */
1185       }
1186    }
1187 }
1188 
1189 static int
openlogfile(logfile,wecreated)1190 openlogfile(logfile, wecreated)
1191    const char *logfile;
1192    int *wecreated;
1193 {
1194    const char *function = "openlogfile()";
1195    int p, flagstoadd, fd;
1196 
1197    *wecreated = 0;
1198 
1199    if (strcmp(logfile, "stdout") == 0) {
1200       fd         = fileno(stdout);
1201       flagstoadd = 0;
1202    }
1203    else if (strcmp(logfile, "stderr") == 0) {
1204       fd         = fileno(stderr);
1205       flagstoadd = 0;
1206    }
1207    else {
1208       const mode_t openmode  = S_IRUSR  | S_IWUSR  | S_IRGRP;
1209       const int    openflags = O_WRONLY | O_APPEND;
1210 
1211 #if !SOCKS_CLIENT
1212       sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_ON);
1213 #endif /* !SOCKS_CLIENT */
1214 
1215       if ((fd = open(logfile, openflags, openmode)) == -1)
1216          if ((fd = open(logfile, openflags | O_CREAT, openmode)) != -1)
1217             *wecreated = 1;
1218 
1219 #if !SOCKS_CLIENT
1220       sockd_priv(SOCKD_PRIV_PRIVILEGED, PRIV_OFF);
1221 #endif /* !SOCKS_CLIENT */
1222 
1223       flagstoadd = FD_CLOEXEC;
1224    }
1225 
1226    if (fd == -1) {
1227       swarn("%s: could not open or create logfile \"%s\" for writing",
1228             function, logfile);
1229 
1230       return -1;
1231    }
1232 
1233    if ((p = fcntl(fd, F_GETFD, 0)) == -1)
1234       swarn("%s: fcntl(F_GETFD) on logfile \"%s\", fd %d, failed",
1235             function, logfile, fd);
1236    else {
1237       if (fcntl(fd, F_SETFD, p | flagstoadd) == -1)
1238          swarn("%s: fcntl(F_SETFD, 0x%x) on logfile \"%s\", fd %d, failed",
1239                function, p | flagstoadd, logfile, fd);
1240    }
1241 
1242    return fd;
1243 }
1244 
1245 static size_t
getlogprefix(priority,buf,buflen)1246 getlogprefix(priority, buf, buflen)
1247    const int priority;
1248    char *buf;
1249    size_t buflen;
1250 {
1251    const char *p;
1252    static time_t last_secondsnow;
1253    static char laststr[128];
1254    static size_t laststr_lenused;
1255    struct timeval timenow;
1256    size_t i, tocopy, lenused;
1257    time_t secondsnow;
1258    pid_t pid;
1259    char s_string[22 /* see ltoa() doc. */],
1260         us_string[sizeof(s_string)], pid_string[sizeof(s_string)];
1261 
1262    if (buflen == 0)
1263       return 0;
1264 
1265    gettimeofday(&timenow, NULL);
1266 
1267    if (sockscf.state.pid == 0)
1268       pid = getpid(); /* don't change sockscf.state.pid; probably client. */
1269    else
1270       pid = sockscf.state.pid;
1271 
1272    lenused = 0;
1273 
1274    if ((secondsnow = (time_t)timenow.tv_sec) == last_secondsnow) {
1275       const size_t tocopy = MIN(buflen - lenused, laststr_lenused);
1276 
1277       memcpy(&buf[lenused], laststr, tocopy);
1278       lenused += tocopy; /* not counting NUL. */
1279    }
1280    else {
1281       struct tm *tm;
1282 
1283       if (sockscf.state.insignal
1284       ||  (tm = localtime(&secondsnow)) == NULL) {
1285          /*
1286           * can not call strftime(3) from signalhandler.
1287           */
1288          const char p[] = "<no localtime available> ";
1289          const size_t tocopy = MIN(buflen - lenused, sizeof(p) - 1);
1290 
1291          memcpy(&buf[lenused], p, tocopy);
1292          lenused += tocopy;
1293       }
1294       else {
1295          const size_t len = strftime(&buf[lenused], buflen - lenused,
1296                                      "%h %e %T ", tm);
1297 
1298          laststr_lenused = MIN(sizeof(laststr) - 1, len);
1299          memcpy(laststr, &buf[lenused], laststr_lenused);
1300          last_secondsnow = secondsnow;
1301 
1302          lenused += len;
1303       }
1304    }
1305 
1306 #if 0
1307    /*
1308     * The rest of the code should produce the equivalent of the following
1309     * snprintf(3) call, but we don't want to call snprintf(3) as we may
1310     * be in a signalhandler.
1311     */
1312     snprintf(&buf[lenused], buflen - lenused,
1313              "(%ld.%06ld) %s[%ld]: %s: ",
1314              (long)timenow.tv_sec,
1315              (long)timenow.tv_usec,
1316              __progname,
1317              (long)pid,
1318              loglevel2string(priority));
1319 #endif
1320 
1321 
1322    ltoa((long)timenow.tv_sec,  s_string,   sizeof(s_string));
1323    ltoa((long)timenow.tv_usec, us_string,  sizeof(us_string));
1324    ltoa((long)pid,             pid_string, sizeof(pid_string));
1325 
1326 #define WANTED_DIGITS (6)  /* always want six digits. */
1327 
1328 #if DIAGNOSTIC
1329    SASSERTX(strlen(us_string) <= WANTED_DIGITS);
1330 #endif /* DIAGNOSTIC */
1331 
1332    if ((i = strlen(us_string)) < WANTED_DIGITS) {
1333       const size_t zeros_to_add = WANTED_DIGITS - i;
1334       size_t added;
1335       char debug[sizeof(us_string)];
1336 
1337       memcpy(debug, us_string, sizeof(debug));
1338 
1339       SASSERTX(us_string[i] == NUL);
1340       memmove(&us_string[zeros_to_add], us_string, i + 1);
1341 
1342       for (added = 0; added < zeros_to_add; ++added)
1343          us_string[added] = '0';
1344 
1345       SASSERTX(us_string[i + zeros_to_add] == NUL);
1346 
1347 #if DIAGNOSTIC
1348       SASSERTX(strlen(us_string) == WANTED_DIGITS);
1349 #endif /* DIAGNOSTIC */
1350    }
1351 
1352 #if DIAGNOSTIC
1353    SASSERTX(strlen(us_string) == WANTED_DIGITS);
1354 
1355    SASSERTX(buflen - lenused >
1356             strlen("(")
1357                + strlen(s_string) + strlen(".") + strlen(us_string)
1358           + strlen(") ")
1359           + strlen(__progname)
1360           + strlen("[") + strlen(pid_string) + strlen("]: ")
1361           + strlen(loglevel2string(priority)) + strlen(": "));
1362 #endif /* DIAGNOSTIC */
1363 
1364    buf[lenused++] = '(';
1365 
1366    p      = s_string;
1367    tocopy = MIN(buflen - lenused, strlen(p));
1368    memcpy(&buf[lenused], p, tocopy);
1369    lenused += tocopy;
1370 
1371    buf[lenused++] = '.';
1372 
1373    p      = us_string;
1374    tocopy = MIN(buflen - lenused, strlen(p));
1375    memcpy(&buf[lenused], p, tocopy);
1376    lenused += tocopy;
1377 
1378    buf[lenused++] = ')';
1379    buf[lenused++] = ' ';
1380 
1381    p      = __progname;
1382    tocopy = MIN(buflen - lenused, strlen(p));
1383    memcpy(&buf[lenused], p, tocopy);
1384    lenused += tocopy;
1385 
1386    buf[lenused++] = '[';
1387 
1388    p      = pid_string;
1389    tocopy = MIN(buflen - lenused, strlen(p));
1390    memcpy(&buf[lenused], p, tocopy);
1391    lenused += tocopy;
1392 
1393    buf[lenused++] = ']';
1394    buf[lenused++] = ':';
1395    buf[lenused++] = ' ';
1396 
1397    p      = loglevel2string(priority);
1398    tocopy = MIN(buflen - lenused, strlen(p));
1399    memcpy(&buf[lenused], p, tocopy);
1400 
1401    lenused += tocopy;
1402    buf[lenused++] = ':';
1403    buf[lenused++] = ' ';
1404 
1405    buf[lenused++] = NUL;
1406 
1407    --lenused;
1408    SASSERTX(buf[lenused] == NUL);
1409 
1410    return lenused;
1411 }
1412 
1413 int
socks_logmatch(d,log)1414 socks_logmatch(d, log)
1415    int d;
1416    const logtype_t *log;
1417 {
1418    size_t i;
1419 
1420    if (d < 0)
1421       return 0;
1422 
1423    for (i = 0; i < log->filenoc; ++i)
1424       if (d == log->filenov[i])
1425          return 1;
1426 
1427    return 0;
1428 }
1429 
1430 
1431 void
slogstack(void)1432 slogstack(void)
1433 {
1434 #if HAVE_BACKTRACE
1435    const char *function = "slogstack()";
1436    void *array[20];
1437    size_t i, size;
1438    char **strings;
1439 
1440    size    = backtrace(array, (int)ELEMENTS(array));
1441    strings = backtrace_symbols(array, size);
1442 
1443    if (strings == NULL)  {
1444       swarn("%s: strings = NULL", function);
1445       return;
1446    }
1447 
1448    for (i = 1; i < size; i++)
1449       slog(LOG_INFO, "%s: stackframe #%lu: %s\n",
1450            function, (unsigned long)i, strings[i]);
1451 
1452    free(strings);
1453 #endif /* HAVE_BACKTRACE */
1454 }
1455 
1456 const loglevel_t *
loglevel(name)1457 loglevel(name)
1458    const char *name;
1459 {
1460    static const loglevel_t loglevelv[MAXLOGLEVELS] = {
1461       { "emerg",   LOG_EMERG    },
1462       { "alert",   LOG_ALERT    },
1463       { "crit",    LOG_CRIT     },
1464       { "err",     LOG_ERR      },
1465       { "warning", LOG_WARNING  },
1466       { "notice",  LOG_NOTICE   },
1467       { "info",    LOG_INFO     },
1468       { "debug",   LOG_DEBUG    },
1469    };
1470    size_t i;
1471 
1472    CTASSERT(LOG_EMERG == 0);
1473    CTASSERT(LOG_DEBUG == 7);
1474    CTASSERT(LOG_DEBUG < MAXLOGLEVELS);
1475    CTASSERT(LOG_DEBUG < sizeof(loglevelv));
1476 
1477    for (i = 0; i < ELEMENTS(loglevelv); ++i)
1478       if (strcmp(name, loglevelv[i].name) == 0)
1479          return &loglevelv[i];
1480 
1481    return NULL;
1482 }
1483 
1484 
1485 static const struct syslogfacility *
syslogfacility(name)1486 syslogfacility(name)
1487    const char *name;
1488 {
1489    static struct syslogfacility syslogfacilityv[] = {
1490          /* POSIX */
1491       { "user",     LOG_USER   },
1492       { "auth",     LOG_AUTH   },
1493       { "daemon",   LOG_DAEMON },
1494       { "local0",   LOG_LOCAL0 },
1495       { "local1",   LOG_LOCAL1 },
1496       { "local2",   LOG_LOCAL2 },
1497       { "local3",   LOG_LOCAL3 },
1498       { "local4",   LOG_LOCAL4 },
1499       { "local5",   LOG_LOCAL5 },
1500       { "local6",   LOG_LOCAL6 },
1501       { "local7",   LOG_LOCAL7 },
1502 
1503          /*
1504           * Non-POSIX.
1505           */
1506 #ifdef LOG_AUTHPRIV
1507       { "authpriv",   LOG_AUTHPRIV  },
1508 #endif /* LOG_AUTHPRIV */
1509    };
1510 
1511    size_t i;
1512 
1513    for (i = 0; i < ELEMENTS(syslogfacilityv); ++i)
1514       if (strcmp(name, syslogfacilityv[i].name) == 0)
1515          return &syslogfacilityv[i];
1516 
1517    return NULL;
1518 }
1519 
1520 
1521 #if HAVE_LIVEDEBUG
1522 
1523 static void
socks_addtorb(str,lenopt)1524 socks_addtorb(str, lenopt)
1525    const char *str;
1526    const size_t lenopt;
1527 {
1528    ssize_t overshoot;
1529    size_t len;
1530 
1531    if (dont_add_to_rb)
1532       return;
1533 
1534    if (lenopt <= 1)
1535       return;
1536 
1537 #if DIAGNOSTIC
1538    SASSERTX(lenopt == strlen(str) + 1);
1539 #endif /* DIAGNOSTIC */
1540 
1541    if (lenopt >= sizeof(ringbuffer))
1542       len = sizeof(ringbuffer) - 1 - 1; /* two strings, extra NUL */
1543    else
1544       len = lenopt - 1; /* ignore trailing NUL */
1545 
1546    overshoot = (ringbuf_curroff + len) - (sizeof(ringbuffer) - 1);
1547    if (overshoot > 0) {
1548       memmove(ringbuffer + ringbuf_curroff, str, len - overshoot);
1549       memmove(ringbuffer, str + len - overshoot, (size_t)overshoot);
1550       ringbuf_curroff = overshoot;
1551    }
1552    else {
1553       memmove(ringbuffer + ringbuf_curroff, str, len);
1554       ringbuf_curroff += len;
1555       if (ringbuf_curroff >= sizeof(ringbuffer) - 1)
1556          ringbuf_curroff = 0;
1557    }
1558 
1559    ringbuffer[ringbuf_curroff] = NUL;
1560    SASSERTX(ringbuffer[sizeof(ringbuffer) - 1] == NUL);
1561 
1562    return;
1563 }
1564 
1565 void
socks_flushrb(void)1566 socks_flushrb(void)
1567 {
1568    const char *function = "socks_flushrb()";
1569    const char *msgv[]
1570    = { function,
1571        ": flushing log buffer.  This should only happen upon fatal error.  "
1572        "\n\"\"\"",
1573        ringbuffer + ringbuf_curroff + 1,
1574        ringbuffer,
1575        "\n\"\"\"",
1576        NULL
1577      };
1578    const int old_dont_add_to_rb = dont_add_to_rb;
1579 
1580    dont_add_to_rb = 1; /* don't add this one to rb ... flushing. */
1581 
1582    signalslog(LOG_WARNING, msgv);
1583 
1584    dont_add_to_rb = old_dont_add_to_rb;
1585 }
1586 
1587 #if SOCKS_CLIENT
1588 static void
atexit_flushrb(void)1589 atexit_flushrb(void)
1590 {
1591    const char *function = "atexit_flushrb()";
1592 
1593    if (sockscf.state.internalerrordetected && !sockscf.option.debug) {
1594       slog(LOG_DEBUG, "%s", function);
1595       socks_flushrb();
1596    }
1597 }
1598 #endif /* SOCKS_CLIENT */
1599 
1600 #endif /* HAVE_LIVEDEBUG */
1601