From 9b1aec4804d1147f476d0cb6136860fe5032c511 Mon Sep 17 00:00:00 2001 From: Lars Fredriksen Date: Nov 12 1994 05:25:32 +0000 Subject: chat for ppp, from ppp 2.1.2 --- diff --git a/usr.bin/chat/Example b/usr.bin/chat/Example new file mode 100644 index 0000000..e46fbd0 --- /dev/null +++ b/usr.bin/chat/Example @@ -0,0 +1,5 @@ +# + +../pppd/pppd -d connect 'chat "" ATDT5551212 CONNECT "" ogin: ppp' netmask 255.255.255.0 /dev/com1 38400 + +../pppd/pppd connect 'chat "" AATDT5551212 CONNECT "" ogin: ppp' netmask 255.255.255.0 /dev/com1 38400 diff --git a/usr.bin/chat/Makefile b/usr.bin/chat/Makefile new file mode 100644 index 0000000..be27271 --- /dev/null +++ b/usr.bin/chat/Makefile @@ -0,0 +1,8 @@ +# $Id: Makefile.bsd,v 1.2 1994/05/26 06:45:03 paulus Exp $ + +PROG= chat +SRCS= chat.c +MAN8= chat.8 +BINDIR= /usr/bin + +.include diff --git a/usr.bin/chat/README b/usr.bin/chat/README new file mode 100644 index 0000000..73d28af --- /dev/null +++ b/usr.bin/chat/README @@ -0,0 +1,169 @@ +I run PPP between crappie.morningstar.com (137.175.6.3, my home +machine) and remora.morningstar.com (137.175.2.7, my workstation at +the office). This document describes how I use it. The installation +of PPP itself is covered in the PPP distribution. + +I put a line like this in remora's /etc/passwd: + + Pkarl:2y4613BDaQD3x:51:10:Karl's PPP login:/tmp:/usr/local/etc/pppstart + +I created a login shell script on remora called +/usr/local/etc/pppstart: + + #!/bin/sh + /usr/bin/mesg n + stty -tostop + exec /usr/local/etc/ppp 137.175.2.7: + +I use the ppp-on command to bring up a connection, and ppp-off to shut +it down. These shell scripts, plus the unlock and fix-cua scripts and +the source to the chat program are included. You will need to heavily +modify these to suit your own situation, including Internet addresses, +machine names, telephone numbers, modem dialing commands, baud rates, +login names and passwords. Make the "ppp..." command in the ppp-on +script look something like this: + + ppp 137.175.6.3: /dev/cua & + +The "137.175.6.3:" is of the format "local-addr:remote-addr" with the +remote address null (it will be negotiated by PPP). Look at the login +shell script above; it can be common to all dial-in PPP users on your +machine because it only specifies the address of the remora +(receiving) end of the link. + +If you use the enclosed chat and unlock programs, be sure they are +suid uucp, and fix-cua should be suid root. The ppp-on script should +be chmod 700, owner yourself, to keep the password (semi-) secure. + +I use the following eeprom settings and /dev and /etc/ttytab entries +in order to support dial-in and dial-out on a single phone line: + + crappie 12% eeprom | grep ttya + ttya-mode=19200,8,1,n,h + ttya-rts-dtr-off=false + ttya-ignore-cd=false + crappie 13% ls -lg /dev/cua /dev/ttya + crw-rw-rw- 1 root staff 12, 128 Nov 20 09:14 /dev/cua + crw--w--w- 1 root wheel 12, 0 Nov 20 08:25 /dev/ttya + crappie 14% grep ttya /etc/ttytab + ttya "/usr/etc/getty std.19200" unknown on + crappie 15% + +On SunOS 4.1 and later, make sure that the /etc/ttytab line for ttya +doesn't say "local": + + ttya "/usr/etc/getty std.38400" unknown on + +Make sure your modem passes data transparently; watch out especially +for ^S, ^Q, ^P (UUCP spoofing) and parity problems. I have a Telebit +Trailblazer+ attached to /dev/ttya with the following register +settings: + + aaatz + OK + aat&n + E1 F1 M1 Q6 P V1 X0 Version BA4.00 + S00=001 S01=000 S02=043 S03=013 S04=010 S05=008 S06=002 S07=060 S08=002 S09=006 + S10=007 S11=070 S12=050 + S45=000 S47=004 S48=000 S49=000 + S50=000 S51=005 S52=002 S53=003 S54=001 S55=000 S56=017 S57=019 S58=002 S59=000 + S60=000 S61=000 S62=003 S63=001 S64=000 S65=000 S66=001 S67=000 S68=255 + S90=000 S91=000 S92=001 S95=000 + S100=000 S101=000 S102=000 S104=000 + S110=001 S111=030 S112=001 + S121=000 + N0: + N1: + N2: + N3: + N4: + N5: + N6: + N7: + N8: + N9: + OK + +And, the following entry is in /etc/gettytab: + + # + # 19200/2400 dialin for Telebit Trailblazer+ modem + # + T|T19200:dial-19200:\ + :nx=T2400:sp#19200: + T2400|dial-2400:\ + :nx=T19200:sp#2400: + +My chat script dialing command looks like "ATs50=255s111=0DT4515678" +instead of just "ATDT4515678" in order to force a PEP mode connection +and to disable the UUCP spoofing (otherwise, the modem swallows or +delays ^P characters). + +I run /usr/etc/in.routed on crappie (the calling end) and have this in +my /etc/gateways file: + + net 0.0.0.0 gateway remora metric 1 passive + host crappie gateway crappie metric 0 passive + +Routed is started in /etc/rc.local. This way, I don't have to +manually add or delete routes when links come up. I ifconfig the ppp0 +interface on crappie at boot time like this (in /etc/rc.local with the +other ifconfig's): + + ifconfig ppp0 crappie remora netmask 0xffffff00 down + +I put "init ppp_attach" in my /sys/sun4c/conf/CRAPPIE file so that the +above ifconfig down will work: + + pseudo-device ppp1 init ppp_attach # Point-to-Point Protocol, 1 line + +Routed now keeps my routes sane at the crappie.MorningStar.Com end. + +My ethernet (le0) and PPP (ppp0) interfaces are configured with the +same address and netmask. IP is smart enough to figure out (via the +routes in /etc/gateways) that everything useful needs to go out ppp0. +Also, the remora end of my PPP link is configured the same way -- the +ppp0 interface there is configured with the same address and netmask +as remora's le0 ethernet. This means that separate interface names +like "remora-ppp" are not needed; point-to-point links (whether PPP, +Xerox Synchronous Point-to-Point Protocol, SLIP, IGP or whatever) have +(apparently) been used this (seemingly bizarre) way for some time. +This works because when IP looks at a POINTOPOINT link it ignores the +local address (unlike an ethernet interface) and only looks at the +remote address. + +Here's what netstat shows for me: + + crappie 109% netstat -r + Routing tables + Destination Gateway Flags Refcnt Use Interface + localhost localhost UH 0 0 lo0 + crappie crappie UH 1 11339 le0 + default remora UG 0 1266 ppp0 + mstar-net-ppp-remora crappie U 0 0 le0 + crappie 110% netstat -rn + Routing tables + Destination Gateway Flags Refcnt Use Interface + 127.0.0.1 127.0.0.1 UH 0 0 lo0 + 137.175.6.3 137.175.6.3 UH 1 11339 le0 + default 137.175.2.7 UG 0 1266 ppp0 + 137.175.6.0 137.175.6.3 U 0 0 le0 + crappie 111% + +The default route to remora is a result of the first line in the +/etc/gateways file ("default" can't be used there; you have to say +"0.0.0.0"). + +On the network at work, I add a static route in our gateway machine's +/etc/rc.local file: + + /usr/etc/route add net 137.175.6 remora 1 + +All the other machines in the office have default routes pointing at +the gateway machine, and all PPP-connected external machines are on the +137.175.6 subnet. + +Send me mail or post to the newsgroup comp.protocols.ppp if you have +any questions. + +Karl Fox diff --git a/usr.bin/chat/chat.8 b/usr.bin/chat/chat.8 new file mode 100644 index 0000000..3d2eee0 --- /dev/null +++ b/usr.bin/chat/chat.8 @@ -0,0 +1,251 @@ +.\" -*- nroff -*- +.\" manual page [] for chat 1.8 +.\" $Id: chat.8,v 1.7 1994/03/04 20:19:30 callahan Exp $ +.\" SH section heading +.\" SS subsection heading +.\" LP paragraph +.\" IP indented paragraph +.\" TP hanging label +.TH CHAT 8 "17 April 1994" "Chat Version 1.8" +.SH NAME +chat \- Automated conversational script with a modem +.SH SYNOPSIS +.B chat +[ +.I options +] +.I script +.SH DESCRIPTION +.LP +The \fIchat\fR program defines a conversational exchange between the +computer and the modem. Its primary purpose is to establish the +connection between the Point-to-Point Protocol Daemon (\fIpppd\fR) and +the remote's \fIpppd\fR process. +.SH OPTIONS +.TP +.B -f \fI +Read the chat script from the chat \fIfile\fR. The use of this option +is mutually exclusive with the chat script parameters. The user must +have read access to the file. Multiple lines are permitted in the +file. Space or horizontal tab characters should be used to separate +the strings. +.TP +.B -l \fI +Perform the UUCP style locking using the indicated lock file. +.IP +If the file could not be created then the \fIchat\fR program will +fail. The lock file will be deleted only if the \fIchat\fR program +fails to perform the script for any reason. If the script is +successful the lock file will be left on the disk. It is expected that +the lock file will be deleted when the \fIpppd\fR process no longer +wishes to use the serial device. +.IP +The use of a lock file with +.I chat +and +\fIpppd\fR\'s +.I lock +option should not be used at the same time. They are mutually +exclusive options and will cause one or the other program to fail to +achieve the required lock if you use both. +.TP +.B -t \fI +Set the timeout for the expected string to be received. If the string +is not received within the time limit then the reply string is not +sent. An alternate reply may be sent or the script will fail if there +is no alternate reply string. A failed script will cause the +\fIchat\fR program to terminate with a non-zero error code. +.TP +.B -v +Request that the \fIchat\fR script be executed in a verbose mode. The +\fIchat\fR program will then log all text received from the modem and +the output strings which it sends to the SYSLOG. +.TP +.B script +If the script is not specified in a file with the \fI-f\fR option then +the script is included as parameters to the \fIchat\fR program. +.SH CHAT SCRIPT +.LP +The \fIchat\fR script defines the communications. +.LP +A script consists of one or more "expect-send" pairs of strings, +separated by spaces, with an optional "subexpect-subsend" string pair, +separated by a dash as in the following example: +.IP +ogin:-BREAK-ogin: ppp ssword: hello2u2 +.LP +This line indicates that the \fIchat\fR program should expect the string +"ogin:". If it fails to receive a login prompt within the time interval +allotted, it is to send a break sequence to the remote and then expect the +string "ogin:". If the first "ogin:" is received then the break sequence is +not generated. +.LP +Once it received the login prompt the \fIchat\fR program will send the string ppp +and then expect the prompt "ssword:". When it receives the prompt for the +password, it will send the password hello2u2. +.LP +A carriage return is normally sent following the reply string. It is not +expected in the "expect" string unless it is specifically requested by using +the \\r character sequence. +.LP +The expect sequence should contain only what is needed to identify the +string. Since it is normally stored on a disk file, it should not contain +variable information. It is generally not acceptable to look for time +strings, network identification strings, or other variable pieces of data as +an expect string. +.LP +To help correct for characters which may be corrupted during the initial +sequence, look for the string "ogin:" rather than "login:". It is possible +that the leading "l" character may be received in error and you may never +find the string even though it was sent by the system. For this reason, +scripts look for "ogin:" rather than "login:" and "ssword:" rather than +"password:". +.LP +A very simple script might look like this: +.IP +ogin: ppp ssword: hello2u2 +.LP +In other words, expect ....ogin:, send ppp, expect ...ssword:, send hello2u2. +.LP +In actual practice, simple scripts are rare. At the vary least, you +should include sub-expect sequences should the original string not be +received. For example, consider the following script: +.IP +ogin:--ogin: ppp ssowrd: hello2u2 +.LP +This would be a better script than the simple one used earlier. This would look +for the same login: prompt, however, if one was not received, a single +return sequence is sent and then it will look for login: again. Should line +noise obscure the first login prompt then sending the empty line will +usually generate a login prompt again. +.SH ABORT STRINGS +Many modems will report the status of the call as a string. These +strings may be \fBCONNECTED\fR or \fBNO CARRIER\fR or \fBBUSY\fR. It +is often desirable to terminate the script should the modem fail to +connect to the remote. The difficulty is that a script would not know +exactly which modem string it may receive. On one attempt, it may +receive \fBBUSY\fR while the next time it may receive \fBNO CARRIER\fR. +.LP +These "abort" strings may be specified in the script using the \fIABORT\fR +sequence. It is written in the script as in the following example: +.IP +ABORT BUSY ABORT 'NO CARRIER' '' ATZ OK ATDT5551212 CONNECT +.LP +This sequence will expect nothing; and then send the string ATZ. The +expected response to this is the string \fIOK\fR. When it receives \fIOK\fR, +the string ATDT5551212 to dial the telephone. The expected string is +\fICONNECT\fR. If the string \fICONNECT\fR is received the remainder of the +script is executed. However, should the modem find a busy telephone, it will +send the string \fIBUSY\fR. This will cause the string to match the abort +character sequence. The script will then fail because it found a match to +the abort string. If it received the string \fINO CARRIER\fR, it will abort +for the same reason. Either string may be received. Either string will +terminate the \fIchat\fR script. +.SH TIMEOUT +The initial timeout value is 45 seconds. This may be changed using the \fB-t\fR +parameter. +.LP +To change the timeout value for the next expect string, the following +example may be used: +.IP +ATZ OK ATDT5551212 CONNECT TIMEOUT 10 ogin:--ogin: TIMEOUT 5 assowrd: hello2u2 +.LP +This will change the timeout to 10 seconds when it expects the login: +prompt. The timeout is then changed to 5 seconds when it looks for the +password prompt. +.LP +The timeout, once changed, remains in effect until it is changed again. +.SH SENDING EOT +The special reply string of \fIEOT\fR indicates that the chat program +should send an EOT character to the remote. This is normally the +End-of-file character sequence. A return character is not sent +following the EOT. +.PR +The EOT sequence may be embedded into the send string using the +sequence \fI^D\fR. +.SH GENERATING BREAK +The special reply string of \fIBREAK\fR will cause a break condition +to be sent. The break is a special signal on the transmitter. The +normal processing on the receiver is to change the transmission rate. +It may be used to cycle through the available transmission rates on +the remote until you are able to receive a valid login prompt. +.PR +The break sequence may be embedded into the send string using the +\fI\\K\fR sequence. +.SH ESCAPE SEQUENCES +The expect and reply strings may contain escape sequences. All of the +sequences are legal in the reply string. Many are legal in the expect. +Those which are not valid in the expect sequence are so indicated. +.TP +.B '' +Expects or sends a null string. If you send a null string then it will still +send the return character. This sequence may either be a pair of apostrophe +or quote characters. +.TP +.B \\\\b +represents a backspace character. +.TP +.B \\\\c +Suppresses the newline at the end of the reply string. This is the only +method to send a string without a trailing return character. It must +be at the end of the send string. For example, +the sequence hello\\c will simply send the characters h, e, l, l, o. +.I (not valid in expect.) +.TP +.B \\\\d +Delay for one second. The program uses sleep(1) which will delay to a +maximum of one second. +.I (not valid in expect.) +.TP +.B \\\\K +Insert a BREAK +.I (not valid in expect.) +.TP +.B \\\\n +Send a newline or linefeed character. +.TP +.B \\\\N +Send a null character. The same sequence may be represented by \\0. +.I (not valid in expect.) +.TP +.B \\\\p +Pause for a fraction of a second. The delay is 1/10th of a second. +.I (not valid in expect.) +.TP +.B \\\\q +Suppress writing the string to the SYSLOG file. The string ?????? is +written to the log in its place. +.I (not valid in expect.) +.TP +.B \\\\r +Send or expect a carriage return. +.TP +.B \\\\s +Represents a space character in the string. This may be used when it +is not desirable to quote the strings which contains spaces. The +sequence 'HI TIM' and HI\\sTIM are the same. +.TP +.B \\\\t +Send or expect a tab character. +.TP +.B \\\\\\\\ +Send or expect a backslash character. +.TP +.B \\\\ddd +Collapse the octal digits (ddd) into a single ASCII character and send that +character. +.I (some characters are not valid in expect.) +.TP +.B \^^C +Substitute the sequence with the control character represented by C. +For example, the character DC1 (17) is shown as \^^Q. +.I (some characters are not valid in expect.) +.SH SEE ALSO +Additional information about \fIchat\fR scripts may be found with UUCP +documentation. The \fIchat\fR script was taken from the ideas proposed by the +scripts used by the \fIuucico\fR program. +.LP +uucico(1), uucp(1) +.SH COPYRIGHT +The \fIchat\fR program is in public domain. This is not the GNU public +license. If it breaks then you get to keep both pieces. diff --git a/usr.bin/chat/chat.c b/usr.bin/chat/chat.c new file mode 100644 index 0000000..6c614d4 --- /dev/null +++ b/usr.bin/chat/chat.c @@ -0,0 +1,1166 @@ +/* + * Chat -- a program for automatic session establishment (i.e. dial + * the phone and log in). + * + * This software is in the public domain. + * + * Please send all bug reports, requests for information, etc. to: + * + * Al Longyear (longyear@netcom.com) + * (I was the last person to change this code.) + * + * The original author is: + * + * Karl Fox + * Morning Star Technologies, Inc. + * 1760 Zollinger Road + * Columbus, OH 43221 + * (614)451-1883 + */ + +static char rcsid[] = "$Id: chat.c,v 1.4 1994/05/30 00:30:37 paulus Exp $"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef TERMIO +#undef TERMIOS +#define TERMIOS +#endif + +#ifdef sun +# if defined(SUNOS) && SUNOS >= 41 +# ifndef HDB +# define HDB +# endif +# endif +#endif + +#ifdef TERMIO +#include +#endif +#ifdef TERMIOS +#include +#endif + +#define STR_LEN 1024 + +#ifndef SIGTYPE +#define SIGTYPE void +#endif + +#ifdef __STDC__ +#undef __P +#define __P(x) x +#else +#define __P(x) () +#define const +#endif + +/*************** Micro getopt() *********************************************/ +#define OPTION(c,v) (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \ + (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\ + &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0)) +#define OPTARG(c,v) (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \ + (_O=4,(char*)0):(char*)0) +#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0) +#define ARG(c,v) (c?(--c,*v++):(char*)0) + +static int _O = 0; /* Internal state */ +/*************** Micro getopt() *********************************************/ + +char *program_name; + +#ifndef LOCK_DIR +# ifdef __NetBSD__ +# define PIDSTRING +# define LOCK_DIR "/var/spool/lock" +# else +# ifdef HDB +# define PIDSTRING +# define LOCK_DIR "/usr/spool/locks" +# else /* HDB */ +# define LOCK_DIR "/usr/spool/uucp" +# endif /* HDB */ +# endif +#endif /* LOCK_DIR */ + +#define MAX_ABORTS 50 +#define DEFAULT_CHAT_TIMEOUT 45 + +int verbose = 0; +int quiet = 0; +char *lock_file = (char *)0; +char *chat_file = (char *)0; +int timeout = DEFAULT_CHAT_TIMEOUT; + +int have_tty_parameters = 0; +#ifdef TERMIO +struct termio saved_tty_parameters; +#endif +#ifdef TERMIOS +struct termios saved_tty_parameters; +#endif + +char *abort_string[MAX_ABORTS], *fail_reason = (char *)0, + fail_buffer[50]; +int n_aborts = 0, abort_next = 0, timeout_next = 0; + +void *dup_mem __P((void *b, size_t c)); +void *copy_of __P((char *s)); +void usage __P((void)); +void logf __P((const char *str)); +void logflush __P((void)); +void fatal __P((const char *msg)); +void sysfatal __P((const char *msg)); +SIGTYPE sigalrm __P((int signo)); +SIGTYPE sigint __P((int signo)); +SIGTYPE sigterm __P((int signo)); +SIGTYPE sighup __P((int signo)); +void unalarm __P((void)); +void init __P((void)); +void set_tty_parameters __P((void)); +void break_sequence __P((void)); +void terminate __P((int status)); +void do_file __P((char *chat_file)); +void lock __P((void)); +void delay __P((void)); +int get_string __P((register char *string)); +int put_string __P((register char *s)); +int write_char __P((int c)); +int put_char __P((char c)); +int get_char __P((void)); +void chat_send __P((register char *s)); +char *character __P((char c)); +void chat_expect __P((register char *s)); +char *clean __P((register char *s, int sending)); +void unlock __P((void)); +void lock __P((void)); +void break_sequence __P((void)); +void terminate __P((int status)); +void die __P((void)); + +void *dup_mem(b, c) +void *b; +size_t c; + { + void *ans = malloc (c); + if (!ans) + fatal ("memory error!\n"); + memcpy (ans, b, c); + return ans; + } + +void *copy_of (s) +char *s; + { + return dup_mem (s, strlen (s) + 1); + } + +/* + * chat [ -v ] [ -t timeout ] [ -l lock-file ] [ -f chat-file ] \ + * [...[[expect[-say[-expect...]] say expect[-say[-expect]] ...]]] + * + * Perform a UUCP-dialer-like chat script on stdin and stdout. + */ +int +main(argc, argv) +int argc; +char **argv; + { + int option; + char *arg; + + program_name = *argv; + + while (option = OPTION(argc, argv)) + switch (option) + { + case 'v': + ++verbose; + break; + + case 'f': + if (arg = OPTARG(argc, argv)) + chat_file = copy_of(arg); + else + usage(); + + break; + + case 'l': + if (arg = OPTARG(argc, argv)) + lock_file = copy_of(arg); + else + usage(); + + break; + + case 't': + if (arg = OPTARG(argc, argv)) + timeout = atoi(arg); + else + usage(); + + break; + + default: + usage(); + } + +#ifdef ultrix + openlog("chat", LOG_PID); +#else + openlog("chat", LOG_PID | LOG_NDELAY, LOG_LOCAL2); + + if (verbose) { + setlogmask(LOG_UPTO(LOG_INFO)); + } else { + setlogmask(LOG_UPTO(LOG_WARNING)); + } +#endif + + init(); + + if (chat_file != NULL) + { + arg = ARG(argc, argv); + if (arg != NULL) + usage(); + else + do_file (chat_file); + } + else + { + while (arg = ARG(argc, argv)) + { + chat_expect(arg); + + if (arg = ARG(argc, argv)) + chat_send(arg); + } + } + + terminate(0); + } + +/* + * Process a chat script when read from a file. + */ + +void do_file (chat_file) +char *chat_file; + { + int linect, len, sendflg; + char *sp, *arg, quote; + char buf [STR_LEN]; + FILE *cfp; + + if ((cfp = fopen (chat_file, "r")) == NULL) + { + syslog (LOG_ERR, "%s -- open failed: %m", chat_file); + terminate (1); + } + + linect = 0; + sendflg = 0; + + while (fgets(buf, STR_LEN, cfp) != NULL) + { + sp = strchr (buf, '\n'); + if (sp) + *sp = '\0'; + + linect++; + sp = buf; + while (*sp != '\0') + { + if (*sp == ' ' || *sp == '\t') + { + ++sp; + continue; + } + + if (*sp == '"' || *sp == '\'') + { + quote = *sp++; + arg = sp; + while (*sp != quote) + { + if (*sp == '\0') + { + syslog (LOG_ERR, "unterminated quote (line %d)", + linect); + terminate (1); + } + + if (*sp++ == '\\') + if (*sp != '\0') + ++sp; + } + } + else + { + arg = sp; + while (*sp != '\0' && *sp != ' ' && *sp != '\t') + ++sp; + } + + if (*sp != '\0') + *sp++ = '\0'; + + if (sendflg) + { + chat_send (arg); + } + else + { + chat_expect (arg); + } + sendflg = !sendflg; + } + } + fclose (cfp); + } + +/* + * We got an error parsing the command line. + */ +void usage() + { + fprintf(stderr, "\ +Usage: %s [-v] [-l lock-file] [-t timeout] {-f chat-file || chat-script}\n", + program_name); + exit(1); + } + +char line[256]; +char *p; + +void logf (str) +const char *str; + { + p = line + strlen(line); + strcat (p, str); + + if (str[strlen(str)-1] == '\n') + { + syslog (LOG_INFO, "%s", line); + line[0] = 0; + } + } + +void logflush() + { + if (line[0] != 0) + { + syslog(LOG_INFO, "%s", line); + line[0] = 0; + } + } + +/* + * Unlock and terminate with an error. + */ +void die() + { + unlock(); + terminate(1); + } + +/* + * Print an error message and terminate. + */ + +void fatal (msg) +const char *msg; + { + syslog(LOG_ERR, "%s", msg); + unlock(); + terminate(1); + } + +/* + * Print an error message along with the system error message and + * terminate. + */ + +void sysfatal (msg) +const char *msg; + { + syslog(LOG_ERR, "%s: %m", msg); + unlock(); + terminate(1); + } + +int alarmed = 0; + +SIGTYPE sigalrm(signo) +int signo; + { + int flags; + + alarm(1); + alarmed = 1; /* Reset alarm to avoid race window */ + signal(SIGALRM, sigalrm); /* that can cause hanging in read() */ + + logflush(); + if ((flags = fcntl(0, F_GETFL, 0)) == -1) + sysfatal("Can't get file mode flags on stdin"); + else + if (fcntl(0, F_SETFL, flags | FNDELAY) == -1) + sysfatal("Can't set file mode flags on stdin"); + + if (verbose) + { + syslog(LOG_INFO, "alarm"); + } + } + +void unalarm() + { + int flags; + + if ((flags = fcntl(0, F_GETFL, 0)) == -1) + sysfatal("Can't get file mode flags on stdin"); + else + if (fcntl(0, F_SETFL, flags & ~FNDELAY) == -1) + sysfatal("Can't set file mode flags on stdin"); + } + +SIGTYPE sigint(signo) +int signo; + { + fatal("SIGINT"); + } + +SIGTYPE sigterm(signo) +int signo; + { + fatal("SIGTERM"); + } + +SIGTYPE sighup(signo) +int signo; + { + fatal("SIGHUP"); + } + +void init() + { + signal(SIGINT, sigint); + signal(SIGTERM, sigterm); + signal(SIGHUP, sighup); + + if (lock_file) + lock(); + + set_tty_parameters(); + signal(SIGALRM, sigalrm); + alarm(0); + alarmed = 0; + } + +void set_tty_parameters() + { +#ifdef TERMIO + struct termio t; + + if (ioctl(0, TCGETA, &t) < 0) + sysfatal("Can't get terminal parameters"); +#endif +#ifdef TERMIOS + struct termios t; + + if (tcgetattr(0, &t) < 0) + sysfatal("Can't get terminal parameters"); +#endif + + saved_tty_parameters = t; + have_tty_parameters = 1; + + t.c_iflag |= IGNBRK | ISTRIP | IGNPAR; + t.c_oflag = 0; + t.c_lflag = 0; + t.c_cc[VERASE] = t.c_cc[VKILL] = 0; + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + +#ifdef TERMIO + if (ioctl(0, TCSETA, &t) < 0) + sysfatal("Can't set terminal parameters"); +#endif +#ifdef TERMIOS + if (tcsetattr(0, TCSANOW, &t) < 0) + sysfatal("Can't set terminal parameters"); +#endif + } + +void break_sequence() + { +#ifdef TERMIOS + tcsendbreak (0, 0); +#endif + } + +void terminate(status) +int status; + { + if (have_tty_parameters && +#ifdef TERMIO + ioctl(0, TCSETA, &saved_tty_parameters) < 0 +#endif +#ifdef TERMIOS + tcsetattr(0, TCSANOW, &saved_tty_parameters) < 0 +#endif + ) { + syslog(LOG_ERR, "Can't restore terminal parameters: %m"); + unlock(); + exit(1); + } + exit(status); + } + +/* + * Create a lock file for the named lock device + */ +void lock() + { + int fd, pid; +# ifdef PIDSTRING + char hdb_lock_buffer[12]; +# endif + + lock_file = strcat(strcat(strcpy(malloc(strlen(LOCK_DIR) + + 1 + strlen(lock_file) + 1), + LOCK_DIR), "/"), lock_file); + + if ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) + { + char *s = lock_file; + lock_file = (char *)0; /* Don't remove someone else's lock file! */ + syslog(LOG_ERR, "Can't get lock file '%s': %m", s); + die(); + } + +# ifdef PIDSTRING + sprintf(hdb_lock_buffer, "%10d\n", getpid()); + write(fd, hdb_lock_buffer, 11); +# else + pid = getpid(); + write(fd, &pid, sizeof pid); +# endif + + close(fd); + } + +/* + * Remove our lockfile + */ +void unlock() + { + if (lock_file) + { + unlink(lock_file); + lock_file = (char *)0; + } + } + +/* + * 'Clean up' this string. + */ +char *clean(s, sending) +register char *s; +int sending; + { + char temp[STR_LEN], cur_chr; + register char *s1; + int add_return = sending; +#define isoctal(chr) (((chr) >= '0') && ((chr) <= '7')) + + s1 = temp; + while (*s) + { + cur_chr = *s++; + if (cur_chr == '^') + { + cur_chr = *s++; + if (cur_chr == '\0') + { + *s1++ = '^'; + break; + } + cur_chr &= 0x1F; + if (cur_chr != 0) + *s1++ = cur_chr; + continue; + } + + if (cur_chr != '\\') + { + *s1++ = cur_chr; + continue; + } + + cur_chr = *s++; + if (cur_chr == '\0') + { + if (sending) + { + *s1++ = '\\'; + *s1++ = '\\'; + } + break; + } + + switch (cur_chr) + { + case 'b': + *s1++ = '\b'; + break; + + case 'c': + if (sending && *s == '\0') + add_return = 0; + else + *s1++ = cur_chr; + break; + + case '\\': + case 'K': + case 'p': + case 'd': + if (sending) + *s1++ = '\\'; + + *s1++ = cur_chr; + break; + + case 'q': + quiet = ! quiet; + break; + + case 'r': + *s1++ = '\r'; + break; + + case 'n': + *s1++ = '\n'; + break; + + case 's': + *s1++ = ' '; + break; + + case 't': + *s1++ = '\t'; + break; + + case 'N': + if (sending) + { + *s1++ = '\\'; + *s1++ = '\0'; + } + else + *s1++ = 'N'; + break; + + default: + if (isoctal (cur_chr)) + { + cur_chr &= 0x07; + if (isoctal (*s)) + { + cur_chr <<= 3; + cur_chr |= *s++ - '0'; + if (isoctal (*s)) + { + cur_chr <<= 3; + cur_chr |= *s++ - '0'; + } + } + + if (cur_chr != 0 || sending) + { + if (sending && (cur_chr == '\\' || cur_chr == 0)) + *s1++ = '\\'; + *s1++ = cur_chr; + } + break; + } + + if (sending) + *s1++ = '\\'; + *s1++ = cur_chr; + break; + } + } + + if (add_return) + *s1++ = '\r'; + + *s1++ = '\0'; /* guarantee closure */ + *s1++ = '\0'; /* terminate the string */ + return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */ + } + +/* + * Process the expect string + */ +void chat_expect(s) +register char *s; + { + if (strcmp(s, "ABORT") == 0) + { + ++abort_next; + return; + } + + if (strcmp(s, "TIMEOUT") == 0) + { + ++timeout_next; + return; + } + + while (*s) + { + register char *hyphen; + + for (hyphen = s; *hyphen; ++hyphen) + if (*hyphen == '-') + if (hyphen == s || hyphen[-1] != '\\') + break; + + if (*hyphen == '-') + { + *hyphen = '\0'; + + if (get_string(s)) + return; + else + { + s = hyphen + 1; + + for (hyphen = s; *hyphen; ++hyphen) + if (*hyphen == '-') + if (hyphen == s || hyphen[-1] != '\\') + break; + + if (*hyphen == '-') + { + *hyphen = '\0'; + + chat_send(s); + s = hyphen + 1; + } + else + { + chat_send(s); + return; + } + } + } + else + if (get_string(s)) + return; + else + { + if (fail_reason) + syslog(LOG_INFO, "Failed (%s)", fail_reason); + else + syslog(LOG_INFO, "Failed"); + + unlock(); + terminate(1); + } + } + } + +char *character(c) +char c; + { + static char string[10]; + char *meta; + + meta = (c & 0x80) ? "M-" : ""; + c &= 0x7F; + + if (c < 32) + sprintf(string, "%s^%c", meta, (int)c + '@'); + else + if (c == 127) + sprintf(string, "%s^?", meta); + else + sprintf(string, "%s%c", meta, c); + + return (string); + } + +/* + * process the reply string + */ +void chat_send (s) +register char *s; + { + if (abort_next) + { + char *s1; + + abort_next = 0; + + if (n_aborts >= MAX_ABORTS) + fatal("Too many ABORT strings"); + + s1 = clean(s, 0); + + if (strlen(s1) > strlen(s) || strlen(s1) > sizeof fail_buffer - 1) + { + syslog(LOG_WARNING, "Illegal or too-long ABORT string ('%s')", s); + die(); + } + + abort_string[n_aborts++] = s1; + + if (verbose) + { + logf("abort on ("); + + for (s1 = s; *s1; ++s1) + logf(character(*s1)); + + logf(")\n"); + } + } + else + if (timeout_next) + { + timeout_next = 0; + timeout = atoi(s); + + if (timeout <= 0) + timeout = DEFAULT_CHAT_TIMEOUT; + + if (verbose) + { + syslog(LOG_INFO, "timeout set to %d seconds", timeout); + } + } + else + { + if (strcmp(s, "EOT") == 0) + s = "^D\\c"; + else + if (strcmp(s, "BREAK") == 0) + s = "\\K\\c"; + if ( ! put_string(s)) + { + syslog(LOG_INFO, "Failed"); + unlock(); + terminate(1); + } + } + } + +int get_char() + { + int status; + char c; + + status = read(0, &c, 1); + + switch (status) + { + case 1: + return ((int)c & 0x7F); + + default: + syslog(LOG_WARNING, "warning: read() on stdin returned %d", + status); + + case -1: + if ((status = fcntl(0, F_GETFL, 0)) == -1) + sysfatal("Can't get file mode flags on stdin"); + else + if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1) + sysfatal("Can't set file mode flags on stdin"); + + return (-1); + } + } + +int put_char(c) +char c; + { + int status; + + delay(); + + status = write(1, &c, 1); + + switch (status) + { + case 1: + return (0); + + default: + syslog(LOG_WARNING, "warning: write() on stdout returned %d", + status); + + case -1: + if ((status = fcntl(0, F_GETFL, 0)) == -1) + sysfatal("Can't get file mode flags on stdin"); + else + if (fcntl(0, F_SETFL, status & ~FNDELAY) == -1) + sysfatal("Can't set file mode flags on stdin"); + + return (-1); + } + } + +int write_char (c) +int c; + { + if (alarmed || put_char(c) < 0) + { + extern int errno; + + alarm(0); alarmed = 0; + + if (verbose) + { + if (errno == EINTR || errno == EWOULDBLOCK) + syslog(LOG_INFO, " -- write timed out"); + else + syslog(LOG_INFO, " -- write failed: %m"); + } + return (0); + } + return (1); + } + +int put_string (s) +register char *s; + { + s = clean(s, 1); + + if (verbose) + { + logf("send ("); + + if (quiet) + logf("??????"); + else + { + register char *s1 = s; + + for (s1 = s; *s1; ++s1) + logf(character(*s1)); + } + + logf(")\n"); + } + + alarm(timeout); alarmed = 0; + + while (*s) + { + register char c = *s++; + + if (c != '\\') + { + if (!write_char (c)) + return 0; + continue; + } + + c = *s++; + switch (c) + { + case 'd': + sleep(1); + break; + + case 'K': + break_sequence(); + break; + + case 'p': + usleep(10000); /* 1/100th of a second. */ + break; + + default: + if (!write_char (c)) + return 0; + break; + } + } + + alarm(0); + alarmed = 0; + return (1); + } + +/* + * 'Wait for' this string to appear on this file descriptor. + */ +int get_string(string) +register char *string; + { + char temp[STR_LEN]; + int c, printed = 0, len, minlen; + register char *s = temp, *end = s + STR_LEN; + + fail_reason = (char *)0; + string = clean(string, 0); + len = strlen(string); + minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1; + + if (verbose) + { + register char *s1; + + logf("expect ("); + + for (s1 = string; *s1; ++s1) + logf(character(*s1)); + + logf(")\n"); + } + + if (len > STR_LEN) + { + syslog(LOG_INFO, "expect string is too long"); + return 0; + } + + if (len == 0) + { + if (verbose) + { + syslog(LOG_INFO, "got it"); + } + + return (1); + } + + alarm(timeout); alarmed = 0; + + while ( ! alarmed && (c = get_char()) >= 0) + { + int n, abort_len; + + if (verbose) + { + if (c == '\n') + logf("\n"); + else + logf(character(c)); + } + + *s++ = c; + + if (s - temp >= len && + c == string[len - 1] && + strncmp(s - len, string, len) == 0) + { + if (verbose) + { + logf(" -- got it\n"); + } + + alarm(0); alarmed = 0; + return (1); + } + + for (n = 0; n < n_aborts; ++n) + if (s - temp >= (abort_len = strlen(abort_string[n])) && + strncmp(s - abort_len, abort_string[n], abort_len) == 0) + { + if (verbose) + { + logf(" -- failed\n"); + } + + alarm(0); alarmed = 0; + strcpy(fail_reason = fail_buffer, abort_string[n]); + return (0); + } + + if (s >= end) + { + strncpy(temp, s - minlen, minlen); + s = temp + minlen; + } + + if (alarmed && verbose) + syslog(LOG_WARNING, "warning: alarm synchronization problem"); + } + + alarm(0); + + if (verbose && printed) + { + if (alarmed) + logf(" -- read timed out\n"); + else + { + logflush(); + syslog(LOG_INFO, " -- read failed: %m"); + } + } + + alarmed = 0; + return (0); + } + +#ifdef ultrix +#undef NO_USLEEP +#include +#include + +/* + usleep -- support routine for 4.2BSD system call emulations + last edit: 29-Oct-1984 D A Gwyn + */ + +extern int select(); + +int +usleep( usec ) /* returns 0 if ok, else -1 */ + long usec; /* delay in microseconds */ +{ + static struct /* `timeval' */ + { + long tv_sec; /* seconds */ + long tv_usec; /* microsecs */ + } delay; /* _select() timeout */ + + delay.tv_sec = usec / 1000000L; + delay.tv_usec = usec % 1000000L; + + return select( 0, (long *)0, (long *)0, (long *)0, &delay ); +} +#endif + +/* + * Delay an amount appropriate for between typed characters. + */ +void delay() + { +# ifdef NO_USLEEP + register int i; + + for (i = 0; i < 30000; ++i) /* ... did we just say appropriate? */ + ; +# else /* NO_USLEEP */ + usleep(100); +# endif /* NO_USLEEP */ + } diff --git a/usr.bin/chat/connect-ppp b/usr.bin/chat/connect-ppp new file mode 100755 index 0000000..2796b9d --- /dev/null +++ b/usr.bin/chat/connect-ppp @@ -0,0 +1,129 @@ +#!/bin/sh +# +# USAGE: connect-ppp +# +# Set up a PPP link to host. +# +# This script locks the tty so that faxd and uucp will not +# interfere. If you are running with faxd as you "getty" then +# faxd will remove the lock once it notices that pppd is gone. +# This is the reason for pppd running in with the -detach flag, +# and you probably would run this script in the background. +# +# I had to create the nodropdtr option to pppd in order to be +# able to do what the script is doing here. Pathces has been +# sent to the respective people, but I don't know if they like +# them :-). +# +# Look for comments with in the string. They identify +# things that you want to set for your system + +# define whatever your config file is. +CON_DB=/etc/ppp-connections + +# define whatever your device is. +DEVICE=tty00 + +# define whatever your device speed is. +DEVICESPEED=57600 + +# define whatever your lock directory is. +LOCKDIR=/var/spool/lock +LOCKFILE=$LOCKDIR/LCK..$DEVICE + +# define whatever debug level you want. +DEBUG="-d -d -d -d" + +# Check that we got a name to connect to. This need not be an actuall hostname +# just the name you specified in the config file. +if [ $# -ne 1 ] ; then + echo "Usage: $0 &" + exit 1 +fi + +# Get the configuration that is in effect for +LINE=`grep "^$1" $CON_DB` +if [ -z "$LINE" ] ; then + echo "Unknow host $1" + exit 1 +fi + +# parse the CON_DB. The format is: +# +# :::::\ +# : +# +# The last three are optional. But I would recomend specifying a netmask also +# when you specify a ip address. + +IP_ADDR="" +IFS=':' +set $LINE +IFS=' ' +HOST=$1 +PHONE=$2 +USER=$3 +PASSWORD=$4 +OUR_IP_ADDR=$5 +THEIR_IP_ADDR=$6 +NETMASK=$7 +shift 7 +OPTIONS=$* + +if [ -f $LOCKFILE ] ; then + echo "PPP device is locked" + exit 1 +else + + # Lock the device + # faxd and UUCP wants 10 character lock id. + echo "$$" | awk '{printf("%10s",$0)}' > $LOCKFILE +fi + + + + +#Do we know our local ip address? If so pppd needs a : at the end of it. +if [ ! -z "$OUR_IP_ADDR" ] ; then + IP_ADDR=${OUR_IP_ADDR}:${THEIR_IP_ADDR} +fi + +#Did we specify a netmask? If so convert to pppd format. +if [ ! -z "$NETMASK" ] ; then + NETMASK="netmask ${NETMASK}" +fi + +# Do the actual work in a subshell so that we can turn off tostop and set +# the tty speed before chat dials. The second reason for doing in like +# is that if you aren't running BIDIR, and you are running faxd, clocal +# doesn't get turned on from pppd so chat will never work if you exec +# it from within pppd. I found that I needed to run uucp with the +# HAVE_CLOCAL_BUG flag set to 1 in order to get it to work in conjunction +# with faxd. Anyway, this setup seem to work. +( + + stty $DEVICESPEED -tostop hupcl 2> /dev/null + + # Modify the Modem initialization strings to be whatever works for you + if chat -v ABORT "NO CARRIER" ABORT BUSY "" ATZ0E1 OK ATS50=255DT$PHONE \ + CONNECT "" ogin: $USER ssword: \\q$PASSWORD + then + # We got connected. + /usr/libexec/pppd $DEBUG $OPTIONS -detach modem defaultroute \ + crtscts $NETMASK $DEVICE $DEVICESPEED $IP_ADDR + + else + echo "PPP call failed" 1>&2 + exit 1 + fi +) < /dev/$DEVICE > /dev/$DEVICE +# Get the return code from the subshell. +RC=$? + +# Clear the lock. Slight window here where someone could detect that +# pppd is no longer running, remove its lock file and create its own. +# How to fix?? +rm -f $LOCKFILE + +#Pass on the exit code. +exit $RC diff --git a/usr.bin/chat/fix-cua b/usr.bin/chat/fix-cua new file mode 100644 index 0000000..74f000a --- /dev/null +++ b/usr.bin/chat/fix-cua @@ -0,0 +1,16 @@ +#!/bin/sh + +LOCKDIR=/var/spool/lock + +case "$1" in + "") echo "Usage: fix-cua device"; exit 1 ;; +esac + +if [ -f $LOCKDIR/LCK..$1 ] +then + echo "/dev/$1 is locked" 2>&1 + exit 1 +fi + +chown root /dev/$1 +chmod 666 /dev/$1 diff --git a/usr.bin/chat/ppp-off b/usr.bin/chat/ppp-off new file mode 100755 index 0000000..22b46f8 --- /dev/null +++ b/usr.bin/chat/ppp-off @@ -0,0 +1,5 @@ +#!/bin/sh + +kill -INT `ps -ax | egrep " ppp " | egrep -v "egrep" | sed 's/^\([ 0-9]*\) .*/\1'/` + +exit 0 diff --git a/usr.bin/chat/ppp-on b/usr.bin/chat/ppp-on new file mode 100755 index 0000000..305f2b0 --- /dev/null +++ b/usr.bin/chat/ppp-on @@ -0,0 +1,37 @@ +#!/bin/sh + +# +# ppp-on +# +# Set up a PPP link +# + +LOCKDIR=/var/spool/lock +DEVICE=com1 + +PHONE=4511234 +USER=Pkarl +PASSWORD=password +OUR_IP_ADDR=137.175.6.3 + +if [ -f $LOCKDIR/LCK..$DEVICE ] +then + echo "PPP device is locked" + exit 1 +fi + +fix-cua $DEVICE + +( + stty 19200 -tostop + + if chat -l LCK..$DEVICE ABORT "NO CARRIER" ABORT BUSY "" ATZ OK ATs50=255s111=0DT$PHONE CONNECT "" ogin: $USER ssword: \\q$PASSWORD + then + ppp mru 1500 $OUR_IP_ADDR: /dev/$DEVICE & + sleep 10 + exit 0 + else + echo "PPP call failed" 1>&2 + exit 1 + fi +) < /dev/$DEVICE > /dev/$DEVICE diff --git a/usr.bin/chat/unlock b/usr.bin/chat/unlock new file mode 100755 index 0000000..978bc6e --- /dev/null +++ b/usr.bin/chat/unlock @@ -0,0 +1,23 @@ +#!/bin/sh + +LOCKDIR=/var/spool/lock + +case "$1" in + "") echo "Usage: unlock lockfile"; exit 1 ;; + .*) echo "Usage: unlock lockfile"; exit 1 ;; +esac + +if [ -f $LOCKDIR/$1 ] +then + if [ `wc -c < $LOCKDIR/$1` -eq 4 ] + then + rm -f $LOCKDIR/$1 + exit 0 + else + echo "Usage: unlock lockfile" + exit 1 + fi +else + echo "lockfile" $LOCKDIR/$1 "does not exist" + exit 1 +fi