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