xref: /freebsd/usr.sbin/ppp/chat.c (revision 274e766c998381279af6ead2d711057aa6307df9)
1af57ed9fSAtsushi Murai /*
2af57ed9fSAtsushi Murai  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
3af57ed9fSAtsushi Murai  *
4af57ed9fSAtsushi Murai  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
5af57ed9fSAtsushi Murai  *
6af57ed9fSAtsushi Murai  *  Most of codes are derived from chat.c by Karl Fox (karl@MorningStar.Com).
7af57ed9fSAtsushi Murai  *
8af57ed9fSAtsushi Murai  *	Chat -- a program for automatic session establishment (i.e. dial
9af57ed9fSAtsushi Murai  *		the phone and log in).
10af57ed9fSAtsushi Murai  *
11af57ed9fSAtsushi Murai  *	This software is in the public domain.
12af57ed9fSAtsushi Murai  *
13af57ed9fSAtsushi Murai  *	Please send all bug reports, requests for information, etc. to:
14af57ed9fSAtsushi Murai  *
15af57ed9fSAtsushi Murai  *		Karl Fox <karl@MorningStar.Com>
16af57ed9fSAtsushi Murai  *		Morning Star Technologies, Inc.
17af57ed9fSAtsushi Murai  *		1760 Zollinger Road
18af57ed9fSAtsushi Murai  *		Columbus, OH  43221
19af57ed9fSAtsushi Murai  *		(614)451-1883
20af57ed9fSAtsushi Murai  *
21274e766cSBrian Somers  * $Id: chat.c,v 1.23 1997/05/07 23:01:23 brian Exp $
22af57ed9fSAtsushi Murai  *
23af57ed9fSAtsushi Murai  *  TODO:
24af57ed9fSAtsushi Murai  *	o Support more UUCP compatible control sequences.
25af57ed9fSAtsushi Murai  *	o Dialing shoud not block monitor process.
2684b8a6ebSAtsushi Murai  *	o Reading modem by select should be unified into main.c
27af57ed9fSAtsushi Murai  */
28af57ed9fSAtsushi Murai #include "defs.h"
29af57ed9fSAtsushi Murai #include <ctype.h>
30af57ed9fSAtsushi Murai #include <sys/uio.h>
31af57ed9fSAtsushi Murai #ifndef isblank
32af57ed9fSAtsushi Murai #define	isblank(c)	((c) == '\t' || (c) == ' ')
33af57ed9fSAtsushi Murai #endif
34af57ed9fSAtsushi Murai #include <sys/time.h>
35af57ed9fSAtsushi Murai #include <fcntl.h>
3653c9f6c0SAtsushi Murai #include <errno.h>
37c3b6ad66SBrian Somers #include <signal.h>
3853c9f6c0SAtsushi Murai #include <sys/wait.h>
39af57ed9fSAtsushi Murai #include "timeout.h"
40af57ed9fSAtsushi Murai #include "vars.h"
41274e766cSBrian Somers #include "chat.h"
42f5ff0f7cSBrian Somers #include "sig.h"
43e68d210eSBrian Somers #include "chat.h"
44af57ed9fSAtsushi Murai 
4553c9f6c0SAtsushi Murai #define	IBSIZE 200
4653c9f6c0SAtsushi Murai 
47af57ed9fSAtsushi Murai static int TimeoutSec;
48af57ed9fSAtsushi Murai static int abort_next, timeout_next;
49af57ed9fSAtsushi Murai static int numaborts;
50af57ed9fSAtsushi Murai char *AbortStrings[50];
5181cc95f2SAndrey A. Chernov char inbuff[IBSIZE*2+1];
52af57ed9fSAtsushi Murai 
53af57ed9fSAtsushi Murai extern int ChangeParity(char *);
54af57ed9fSAtsushi Murai 
55af57ed9fSAtsushi Murai #define	MATCH	1
56af57ed9fSAtsushi Murai #define	NOMATCH	0
57af57ed9fSAtsushi Murai #define	ABORT	-1
58af57ed9fSAtsushi Murai 
59af57ed9fSAtsushi Murai static char *
60af57ed9fSAtsushi Murai findblank(p, instring)
61af57ed9fSAtsushi Murai char *p;
62af57ed9fSAtsushi Murai int instring;
63af57ed9fSAtsushi Murai {
64af57ed9fSAtsushi Murai   if (instring) {
65af57ed9fSAtsushi Murai     while (*p) {
66af57ed9fSAtsushi Murai       if (*p == '\\') {
67af57ed9fSAtsushi Murai 	strcpy(p, p + 1);
68af57ed9fSAtsushi Murai 	if (!*p)
69af57ed9fSAtsushi Murai 	  break;
70af57ed9fSAtsushi Murai       } else if (*p == '"')
71af57ed9fSAtsushi Murai 	return(p);
72af57ed9fSAtsushi Murai       p++;
73af57ed9fSAtsushi Murai     }
74af57ed9fSAtsushi Murai   } else {
75af57ed9fSAtsushi Murai     while (*p) {
76af57ed9fSAtsushi Murai       if (isblank(*p))
77af57ed9fSAtsushi Murai 	return(p);
78af57ed9fSAtsushi Murai       p++;
79af57ed9fSAtsushi Murai     }
80af57ed9fSAtsushi Murai   }
81af57ed9fSAtsushi Murai   return p;
82af57ed9fSAtsushi Murai }
83af57ed9fSAtsushi Murai 
84af57ed9fSAtsushi Murai int
85e68d210eSBrian Somers MakeArgs(script, pvect, maxargs)
86af57ed9fSAtsushi Murai char *script;
87af57ed9fSAtsushi Murai char **pvect;
88e68d210eSBrian Somers int maxargs;
89af57ed9fSAtsushi Murai {
90af57ed9fSAtsushi Murai   int nargs, nb;
91af57ed9fSAtsushi Murai   int instring;
92af57ed9fSAtsushi Murai 
93af57ed9fSAtsushi Murai   nargs = 0;
94af57ed9fSAtsushi Murai   while (*script) {
95af57ed9fSAtsushi Murai     nb = strspn(script, " \t");
96af57ed9fSAtsushi Murai     script += nb;
97af57ed9fSAtsushi Murai     if (*script) {
98af57ed9fSAtsushi Murai       if (*script == '"') {
99af57ed9fSAtsushi Murai 	instring = 1;
100af57ed9fSAtsushi Murai 	script++;
101af57ed9fSAtsushi Murai 	if (*script == '\0')
102e68d210eSBrian Somers 	  break; /* Shouldn't return here. Need to null terminate below */
103af57ed9fSAtsushi Murai       } else
104af57ed9fSAtsushi Murai 	instring = 0;
105e68d210eSBrian Somers       if (nargs >= maxargs-1)
106e68d210eSBrian Somers 	break;
107af57ed9fSAtsushi Murai       *pvect++ = script;
108af57ed9fSAtsushi Murai       nargs++;
109af57ed9fSAtsushi Murai       script = findblank(script, instring);
110af57ed9fSAtsushi Murai       if (*script)
111af57ed9fSAtsushi Murai 	*script++ = '\0';
112af57ed9fSAtsushi Murai     }
113af57ed9fSAtsushi Murai   }
114af57ed9fSAtsushi Murai   *pvect = NULL;
115af57ed9fSAtsushi Murai   return nargs;
116af57ed9fSAtsushi Murai }
117af57ed9fSAtsushi Murai 
118af57ed9fSAtsushi Murai /*
11999c02d39SWarner Losh  *  \c	don't add a cr
12099c02d39SWarner Losh  *  \d  Sleep a little (delay 2 seconds
12199c02d39SWarner Losh  *  \n  Line feed character
12299c02d39SWarner Losh  *  \P  Auth Key password
12399c02d39SWarner Losh  *  \p  pause 0.25 sec
124af57ed9fSAtsushi Murai  *  \r	Carrige return character
125af57ed9fSAtsushi Murai  *  \s  Space character
1261dff3fc5SAndrey A. Chernov  *  \T  Telephone number(s) (defined via `set phone')
127af57ed9fSAtsushi Murai  *  \t  Tab character
12899c02d39SWarner Losh  *  \U  Auth User
129af57ed9fSAtsushi Murai  */
130af57ed9fSAtsushi Murai char *
13199c02d39SWarner Losh ExpandString(str, result, reslen, sendmode)
132af57ed9fSAtsushi Murai char *str;
133af57ed9fSAtsushi Murai char *result;
13499c02d39SWarner Losh int reslen;
135af57ed9fSAtsushi Murai int sendmode;
136af57ed9fSAtsushi Murai {
137af57ed9fSAtsushi Murai   int addcr = 0;
1381dff3fc5SAndrey A. Chernov   char *phone;
139af57ed9fSAtsushi Murai 
14099c02d39SWarner Losh   result[--reslen] = '\0';
141af57ed9fSAtsushi Murai   if (sendmode)
142af57ed9fSAtsushi Murai     addcr = 1;
14399c02d39SWarner Losh   while (*str && reslen > 0) {
144af57ed9fSAtsushi Murai     switch (*str) {
145af57ed9fSAtsushi Murai     case '\\':
146af57ed9fSAtsushi Murai       str++;
147af57ed9fSAtsushi Murai       switch (*str) {
148af57ed9fSAtsushi Murai       case 'c':
149af57ed9fSAtsushi Murai 	if (sendmode)
150af57ed9fSAtsushi Murai 	  addcr = 0;
151af57ed9fSAtsushi Murai 	break;
152af57ed9fSAtsushi Murai       case 'd':		/* Delay 2 seconds */
153af57ed9fSAtsushi Murai         sleep(2); break;
154af57ed9fSAtsushi Murai       case 'p':
155af57ed9fSAtsushi Murai         usleep(250000); break;	/* Pause 0.25 sec */
156af57ed9fSAtsushi Murai       case 'n':
15799c02d39SWarner Losh 	*result++ = '\n'; reslen--; break;
158af57ed9fSAtsushi Murai       case 'r':
15999c02d39SWarner Losh 	*result++ = '\r'; reslen--; break;
160af57ed9fSAtsushi Murai       case 's':
16199c02d39SWarner Losh 	*result++ = ' '; reslen--; break;
162af57ed9fSAtsushi Murai       case 't':
16399c02d39SWarner Losh 	*result++ = '\t'; reslen--; break;
164af57ed9fSAtsushi Murai       case 'P':
16599c02d39SWarner Losh         strncpy(result, VarAuthKey, reslen);
16699c02d39SWarner Losh 	reslen -= strlen(result);
16799c02d39SWarner Losh 	result += strlen(result);
168af57ed9fSAtsushi Murai 	break;
169af57ed9fSAtsushi Murai       case 'T':
170a81c9c68SAndrey A. Chernov 	if (VarNextPhone == NULL) {
171a81c9c68SAndrey A. Chernov 	  strcpy(VarPhoneCopy, VarPhoneList);
172a81c9c68SAndrey A. Chernov 	  VarNextPhone = VarPhoneCopy;
173a81c9c68SAndrey A. Chernov 	}
1741dff3fc5SAndrey A. Chernov 	phone = strsep(&VarNextPhone, ":");
17599c02d39SWarner Losh 	strncpy(result, phone, reslen);
17699c02d39SWarner Losh 	reslen -= strlen(result);
17799c02d39SWarner Losh 	result += strlen(result);
1781dff3fc5SAndrey A. Chernov 	if ((mode & (MODE_INTER|MODE_AUTO)) == MODE_INTER)
1791dff3fc5SAndrey A. Chernov 	  fprintf(stderr, "Phone: %s\n", phone);
1809c749ffbSPoul-Henning Kamp 	LogPrintf(LOG_PHASE_BIT, "Phone: %s\n", phone);
181af57ed9fSAtsushi Murai 	break;
182af57ed9fSAtsushi Murai       case 'U':
18399c02d39SWarner Losh 	strncpy(result, VarAuthName, reslen);
18499c02d39SWarner Losh 	reslen -= strlen(result);
18599c02d39SWarner Losh 	result += strlen(result);
186af57ed9fSAtsushi Murai 	break;
187af57ed9fSAtsushi Murai       default:
18899c02d39SWarner Losh 	reslen--;
18999c02d39SWarner Losh 	*result++ = *str;
19099c02d39SWarner Losh 	break;
191af57ed9fSAtsushi Murai       }
19299c02d39SWarner Losh       if (*str)
19399c02d39SWarner Losh           str++;
194af57ed9fSAtsushi Murai       break;
195af57ed9fSAtsushi Murai     case '^':
196af57ed9fSAtsushi Murai       str++;
19799c02d39SWarner Losh       if (*str) {
198af57ed9fSAtsushi Murai 	*result++ = *str++ & 0x1f;
19999c02d39SWarner Losh 	reslen--;
20099c02d39SWarner Losh       }
201af57ed9fSAtsushi Murai       break;
202af57ed9fSAtsushi Murai     default:
203af57ed9fSAtsushi Murai       *result++ = *str++;
20499c02d39SWarner Losh       reslen--;
205af57ed9fSAtsushi Murai       break;
206af57ed9fSAtsushi Murai     }
207af57ed9fSAtsushi Murai   }
20899c02d39SWarner Losh   if (--reslen > 0) {
209af57ed9fSAtsushi Murai     if (addcr)
210af57ed9fSAtsushi Murai       *result++ = '\r';
21199c02d39SWarner Losh   }
21299c02d39SWarner Losh   if (--reslen > 0)
213af57ed9fSAtsushi Murai     *result++ = '\0';
214af57ed9fSAtsushi Murai   return(result);
215af57ed9fSAtsushi Murai }
216af57ed9fSAtsushi Murai 
2179c749ffbSPoul-Henning Kamp #define MAXLOGBUFF 200
2189c749ffbSPoul-Henning Kamp static char logbuff[MAXLOGBUFF];
2199c749ffbSPoul-Henning Kamp static int loglen = 0;
2209c749ffbSPoul-Henning Kamp 
2219c749ffbSPoul-Henning Kamp static void clear_log() {
2229c749ffbSPoul-Henning Kamp   memset(logbuff,0,MAXLOGBUFF);
2239c749ffbSPoul-Henning Kamp   loglen = 0;
2249c749ffbSPoul-Henning Kamp }
2259c749ffbSPoul-Henning Kamp 
2269c749ffbSPoul-Henning Kamp static void flush_log() {
2279c749ffbSPoul-Henning Kamp   if ((loglevel & LOG_CONNECT_BIT)
2289c749ffbSPoul-Henning Kamp       || ((loglevel & LOG_CARRIER_BIT)
2299c749ffbSPoul-Henning Kamp 	  && strstr(logbuff,"CARRIER"))) {
2309c749ffbSPoul-Henning Kamp     LogPrintf(LOG_CONNECT_BIT|LOG_CARRIER_BIT,"Chat: %s\n",logbuff);
2319c749ffbSPoul-Henning Kamp   }
2329c749ffbSPoul-Henning Kamp   clear_log();
2339c749ffbSPoul-Henning Kamp }
2349c749ffbSPoul-Henning Kamp 
2359c749ffbSPoul-Henning Kamp static void connect_log(char *str, int single_p) {
2369c749ffbSPoul-Henning Kamp   int space = MAXLOGBUFF - loglen - 1;
2379c749ffbSPoul-Henning Kamp 
2389c749ffbSPoul-Henning Kamp   while (space--) {
2399c749ffbSPoul-Henning Kamp     if (*str == '\n') {
2409c749ffbSPoul-Henning Kamp       flush_log();
2419c749ffbSPoul-Henning Kamp     } else {
2429c749ffbSPoul-Henning Kamp       logbuff[loglen++] = *str;
2439c749ffbSPoul-Henning Kamp     }
2449c749ffbSPoul-Henning Kamp     if (single_p || !*++str) break;
2459c749ffbSPoul-Henning Kamp   }
2469c749ffbSPoul-Henning Kamp   if (!space) flush_log();
2479c749ffbSPoul-Henning Kamp }
2489c749ffbSPoul-Henning Kamp 
2499c749ffbSPoul-Henning Kamp 
2509c749ffbSPoul-Henning Kamp 
251af57ed9fSAtsushi Murai int
252af57ed9fSAtsushi Murai WaitforString(estr)
253af57ed9fSAtsushi Murai char *estr;
254af57ed9fSAtsushi Murai {
255af57ed9fSAtsushi Murai   struct timeval timeout;
256af57ed9fSAtsushi Murai   char *s, *str, ch;
257af57ed9fSAtsushi Murai   char *inp;
258af57ed9fSAtsushi Murai   fd_set rfds;
259274e766cSBrian Somers   int i, nfds, nb;
260274e766cSBrian Somers   char buff[IBSIZE];
261af57ed9fSAtsushi Murai 
2629c749ffbSPoul-Henning Kamp 
26353c9f6c0SAtsushi Murai #ifdef SIGALRM
26453c9f6c0SAtsushi Murai   int omask;
26553c9f6c0SAtsushi Murai   omask = sigblock(sigmask(SIGALRM));
26653c9f6c0SAtsushi Murai #endif
2679c749ffbSPoul-Henning Kamp   clear_log();
26899c02d39SWarner Losh   (void) ExpandString(estr, buff, sizeof(buff), 0);
2699c749ffbSPoul-Henning Kamp   LogPrintf(LOG_CHAT_BIT, "Wait for (%d): %s --> %s\n", TimeoutSec, estr, buff);
270af57ed9fSAtsushi Murai   str = buff;
271af57ed9fSAtsushi Murai   inp = inbuff;
272af57ed9fSAtsushi Murai 
27381cc95f2SAndrey A. Chernov   if (strlen(str)>=IBSIZE){
274274e766cSBrian Somers     str[IBSIZE-1]=0;
2759c749ffbSPoul-Henning Kamp     LogPrintf(LOG_CHAT_BIT, "Truncating String to %d character: %s\n", IBSIZE, str);
27681cc95f2SAndrey A. Chernov   }
27781cc95f2SAndrey A. Chernov 
278af57ed9fSAtsushi Murai   nfds = modem + 1;
279af57ed9fSAtsushi Murai   s = str;
280af57ed9fSAtsushi Murai   for (;;) {
281af57ed9fSAtsushi Murai     FD_ZERO(&rfds);
282af57ed9fSAtsushi Murai     FD_SET(modem, &rfds);
283af57ed9fSAtsushi Murai     /*
284af57ed9fSAtsushi Murai      *  Because it is not clear whether select() modifies timeout value,
285af57ed9fSAtsushi Murai      *  it is better to initialize timeout values everytime.
286af57ed9fSAtsushi Murai      */
287af57ed9fSAtsushi Murai     timeout.tv_sec = TimeoutSec;
288af57ed9fSAtsushi Murai     timeout.tv_usec = 0;
289af57ed9fSAtsushi Murai     i = select(nfds, &rfds, NULL, NULL, &timeout);
290af57ed9fSAtsushi Murai #ifdef notdef
291af57ed9fSAtsushi Murai     TimerService();
292af57ed9fSAtsushi Murai #endif
293af57ed9fSAtsushi Murai     if (i < 0) {
29453c9f6c0SAtsushi Murai #ifdef SIGALRM
29553c9f6c0SAtsushi Murai       if (errno == EINTR)
29653c9f6c0SAtsushi Murai 	continue;
29753c9f6c0SAtsushi Murai       sigsetmask(omask);
29853c9f6c0SAtsushi Murai #endif
299af57ed9fSAtsushi Murai       perror("select");
30053c9f6c0SAtsushi Murai       *inp = 0;
301af57ed9fSAtsushi Murai       return(NOMATCH);
302af57ed9fSAtsushi Murai     } else if (i == 0) { 	/* Timeout reached! */
30353c9f6c0SAtsushi Murai       *inp = 0;
30453c9f6c0SAtsushi Murai       if (inp != inbuff)
3059c749ffbSPoul-Henning Kamp 	LogPrintf(LOG_CHAT_BIT, "got: %s\n", inbuff);
3069c749ffbSPoul-Henning Kamp       LogPrintf(LOG_CHAT_BIT, "can't get (%d).\n", timeout.tv_sec);
30753c9f6c0SAtsushi Murai #ifdef SIGALRM
30853c9f6c0SAtsushi Murai       sigsetmask(omask);
30953c9f6c0SAtsushi Murai #endif
310af57ed9fSAtsushi Murai       return(NOMATCH);
311af57ed9fSAtsushi Murai     }
312af57ed9fSAtsushi Murai     if (FD_ISSET(modem, &rfds)) {	/* got something */
31353c9f6c0SAtsushi Murai       if (DEV_IS_SYNC) {
31481cc95f2SAndrey A. Chernov 	int length;
31581cc95f2SAndrey A. Chernov 	if ((length=strlen(inbuff))>IBSIZE){
31681cc95f2SAndrey A. Chernov 	  bcopy(&(inbuff[IBSIZE]),inbuff,IBSIZE+1); /* shuffle down next part*/
31781cc95f2SAndrey A. Chernov 	  length=strlen(inbuff);
31881cc95f2SAndrey A. Chernov 	}
31981cc95f2SAndrey A. Chernov 	nb = read(modem, &(inbuff[length]), IBSIZE);
32081cc95f2SAndrey A. Chernov 	inbuff[nb + length] = 0;
3219c749ffbSPoul-Henning Kamp 	connect_log(inbuff,0);
32253c9f6c0SAtsushi Murai 	if (strstr(inbuff, str)) {
32353c9f6c0SAtsushi Murai #ifdef SIGALRM
32453c9f6c0SAtsushi Murai           sigsetmask(omask);
32553c9f6c0SAtsushi Murai #endif
3269c749ffbSPoul-Henning Kamp 	  flush_log();
32753c9f6c0SAtsushi Murai 	  return(MATCH);
32853c9f6c0SAtsushi Murai 	}
32953c9f6c0SAtsushi Murai 	for (i = 0; i < numaborts; i++) {
33053c9f6c0SAtsushi Murai 	  if (strstr(inbuff, AbortStrings[i])) {
3319c749ffbSPoul-Henning Kamp 	    LogPrintf(LOG_CHAT_BIT, "Abort: %s\n", AbortStrings[i]);
33253c9f6c0SAtsushi Murai #ifdef SIGALRM
33353c9f6c0SAtsushi Murai             sigsetmask(omask);
33453c9f6c0SAtsushi Murai #endif
3359c749ffbSPoul-Henning Kamp 	    flush_log();
33653c9f6c0SAtsushi Murai 	    return(ABORT);
33753c9f6c0SAtsushi Murai 	  }
33853c9f6c0SAtsushi Murai 	}
33953c9f6c0SAtsushi Murai       } else {
340274e766cSBrian Somers         if (read(modem, &ch, 1) < 0) {
341274e766cSBrian Somers 	   perror("read error");
342274e766cSBrian Somers 	   *inp = '\0';
343274e766cSBrian Somers 	   return(NOMATCH);
344274e766cSBrian Somers 	}
3459c749ffbSPoul-Henning Kamp 	connect_log(&ch,1);
346af57ed9fSAtsushi Murai         *inp++ = ch;
347af57ed9fSAtsushi Murai         if (ch == *s) {
348af57ed9fSAtsushi Murai 	  s++;
349af57ed9fSAtsushi Murai 	  if (*s == '\0') {
35053c9f6c0SAtsushi Murai #ifdef SIGALRM
35153c9f6c0SAtsushi Murai             sigsetmask(omask);
35253c9f6c0SAtsushi Murai #endif
35353c9f6c0SAtsushi Murai 	    *inp = 0;
3549c749ffbSPoul-Henning Kamp 	    flush_log();
355af57ed9fSAtsushi Murai 	    return(MATCH);
356af57ed9fSAtsushi Murai 	  }
357af57ed9fSAtsushi Murai         } else {
358af57ed9fSAtsushi Murai 	  s = str;
359af57ed9fSAtsushi Murai 	  if (inp == inbuff+ IBSIZE) {
360af57ed9fSAtsushi Murai 	    bcopy(inp - 100, inbuff, 100);
361af57ed9fSAtsushi Murai 	    inp = inbuff + 100;
362af57ed9fSAtsushi Murai 	  }
363af57ed9fSAtsushi Murai 	  for (i = 0; i < numaborts; i++) {	/* Look for Abort strings */
364af57ed9fSAtsushi Murai 	    int len;
365af57ed9fSAtsushi Murai 	    char *s1;
366af57ed9fSAtsushi Murai 
367af57ed9fSAtsushi Murai 	    s1 = AbortStrings[i];
368af57ed9fSAtsushi Murai 	    len = strlen(s1);
369af57ed9fSAtsushi Murai 	    if ((len <= inp - inbuff) && (strncmp(inp - len, s1, len) == 0)) {
3709c749ffbSPoul-Henning Kamp 	      LogPrintf(LOG_CHAT_BIT, "Abort: %s\n", s1);
37153c9f6c0SAtsushi Murai 	      *inp = 0;
37253c9f6c0SAtsushi Murai #ifdef SIGALRM
37353c9f6c0SAtsushi Murai       	      sigsetmask(omask);
37453c9f6c0SAtsushi Murai #endif
3759c749ffbSPoul-Henning Kamp 	      flush_log();
376af57ed9fSAtsushi Murai 	      return(ABORT);
377af57ed9fSAtsushi Murai 	    }
378af57ed9fSAtsushi Murai 	  }
379af57ed9fSAtsushi Murai         }
380af57ed9fSAtsushi Murai       }
381af57ed9fSAtsushi Murai     }
382af57ed9fSAtsushi Murai   }
38353c9f6c0SAtsushi Murai }
38453c9f6c0SAtsushi Murai 
38553c9f6c0SAtsushi Murai void
38653c9f6c0SAtsushi Murai ExecStr(command, out)
38753c9f6c0SAtsushi Murai char *command, *out;
38853c9f6c0SAtsushi Murai {
38953c9f6c0SAtsushi Murai   int pid;
39053c9f6c0SAtsushi Murai   int fids[2];
39153c9f6c0SAtsushi Murai   char *vector[20];
39253c9f6c0SAtsushi Murai   int stat, nb;
39353c9f6c0SAtsushi Murai   char *cp;
39453c9f6c0SAtsushi Murai   char tmp[300];
39553c9f6c0SAtsushi Murai   extern int errno;
39653c9f6c0SAtsushi Murai 
39753c9f6c0SAtsushi Murai   cp = inbuff + strlen(inbuff) - 1;
39853c9f6c0SAtsushi Murai   while (cp > inbuff) {
39953c9f6c0SAtsushi Murai     if (*cp < ' ' && *cp != '\t') {
40053c9f6c0SAtsushi Murai       cp++;
40153c9f6c0SAtsushi Murai       break;
40253c9f6c0SAtsushi Murai     }
40353c9f6c0SAtsushi Murai     cp--;
40453c9f6c0SAtsushi Murai   }
405274e766cSBrian Somers   if (snprintf(tmp, sizeof tmp, "%s %s", command, cp) >= sizeof tmp) {
406274e766cSBrian Somers     LogPrintf(LOG_CHAT_BIT, "Too long string to ExecStr: \"%s\"\n",
407274e766cSBrian Somers 	      command);
408274e766cSBrian Somers     return;
409274e766cSBrian Somers   }
410e68d210eSBrian Somers   (void) MakeArgs(tmp, vector, VECSIZE(vector));
41153c9f6c0SAtsushi Murai 
412274e766cSBrian Somers   if (pipe(fids) < 0) {
413274e766cSBrian Somers     LogPrintf(LOG_CHAT_BIT, "Unable to create pipe in ExecStr: %s\n",
414274e766cSBrian Somers 	      strerror(errno));
415274e766cSBrian Somers     return;
416274e766cSBrian Somers   }
417274e766cSBrian Somers 
41853c9f6c0SAtsushi Murai   pid = fork();
41953c9f6c0SAtsushi Murai   if (pid == 0) {
420f5ff0f7cSBrian Somers     TermTimerService();
42106257ca4SAndrey A. Chernov     signal(SIGINT, SIG_DFL);
42206257ca4SAndrey A. Chernov     signal(SIGQUIT, SIG_DFL);
42306257ca4SAndrey A. Chernov     signal(SIGTERM, SIG_DFL);
4240b6828d1SAndrey A. Chernov     signal(SIGHUP, SIG_DFL);
425f5ff0f7cSBrian Somers     signal(SIGALRM, SIG_DFL);
42653c9f6c0SAtsushi Murai     close(fids[0]);
427274e766cSBrian Somers     if (dup2(fids[1], 1) < 0) {
428274e766cSBrian Somers       LogPrintf(LOG_CHAT_BIT, "dup2(fids[1], 1) in ExecStr: %s\n",
429274e766cSBrian Somers 		strerror(errno));
430274e766cSBrian Somers       return;
431274e766cSBrian Somers     }
43253c9f6c0SAtsushi Murai     close(fids[1]);
43353c9f6c0SAtsushi Murai     nb = open("/dev/tty", O_RDWR);
434274e766cSBrian Somers     if (dup2(nb, 0) < 0) {
435274e766cSBrian Somers       LogPrintf(LOG_CHAT_BIT, "dup2(nb, 0) in ExecStr: %s\n",
436274e766cSBrian Somers 		strerror(errno));
437274e766cSBrian Somers       return;
438274e766cSBrian Somers     }
4399c749ffbSPoul-Henning Kamp     LogPrintf(LOG_CHAT_BIT, "exec: %s\n", command);
440113dea91SAndrey A. Chernov     /* switch back to original privileges */
441113dea91SAndrey A. Chernov     if (setgid(getgid()) < 0) {
442113dea91SAndrey A. Chernov       LogPrintf(LOG_CHAT_BIT, "setgid: %s\n", strerror(errno));
443113dea91SAndrey A. Chernov       exit(1);
444113dea91SAndrey A. Chernov     }
445113dea91SAndrey A. Chernov     if (setuid(getuid()) < 0) {
446113dea91SAndrey A. Chernov       LogPrintf(LOG_CHAT_BIT, "setuid: %s\n", strerror(errno));
447113dea91SAndrey A. Chernov       exit(1);
448113dea91SAndrey A. Chernov     }
44953c9f6c0SAtsushi Murai     pid = execvp(command, vector);
4509c749ffbSPoul-Henning Kamp     LogPrintf(LOG_CHAT_BIT, "execvp failed for (%d/%d): %s\n", pid, errno, command);
45153c9f6c0SAtsushi Murai     exit(127);
45253c9f6c0SAtsushi Murai   } else {
45353c9f6c0SAtsushi Murai     close(fids[1]);
45453c9f6c0SAtsushi Murai     for (;;) {
45553c9f6c0SAtsushi Murai       nb = read(fids[0], out, 1);
45653c9f6c0SAtsushi Murai       if (nb <= 0)
45753c9f6c0SAtsushi Murai 	break;
45853c9f6c0SAtsushi Murai       out++;
45953c9f6c0SAtsushi Murai     }
46053c9f6c0SAtsushi Murai     *out = '\0';
46153c9f6c0SAtsushi Murai     close(fids[0]);
46253c9f6c0SAtsushi Murai     close(fids[1]);
46353c9f6c0SAtsushi Murai     waitpid(pid, &stat, WNOHANG);
46453c9f6c0SAtsushi Murai   }
46553c9f6c0SAtsushi Murai }
466af57ed9fSAtsushi Murai 
467af57ed9fSAtsushi Murai void
468af57ed9fSAtsushi Murai SendString(str)
469af57ed9fSAtsushi Murai char *str;
470af57ed9fSAtsushi Murai {
47153c9f6c0SAtsushi Murai   char *cp;
472274e766cSBrian Somers   int on;
473af57ed9fSAtsushi Murai   char buff[200];
474af57ed9fSAtsushi Murai 
475af57ed9fSAtsushi Murai   if (abort_next) {
476af57ed9fSAtsushi Murai     abort_next = 0;
47799c02d39SWarner Losh     ExpandString(str, buff, sizeof(buff), 0);
478af57ed9fSAtsushi Murai     AbortStrings[numaborts++] = strdup(buff);
479af57ed9fSAtsushi Murai   } else if (timeout_next) {
480af57ed9fSAtsushi Murai     timeout_next = 0;
481af57ed9fSAtsushi Murai     TimeoutSec = atoi(str);
482af57ed9fSAtsushi Murai     if (TimeoutSec <= 0)
483af57ed9fSAtsushi Murai       TimeoutSec = 30;
484af57ed9fSAtsushi Murai   } else {
48553c9f6c0SAtsushi Murai     if (*str == '!') {
48699c02d39SWarner Losh       (void) ExpandString(str+1, buff+2, sizeof(buff)-2, 0);
48753c9f6c0SAtsushi Murai       ExecStr(buff + 2, buff + 2);
48853c9f6c0SAtsushi Murai     } else {
48999c02d39SWarner Losh       (void) ExpandString(str, buff+2, sizeof(buff)-2, 1);
49053c9f6c0SAtsushi Murai     }
491c3899f8dSAtsushi Murai     if (strstr(str, "\\P")) { /* Do not log the password itself. */
4929c749ffbSPoul-Henning Kamp       LogPrintf(LOG_CHAT_BIT, "sending: %s\n", str);
493c3899f8dSAtsushi Murai     } else {
4949c749ffbSPoul-Henning Kamp       LogPrintf(LOG_CHAT_BIT, "sending: %s\n", buff+2);
495c3899f8dSAtsushi Murai     }
49653c9f6c0SAtsushi Murai     cp = buff;
49753c9f6c0SAtsushi Murai     if (DEV_IS_SYNC)
49853c9f6c0SAtsushi Murai       bcopy("\377\003", buff, 2);	/* Prepend HDLC header */
49953c9f6c0SAtsushi Murai     else
50053c9f6c0SAtsushi Murai       cp += 2;
50153c9f6c0SAtsushi Murai     on = strlen(cp);
502274e766cSBrian Somers     write(modem, cp, on);
503af57ed9fSAtsushi Murai   }
504af57ed9fSAtsushi Murai }
505af57ed9fSAtsushi Murai 
506af57ed9fSAtsushi Murai int
507af57ed9fSAtsushi Murai ExpectString(str)
508af57ed9fSAtsushi Murai char *str;
509af57ed9fSAtsushi Murai {
510af57ed9fSAtsushi Murai   char *minus;
511af57ed9fSAtsushi Murai   int state;
512af57ed9fSAtsushi Murai 
513af57ed9fSAtsushi Murai   if (strcmp(str, "ABORT") == 0) {
514af57ed9fSAtsushi Murai     ++abort_next;
515af57ed9fSAtsushi Murai     return(MATCH);
516af57ed9fSAtsushi Murai   }
517af57ed9fSAtsushi Murai   if (strcmp(str, "TIMEOUT") == 0) {
518af57ed9fSAtsushi Murai     ++timeout_next;
519af57ed9fSAtsushi Murai     return(MATCH);
520af57ed9fSAtsushi Murai   }
5219c749ffbSPoul-Henning Kamp   LogPrintf(LOG_CHAT_BIT, "Expecting %s\n", str);
522af57ed9fSAtsushi Murai   while (*str) {
523af57ed9fSAtsushi Murai     /*
524af57ed9fSAtsushi Murai      *  Check whether if string contains sub-send-expect.
525af57ed9fSAtsushi Murai      */
526af57ed9fSAtsushi Murai     for (minus = str; *minus; minus++) {
527af57ed9fSAtsushi Murai       if (*minus == '-') {
528af57ed9fSAtsushi Murai 	if (minus == str || minus[-1] != '\\')
529af57ed9fSAtsushi Murai 	  break;
530af57ed9fSAtsushi Murai       }
531af57ed9fSAtsushi Murai     }
532af57ed9fSAtsushi Murai     if (*minus == '-') {      /* We have sub-send-expect. */
533af57ed9fSAtsushi Murai       *minus++ = '\0';
534af57ed9fSAtsushi Murai       state = WaitforString(str);
535af57ed9fSAtsushi Murai       if (state != NOMATCH)
536af57ed9fSAtsushi Murai 	return(state);
537af57ed9fSAtsushi Murai       /*
538af57ed9fSAtsushi Murai        * Can't get expect string. Sendout send part.
539af57ed9fSAtsushi Murai        */
540af57ed9fSAtsushi Murai       str = minus;
541af57ed9fSAtsushi Murai       for (minus = str; *minus; minus++) {
542af57ed9fSAtsushi Murai 	if (*minus == '-') {
543af57ed9fSAtsushi Murai 	  if (minus == str || minus[-1] != '\\')
544af57ed9fSAtsushi Murai 	    break;
545af57ed9fSAtsushi Murai 	}
546af57ed9fSAtsushi Murai       }
547af57ed9fSAtsushi Murai       if (*minus == '-') {
548af57ed9fSAtsushi Murai 	*minus++ = '\0';
549af57ed9fSAtsushi Murai 	SendString(str);
550af57ed9fSAtsushi Murai 	str = minus;
551af57ed9fSAtsushi Murai       } else {
552af57ed9fSAtsushi Murai 	SendString(str);
553af57ed9fSAtsushi Murai 	return(MATCH);
554af57ed9fSAtsushi Murai       }
555af57ed9fSAtsushi Murai     } else {
556af57ed9fSAtsushi Murai       /*
557af57ed9fSAtsushi Murai        *  Simple case. Wait for string.
558af57ed9fSAtsushi Murai        */
559af57ed9fSAtsushi Murai       return(WaitforString(str));
560af57ed9fSAtsushi Murai     }
561af57ed9fSAtsushi Murai   }
562af57ed9fSAtsushi Murai   return(MATCH);
563af57ed9fSAtsushi Murai }
564af57ed9fSAtsushi Murai 
565af57ed9fSAtsushi Murai int
566af57ed9fSAtsushi Murai DoChat(script)
567af57ed9fSAtsushi Murai char *script;
568af57ed9fSAtsushi Murai {
569e68d210eSBrian Somers   char *vector[40];
570af57ed9fSAtsushi Murai   char **argv;
571af57ed9fSAtsushi Murai   int argc, n, state;
572af57ed9fSAtsushi Murai #ifdef DEBUG
573af57ed9fSAtsushi Murai   int i;
574af57ed9fSAtsushi Murai #endif
575af57ed9fSAtsushi Murai 
576af57ed9fSAtsushi Murai   timeout_next = abort_next = 0;
577af57ed9fSAtsushi Murai   for (n = 0; AbortStrings[n]; n++) {
578af57ed9fSAtsushi Murai     free(AbortStrings[n]);
579af57ed9fSAtsushi Murai     AbortStrings[n] = NULL;
580af57ed9fSAtsushi Murai   }
581af57ed9fSAtsushi Murai   numaborts = 0;
582af57ed9fSAtsushi Murai 
583af57ed9fSAtsushi Murai   bzero(vector, sizeof(vector));
584e68d210eSBrian Somers   n = MakeArgs(script, vector, VECSIZE(vector));
585af57ed9fSAtsushi Murai #ifdef DEBUG
586af57ed9fSAtsushi Murai   logprintf("n = %d\n", n);
587af57ed9fSAtsushi Murai   for (i = 0; i < n; i++)
588af57ed9fSAtsushi Murai     logprintf("  %s\n", vector[i]);
589af57ed9fSAtsushi Murai #endif
590af57ed9fSAtsushi Murai   argc = n;
591af57ed9fSAtsushi Murai   argv = vector;
592af57ed9fSAtsushi Murai   TimeoutSec = 30;
593af57ed9fSAtsushi Murai   while (*argv) {
594af57ed9fSAtsushi Murai     if (strcmp(*argv, "P_ZERO") == 0 ||
595af57ed9fSAtsushi Murai 	strcmp(*argv, "P_ODD") == 0 || strcmp(*argv, "P_EVEN") == 0) {
596af57ed9fSAtsushi Murai       ChangeParity(*argv++);
597af57ed9fSAtsushi Murai       continue;
598af57ed9fSAtsushi Murai     }
599af57ed9fSAtsushi Murai     state = ExpectString(*argv++);
600af57ed9fSAtsushi Murai     switch (state) {
601af57ed9fSAtsushi Murai     case MATCH:
602af57ed9fSAtsushi Murai       if (*argv)
603af57ed9fSAtsushi Murai 	SendString(*argv++);
604af57ed9fSAtsushi Murai       break;
605af57ed9fSAtsushi Murai     case ABORT:
606af57ed9fSAtsushi Murai #ifdef notdef
607af57ed9fSAtsushi Murai       HangupModem();
608af57ed9fSAtsushi Murai #endif
609af57ed9fSAtsushi Murai     case NOMATCH:
610af57ed9fSAtsushi Murai       return(NOMATCH);
611af57ed9fSAtsushi Murai     }
612af57ed9fSAtsushi Murai   }
613af57ed9fSAtsushi Murai   return(MATCH);
614af57ed9fSAtsushi Murai }
615