1/* 2 * utils.c - various utility functions used in pppd. 3 * 4 * Copyright (c) 1999 The Australian National University. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms are permitted 8 * provided that the above copyright notice and this paragraph are 9 * duplicated in all such forms and that any documentation, 10 * advertising materials, and other materials related to such 11 * distribution and use acknowledge that the software was developed 12 * by the Australian National University. The name of the University 13 * may not be used to endorse or promote products derived from this 14 * software without specific prior written permission. 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 18 */ 19 20#define RCSID "$Id: utils.c,v 1.1.1.1 2008/10/15 03:30:13 james26_jang Exp $" 21 22#include <stdio.h> 23#include <ctype.h> 24#include <stdlib.h> 25#include <string.h> 26#include <unistd.h> 27#include <signal.h> 28#include <errno.h> 29#include <fcntl.h> 30#include <syslog.h> 31#include <netdb.h> 32#include <utmp.h> 33#include <pwd.h> 34#include <sys/param.h> 35#include <sys/types.h> 36#include <sys/wait.h> 37#include <sys/time.h> 38#include <sys/resource.h> 39#include <sys/stat.h> 40#include <sys/socket.h> 41#include <net/ethernet.h> 42#include <netinet/in.h> 43#ifdef SVR4 44#include <sys/mkdev.h> 45#endif 46 47#include "pppd.h" 48 49static const char rcsid[] = RCSID; 50 51#if defined(SUNOS4) 52extern char *strerror(); 53#endif 54 55static void logit __P((int, char *, va_list)); 56static void log_write __P((int, char *)); 57static void vslp_printer __P((void *, char *, ...)); 58static void format_packet __P((u_char *, int, void (*) (void *, char *, ...), 59 void *)); 60 61struct buffer_info { 62 char *ptr; 63 int len; 64}; 65 66/* 67 * strlcpy - like strcpy/strncpy, doesn't overflow destination buffer, 68 * always leaves destination null-terminated (for len > 0). 69 */ 70size_t 71strlcpy(dest, src, len) 72 char *dest; 73 const char *src; 74 size_t len; 75{ 76 size_t ret = strlen(src); 77 78 if (len != 0) { 79 if (ret < len) 80 strcpy(dest, src); 81 else { 82 strncpy(dest, src, len - 1); 83 dest[len-1] = 0; 84 } 85 } 86 return ret; 87} 88 89/* 90 * strlcat - like strcat/strncat, doesn't overflow destination buffer, 91 * always leaves destination null-terminated (for len > 0). 92 */ 93size_t 94strlcat(dest, src, len) 95 char *dest; 96 const char *src; 97 size_t len; 98{ 99 size_t dlen = strlen(dest); 100 101 return dlen + strlcpy(dest + dlen, src, (len > dlen? len - dlen: 0)); 102} 103 104 105/* 106 * slprintf - format a message into a buffer. Like sprintf except we 107 * also specify the length of the output buffer, and we handle 108 * %r (recursive format), %m (error message), %v (visible string), 109 * %q (quoted string), %t (current time) and %I (IP address) formats. 110 * Doesn't do floating-point formats. 111 * Returns the number of chars put into buf. 112 */ 113int 114slprintf __V((char *buf, int buflen, char *fmt, ...)) 115{ 116 va_list args; 117 int n; 118 119#if defined(__STDC__) 120 va_start(args, fmt); 121#else 122 char *buf; 123 int buflen; 124 char *fmt; 125 va_start(args); 126 buf = va_arg(args, char *); 127 buflen = va_arg(args, int); 128 fmt = va_arg(args, char *); 129#endif 130 n = vslprintf(buf, buflen, fmt, args); 131 va_end(args); 132 return n; 133} 134 135/* 136 * vslprintf - like slprintf, takes a va_list instead of a list of args. 137 */ 138#define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) 139 140int 141vslprintf(buf, buflen, fmt, args) 142 char *buf; 143 int buflen; 144 char *fmt; 145 va_list args; 146{ 147 int c, i, n; 148 int width, prec, fillch; 149 int base, len, neg, quoted; 150 unsigned long val = 0; 151 char *str, *f, *buf0; 152 unsigned char *p; 153 char num[32]; 154 time_t t; 155 u_int32_t ip; 156 static char hexchars[] = "0123456789abcdef"; 157 struct buffer_info bufinfo; 158 159 buf0 = buf; 160 --buflen; 161 while (buflen > 0) { 162 for (f = fmt; *f != '%' && *f != 0; ++f) 163 ; 164 if (f > fmt) { 165 len = f - fmt; 166 if (len > buflen) 167 len = buflen; 168 memcpy(buf, fmt, len); 169 buf += len; 170 buflen -= len; 171 fmt = f; 172 } 173 if (*fmt == 0) 174 break; 175 c = *++fmt; 176 width = 0; 177 prec = -1; 178 fillch = ' '; 179 if (c == '0') { 180 fillch = '0'; 181 c = *++fmt; 182 } 183 if (c == '*') { 184 width = va_arg(args, int); 185 c = *++fmt; 186 } else { 187 while (isdigit(c)) { 188 width = width * 10 + c - '0'; 189 c = *++fmt; 190 } 191 } 192 if (c == '.') { 193 c = *++fmt; 194 if (c == '*') { 195 prec = va_arg(args, int); 196 c = *++fmt; 197 } else { 198 prec = 0; 199 while (isdigit(c)) { 200 prec = prec * 10 + c - '0'; 201 c = *++fmt; 202 } 203 } 204 } 205 str = 0; 206 base = 0; 207 neg = 0; 208 ++fmt; 209 switch (c) { 210 case 'd': 211 i = va_arg(args, int); 212 if (i < 0) { 213 neg = 1; 214 val = -i; 215 } else 216 val = i; 217 base = 10; 218 break; 219 case 'u': 220 val = va_arg(args, unsigned int); 221 base = 10; 222 break; 223 case 'o': 224 val = va_arg(args, unsigned int); 225 base = 8; 226 break; 227 case 'x': 228 case 'X': 229 val = va_arg(args, unsigned int); 230 base = 16; 231 break; 232 case 'p': 233 val = (unsigned long) va_arg(args, void *); 234 base = 16; 235 neg = 2; 236 break; 237 case 's': 238 str = va_arg(args, char *); 239 break; 240 case 'c': 241 num[0] = va_arg(args, int); 242 num[1] = 0; 243 str = num; 244 break; 245 case 'm': 246 str = strerror(errno); 247 break; 248 case 'I': 249 ip = va_arg(args, u_int32_t); 250 ip = ntohl(ip); 251 slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff, 252 (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); 253 str = num; 254 break; 255 case 'E': 256 p = va_arg (args, unsigned char *); 257 for (n = ETH_ALEN; n > 0; --n) { 258 c = *p++; 259 OUTCHAR (hexchars[(c >> 4) & 0xf]); 260 OUTCHAR (hexchars[c & 0xf]); 261 if (n > 1) 262 OUTCHAR (':'); 263 } 264 continue; 265 case 'r': 266 f = va_arg(args, char *); 267#ifndef __powerpc__ 268 n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list)); 269#else 270 /* On the powerpc, a va_list is an array of 1 structure */ 271 n = vslprintf(buf, buflen + 1, f, va_arg(args, void *)); 272#endif 273 buf += n; 274 buflen -= n; 275 continue; 276 case 't': 277 time(&t); 278 str = ctime(&t); 279 str += 4; /* chop off the day name */ 280 str[15] = 0; /* chop off year and newline */ 281 break; 282 case 'v': /* "visible" string */ 283 case 'q': /* quoted string */ 284 quoted = c == 'q'; 285 p = va_arg(args, unsigned char *); 286 if (fillch == '0' && prec >= 0) { 287 n = prec; 288 } else { 289 n = strlen((char *)p); 290 if (prec >= 0 && n > prec) 291 n = prec; 292 } 293 while (n > 0 && buflen > 0) { 294 c = *p++; 295 --n; 296 if (!quoted && c >= 0x80) { 297 OUTCHAR('M'); 298 OUTCHAR('-'); 299 c -= 0x80; 300 } 301 if (quoted && (c == '"' || c == '\\')) 302 OUTCHAR('\\'); 303 if (c < 0x20 || (0x7f <= c && c < 0xa0)) { 304 if (quoted) { 305 OUTCHAR('\\'); 306 switch (c) { 307 case '\t': OUTCHAR('t'); break; 308 case '\n': OUTCHAR('n'); break; 309 case '\b': OUTCHAR('b'); break; 310 case '\f': OUTCHAR('f'); break; 311 default: 312 OUTCHAR('x'); 313 OUTCHAR(hexchars[c >> 4]); 314 OUTCHAR(hexchars[c & 0xf]); 315 } 316 } else { 317 if (c == '\t') 318 OUTCHAR(c); 319 else { 320 OUTCHAR('^'); 321 OUTCHAR(c ^ 0x40); 322 } 323 } 324 } else 325 OUTCHAR(c); 326 } 327 continue; 328 case 'P': /* print PPP packet */ 329 bufinfo.ptr = buf; 330 bufinfo.len = buflen + 1; 331 p = va_arg(args, unsigned char *); 332 n = va_arg(args, int); 333 format_packet(p, n, vslp_printer, &bufinfo); 334 buf = bufinfo.ptr; 335 buflen = bufinfo.len - 1; 336 continue; 337 case 'B': 338 p = va_arg(args, unsigned char *); 339 for (n = prec; n > 0; --n) { 340 c = *p++; 341 if (fillch == ' ') 342 OUTCHAR(' '); 343 OUTCHAR(hexchars[(c >> 4) & 0xf]); 344 OUTCHAR(hexchars[c & 0xf]); 345 } 346 continue; 347 default: 348 *buf++ = '%'; 349 if (c != '%') 350 --fmt; /* so %z outputs %z etc. */ 351 --buflen; 352 continue; 353 } 354 if (base != 0) { 355 str = num + sizeof(num); 356 *--str = 0; 357 while (str > num + neg) { 358 *--str = hexchars[val % base]; 359 val = val / base; 360 if (--prec <= 0 && val == 0) 361 break; 362 } 363 switch (neg) { 364 case 1: 365 *--str = '-'; 366 break; 367 case 2: 368 *--str = 'x'; 369 *--str = '0'; 370 break; 371 } 372 len = num + sizeof(num) - 1 - str; 373 } else { 374 len = strlen(str); 375 if (prec >= 0 && len > prec) 376 len = prec; 377 } 378 if (width > 0) { 379 if (width > buflen) 380 width = buflen; 381 if ((n = width - len) > 0) { 382 buflen -= n; 383 for (; n > 0; --n) 384 *buf++ = fillch; 385 } 386 } 387 if (len > buflen) 388 len = buflen; 389 memcpy(buf, str, len); 390 buf += len; 391 buflen -= len; 392 } 393 *buf = 0; 394 return buf - buf0; 395} 396 397/* 398 * vslp_printer - used in processing a %P format 399 */ 400static void 401vslp_printer __V((void *arg, char *fmt, ...)) 402{ 403 int n; 404 va_list pvar; 405 struct buffer_info *bi; 406 407#if defined(__STDC__) 408 va_start(pvar, fmt); 409#else 410 void *arg; 411 char *fmt; 412 va_start(pvar); 413 arg = va_arg(pvar, void *); 414 fmt = va_arg(pvar, char *); 415#endif 416 417 bi = (struct buffer_info *) arg; 418 n = vslprintf(bi->ptr, bi->len, fmt, pvar); 419 va_end(pvar); 420 421 bi->ptr += n; 422 bi->len -= n; 423} 424 425#ifdef unused 426/* 427 * log_packet - format a packet and log it. 428 */ 429 430void 431log_packet(p, len, prefix, level) 432 u_char *p; 433 int len; 434 char *prefix; 435 int level; 436{ 437 init_pr_log(prefix, level); 438 format_packet(p, len, pr_log, &level); 439 end_pr_log(); 440} 441#endif /* unused */ 442 443/* 444 * format_packet - make a readable representation of a packet, 445 * calling `printer(arg, format, ...)' to output it. 446 */ 447static void 448format_packet(p, len, printer, arg) 449 u_char *p; 450 int len; 451 void (*printer) __P((void *, char *, ...)); 452 void *arg; 453{ 454 int i, n; 455 u_short proto; 456 struct protent *protp; 457 458 if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) { 459 p += 2; 460 GETSHORT(proto, p); 461 len -= PPP_HDRLEN; 462 for (i = 0; (protp = protocols[i]) != NULL; ++i) 463 if (proto == protp->protocol) 464 break; 465 if (protp != NULL) { 466 printer(arg, "[%s", protp->name); 467 n = (*protp->printpkt)(p, len, printer, arg); 468 printer(arg, "]"); 469 p += n; 470 len -= n; 471 } else { 472 for (i = 0; (protp = protocols[i]) != NULL; ++i) 473 if (proto == (protp->protocol & ~0x8000)) 474 break; 475 if (protp != 0 && protp->data_name != 0) { 476 printer(arg, "[%s data]", protp->data_name); 477 if (len > 8) 478 printer(arg, "%.8B ...", p); 479 else 480 printer(arg, "%.*B", len, p); 481 len = 0; 482 } else 483 printer(arg, "[proto=0x%x]", proto); 484 } 485 } 486 487 if (len > 32) 488 printer(arg, "%.32B ...", p); 489 else 490 printer(arg, "%.*B", len, p); 491} 492 493#ifdef DEBUG 494 495/* 496 * init_pr_log, end_pr_log - initialize and finish use of pr_log. 497 */ 498 499static char line[256]; /* line to be logged accumulated here */ 500static char *linep; /* current pointer within line */ 501static int llevel; /* level for logging */ 502 503void 504init_pr_log(prefix, level) 505 char *prefix; 506 int level; 507{ 508 linep = line; 509 if (prefix != NULL) { 510 strlcpy(line, prefix, sizeof(line)); 511 linep = line + strlen(line); 512 } 513 llevel = level; 514} 515 516void 517end_pr_log() 518{ 519 if (linep != line) { 520 *linep = 0; 521 log_write(llevel, line); 522 } 523} 524 525/* 526 * pr_log - printer routine for outputting to syslog 527 */ 528void 529pr_log __V((void *arg, char *fmt, ...)) 530{ 531 int l, n; 532 va_list pvar; 533 char *p, *eol; 534 char buf[256]; 535 536#if defined(__STDC__) 537 va_start(pvar, fmt); 538#else 539 void *arg; 540 char *fmt; 541 va_start(pvar); 542 arg = va_arg(pvar, void *); 543 fmt = va_arg(pvar, char *); 544#endif 545 546 n = vslprintf(buf, sizeof(buf), fmt, pvar); 547 va_end(pvar); 548 549 p = buf; 550 eol = strchr(buf, '\n'); 551 if (linep != line) { 552 l = (eol == NULL)? n: eol - buf; 553 if (linep + l < line + sizeof(line)) { 554 if (l > 0) { 555 memcpy(linep, buf, l); 556 linep += l; 557 } 558 if (eol == NULL) 559 return; 560 p = eol + 1; 561 eol = strchr(p, '\n'); 562 } 563 *linep = 0; 564 log_write(llevel, line); 565 linep = line; 566 } 567 568 while (eol != NULL) { 569 *eol = 0; 570 log_write(llevel, p); 571 p = eol + 1; 572 eol = strchr(p, '\n'); 573 } 574 575 /* assumes sizeof(buf) <= sizeof(line) */ 576 l = buf + n - p; 577 if (l > 0) { 578 memcpy(line, p, n); 579 linep = line + l; 580 } 581} 582 583/* 584 * print_string - print a readable representation of a string using 585 * printer. 586 */ 587void 588print_string(p, len, printer, arg) 589 char *p; 590 int len; 591 void (*printer) __P((void *, char *, ...)); 592 void *arg; 593{ 594 int c; 595 596 printer(arg, "\""); 597 for (; len > 0; --len) { 598 c = *p++; 599 if (' ' <= c && c <= '~') { 600 if (c == '\\' || c == '"') 601 printer(arg, "\\"); 602 printer(arg, "%c", c); 603 } else { 604 switch (c) { 605 case '\n': 606 printer(arg, "\\n"); 607 break; 608 case '\r': 609 printer(arg, "\\r"); 610 break; 611 case '\t': 612 printer(arg, "\\t"); 613 break; 614 default: 615 printer(arg, "\\%.3o", c); 616 } 617 } 618 } 619 printer(arg, "\""); 620} 621 622/* 623 * logit - does the hard work for fatal et al. 624 */ 625static void 626logit(level, fmt, args) 627 int level; 628 char *fmt; 629 va_list args; 630{ 631 int n; 632 char buf[1024]; 633 634 n = vslprintf(buf, sizeof(buf), fmt, args); 635 log_write(level, buf); 636} 637 638static void 639log_write(level, buf) 640 int level; 641 char *buf; 642{ 643 syslog(level, "%s", buf); 644 if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) { 645 int n = strlen(buf); 646 647 if (n > 0 && buf[n-1] == '\n') 648 --n; 649 if (write(log_to_fd, buf, n) != n 650 || write(log_to_fd, "\n", 1) != 1) 651 log_to_fd = -1; 652 } 653} 654 655/* 656 * fatal - log an error message and die horribly. 657 */ 658void 659fatal __V((char *fmt, ...)) 660{ 661 va_list pvar; 662 663#if defined(__STDC__) 664 va_start(pvar, fmt); 665#else 666 char *fmt; 667 va_start(pvar); 668 fmt = va_arg(pvar, char *); 669#endif 670 671 logit(LOG_ERR, fmt, pvar); 672 va_end(pvar); 673 674 die(1); /* as promised */ 675} 676 677/* 678 * error - log an error message. 679 */ 680void 681error __V((char *fmt, ...)) 682{ 683 va_list pvar; 684 685#if defined(__STDC__) 686 va_start(pvar, fmt); 687#else 688 char *fmt; 689 va_start(pvar); 690 fmt = va_arg(pvar, char *); 691#endif 692 693 logit(LOG_ERR, fmt, pvar); 694 va_end(pvar); 695} 696 697/* 698 * warn - log a warning message. 699 */ 700void 701warn __V((char *fmt, ...)) 702{ 703 va_list pvar; 704 705#if defined(__STDC__) 706 va_start(pvar, fmt); 707#else 708 char *fmt; 709 va_start(pvar); 710 fmt = va_arg(pvar, char *); 711#endif 712 713 logit(LOG_WARNING, fmt, pvar); 714 va_end(pvar); 715} 716 717/* 718 * notice - log a notice-level message. 719 */ 720void 721notice __V((char *fmt, ...)) 722{ 723 va_list pvar; 724 725#if defined(__STDC__) 726 va_start(pvar, fmt); 727#else 728 char *fmt; 729 va_start(pvar); 730 fmt = va_arg(pvar, char *); 731#endif 732 733 logit(LOG_NOTICE, fmt, pvar); 734 va_end(pvar); 735} 736 737/* 738 * info - log an informational message. 739 */ 740void 741info __V((char *fmt, ...)) 742{ 743 va_list pvar; 744 745#if defined(__STDC__) 746 va_start(pvar, fmt); 747#else 748 char *fmt; 749 va_start(pvar); 750 fmt = va_arg(pvar, char *); 751#endif 752 753 logit(LOG_INFO, fmt, pvar); 754 va_end(pvar); 755} 756 757/* 758 * dbglog - log a debug message. 759 */ 760void 761dbglog __V((char *fmt, ...)) 762{ 763 va_list pvar; 764 765#if defined(__STDC__) 766 va_start(pvar, fmt); 767#else 768 char *fmt; 769 va_start(pvar); 770 fmt = va_arg(pvar, char *); 771#endif 772 773 logit(LOG_DEBUG, fmt, pvar); 774 va_end(pvar); 775} 776 777#endif /* DEBUG */ 778 779 780/* JYWeng 20031216: add to wanstatus.log */ 781 782void saveWANStatus(char *currentstatus, int statusindex) 783{ 784 FILE *STATUSFILE; 785#ifdef ONWL500G_SHELL 786 if ((STATUSFILE = fopen("/etc/linuxigd/wanstatus.log", "w"))!=NULL) 787 { 788 fprintf(STATUSFILE, "StatusCode=\"%d\"\n", statusindex); 789 fprintf(STATUSFILE, "StatusReason=\"%s\"\n", currentstatus); 790 fclose(STATUSFILE); 791 } 792#else 793 if ((STATUSFILE = fopen("/tmp/wanstatus.log", "w"))!=NULL) 794 { 795 fprintf(STATUSFILE, "%d,%s\n", statusindex, currentstatus); 796 fclose(STATUSFILE); 797 } 798#endif 799} 800