X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fmain.c;h=3e7ea420cc606a6b9fbee1f0b7d2dc019c156dee;hb=bcffc4820fca2aba7b91657909bc0cb76f69227e;hp=2141879090fc378c770119c08e03c41700ef3b20;hpb=ef6f6d62459620b334457a58cb17e40f450814dc;p=ppp.git diff --git a/pppd/main.c b/pppd/main.c index 2141879..3e7ea42 100644 --- a/pppd/main.c +++ b/pppd/main.c @@ -18,7 +18,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: main.c,v 1.54 1999/03/02 05:36:42 paulus Exp $"; +static char rcsid[] = "$Id: main.c,v 1.60 1999/03/16 03:14:50 paulus Exp $"; #endif #include @@ -41,6 +41,7 @@ static char rcsid[] = "$Id: main.c,v 1.54 1999/03/02 05:36:42 paulus Exp $"; #include #include #include +#include #include "pppd.h" #include "magic.h" @@ -87,13 +88,17 @@ int hungup; /* terminal has been hung up */ int privileged; /* we're running as real uid root */ int need_holdoff; /* need holdoff period before restarting */ int detached; /* have detached from terminal */ +int log_to_stderr; /* send log messages to stderr too */ + +static int fd_ppp; /* fd for talking PPP */ +static int fd_loop; /* fd for getting demand-dial packets */ int phase; /* where the link is at */ int kill_link; int open_ccp_flag; static int waiting; -static jmp_buf sigjmp; +static sigjmp_buf sigjmp; char **script_env; /* Env. variable values for scripts */ int s_env_nalloc; /* # words avail at script_env */ @@ -107,6 +112,9 @@ static int locked; /* lock() has succeeded */ char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n"; +GIDSET_TYPE groups[NGROUPS_MAX];/* groups the user is in */ +int ngroups; /* How many groups valid in groups */ + /* Prototypes for procedures local to this file. */ static void create_pidfile __P((void)); @@ -126,6 +134,8 @@ static void holdoff_end __P((void *)); static int device_script __P((char *, int, int)); static void reap_kids __P((void)); static void pr_log __P((void *, char *, ...)); +static void logit __P((int, char *, va_list)); +static void vslp_printer __P((void *, char *, ...)); extern char *ttyname __P((int)); extern char *getlogin __P((void)); @@ -181,8 +191,8 @@ main(argc, argv) phase = PHASE_INITIALIZE; p = ttyname(0); if (p) - strcpy(devnam, p); - strcpy(default_devnam, devnam); + strlcpy(devnam, sizeof(devnam), p); + strlcpy(default_devnam, sizeof(default_devnam), devnam); script_env = NULL; @@ -202,9 +212,11 @@ main(argc, argv) uid = getuid(); privileged = uid == 0; - sprintf(numbuf, "%d", uid); + slprintf(numbuf, sizeof(numbuf), "%d", uid); script_setenv("ORIG_UID", numbuf); + ngroups = getgroups(NGROUPS_MAX, groups); + /* * Initialize to the standard option set, then parse, in order, * the system options file, the user's options file, @@ -252,7 +264,7 @@ main(argc, argv) } script_setenv("DEVICE", devnam); - sprintf(numbuf, "%d", baud_rate); + slprintf(numbuf, sizeof(numbuf), "%d", baud_rate); script_setenv("SPEED", numbuf); /* @@ -263,6 +275,7 @@ main(argc, argv) default_device = 1; if (default_device) nodetach = 1; + log_to_stderr = !default_device; /* * Initialize system-dependent stuff and magic number package. @@ -302,13 +315,11 @@ main(argc, argv) sigaddset(&mask, SIGCHLD); sigaddset(&mask, SIGUSR2); -#define SIGNAL(s, handler) { \ +#define SIGNAL(s, handler) do { \ sa.sa_handler = handler; \ - if (sigaction(s, &sa, NULL) < 0) { \ - syslog(LOG_ERR, "Couldn't establish signal handler (%d): %m", s); \ - exit(1); \ - } \ - } + if (sigaction(s, &sa, NULL) < 0) \ + fatal("Couldn't establish signal handler (%d): %m", s); \ + } while (0) sa.sa_mask = mask; sa.sa_flags = 0; @@ -367,7 +378,6 @@ main(argc, argv) signal(SIGPIPE, SIG_IGN); waiting = 0; - sigprocmask(SIG_BLOCK, &mask, NULL); /* * If we're doing dial-on-demand, set up the interface now. @@ -376,10 +386,10 @@ main(argc, argv) /* * Open the loopback channel and set it up to be the ppp interface. */ - open_ppp_loopback(); + fd_loop = open_ppp_loopback(); syslog(LOG_INFO, "Using interface ppp%d", ifunit); - (void) sprintf(ifname, "ppp%d", ifunit); + slprintf(ifname, sizeof(ifname), "ppp%d", ifunit); script_setenv("IFNAME", ifname); create_pidfile(); /* write pid to file */ @@ -398,16 +408,21 @@ main(argc, argv) /* * Don't do anything until we see some activity. */ - phase = PHASE_DORMANT; kill_link = 0; + phase = PHASE_DORMANT; demand_unblock(); + add_fd(fd_loop); for (;;) { - if (setjmp(sigjmp) == 0) { - waiting = 1; - sigprocmask(SIG_UNBLOCK, &mask, NULL); - wait_loop_output(timeleft(&timo)); + if (sigsetjmp(sigjmp, 1) == 0) { + sigprocmask(SIG_BLOCK, &mask, NULL); + if (kill_link) { + sigprocmask(SIG_UNBLOCK, &mask, NULL); + } else { + waiting = 1; + sigprocmask(SIG_UNBLOCK, &mask, NULL); + wait_input(timeleft(&timo)); + } } - sigprocmask(SIG_BLOCK, &mask, NULL); waiting = 0; calltimeout(); if (kill_link) { @@ -419,14 +434,15 @@ main(argc, argv) break; reap_kids(); } - if (kill_link) + remove_fd(fd_loop); + if (kill_link && !persist) break; /* * Now we want to bring up the link. */ demand_block(); - syslog(LOG_INFO, "Starting link"); + info("Starting link"); } /* @@ -447,32 +463,37 @@ main(argc, argv) */ hungup = 0; kill_link = 0; - sigprocmask(SIG_UNBLOCK, &mask, NULL); - while ((ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0)) < 0) { + for (;;) { + /* If the user specified the device name, become the + user before opening it. */ + if (!devnam_info.priv) + seteuid(uid); + ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0); + if (!devnam_info.priv) + seteuid(0); + if (ttyfd >= 0) + break; if (errno != EINTR) - syslog(LOG_ERR, "Failed to open %s: %m", devnam); + error("Failed to open %s: %m", devnam); if (!persist || errno != EINTR) goto fail; } - sigprocmask(SIG_BLOCK, &mask, NULL); if ((fdflags = fcntl(ttyfd, F_GETFL)) == -1 || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) - syslog(LOG_WARNING, - "Couldn't reset non-blocking mode on device: %m"); + warn("Couldn't reset non-blocking mode on device: %m"); /* * Do the equivalent of `mesg n' to stop broadcast messages. */ if (fstat(ttyfd, &statbuf) < 0 || fchmod(ttyfd, statbuf.st_mode & ~(S_IWGRP | S_IWOTH)) < 0) { - syslog(LOG_WARNING, - "Couldn't restrict write permissions to %s: %m", devnam); + warn("Couldn't restrict write permissions to %s: %m", devnam); } else tty_mode = statbuf.st_mode; /* run connection script */ if (connector && connector[0]) { - MAINDEBUG((LOG_INFO, "Connecting with <%s>", connector)); + MAINDEBUG(("Connecting with <%s>", connector)); if (!default_device && modem) { hangup_modem(ttyfd); /* in case modem is off hook */ @@ -491,11 +512,11 @@ main(argc, argv) set_up_tty(ttyfd, 1); if (device_script(connector, ttyfd, ttyfd) < 0) { - syslog(LOG_ERR, "Connect script failed"); + error("Connect script failed"); goto fail; } - syslog(LOG_INFO, "Serial connection established."); + info("Serial connection established."); sleep(1); /* give it time to set up its terminal */ } @@ -504,9 +525,11 @@ main(argc, argv) /* reopen tty if necessary to wait for carrier */ if (connector == NULL && modem) { - while ((i = open(devnam, O_RDWR)) < 0) { + for (;;) { + if ((i = open(devnam, O_RDWR)) >= 0) + break; if (errno != EINTR) - syslog(LOG_ERR, "Failed to reopen %s: %m", devnam); + error("Failed to reopen %s: %m", devnam); if (!persist || errno != EINTR || hungup || kill_link) goto fail; } @@ -516,16 +539,16 @@ main(argc, argv) /* run welcome script, if any */ if (welcomer && welcomer[0]) { if (device_script(welcomer, ttyfd, ttyfd) < 0) - syslog(LOG_WARNING, "Welcome script failed"); + warn("Welcome script failed"); } /* set up the serial device as a ppp interface */ - establish_ppp(ttyfd); + fd_ppp = establish_ppp(ttyfd); if (!demand) { - syslog(LOG_INFO, "Using interface ppp%d", ifunit); - (void) sprintf(ifname, "ppp%d", ifunit); + info("Using interface ppp%d", ifunit); + slprintf(ifname, sizeof(ifname), "ppp%d", ifunit); script_setenv("IFNAME", ifname); create_pidfile(); /* write pid to file */ @@ -535,17 +558,22 @@ main(argc, argv) * Start opening the connection and wait for * incoming events (reply, timeout, etc.). */ - syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam); + notice("Connect: %s <--> %s", ifname, devnam); lcp_lowerup(0); lcp_open(0); /* Start protocol */ open_ccp_flag = 0; + add_fd(fd_ppp); for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; ) { - if (setjmp(sigjmp) == 0) { - waiting = 1; - sigprocmask(SIG_UNBLOCK, &mask, NULL); - wait_input(timeleft(&timo)); + if (sigsetjmp(sigjmp, 1) == 0) { + sigprocmask(SIG_BLOCK, &mask, NULL); + if (kill_link || open_ccp_flag) { + sigprocmask(SIG_UNBLOCK, &mask, NULL); + } else { + waiting = 1; + sigprocmask(SIG_UNBLOCK, &mask, NULL); + wait_input(timeleft(&timo)); + } } - sigprocmask(SIG_BLOCK, &mask, NULL); waiting = 0; calltimeout(); if (kill_link) { @@ -568,6 +596,7 @@ main(argc, argv) * the ppp unit back to the loopback. Set the * real serial device back to its normal mode of operation. */ + remove_fd(fd_ppp); clean_check(); if (demand) restore_loop(); @@ -580,9 +609,9 @@ main(argc, argv) if (disconnector && !hungup) { set_up_tty(ttyfd, 1); if (device_script(disconnector, ttyfd, ttyfd) < 0) { - syslog(LOG_WARNING, "disconnect script failed"); + warn("disconnect script failed"); } else { - syslog(LOG_INFO, "Serial link disconnected."); + info("Serial link disconnected."); } } @@ -597,25 +626,30 @@ main(argc, argv) if (!demand) { if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT) - syslog(LOG_WARNING, "unable to delete pid file: %m"); + warn("unable to delete pid file: %m"); pidfilename[0] = 0; } if (!persist) break; + kill_link = 0; if (demand) demand_discard(); if (holdoff > 0 && need_holdoff) { phase = PHASE_HOLDOFF; TIMEOUT(holdoff_end, NULL, holdoff); do { - if (setjmp(sigjmp) == 0) { - waiting = 1; - sigprocmask(SIG_UNBLOCK, &mask, NULL); - wait_time(timeleft(&timo)); + if (sigsetjmp(sigjmp, 1) == 0) { + sigprocmask(SIG_BLOCK, &mask, NULL); + if (kill_link) { + sigprocmask(SIG_UNBLOCK, &mask, NULL); + } else { + waiting = 1; + sigprocmask(SIG_UNBLOCK, &mask, NULL); + wait_input(timeleft(&timo)); + } } - sigprocmask(SIG_BLOCK, &mask, NULL); waiting = 0; calltimeout(); if (kill_link) { @@ -650,6 +684,7 @@ detach() die(1); } detached = 1; + log_to_stderr = 0; pid = getpid(); /* update pid file if it has been written already */ if (pidfilename[0]) @@ -665,15 +700,16 @@ create_pidfile() FILE *pidfile; char numbuf[16]; - (void) sprintf(pidfilename, "%s%s.pid", _PATH_VARRUN, ifname); + slprintf(pidfilename, sizeof(pidfilename), "%s%s.pid", + _PATH_VARRUN, ifname); if ((pidfile = fopen(pidfilename, "w")) != NULL) { fprintf(pidfile, "%d\n", pid); (void) fclose(pidfile); } else { - syslog(LOG_ERR, "Failed to create pid file %s: %m", pidfilename); + error("Failed to create pid file %s: %m", pidfilename); pidfilename[0] = 0; } - sprintf(numbuf, "%d", pid); + slprintf(numbuf, sizeof(numbuf), "%d", pid); script_setenv("PPPD_PID", numbuf); } @@ -705,7 +741,7 @@ get_input() return; if (len == 0) { - syslog(LOG_NOTICE, "Modem hangup"); + notice("Modem hangup"); hungup = 1; lcp_lowerdown(0); /* serial link is no longer available */ link_terminated(0); @@ -713,10 +749,10 @@ get_input() } if (debug /*&& (debugflags & DBG_INPACKET)*/) - log_packet(p, len, "rcvd ", LOG_DEBUG); + dbglog("rcvd %P", p, len); if (len < PPP_HDRLEN) { - MAINDEBUG((LOG_INFO, "io(): Received short packet.")); + MAINDEBUG(("io(): Received short packet.")); return; } @@ -728,8 +764,7 @@ get_input() * Toss all non-LCP packets unless LCP is OPEN. */ if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) { - MAINDEBUG((LOG_INFO, - "get_input: Received non-LCP packet when LCP not open.")); + MAINDEBUG(("get_input: Received non-LCP packet when LCP not open.")); return; } @@ -740,7 +775,7 @@ get_input() if (phase <= PHASE_AUTHENTICATE && !(protocol == PPP_LCP || protocol == PPP_LQR || protocol == PPP_PAP || protocol == PPP_CHAP)) { - MAINDEBUG((LOG_INFO, "get_input: discarding proto 0x%x in phase %d", + MAINDEBUG(("get_input: discarding proto 0x%x in phase %d", protocol, phase)); return; } @@ -761,7 +796,7 @@ get_input() } if (debug) - syslog(LOG_WARNING, "Unsupported protocol (0x%x) received", protocol); + warn("Unsupported protocol (0x%x) received", protocol); lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN); } @@ -800,7 +835,7 @@ cleanup() close_tty(); if (pidfilename[0] != 0 && unlink(pidfilename) < 0 && errno != ENOENT) - syslog(LOG_WARNING, "unable to delete pid file: %m"); + warn("unable to delete pid file: %m"); pidfilename[0] = 0; if (locked) @@ -838,6 +873,15 @@ close_tty() ttyfd = -1; } +/* + * hangup_modem - hang up the modem by clearing DTR. + */ +void hangup_modem(ttyfd) + int ttyfd; +{ + setdtr(ttyfd, 0); +} + struct callout { struct timeval c_time; /* time at which to call routine */ @@ -863,16 +907,13 @@ timeout(func, arg, time) { struct callout *newp, *p, **pp; - MAINDEBUG((LOG_DEBUG, "Timeout %lx:%lx in %d seconds.", - (long) func, (long) arg, time)); + MAINDEBUG(("Timeout %p:%p in %d seconds.", func, arg, time)); /* * Allocate timeout. */ - if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) { - syslog(LOG_ERR, "Out of memory in timeout()!"); - die(1); - } + if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) + fatal("Out of memory in timeout()!"); newp->c_arg = arg; newp->c_func = func; gettimeofday(&timenow, NULL); @@ -902,7 +943,7 @@ untimeout(func, arg) { struct callout **copp, *freep; - MAINDEBUG((LOG_DEBUG, "Untimeout %lx:%lx.", (long) func, (long) arg)); + MAINDEBUG(("Untimeout %p:%p.", func, arg)); /* * Find first matching timeout and remove it from the list. @@ -927,10 +968,8 @@ calltimeout() while (callout != NULL) { p = callout; - if (gettimeofday(&timenow, NULL) < 0) { - syslog(LOG_ERR, "Failed to get time of day: %m"); - die(1); - } + if (gettimeofday(&timenow, NULL) < 0) + fatal("Failed to get time of day: %m"); if (!(p->c_time.tv_sec < timenow.tv_sec || (p->c_time.tv_sec == timenow.tv_sec && p->c_time.tv_usec <= timenow.tv_usec))) @@ -996,13 +1035,13 @@ static void hup(sig) int sig; { - syslog(LOG_INFO, "Hangup (SIGHUP)"); + info("Hangup (SIGHUP)"); kill_link = 1; if (conn_running) /* Send the signal to the [dis]connector process(es) also */ kill_my_pg(sig); if (waiting) - longjmp(sigjmp, 1); + siglongjmp(sigjmp, 1); } @@ -1016,14 +1055,14 @@ static void term(sig) int sig; { - syslog(LOG_INFO, "Terminating on signal %d.", sig); + info("Terminating on signal %d.", sig); persist = 0; /* don't try to restart */ kill_link = 1; if (conn_running) /* Send the signal to the [dis]connector process(es) also */ kill_my_pg(sig); if (waiting) - longjmp(sigjmp, 1); + siglongjmp(sigjmp, 1); } @@ -1036,7 +1075,7 @@ chld(sig) int sig; { if (waiting) - longjmp(sigjmp, 1); + siglongjmp(sigjmp, 1); } @@ -1071,7 +1110,7 @@ open_ccp(sig) { open_ccp_flag = 1; if (waiting) - longjmp(sigjmp, 1); + siglongjmp(sigjmp, 1); } @@ -1087,7 +1126,7 @@ bad_signal(sig) if (crashed) _exit(127); crashed = 1; - syslog(LOG_ERR, "Fatal signal %d", sig); + error("Fatal signal %d", sig); if (conn_running) kill_my_pg(SIGTERM); die(1); @@ -1112,8 +1151,7 @@ device_script(program, in, out) if (pid < 0) { conn_running = 0; - syslog(LOG_ERR, "Failed to create child process: %m"); - die(1); + fatal("Failed to create child process: %m"); } if (pid == 0) { @@ -1145,19 +1183,22 @@ device_script(program, in, out) close(errfd); } } - setuid(getuid()); + setuid(uid); + if (getuid() != uid) { + error("setuid failed"); + exit(1); + } setgid(getgid()); execl("/bin/sh", "sh", "-c", program, (char *)0); - syslog(LOG_ERR, "could not exec /bin/sh: %m"); - _exit(99); + error("could not exec /bin/sh: %m"); + exit(99); /* NOTREACHED */ } while (waitpid(pid, &status, 0) < 0) { if (errno == EINTR) continue; - syslog(LOG_ERR, "error waiting for (dis)connection process: %m"); - die(1); + fatal("error waiting for (dis)connection process: %m"); } conn_running = 0; @@ -1211,23 +1252,21 @@ run_program(prog, args, must_exist, done, arg) if (stat(prog, &sbuf) < 0 || !S_ISREG(sbuf.st_mode) || (sbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) == 0) { if (must_exist || errno != ENOENT) - syslog(LOG_WARNING, "Can't execute %s: %m", prog); + warn("Can't execute %s: %m", prog); return 0; } pid = fork(); - if (pid == -1) { - syslog(LOG_ERR, "Failed to create child process for %s: %m", prog); - die(1); - } + if (pid == -1) + fatal("Failed to create child process for %s: %m", prog); if (pid == 0) { int new_fd; /* Leave the current location */ - (void) setsid(); /* No controlling tty. */ + (void) setsid(); /* No controlling tty. */ (void) umask (S_IRWXG|S_IRWXO); - (void) chdir ("/"); /* no current directory. */ - setuid(geteuid()); + (void) chdir ("/"); /* no current directory. */ + setuid(0); /* set real UID = root */ setgid(getegid()); /* Ensure that nothing of our device environment is inherited. */ @@ -1252,31 +1291,25 @@ run_program(prog, args, must_exist, done, arg) #ifdef BSD /* Force the priority back to zero if pppd is running higher. */ if (setpriority (PRIO_PROCESS, 0, 0) < 0) - syslog (LOG_WARNING, "can't reset priority to 0: %m"); + warn("can't reset priority to 0: %m"); #endif /* SysV recommends a second fork at this point. */ /* run the program */ execve(prog, args, script_env); - if (must_exist || errno != ENOENT) { - int i; - syslog(LOG_WARNING, "Can't execute %s: %m", prog); - for (i = 0; args[i]; ++i) - syslog(LOG_DEBUG, "args[%d] = '%s'", i, args[i]); - for (i = 0; script_env[i]; ++i) - syslog(LOG_DEBUG, "env[%d] = '%s'", i, script_env[i]); - } + if (must_exist || errno != ENOENT) + warn("Can't execute %s: %m", prog); _exit(-1); } if (debug) - syslog(LOG_DEBUG, "Script %s started; pid = %d", prog, pid); + dbglog("Script %s started; pid = %d", prog, pid); ++n_children; chp = (struct subprocess *) malloc(sizeof(struct subprocess)); if (chp == NULL) { - syslog(LOG_WARNING, "losing track of %s process", prog); + warn("losing track of %s process", prog); } else { chp->pid = pid; chp->prog = prog; @@ -1308,18 +1341,17 @@ reap_kids() if (chp->pid == pid) break; if (debug) - syslog(LOG_DEBUG, "process %d (%s) finished, status = 0x%x", + dbglog("process %d (%s) finished, status = 0x%x", pid, (chp? chp->prog: "??"), status); if (WIFSIGNALED(status)) { - syslog(LOG_WARNING, - "Child process %s (pid %d) terminated with signal %d", - (chp? chp->prog: "??"), pid, WTERMSIG(status)); + warn("Child process %s (pid %d) terminated with signal %d", + (chp? chp->prog: "??"), pid, WTERMSIG(status)); } if (chp && chp->done) (*chp->done)(chp->arg); } if (pid == -1 && errno != ECHILD) - syslog(LOG_ERR, "Error waiting for child process: %m"); + error("Error waiting for child process: %m"); } @@ -1337,7 +1369,7 @@ log_packet(p, len, prefix, level) char *prefix; int level; { - strcpy(line, prefix); + strlcpy(line, sizeof(line), prefix); linep = line + strlen(line); format_packet(p, len, pr_log, NULL); if (linep != line) @@ -1403,17 +1435,50 @@ pr_log __V((void *arg, char *fmt, ...)) fmt = va_arg(pvar, char *); #endif - n = vfmtmsg(buf, sizeof(buf), fmt, pvar); + n = vslprintf(buf, sizeof(buf), fmt, pvar); va_end(pvar); if (linep + n + 1 > line + sizeof(line)) { syslog(LOG_DEBUG, "%s", line); linep = line; } - strcpy(linep, buf); + strlcpy(linep, line + sizeof(line) - linep, buf); linep += n; } +/* + * vslp_printer - used in processing a %P format + */ +struct buffer_info { + char *ptr; + int len; +}; + +static void +vslp_printer __V((void *arg, char *fmt, ...)) +{ + int n; + va_list pvar; + struct buffer_info *bi; + +#if __STDC__ + va_start(pvar, fmt); +#else + void *arg; + char *fmt; + va_start(pvar); + arg = va_arg(pvar, void *); + fmt = va_arg(pvar, char *); +#endif + + bi = (struct buffer_info *) arg; + n = vslprintf(bi->ptr, bi->len, fmt, pvar); + va_end(pvar); + + bi->ptr += n; + bi->len -= n; +} + /* * print_string - print a readable representation of a string using * printer. @@ -1460,19 +1525,19 @@ void novm(msg) char *msg; { - syslog(LOG_ERR, "Virtual memory exhausted allocating %s\n", msg); - die(1); + fatal("Virtual memory exhausted allocating %s\n", msg); } /* - * fmtmsg - format a message into a buffer. Like sprintf except we + * slprintf - format a message into a buffer. Like sprintf except we * also specify the length of the output buffer, and we handle - * %r (recursive format), %m (error message) and %I (IP address) formats. + * %r (recursive format), %m (error message), %v (visible string), + * %q (quoted string), %t (current time) and %I (IP address) formats. * Doesn't do floating-point formats. * Returns the number of chars put into buf. */ int -fmtmsg __V((char *buf, int buflen, char *fmt, ...)) +slprintf __V((char *buf, int buflen, char *fmt, ...)) { va_list args; int n; @@ -1488,18 +1553,18 @@ fmtmsg __V((char *buf, int buflen, char *fmt, ...)) buflen = va_arg(args, int); fmt = va_arg(args, char *); #endif - n = vfmtmsg(buf, buflen, fmt, args); + n = vslprintf(buf, buflen, fmt, args); va_end(args); return n; } /* - * vfmtmsg - like fmtmsg, takes a va_list instead of a list of args. + * vslprintf - like slprintf, takes a va_list instead of a list of args. */ #define OUTCHAR(c) (buflen > 0? (--buflen, *buf++ = (c)): 0) int -vfmtmsg(buf, buflen, fmt, args) +vslprintf(buf, buflen, fmt, args) char *buf; int buflen; char *fmt; @@ -1513,7 +1578,9 @@ vfmtmsg(buf, buflen, fmt, args) unsigned char *p; char num[32]; time_t t; + u_int32_t ip; static char hexchars[] = "0123456789abcdef"; + struct buffer_info bufinfo; buf0 = buf; --buflen; @@ -1578,6 +1645,7 @@ vfmtmsg(buf, buflen, fmt, args) base = 8; break; case 'x': + case 'X': val = va_arg(args, unsigned int); base = 16; break; @@ -1598,15 +1666,19 @@ vfmtmsg(buf, buflen, fmt, args) str = strerror(errno); break; case 'I': - str = ip_ntoa(va_arg(args, u_int32_t)); + ip = va_arg(args, u_int32_t); + ip = ntohl(ip); + slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff, + (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); + str = num; break; case 'r': f = va_arg(args, char *); #ifndef __powerpc__ - n = vfmtmsg(buf, buflen + 1, f, va_arg(args, va_list)); + n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list)); #else /* On the powerpc, a va_list is an array of 1 structure */ - n = vfmtmsg(buf, buflen + 1, f, va_arg(args, void *)); + n = vslprintf(buf, buflen + 1, f, va_arg(args, void *)); #endif buf += n; buflen -= n; @@ -1663,6 +1735,25 @@ vfmtmsg(buf, buflen, fmt, args) OUTCHAR(c); } continue; + case 'P': /* print PPP packet */ + bufinfo.ptr = buf; + bufinfo.len = buflen + 1; + p = va_arg(args, unsigned char *); + n = va_arg(args, int); + format_packet(p, n, vslp_printer, &bufinfo); + buf = bufinfo.ptr; + buflen = bufinfo.len - 1; + continue; + case 'B': + p = va_arg(args, unsigned char *); + for (n = prec; n > 0; --n) { + c = *p++; + if (fillch == ' ') + OUTCHAR(' '); + OUTCHAR(hexchars[(c >> 4) & 0xf]); + OUTCHAR(hexchars[c & 0xf]); + } + continue; default: *buf++ = '%'; if (c != '%') @@ -1721,16 +1812,14 @@ void script_setenv(var, value) char *var, *value; { - int vl = strlen(var); + size_t vl = strlen(var) + strlen(value) + 2; int i; char *p, *newstring; - newstring = (char *) malloc(vl + strlen(value) + 2); + newstring = (char *) malloc(vl); if (newstring == 0) return; - strcpy(newstring, var); - newstring[vl] = '='; - strcpy(newstring+vl+1, value); + slprintf(newstring, vl, "%s=%s", var, value); /* check if this variable is already set */ if (script_env != 0) { @@ -1787,3 +1876,180 @@ script_unsetenv(var) } } } + +/* + * strlcpy - like strcpy/strncpy, doesn't overflow destination buffer, + * always leaves destination null-terminated (for len > 0). + */ +void +strlcpy(char *dest, size_t len, const char *src) +{ + if (len == 0) + return; + if (strlen(src) < len) + strcpy(dest, src); + else { + strncpy(dest, src, len - 1); + dest[len-1] = 0; + } +} + +/* + * strlcat - like strcat/strncat, doesn't overflow destination buffer, + * always leaves destination null-terminated (for len > 0). + */ +void +strlcat(char *dest, size_t len, const char *src) +{ + size_t dlen; + + if (len == 0) + return; + dlen = strlen(dest); + if (dlen < len - 1) + strlcpy(dest + dlen, len - dlen, src); +} + +/* + * logit - does the hard work for fatal et al. + */ +static void +logit(level, fmt, args) + int level; + char *fmt; + va_list args; +{ + int n; + char buf[256]; + static char nl = '\n'; + + n = vslprintf(buf, sizeof(buf), fmt, args); + syslog(level, "%s", buf); + if (log_to_stderr && (level != LOG_DEBUG || debug)) { + if (write(2, buf, n) != n + || (buf[n-1] != '\n' && write(2, &nl, 1) != 1)) + log_to_stderr = 0; + } +} + +/* + * fatal - log an error message and die horribly. + */ +void +fatal __V((char *fmt, ...)) +{ + va_list pvar; + +#if __STDC__ + va_start(pvar, fmt); +#else + char *fmt; + va_start(pvar); + fmt = va_arg(pvar, char *); +#endif + + logit(LOG_ERR, fmt, pvar); + va_end(pvar); + + die(1); /* as promised */ +} + +/* + * error - log an error message. + */ +void +error __V((char *fmt, ...)) +{ + va_list pvar; + +#if __STDC__ + va_start(pvar, fmt); +#else + char *fmt; + va_start(pvar); + fmt = va_arg(pvar, char *); +#endif + + logit(LOG_ERR, fmt, pvar); + va_end(pvar); +} + +/* + * warn - log a warning message. + */ +void +warn __V((char *fmt, ...)) +{ + va_list pvar; + +#if __STDC__ + va_start(pvar, fmt); +#else + char *fmt; + va_start(pvar); + fmt = va_arg(pvar, char *); +#endif + + logit(LOG_WARNING, fmt, pvar); + va_end(pvar); +} + +/* + * notice - log a notice-level message. + */ +void +notice __V((char *fmt, ...)) +{ + va_list pvar; + +#if __STDC__ + va_start(pvar, fmt); +#else + char *fmt; + va_start(pvar); + fmt = va_arg(pvar, char *); +#endif + + logit(LOG_NOTICE, fmt, pvar); + va_end(pvar); +} + +/* + * info - log an informational message. + */ +void +info __V((char *fmt, ...)) +{ + va_list pvar; + +#if __STDC__ + va_start(pvar, fmt); +#else + char *fmt; + va_start(pvar); + fmt = va_arg(pvar, char *); +#endif + + logit(LOG_INFO, fmt, pvar); + va_end(pvar); +} + +/* + * dbglog - log a debug message. + */ +void +dbglog __V((char *fmt, ...)) +{ + va_list pvar; + +#if __STDC__ + va_start(pvar, fmt); +#else + char *fmt; + va_start(pvar); + fmt = va_arg(pvar, char *); +#endif + + logit(LOG_DEBUG, fmt, pvar); + va_end(pvar); +}