X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Ftty.c;h=7d65ba86435c4c5c4531c11d55997f300b225063;hp=b7e61650d48357f692d3353a77ea2db71ef7fcee;hb=a4c31ee8e5bdcc69db6205df512ee7edfc791f7a;hpb=f7ee87797ae1851c7bfb57752185b66f127326e8 diff --git a/pppd/tty.c b/pppd/tty.c index b7e6165..7d65ba8 100644 --- a/pppd/tty.c +++ b/pppd/tty.c @@ -1,26 +1,79 @@ /* * tty.c - code for handling serial ports in pppd. * - * Copyright (C) 2000 Paul Mackerras. - * All rights reserved. + * Copyright (C) 2000-2002 Paul Mackerras. All rights reserved. * - * Portions Copyright (c) 1989 Carnegie Mellon University. - * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by Carnegie Mellon University. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name(s) of the authors of this software must not be used to + * endorse or promote products derived from this software without + * prior written permission. + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Paul Mackerras + * ". + * + * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Portions derived from main.c, which is: + * + * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The name "Carnegie Mellon University" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For permission or any legal + * details, please contact + * Office of Technology Transfer + * Carnegie Mellon University + * 5000 Forbes Avenue + * Pittsburgh, PA 15213-3890 + * (412) 268-4387, fax: (412) 268-7395 + * tech-transfer@andrew.cmu.edu + * + * 4. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by Computing Services + * at Carnegie Mellon University (http://www.cmu.edu/computing/)." + * + * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE + * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#define RCSID "$Id: tty.c,v 1.4 2001/02/22 03:15:21 paulus Exp $" +#define RCSID "$Id: tty.c,v 1.17 2004/11/04 09:59:12 paulus Exp $" #include #include @@ -49,9 +102,19 @@ #include "fsm.h" #include "lcp.h" +void tty_process_extra_options __P((void)); +void tty_check_options __P((void)); +int connect_tty __P((void)); +void disconnect_tty __P((void)); +void tty_close_fds __P((void)); +void cleanup_tty __P((void)); +void tty_do_send_config __P((int, u_int32_t, int, int)); + static int setdevname __P((char *, char **, int)); static int setspeed __P((char *, char **, int)); static int setxonxoff __P((char **)); +static int setescape __P((char **)); +static void printescape __P((option_t *, void (*)(void *, char *,...),void *)); static void finish_tty __P((void)); static int start_charshunt __P((int, int)); static void stop_charshunt __P((void *, int)); @@ -66,6 +129,7 @@ static int pty_master; /* fd for master side of pty */ static int pty_slave; /* fd for slave side of pty */ static int real_ttyfd; /* fd for actual serial port (not pty) */ static int ttyfd; /* Serial port file descriptor */ +static char speed_str[16]; /* Serial port speed as string */ mode_t tty_mode = (mode_t)-1; /* Original access permissions to tty */ int baud_rate; /* Actual bits/second for serial device */ @@ -97,57 +161,103 @@ extern int kill_link; /* XXX */ extern int privopen; /* don't lock, open device as root */ +u_int32_t xmit_accm[8]; /* extended transmit ACCM */ + /* option descriptors */ option_t tty_options[] = { /* device name must be first, or change connect_tty() below! */ { "device name", o_wild, (void *) &setdevname, - "Serial port device name", OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG }, + "Serial port device name", + OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC, + devnam}, + { "tty speed", o_wild, (void *) &setspeed, - "Baud rate for serial port", OPT_NOARG }, + "Baud rate for serial port", + OPT_PRIO | OPT_NOARG | OPT_A2STRVAL | OPT_STATIC, speed_str }, + { "lock", o_bool, &lockflag, - "Lock serial device with UUCP-style lock file", 1 }, + "Lock serial device with UUCP-style lock file", OPT_PRIO | 1 }, { "nolock", o_bool, &lockflag, - "Don't lock serial device", OPT_PRIV }, + "Don't lock serial device", OPT_PRIOSUB | OPT_PRIV }, + { "init", o_string, &initializer, - "A program to initialize the device", OPT_PRIVFIX }, + "A program to initialize the device", OPT_PRIO | OPT_PRIVFIX }, + { "connect", o_string, &connect_script, - "A program to set up a connection", OPT_PRIVFIX }, + "A program to set up a connection", OPT_PRIO | OPT_PRIVFIX }, + { "disconnect", o_string, &disconnect_script, - "Program to disconnect serial device", OPT_PRIVFIX }, + "Program to disconnect serial device", OPT_PRIO | OPT_PRIVFIX }, + { "welcome", o_string, &welcomer, - "Script to welcome client", OPT_PRIVFIX }, + "Script to welcome client", OPT_PRIO | OPT_PRIVFIX }, + { "pty", o_string, &ptycommand, - "Script to run on pseudo-tty master side", OPT_PRIVFIX | OPT_DEVNAM }, + "Script to run on pseudo-tty master side", + OPT_PRIO | OPT_PRIVFIX | OPT_DEVNAM }, + { "notty", o_bool, ¬ty, "Input/output is not a tty", OPT_DEVNAM | 1 }, + { "socket", o_string, &pty_socket, - "Send and receive over socket, arg is host:port", OPT_DEVNAM }, + "Send and receive over socket, arg is host:port", + OPT_PRIO | OPT_DEVNAM }, + { "record", o_string, &record_file, - "Record characters sent/received to file" }, + "Record characters sent/received to file", OPT_PRIO }, + { "crtscts", o_int, &crtscts, - "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1) }, + "Set hardware (RTS/CTS) flow control", + OPT_PRIO | OPT_NOARG | OPT_VAL(1) }, + { "cdtrcts", o_int, &crtscts, + "Set alternate hardware (DTR/CTS) flow control", + OPT_PRIOSUB | OPT_NOARG | OPT_VAL(2) }, { "nocrtscts", o_int, &crtscts, - "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) }, + "Disable hardware flow control", + OPT_PRIOSUB | OPT_NOARG | OPT_VAL(-1) }, { "-crtscts", o_int, &crtscts, - "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) }, - { "cdtrcts", o_int, &crtscts, - "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2) }, + "Disable hardware flow control", + OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) }, { "nocdtrcts", o_int, &crtscts, - "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1) }, + "Disable hardware flow control", + OPT_PRIOSUB | OPT_ALIAS | OPT_NOARG | OPT_VAL(-1) }, { "xonxoff", o_special_noarg, (void *)setxonxoff, - "Set software (XON/XOFF) flow control" }, + "Set software (XON/XOFF) flow control", OPT_PRIOSUB }, + { "modem", o_bool, &modem, - "Use modem control lines", 1 }, + "Use modem control lines", OPT_PRIO | 1 }, { "local", o_bool, &modem, - "Don't use modem control lines" }, + "Don't use modem control lines", OPT_PRIOSUB | 0 }, + { "sync", o_bool, &sync_serial, "Use synchronous HDLC serial encoding", 1 }, + { "datarate", o_int, &max_data_rate, - "Maximum data rate in bytes/sec (with pty, notty or record option)" }, + "Maximum data rate in bytes/sec (with pty, notty or record option)", + OPT_PRIO }, + + { "escape", o_special, (void *)setescape, + "List of character codes to escape on transmission", + OPT_A2PRINTER, (void *)printescape }, + { NULL } }; +struct channel tty_channel = { + tty_options, + &tty_process_extra_options, + &tty_check_options, + &connect_tty, + &disconnect_tty, + &tty_establish_ppp, + &tty_disestablish_ppp, + &tty_do_send_config, + &tty_recv_config, + &cleanup_tty, + &tty_close_fds +}; + /* * setspeed - Set the serial port baud rate. * If doit is 0, the call is to check whether this option is @@ -165,8 +275,10 @@ setspeed(arg, argv, doit) spd = strtol(arg, &ptr, 0); if (ptr == arg || *ptr != 0 || spd == 0) return 0; - if (doit) + if (doit) { inspeed = spd; + slprintf(speed_str, sizeof(speed_str), "%d", spd); + } return 1; } @@ -188,7 +300,7 @@ setdevname(cp, argv, doit) if (*cp == 0) return 0; - if (strncmp("/dev/", cp, 5) != 0) { + if (*cp != '/') { strlcpy(dev, "/dev/", sizeof(dev)); strlcat(dev, cp, sizeof(dev)); cp = dev; @@ -229,20 +341,77 @@ setxonxoff(argv) return 1; } +/* + * setescape - add chars to the set we escape on transmission. + */ +static int +setescape(argv) + char **argv; +{ + int n, ret; + char *p, *endp; + + p = *argv; + ret = 1; + while (*p) { + n = strtol(p, &endp, 16); + if (p == endp) { + option_error("escape parameter contains invalid hex number '%s'", + p); + return 0; + } + p = endp; + if (n < 0 || n == 0x5E || n > 0xFF) { + option_error("can't escape character 0x%x", n); + ret = 0; + } else + xmit_accm[n >> 5] |= 1 << (n & 0x1F); + while (*p == ',' || *p == ' ') + ++p; + } + lcp_allowoptions[0].asyncmap = xmit_accm[0]; + return ret; +} + +static void +printescape(opt, printer, arg) + option_t *opt; + void (*printer) __P((void *, char *, ...)); + void *arg; +{ + int n; + int first = 1; + + for (n = 0; n < 256; ++n) { + if (n == 0x7d) + n += 2; /* skip 7d, 7e */ + if (xmit_accm[n >> 5] & (1 << (n & 0x1f))) { + if (!first) + printer(arg, ","); + else + first = 0; + printer(arg, "%x", n); + } + } + if (first) + printer(arg, "oops # nothing escaped"); +} + /* * tty_init - do various tty-related initializations. */ void tty_init() { add_notifier(&pidchange, maybe_relock, 0); - add_options(tty_options); + the_channel = &tty_channel; + xmit_accm[3] = 0x60000000; } /* - * tty_device_check - work out which tty device we are using + * tty_process_extra_options - work out which tty device we are using * and read its options file. */ -void tty_device_check() +void tty_process_extra_options() { using_pty = notty || ptycommand != NULL || pty_socket != NULL; if (using_pty) @@ -290,7 +459,7 @@ tty_check_options() if (using_pty) { if (!default_device) { option_error("%s option precludes specifying device name", - notty? "notty": "pty"); + pty_socket? "socket": notty? "notty": "pty"); exit(EXIT_OPTION_ERROR); } if (ptycommand != NULL && notty) { @@ -343,7 +512,9 @@ int connect_tty() { char *connector; int fdflags; +#ifndef __linux__ struct stat statbuf; +#endif char numbuf[16]; /* @@ -411,6 +582,11 @@ int connect_tty() || fcntl(ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) warn("Couldn't reset non-blocking mode on device: %m"); +#ifndef __linux__ + /* + * Linux 2.4 and above blocks normal writes to the tty + * when it is in PPP line discipline, so this isn't needed. + */ /* * Do the equivalent of `mesg n' to stop broadcast messages. */ @@ -419,6 +595,7 @@ int connect_tty() warn("Couldn't restrict write permissions to %s: %m", devnam); } else tty_mode = statbuf.st_mode; +#endif /* __linux__ */ /* * Set line speed, flow control, etc. @@ -445,6 +622,11 @@ int connect_tty() if (pipe(ipipe) < 0 || pipe(opipe) < 0) fatal("Couldn't create pipes for record option: %m"); + + /* don't leak these to the ptycommand */ + (void) fcntl(ipipe[0], F_SETFD, FD_CLOEXEC); + (void) fcntl(opipe[1], F_SETFD, FD_CLOEXEC); + ok = device_script(ptycommand, opipe[0], ipipe[1], 1) == 0 && start_charshunt(ipipe[0], opipe[1]); close(ipipe[0]); @@ -474,6 +656,9 @@ int connect_tty() return -1; } + if (using_pty || record_file != NULL) + ttyfd = pty_slave; + /* run connection script */ if ((connector && connector[0]) || initializer) { if (real_ttyfd != -1) { @@ -594,6 +779,20 @@ void cleanup_tty() } } +/* + * tty_do_send_config - set transmit-side PPP configuration. + * We set the extended transmit ACCM here as well. + */ +void +tty_do_send_config(mtu, accm, pcomp, accomp) + int mtu; + u_int32_t accm; + int pcomp, accomp; +{ + tty_set_xaccm(xmit_accm); + tty_send_config(mtu, accm, pcomp, accomp); +} + /* * finish_tty - restore the terminal device to its original settings */ @@ -612,12 +811,12 @@ finish_tty() restore_tty(real_ttyfd); +#ifndef __linux__ if (tty_mode != (mode_t) -1) { - if (fchmod(real_ttyfd, tty_mode) != 0) { - /* XXX if devnam is a symlink, this will change the link */ - chmod(devnam, tty_mode); - } + if (fchmod(real_ttyfd, tty_mode) != 0) + error("Couldn't restore tty permissions"); } +#endif /* __linux__ */ close(real_ttyfd); real_ttyfd = -1; @@ -699,7 +898,7 @@ start_charshunt(ifd, ofd) { int cpid; - cpid = fork(); + cpid = safe_fork(); if (cpid == -1) { error("Can't fork process for character shunt: %m"); return 0; @@ -720,7 +919,6 @@ start_charshunt(ifd, ofd) add_notifier(&sigreceived, stop_charshunt, 0); close(pty_master); pty_master = -1; - ttyfd = pty_slave; record_child(cpid, "pppd (charshunt)", charshunt_done, NULL); return 1; } @@ -808,6 +1006,13 @@ charshunt(ifd, ofd, record_file) signal(SIGXFSZ, SIG_DFL); #endif + /* + * Check that the fds won't overrun the fd_sets + */ + if (ifd >= FD_SETSIZE || ofd >= FD_SETSIZE || pty_master >= FD_SETSIZE) + fatal("internal error: file descriptor too large (%d, %d, %d)", + ifd, ofd, pty_master); + /* * Open the record file if required. */