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$ 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 struct prompt *promptlist; /* Where to log local stuff */ 79 struct prompt *log_PromptContext; 80 int log_PromptListChanged; 81 82 struct prompt * 83 log_PromptList() 84 { 85 return promptlist; 86 } 87 88 void 89 log_RegisterPrompt(struct prompt *prompt) 90 { 91 prompt->next = promptlist; 92 promptlist = prompt; 93 prompt->active = 1; 94 log_DiscardAllLocal(&prompt->logmask); 95 } 96 97 void 98 log_ActivatePrompt(struct prompt *prompt) 99 { 100 prompt->active = 1; 101 LogMaskLocal |= prompt->logmask; 102 } 103 104 static void 105 LogSetMaskLocal(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 114 void 115 log_DeactivatePrompt(struct prompt *prompt) 116 { 117 if (prompt->active) { 118 prompt->active = 0; 119 LogSetMaskLocal(); 120 } 121 } 122 123 void 124 log_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 140 void 141 log_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 162 void 163 log_DisplayPrompts() 164 { 165 struct prompt *p; 166 167 for (p = promptlist; p; p = p->next) 168 prompt_Required(p); 169 } 170 171 void 172 log_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 184 void 185 log_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 194 static int 195 syslogLevel(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 213 const char * 214 log_Name(int id) 215 { 216 if (id == LogLOG) 217 return "LOG"; 218 return id < LogMIN || id > LogMAX ? "Unknown" : LogNames[id - 1]; 219 } 220 221 void 222 log_Keep(int id) 223 { 224 if (id >= LogMIN && id <= LogMAXCONF) 225 LogMask |= MSK(id); 226 } 227 228 void 229 log_KeepLocal(int id, u_long *mask) 230 { 231 if (id >= LogMIN && id <= LogMAXCONF) { 232 LogMaskLocal |= MSK(id); 233 *mask |= MSK(id); 234 } 235 } 236 237 void 238 log_Discard(int id) 239 { 240 if (id >= LogMIN && id <= LogMAXCONF) 241 LogMask &= ~MSK(id); 242 } 243 244 void 245 log_DiscardLocal(int id, u_long *mask) 246 { 247 if (id >= LogMIN && id <= LogMAXCONF) { 248 *mask &= ~MSK(id); 249 LogSetMaskLocal(); 250 } 251 } 252 253 void 254 log_DiscardAll() 255 { 256 LogMask = 0; 257 } 258 259 void 260 log_DiscardAllLocal(u_long *mask) 261 { 262 *mask = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN); 263 LogSetMaskLocal(); 264 } 265 266 int 267 log_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 280 int 281 log_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 292 void 293 log_Open(const char *Name) 294 { 295 openlog(Name, LOG_PID, LOG_DAEMON); 296 } 297 298 void 299 log_SetTun(int tunno) 300 { 301 LogTunno = tunno; 302 } 303 304 void 305 log_Close() 306 { 307 closelog(); 308 LogTunno = -1; 309 } 310 311 void 312 log_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 351 void 352 log_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 391 void 392 log_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 414 int 415 log_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 434 int 435 log_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 506 int 507 log_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