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