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