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