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