1/*-
2 * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: src/usr.sbin/ppp/log.c,v 1.53.34.1 2010/12/21 17:10:29 kensmith Exp $
27 */
28
29#include <sys/types.h>
30
31#include <ctype.h>
32#include <stdarg.h>
33#include <stdio.h>
34#include <string.h>
35#include <syslog.h>
36#include <termios.h>
37
38#include "defs.h"
39#include "command.h"
40#include "mbuf.h"
41#include "log.h"
42#include "descriptor.h"
43#include "prompt.h"
44
45static const char *const LogNames[] = {
46  "Async",
47  "CBCP",
48  "CCP",
49  "Chat",
50  "Command",
51  "Connect",
52  "Debug",
53  "DNS",
54  "Filter",			/* Log discarded packets */
55  "HDLC",
56  "ID0",
57  "IPCP",
58  "IPV6CP",
59  "LCP",
60  "LQM",
61  "Phase",
62  "Physical",
63  "Radius",
64  "Sync",
65  "TCP/IP",
66  "Timer",
67  "Tun",
68  "Warning",
69  "Error",
70  "Alert"
71};
72
73#define MSK(n) (1<<((n)-1))
74
75static u_long LogMask = MSK(LogPHASE);
76static u_long LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
77static int LogTunno = -1;
78static struct prompt *promptlist;	/* Where to log local stuff */
79struct prompt *log_PromptContext;
80int log_PromptListChanged;
81
82struct prompt *
83log_PromptList()
84{
85  return promptlist;
86}
87
88void
89log_RegisterPrompt(struct prompt *prompt)
90{
91  prompt->next = promptlist;
92  promptlist = prompt;
93  prompt->active = 1;
94  log_DiscardAllLocal(&prompt->logmask);
95}
96
97void
98log_ActivatePrompt(struct prompt *prompt)
99{
100  prompt->active = 1;
101  LogMaskLocal |= prompt->logmask;
102}
103
104static void
105LogSetMaskLocal(void)
106{
107  struct prompt *p;
108
109  LogMaskLocal = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
110  for (p = promptlist; p; p = p->next)
111    LogMaskLocal |= p->logmask;
112}
113
114void
115log_DeactivatePrompt(struct prompt *prompt)
116{
117  if (prompt->active) {
118    prompt->active = 0;
119    LogSetMaskLocal();
120  }
121}
122
123void
124log_UnRegisterPrompt(struct prompt *prompt)
125{
126  if (prompt) {
127    struct prompt **p;
128
129    for (p = &promptlist; *p; p = &(*p)->next)
130      if (*p == prompt) {
131        *p = prompt->next;
132        prompt->next = NULL;
133        break;
134      }
135    LogSetMaskLocal();
136    log_PromptListChanged++;
137  }
138}
139
140void
141log_DestroyPrompts(struct server *s)
142{
143  struct prompt *p, *pn, *pl;
144
145  p = promptlist;
146  pl = NULL;
147  while (p) {
148    pn = p->next;
149    if (s && p->owner == s) {
150      if (pl)
151        pl->next = p->next;
152      else
153        promptlist = p->next;
154      p->next = NULL;
155      prompt_Destroy(p, 1);
156    } else
157      pl = p;
158    p = pn;
159  }
160}
161
162void
163log_DisplayPrompts()
164{
165  struct prompt *p;
166
167  for (p = promptlist; p; p = p->next)
168    prompt_Required(p);
169}
170
171void
172log_WritePrompts(struct datalink *dl, const char *fmt,...)
173{
174  va_list ap;
175  struct prompt *p;
176
177  va_start(ap, fmt);
178  for (p = promptlist; p; p = p->next)
179    if (prompt_IsTermMode(p, dl))
180      prompt_vPrintf(p, fmt, ap);
181  va_end(ap);
182}
183
184void
185log_SetTtyCommandMode(struct datalink *dl)
186{
187  struct prompt *p;
188
189  for (p = promptlist; p; p = p->next)
190    if (prompt_IsTermMode(p, dl))
191      prompt_TtyCommandMode(p);
192}
193
194static int
195syslogLevel(int lev)
196{
197  switch (lev) {
198  case LogLOG:
199    return LOG_INFO;
200  case LogDEBUG:
201  case LogTIMER:
202    return LOG_DEBUG;
203  case LogWARN:
204    return LOG_WARNING;
205  case LogERROR:
206    return LOG_ERR;
207  case LogALERT:
208    return LOG_ALERT;
209  }
210  return lev >= LogMIN && lev <= LogMAX ? LOG_INFO : 0;
211}
212
213const char *
214log_Name(int id)
215{
216  if (id == LogLOG)
217    return "LOG";
218  return id < LogMIN || id > LogMAX ? "Unknown" : LogNames[id - 1];
219}
220
221void
222log_Keep(int id)
223{
224  if (id >= LogMIN && id <= LogMAXCONF)
225    LogMask |= MSK(id);
226}
227
228void
229log_KeepLocal(int id, u_long *mask)
230{
231  if (id >= LogMIN && id <= LogMAXCONF) {
232    LogMaskLocal |= MSK(id);
233    *mask |= MSK(id);
234  }
235}
236
237void
238log_Discard(int id)
239{
240  if (id >= LogMIN && id <= LogMAXCONF)
241    LogMask &= ~MSK(id);
242}
243
244void
245log_DiscardLocal(int id, u_long *mask)
246{
247  if (id >= LogMIN && id <= LogMAXCONF) {
248    *mask &= ~MSK(id);
249    LogSetMaskLocal();
250  }
251}
252
253void
254log_DiscardAll()
255{
256  LogMask = 0;
257}
258
259void
260log_DiscardAllLocal(u_long *mask)
261{
262  *mask = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN);
263  LogSetMaskLocal();
264}
265
266int
267log_IsKept(int id)
268{
269  if (id == LogLOG)
270    return LOG_KEPT_SYSLOG;
271  if (id < LogMIN || id > LogMAX)
272    return 0;
273  if (id > LogMAXCONF)
274    return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG;
275
276  return ((LogMaskLocal & MSK(id)) ? LOG_KEPT_LOCAL : 0) |
277    ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0);
278}
279
280int
281log_IsKeptLocal(int id, u_long mask)
282{
283  if (id < LogMIN || id > LogMAX)
284    return 0;
285  if (id > LogMAXCONF)
286    return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG;
287
288  return ((mask & MSK(id)) ? LOG_KEPT_LOCAL : 0) |
289    ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0);
290}
291
292void
293log_Open(const char *Name)
294{
295  openlog(Name, LOG_PID, LOG_DAEMON);
296}
297
298void
299log_SetTun(int tunno)
300{
301  LogTunno = tunno;
302}
303
304void
305log_Close()
306{
307  closelog();
308  LogTunno = -1;
309}
310
311void
312log_Printf(int lev, const char *fmt,...)
313{
314  va_list ap;
315  struct prompt *prompt;
316
317  if (log_IsKept(lev)) {
318    char nfmt[200];
319
320    va_start(ap, fmt);
321    if (promptlist && (log_IsKept(lev) & LOG_KEPT_LOCAL)) {
322      if ((log_IsKept(LogTUN) & LOG_KEPT_LOCAL) && LogTunno != -1)
323        snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME,
324	         LogTunno, log_Name(lev), fmt);
325      else
326        snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt);
327
328      if (log_PromptContext && lev == LogWARN)
329        /* Warnings just go to the current prompt */
330        prompt_vPrintf(log_PromptContext, nfmt, ap);
331      else for (prompt = promptlist; prompt; prompt = prompt->next)
332        if (lev > LogMAXCONF || (prompt->logmask & MSK(lev)))
333          prompt_vPrintf(prompt, nfmt, ap);
334    }
335    va_end(ap);
336
337    va_start(ap, fmt);
338    if ((log_IsKept(lev) & LOG_KEPT_SYSLOG) &&
339        (lev != LogWARN || !log_PromptContext)) {
340      if ((log_IsKept(LogTUN) & LOG_KEPT_SYSLOG) && LogTunno != -1)
341        snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME,
342	         LogTunno, log_Name(lev), fmt);
343      else
344        snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt);
345      vsyslog(syslogLevel(lev), nfmt, ap);
346    }
347    va_end(ap);
348  }
349}
350
351void
352log_DumpBp(int lev, const char *hdr, const struct mbuf *bp)
353{
354  if (log_IsKept(lev)) {
355    char buf[68];
356    char *b, *c;
357    const u_char *ptr;
358    int f;
359
360    if (hdr && *hdr)
361      log_Printf(lev, "%s\n", hdr);
362
363    b = buf;
364    c = b + 50;
365    do {
366      f = bp->m_len;
367      ptr = CONST_MBUF_CTOP(bp);
368      while (f--) {
369	sprintf(b, " %02x", (int) *ptr);
370        *c++ = isprint(*ptr) ? *ptr : '.';
371        ptr++;
372        b += 3;
373        if (b == buf + 48) {
374          memset(b, ' ', 2);
375          *c = '\0';
376          log_Printf(lev, "%s\n", buf);
377          b = buf;
378          c = b + 50;
379        }
380      }
381    } while ((bp = bp->m_next) != NULL);
382
383    if (b > buf) {
384      memset(b, ' ', 50 - (b - buf));
385      *c = '\0';
386      log_Printf(lev, "%s\n", buf);
387    }
388  }
389}
390
391void
392log_DumpBuff(int lev, const char *hdr, const u_char *ptr, int n)
393{
394  if (log_IsKept(lev)) {
395    char buf[68];
396    char *b, *c;
397
398    if (hdr && *hdr)
399      log_Printf(lev, "%s\n", hdr);
400    while (n > 0) {
401      b = buf;
402      c = b + 50;
403      for (b = buf; b != buf + 48 && n--; b += 3, ptr++) {
404	sprintf(b, " %02x", (int) *ptr);
405        *c++ = isprint(*ptr) ? *ptr : '.';
406      }
407      memset(b, ' ', 50 - (b - buf));
408      *c = '\0';
409      log_Printf(lev, "%s\n", buf);
410    }
411  }
412}
413
414int
415log_ShowLevel(struct cmdargs const *arg)
416{
417  int i;
418
419  prompt_Printf(arg->prompt, "Log:  ");
420  for (i = LogMIN; i <= LogMAX; i++)
421    if (log_IsKept(i) & LOG_KEPT_SYSLOG)
422      prompt_Printf(arg->prompt, " %s", log_Name(i));
423
424  prompt_Printf(arg->prompt, "\nLocal:");
425  for (i = LogMIN; i <= LogMAX; i++)
426    if (log_IsKeptLocal(i, arg->prompt->logmask) & LOG_KEPT_LOCAL)
427      prompt_Printf(arg->prompt, " %s", log_Name(i));
428
429  prompt_Printf(arg->prompt, "\n");
430
431  return 0;
432}
433
434int
435log_SetLevel(struct cmdargs const *arg)
436{
437  int i, res, argc, local;
438  char const *const *argv, *argp;
439
440  argc = arg->argc - arg->argn;
441  argv = arg->argv + arg->argn;
442  res = 0;
443
444  if (argc == 0 || strcasecmp(argv[0], "local"))
445    local = 0;
446  else {
447    if (arg->prompt == NULL) {
448      log_Printf(LogWARN, "set log local: Only available on the"
449                 " command line\n");
450      return 1;
451    }
452    argc--;
453    argv++;
454    local = 1;
455  }
456
457  if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-')) {
458    if (local)
459      log_DiscardAllLocal(&arg->prompt->logmask);
460    else
461      log_DiscardAll();
462  }
463
464  while (argc--) {
465    argp = **argv == '+' || **argv == '-' ? *argv + 1 : *argv;
466    /* Special case 'all' */
467    if (strcasecmp(argp, "all") == 0) {
468        if (**argv == '-') {
469          if (local)
470            for (i = LogMIN; i <= LogMAX; i++)
471              log_DiscardLocal(i, &arg->prompt->logmask);
472          else
473            for (i = LogMIN; i <= LogMAX; i++)
474              log_Discard(i);
475        } else if (local)
476          for (i = LogMIN; i <= LogMAX; i++)
477            log_KeepLocal(i, &arg->prompt->logmask);
478        else
479          for (i = LogMIN; i <= LogMAX; i++)
480            log_Keep(i);
481        argv++;
482        continue;
483    }
484    for (i = LogMIN; i <= LogMAX; i++)
485      if (strcasecmp(argp, log_Name(i)) == 0) {
486	if (**argv == '-') {
487          if (local)
488            log_DiscardLocal(i, &arg->prompt->logmask);
489          else
490	    log_Discard(i);
491	} else if (local)
492          log_KeepLocal(i, &arg->prompt->logmask);
493        else
494          log_Keep(i);
495	break;
496      }
497    if (i > LogMAX) {
498      log_Printf(LogWARN, "%s: Invalid log value\n", argp);
499      res = -1;
500    }
501    argv++;
502  }
503  return res;
504}
505
506int
507log_ShowWho(struct cmdargs const *arg)
508{
509  struct prompt *p;
510
511  for (p = promptlist; p; p = p->next) {
512    prompt_Printf(arg->prompt, "%s (%s)", p->src.type, p->src.from);
513    if (p == arg->prompt)
514      prompt_Printf(arg->prompt, " *");
515    if (!p->active)
516      prompt_Printf(arg->prompt, " ^Z");
517    prompt_Printf(arg->prompt, "\n");
518  }
519
520  return 0;
521}
522