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 LogDEBUG: 198 case LogTIMER: 199 return LOG_DEBUG; 200 case LogWARN: 201 return LOG_WARNING; 202 case LogERROR: 203 return LOG_ERR; 204 case LogALERT: 205 return LOG_ALERT; 206 } 207 return lev >= LogMIN && lev <= LogMAX ? LOG_INFO : 0; 208 } 209 210 const char * 211 log_Name(int id) 212 { 213 return id < LogMIN || id > LogMAX ? "Unknown" : LogNames[id - 1]; 214 } 215 216 void 217 log_Keep(int id) 218 { 219 if (id >= LogMIN && id <= LogMAXCONF) 220 LogMask |= MSK(id); 221 } 222 223 void 224 log_KeepLocal(int id, u_long *mask) 225 { 226 if (id >= LogMIN && id <= LogMAXCONF) { 227 LogMaskLocal |= MSK(id); 228 *mask |= MSK(id); 229 } 230 } 231 232 void 233 log_Discard(int id) 234 { 235 if (id >= LogMIN && id <= LogMAXCONF) 236 LogMask &= ~MSK(id); 237 } 238 239 void 240 log_DiscardLocal(int id, u_long *mask) 241 { 242 if (id >= LogMIN && id <= LogMAXCONF) { 243 *mask &= ~MSK(id); 244 LogSetMaskLocal(); 245 } 246 } 247 248 void 249 log_DiscardAll() 250 { 251 LogMask = 0; 252 } 253 254 void 255 log_DiscardAllLocal(u_long *mask) 256 { 257 *mask = MSK(LogERROR) | MSK(LogALERT) | MSK(LogWARN); 258 LogSetMaskLocal(); 259 } 260 261 int 262 log_IsKept(int id) 263 { 264 if (id < LogMIN || id > LogMAX) 265 return 0; 266 if (id > LogMAXCONF) 267 return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG; 268 269 return ((LogMaskLocal & MSK(id)) ? LOG_KEPT_LOCAL : 0) | 270 ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0); 271 } 272 273 int 274 log_IsKeptLocal(int id, u_long mask) 275 { 276 if (id < LogMIN || id > LogMAX) 277 return 0; 278 if (id > LogMAXCONF) 279 return LOG_KEPT_LOCAL | LOG_KEPT_SYSLOG; 280 281 return ((mask & MSK(id)) ? LOG_KEPT_LOCAL : 0) | 282 ((LogMask & MSK(id)) ? LOG_KEPT_SYSLOG : 0); 283 } 284 285 void 286 log_Open(const char *Name) 287 { 288 openlog(Name, LOG_PID, LOG_DAEMON); 289 } 290 291 void 292 log_SetTun(int tunno) 293 { 294 LogTunno = tunno; 295 } 296 297 void 298 log_Close() 299 { 300 closelog(); 301 LogTunno = -1; 302 } 303 304 void 305 log_Printf(int lev, const char *fmt,...) 306 { 307 va_list ap; 308 struct prompt *prompt; 309 310 if (log_IsKept(lev)) { 311 char nfmt[200]; 312 313 va_start(ap, fmt); 314 if (promptlist && (log_IsKept(lev) & LOG_KEPT_LOCAL)) { 315 if ((log_IsKept(LogTUN) & LOG_KEPT_LOCAL) && LogTunno != -1) 316 snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME, 317 LogTunno, log_Name(lev), fmt); 318 else 319 snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt); 320 321 if (log_PromptContext && lev == LogWARN) 322 /* Warnings just go to the current prompt */ 323 prompt_vPrintf(log_PromptContext, nfmt, ap); 324 else for (prompt = promptlist; prompt; prompt = prompt->next) 325 if (lev > LogMAXCONF || (prompt->logmask & MSK(lev))) 326 prompt_vPrintf(prompt, nfmt, ap); 327 } 328 va_end(ap); 329 330 va_start(ap, fmt); 331 if ((log_IsKept(lev) & LOG_KEPT_SYSLOG) && 332 (lev != LogWARN || !log_PromptContext)) { 333 if ((log_IsKept(LogTUN) & LOG_KEPT_SYSLOG) && LogTunno != -1) 334 snprintf(nfmt, sizeof nfmt, "%s%d: %s: %s", TUN_NAME, 335 LogTunno, log_Name(lev), fmt); 336 else 337 snprintf(nfmt, sizeof nfmt, "%s: %s", log_Name(lev), fmt); 338 vsyslog(syslogLevel(lev), nfmt, ap); 339 } 340 va_end(ap); 341 } 342 } 343 344 void 345 log_DumpBp(int lev, const char *hdr, const struct mbuf *bp) 346 { 347 if (log_IsKept(lev)) { 348 char buf[68]; 349 char *b, *c; 350 const u_char *ptr; 351 int f; 352 353 if (hdr && *hdr) 354 log_Printf(lev, "%s\n", hdr); 355 356 b = buf; 357 c = b + 50; 358 do { 359 f = bp->m_len; 360 ptr = CONST_MBUF_CTOP(bp); 361 while (f--) { 362 sprintf(b, " %02x", (int) *ptr); 363 *c++ = isprint(*ptr) ? *ptr : '.'; 364 ptr++; 365 b += 3; 366 if (b == buf + 48) { 367 memset(b, ' ', 2); 368 *c = '\0'; 369 log_Printf(lev, "%s\n", buf); 370 b = buf; 371 c = b + 50; 372 } 373 } 374 } while ((bp = bp->m_next) != NULL); 375 376 if (b > buf) { 377 memset(b, ' ', 50 - (b - buf)); 378 *c = '\0'; 379 log_Printf(lev, "%s\n", buf); 380 } 381 } 382 } 383 384 void 385 log_DumpBuff(int lev, const char *hdr, const u_char *ptr, int n) 386 { 387 if (log_IsKept(lev)) { 388 char buf[68]; 389 char *b, *c; 390 391 if (hdr && *hdr) 392 log_Printf(lev, "%s\n", hdr); 393 while (n > 0) { 394 b = buf; 395 c = b + 50; 396 for (b = buf; b != buf + 48 && n--; b += 3, ptr++) { 397 sprintf(b, " %02x", (int) *ptr); 398 *c++ = isprint(*ptr) ? *ptr : '.'; 399 } 400 memset(b, ' ', 50 - (b - buf)); 401 *c = '\0'; 402 log_Printf(lev, "%s\n", buf); 403 } 404 } 405 } 406 407 int 408 log_ShowLevel(struct cmdargs const *arg) 409 { 410 int i; 411 412 prompt_Printf(arg->prompt, "Log: "); 413 for (i = LogMIN; i <= LogMAX; i++) 414 if (log_IsKept(i) & LOG_KEPT_SYSLOG) 415 prompt_Printf(arg->prompt, " %s", log_Name(i)); 416 417 prompt_Printf(arg->prompt, "\nLocal:"); 418 for (i = LogMIN; i <= LogMAX; i++) 419 if (log_IsKeptLocal(i, arg->prompt->logmask) & LOG_KEPT_LOCAL) 420 prompt_Printf(arg->prompt, " %s", log_Name(i)); 421 422 prompt_Printf(arg->prompt, "\n"); 423 424 return 0; 425 } 426 427 int 428 log_SetLevel(struct cmdargs const *arg) 429 { 430 int i, res, argc, local; 431 char const *const *argv, *argp; 432 433 argc = arg->argc - arg->argn; 434 argv = arg->argv + arg->argn; 435 res = 0; 436 437 if (argc == 0 || strcasecmp(argv[0], "local")) 438 local = 0; 439 else { 440 if (arg->prompt == NULL) { 441 log_Printf(LogWARN, "set log local: Only available on the" 442 " command line\n"); 443 return 1; 444 } 445 argc--; 446 argv++; 447 local = 1; 448 } 449 450 if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-')) { 451 if (local) 452 log_DiscardAllLocal(&arg->prompt->logmask); 453 else 454 log_DiscardAll(); 455 } 456 457 while (argc--) { 458 argp = **argv == '+' || **argv == '-' ? *argv + 1 : *argv; 459 /* Special case 'all' */ 460 if (strcasecmp(argp, "all") == 0) { 461 if (**argv == '-') { 462 if (local) 463 for (i = LogMIN; i <= LogMAX; i++) 464 log_DiscardLocal(i, &arg->prompt->logmask); 465 else 466 for (i = LogMIN; i <= LogMAX; i++) 467 log_Discard(i); 468 } else if (local) 469 for (i = LogMIN; i <= LogMAX; i++) 470 log_KeepLocal(i, &arg->prompt->logmask); 471 else 472 for (i = LogMIN; i <= LogMAX; i++) 473 log_Keep(i); 474 argv++; 475 continue; 476 } 477 for (i = LogMIN; i <= LogMAX; i++) 478 if (strcasecmp(argp, log_Name(i)) == 0) { 479 if (**argv == '-') { 480 if (local) 481 log_DiscardLocal(i, &arg->prompt->logmask); 482 else 483 log_Discard(i); 484 } else if (local) 485 log_KeepLocal(i, &arg->prompt->logmask); 486 else 487 log_Keep(i); 488 break; 489 } 490 if (i > LogMAX) { 491 log_Printf(LogWARN, "%s: Invalid log value\n", argp); 492 res = -1; 493 } 494 argv++; 495 } 496 return res; 497 } 498 499 int 500 log_ShowWho(struct cmdargs const *arg) 501 { 502 struct prompt *p; 503 504 for (p = promptlist; p; p = p->next) { 505 prompt_Printf(arg->prompt, "%s (%s)", p->src.type, p->src.from); 506 if (p == arg->prompt) 507 prompt_Printf(arg->prompt, " *"); 508 if (!p->active) 509 prompt_Printf(arg->prompt, " ^Z"); 510 prompt_Printf(arg->prompt, "\n"); 511 } 512 513 return 0; 514 } 515