callers.c revision 1219:f89f56c2d9ac
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22
23/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
24/*	  All Rights Reserved	*/
25
26/*
27 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
28 * Use is subject to license terms.
29 */
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33#include "mt.h"
34#include "uucp.h"
35
36static void alarmtr(int);
37static jmp_buf Sjbuf;
38static char *fdig(char *);
39#ifndef SMALL
40static char *strecpy(char *, char *, char *);
41#endif
42static int interface(const char *);
43static int fd_mklock(int);
44static int getdialline(char *, int);
45static int chat(int, char *[], int, char *, char *);
46static void fixline(), fd_rmlock();
47static void translate(char *, char *);
48static int gdial(char *, char *[], int);
49static int	Modemctrl;
50static unsigned connecttime;
51static int (*Setup)();
52
53/*
54 *	to add a new caller:
55 *	declare the function that knows how to call on the device,
56 *	add a line to the callers table giving the name of the device
57 *	(from Devices file) and the name of the function
58 *	add the function to the end of this file
59 */
60
61#ifdef TLI
62static int	tlicall(char *[], char *[]);
63#endif /* TLI */
64
65static struct caller Caller[] = {
66
67#ifdef TLI
68	{"TLI",		tlicall},	/* AT&T Transport Layer Interface */
69#ifdef TLIS
70	{"TLIS",	tlicall},	/* AT&T Transport Layer Interface */
71#endif /*  TLIS  */
72#endif /* TLI */
73
74	{NULL,		NULL}		/* this line must be last */
75};
76
77/*
78 *	exphone - expand phone number for given prefix and number
79 *
80 *	return code - none
81 */
82
83static void
84exphone(char *in, char *out)
85{
86	FILE *fn;
87	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
88	char buf[BUFSIZ];
89	char *s1;
90
91	if (!isalpha(*in)) {
92		(void) strcpy(out, in);
93		return;
94	}
95
96	s1 = pre;
97	while (isalpha(*in))
98		*s1++ = *in++;
99	*s1 = NULLCHAR;
100	s1 = npart;
101	while (*in != NULLCHAR)
102		*s1++ = *in++;
103	*s1 = NULLCHAR;
104
105	tpre[0] = NULLCHAR;
106	fn = fopen(DIALCODES, "r");
107	if (fn != NULL) {
108		while (fgets(buf, BUFSIZ, fn)) {
109			if (sscanf(buf, "%60s%60s", p, tpre) < 1)
110				continue;
111			if (EQUALS(p, pre))
112				break;
113			tpre[0] = NULLCHAR;
114		}
115		(void) fclose(fn);
116	}
117
118	(void) strcpy(out, tpre);
119	(void) strcat(out, npart);
120}
121
122/*
123 * repphone - Replace \D and \T sequences in arg with phone
124 * expanding and translating as appropriate.
125 */
126static char *
127repphone(char *arg, char *phone, char *trstr)
128{
129	static char *pbuf;	/* dynamically allocated below */
130	char *fp, *tp;
131
132	if (pbuf == NULL) {
133		pbuf = malloc(2*(MAXPH+2));
134		if (pbuf == NULL)
135			return (arg);
136	}
137	for (tp = pbuf; *arg; arg++) {
138		if (*arg != '\\') {
139			*tp++ = *arg;
140			continue;
141		} else {
142			switch (*(arg+1)) {
143			case 'T':
144				exphone(phone, tp);
145				translate(trstr, tp);
146				for (; *tp; tp++)
147					;
148				arg++;
149				break;
150			case 'D':
151				for (fp = phone; *tp = *fp++; tp++)
152					;
153				arg++;
154				break;
155			default:
156				*tp++ = *arg;
157				break;
158			}
159		}
160	}
161	*tp = '\0';
162	return (pbuf);
163}
164
165static uint_t saved_mode;
166static char saved_dcname[20];
167
168/*
169 * processdev - Process a line from the Devices file
170 *
171 * return codes:
172 *	file descriptor  -  succeeded
173 *	FAIL  -  failed
174 */
175static int
176processdev(char *flds[], char *dev[])
177{
178	int dcf = -1;
179	struct caller	*ca;
180	char *args[D_MAX+1], dcname[20];
181	char **sdev;
182	static int pop_push(int);
183	static void setdevcfg(char *, char *);
184	int nullfd;
185	char *phonecl;			/* clear phone string */
186	char phoneex[2*(MAXPH+2)];	/* expanded phone string */
187	static void ttygenbrk(int);
188	struct termio tty_orig;
189	int ret_orig = -1;
190
191	sdev = dev;
192	/*	set up default "break" routine	*/
193	genbrk = ttygenbrk;
194
195	/*	initialize Devconfig info	*/
196	DEBUG(5, "processdev: calling setdevcfg(%s, ", Progname);
197	DEBUG(5, "%s)\n", flds[F_TYPE]);
198	setdevcfg(Progname, flds[F_TYPE]);
199
200	for (ca = Caller; ca->CA_type != NULL; ca++) {
201		/* This will find built-in caller functions */
202		if (EQUALS(ca->CA_type, dev[D_CALLER])) {
203			DEBUG(5, "Internal caller type %s\n", dev[D_CALLER]);
204			if (dev[D_ARG] == NULL) {
205				/* if NULL - assume translate */
206				/* needed for for loop later to mark the end */
207				dev[D_ARG+1] = NULL;
208				dev[D_ARG] = "\\T";
209			}
210			dev[D_ARG] = repphone(dev[D_ARG], flds[F_PHONE], "");
211			if ((dcf = (*(ca->CA_caller))(flds, dev)) < 0)
212				return (dcf);
213			if (interface(ca->CA_type)) {
214				DEBUG(5, "interface(%s) failed", ca->CA_type);
215				Uerror = SS_DEVICE_FAILED;
216				/*	restore vanilla unix interface	*/
217				(void) interface("UNIX");
218				return (FAIL);
219			}
220			dev += 2; /* Skip to next CALLER and ARG */
221			break;
222		}
223	}
224	if (dcf == -1) {
225		/* Here if not a built-in caller function */
226
227		/* We do locking (file and advisory) after open	*/
228
229		/*
230		 * Open the line
231		 */
232		if (*dev[D_LINE] != '/') {
233			(void) snprintf(dcname, sizeof (dcname),
234							"/dev/%s", dev[D_LINE]);
235		} else {
236			(void) strcpy(dcname, dev[D_LINE]);
237		}
238		/* take care of the possible partial open fd */
239		(void) close(nullfd = open("/", O_RDONLY));
240		if (setjmp(Sjbuf)) {
241			(void) close(nullfd);
242			DEBUG(1, "generic open timeout\n%s", "");
243			logent("generic open", "TIMEOUT");
244			Uerror = SS_CANT_ACCESS_DEVICE;
245			goto bad;
246		}
247		(void) signal(SIGALRM, alarmtr);
248		(void) alarm(10);
249		if (Modemctrl) {
250			DEBUG(7, "opening with O_NDELAY set\n%s", "");
251			dcf = open(dcname, (O_RDWR | O_NDELAY));
252			saved_mode = O_RDWR | O_NDELAY;
253		} else {
254			dcf = open(dcname, O_RDWR);
255			saved_mode = O_RDWR;
256		}
257		(void) strcpy(saved_dcname, dcname);
258		(void) alarm(0);
259		if (dcf < 0) {
260			DEBUG(1, "generic open failed, errno = %d\n", errno);
261			(void) close(nullfd);
262			logent("generic open", "FAILED");
263			Uerror = SS_CANT_ACCESS_DEVICE;
264			goto bad;
265		}
266
267		/* check locks BEFORE modifying the stream */
268
269		if (fd_mklock(dcf) != SUCCESS) {
270			DEBUG(1, "failed to lock device %s\n", dcname);
271			Uerror = SS_LOCKED_DEVICE;
272			goto bad;
273		}
274
275		if (Modemctrl) {
276			DEBUG(7, "clear O_NDELAY\n%s", "");
277			if (fcntl(dcf, F_SETFL,
278			    (fcntl(dcf, F_GETFL, 0) & ~O_NDELAY)) < 0) {
279				DEBUG(7, "clear O_NDELAY failed, errno %d\n",
280								errno);
281				Uerror = SS_DEVICE_FAILED;
282				goto bad;
283			}
284		}
285	}
286
287	if ((*Setup)(MASTER, &dcf, &dcf)) {
288		/*	any device|system lock files we should remove?	*/
289		DEBUG(5, "MASTER Setup failed%s", "");
290		Uerror = SS_DEVICE_FAILED;
291		goto bad;
292	}
293
294	/* configure any requested streams modules */
295	if (!pop_push(dcf)) {
296		DEBUG(5, "STREAMS module configuration failed%s\n", "");
297		Uerror = SS_DEVICE_FAILED;
298		goto bad;
299	}
300
301	/* save initial state of line in case script fails */
302	ret_orig = ioctl(dcf, TCGETA, &tty_orig);
303
304	/* use sdev[] since dev[] is incremented for internal callers */
305	fixline(dcf, atoi(fdig(sdev[D_CLASS])), D_DIRECT);
306
307	/*
308	 * Now loop through the remaining callers and chat
309	 * according to scripts in dialers file.
310	 */
311	for (; dev[D_CALLER] != NULL; dev += 2) {
312		int w;
313		/*
314		 * Scan Dialers file to find an entry
315		 */
316		if ((w = gdial(dev[D_CALLER], args, D_MAX)) < 1) {
317			logent("generic call to gdial", "FAILED");
318			Uerror = SS_CANT_ACCESS_DEVICE;
319			goto bad;
320		}
321		if (w <= 2)	/* do nothing - no chat */
322			break;
323		/*
324		 * Translate the phone number
325		 */
326		if (dev[D_ARG] == NULL) {
327			/* if NULL - assume no translation */
328			/* needed for for loop to mark the end */
329			dev[D_ARG+1] = NULL;
330			dev[D_ARG] = "\\D";
331		}
332
333		phonecl = repphone(dev[D_ARG], flds[F_PHONE], args[1]);
334		exphone(phonecl, phoneex);
335		translate(args[1], phoneex);
336		/*
337		 * Chat
338		 */
339		if (chat(w-2, &args[2], dcf, phonecl, phoneex) != SUCCESS) {
340			CDEBUG(5, "\nCHAT gdial(%s) FAILED\n", dev[D_CALLER]);
341			Uerror = SS_CHAT_FAILED;
342			goto bad;
343		}
344	}
345	/*
346	 * Success at last!
347	 */
348	(void) strcpy(Dc, sdev[D_LINE]);
349	return (dcf);
350bad:
351	if (dcf >= 0) {
352		/* reset line settings if we got them in the beginning */
353		if (ret_orig == 0)
354			(void) ioctl(dcf, TCSETAW, &tty_orig);
355		fd_rmlock(dcf);
356		(void) close(dcf);
357	}
358	/*	restore vanilla unix interface	*/
359	(void) interface("UNIX");
360	return (FAIL);
361}
362
363/*
364 * clear_hup()	clear the hangup state of the given device
365 */
366static int
367clear_hup(int dcf)
368{
369	int ndcf;
370	if ((ndcf = open(saved_dcname, saved_mode)) < 0) {
371		return (FAIL);
372	}
373	if (ndcf != dcf) {
374		(void) close(ndcf);
375	}
376	return (SUCCESS);
377}
378
379
380/*
381 * translate the pairs of characters present in the first
382 * string whenever the first of the pair appears in the second
383 * string.
384 */
385static void
386translate(char *ttab, char *str)
387{
388	char *s;
389
390	for (; *ttab && *(ttab+1); ttab += 2)
391		for (s = str; *s; s++)
392			if (*ttab == *s)
393				*s = *(ttab+1);
394}
395
396#define	MAXLINE	512
397/*
398 * Get the information about the dialer.
399 * gdial(type, arps, narps)
400 *	type	-> type of dialer (e.g., penril)
401 *	arps	-> array of pointers returned by gdial
402 *	narps	-> number of elements in array returned by gdial
403 * Return value:
404 *	-1	-> Can't open DIALERFILE
405 *	0	-> requested type not found
406 *	>0	-> success - number of fields filled in
407 */
408static int
409gdial(char *type, char *arps[], int narps)
410{
411	static char *info;	/* dynamically allocated MAXLINE */
412	int na;
413	static void dialreset(void);
414#ifndef SMALL
415	static char *currdial(void);
416#endif
417
418	DEBUG(2, "gdial(%s) called\n", type);
419	if (info == NULL) {
420		info = malloc(MAXLINE);
421		if (info == NULL) {
422			DEBUG(1, "malloc failed for info in gdial\n", 0);
423			return (0);
424		}
425	}
426	while (getdialline(info, MAXLINE)) {
427		if ((info[0] == '#') || (info[0] == ' ') ||
428		    (info[0] == '\t') || (info[0] == '\n'))
429			continue;
430		if ((na = getargs(info, arps, narps)) == 0)
431			continue;
432		if (EQUALS(arps[0], type)) {
433		    DEBUG(5, "Trying caller script '%s'", type);
434		    DEBUG(5, " from '%s'.\n", currdial());
435		    dialreset();
436		    bsfix(arps);
437		    return (na);
438		}
439	}
440	DEBUG(1, "%s not found in Dialers file\n", type);
441	dialreset();
442	return (0);
443}
444
445#ifdef TLI
446/*
447 *
448 * AT&T Transport Layer Interface
449 *
450 * expected in Devices
451 *	TLI line1 - - TLI
452 * or
453 *	TLIS line1 - - TLIS
454 *
455 */
456
457#include <tiuser.h>
458
459static void tfaillog(int fd, const char *s);
460
461#define	CONNECT_ATTEMPTS	3
462#define	TFREE(p, type)	if ((p)) (void) t_free((char *)(p), (type))
463
464/*
465 * returns fd to remote uucp daemon
466 */
467/*ARGSUSED*/
468static int
469tlicall(char *flds[], char *dev[])
470{
471	char		addrbuf[ BUFSIZ ];
472	char		devname[MAXNAMESIZE];
473	int		fd;
474	int		i, j;
475	struct t_bind	*bind_ret = 0;
476	struct t_info	tinfo;
477	struct t_call	*sndcall = 0, *rcvcall = 0;
478
479	static struct netbuf	*stoa(char *, struct netbuf *);
480
481	if (dev[D_LINE][0] != '/') {
482		/*	dev holds device name relative to /dev	*/
483		(void) snprintf(devname, sizeof (devname),
484							"/dev/%s", dev[D_LINE]);
485	} else {
486		/*	dev holds full path name of device	*/
487		(void) strcpy(devname, dev[D_LINE]);
488	}
489	/* gimme local transport endpoint */
490	errno = t_errno = 0;
491	if (setjmp(Sjbuf)) {
492		DEBUG(1, "t_open timeout\n%s", "");
493		logent("t_open", "TIMEOUT");
494		Uerror = SS_NO_DEVICE;
495		return (FAIL);
496	}
497	(void) signal(SIGALRM, alarmtr);
498	(void) alarm(5);
499	fd = t_open(devname, O_RDWR, &tinfo);
500	(void) alarm(0);
501	if (fd < 0) {
502		tfaillog(fd, "t_open");
503		Uerror = SS_NO_DEVICE;
504		return (FAIL);
505	}
506	if (fd_mklock(fd) != SUCCESS) {
507		(void) t_close(fd);
508		DEBUG(1, "tlicall: failed to lock device %s\n", devname);
509		Uerror = SS_LOCKED_DEVICE;
510		return (FAIL);
511	}
512
513	/* allocate tli structures	*/
514	errno = t_errno = 0;
515	/* LINTED pointer cast */
516	if ((bind_ret = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL)) == NULL ||
517	    /* LINTED pointer cast */
518	    (sndcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) == NULL ||
519	    /* LINTED pointer cast */
520	    (rcvcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) == NULL) {
521		tfaillog(fd, "t_alloc");
522		TFREE(bind_ret, T_BIND);
523		TFREE(sndcall, T_CALL);
524		TFREE(rcvcall, T_CALL);
525		Uerror = SS_NO_DEVICE;
526		return (FAIL);
527	}
528
529	/* bind */
530	errno = t_errno = 0;
531	if (t_bind(fd, (struct t_bind *)0, bind_ret) < 0) {
532		tfaillog(fd, "t_bind");
533		TFREE(bind_ret, T_BIND);
534		TFREE(sndcall, T_CALL);
535		TFREE(rcvcall, T_CALL);
536		Uerror = SS_NO_DEVICE;
537		fd_rmlock(fd);
538		(void) t_close(fd);
539		return (FAIL);
540	}
541	DEBUG(5, "tlicall: bound to %s\n", bind_ret->addr.buf);
542
543	/*
544	 * Prepare to connect.
545	 *
546	 * If address begins with "\x", "\X", "\o", or "\O",
547	 * assume is hexadecimal or octal address and use stoa()
548	 * to convert it.
549	 *
550	 * Else is usual uucico address -- only \N's left to process.
551	 * Walk thru connection address, changing \N's to NULLCHARs.
552	 * Note:  If a NULLCHAR must be part of the connection address,
553	 * it must be overtly included in the address.  One recommended
554	 * way is to do it in the Devices file, thusly:
555	 *		Netname /dev/netport - - TLI \D\000
556	 * bsfix() turns \000 into \N and then the loop below makes it a
557	 * real, included-in-the-length null-byte.
558	 *
559	 * The DEBUG must print the strecpy'd address (so that
560	 * non-printables will have been replaced with C escapes).
561	 */
562
563	DEBUG(5, "t_connect to addr \"%s\"\n",
564		strecpy(addrbuf, dev[D_ARG], "\\"));
565
566	if (dev[D_ARG][0] == '\\' && (dev[D_ARG][1] == 'x' ||
567			dev[D_ARG][1] == 'X' || dev[D_ARG][1] == 'o' ||
568			dev[D_ARG][1] == 'O')) {
569		if (stoa(dev[D_ARG], &(sndcall->addr)) == NULL) {
570			DEBUG(5, "tlicall: stoa failed\n%s", "");
571			logent("tlicall", "string-to-address failed");
572			TFREE(bind_ret, T_BIND);
573			TFREE(sndcall, T_CALL);
574			TFREE(rcvcall, T_CALL);
575			Uerror = SS_NO_DEVICE;
576			fd_rmlock(fd);
577			(void) t_close(fd);
578			return (FAIL);
579		}
580	} else {
581		for (i = j = 0; i < BUFSIZ && dev[D_ARG][i] != NULLCHAR;
582								++i, ++j) {
583			if (dev[D_ARG][i] == '\\' && dev[D_ARG][i+1] == 'N') {
584				addrbuf[j] = NULLCHAR;
585				++i;
586			} else {
587				addrbuf[j] = dev[D_ARG][i];
588			}
589		}
590		sndcall->addr.buf = addrbuf;
591		sndcall->addr.len = j;
592	}
593
594	if (setjmp(Sjbuf)) {
595		DEBUG(4, "timeout tlicall\n%s", "");
596		logent("tlicall", "TIMEOUT");
597		TFREE(bind_ret, T_BIND);
598		TFREE(sndcall, T_CALL);
599		TFREE(rcvcall, T_CALL);
600		Uerror = SS_NO_DEVICE;
601		fd_rmlock(fd);
602		(void) t_close(fd);
603		return (FAIL);
604	}
605	(void) signal(SIGALRM, alarmtr);
606	(void) alarm(connecttime);
607
608	/* connect to the service -- some listeners can't handle */
609	/* multiple connect requests, so try it a few times */
610	errno = t_errno = 0;
611	for (i = 0; i < CONNECT_ATTEMPTS; ++i) {
612		if (t_connect(fd, sndcall, rcvcall) == 0)
613			break;
614		if ((t_errno == TLOOK) && (t_look(fd) == T_DISCONNECT)) {
615			(void) t_rcvdis(fd, NULL);
616			(void) alarm(0);
617		} else {
618			(void) alarm(0);
619			tfaillog(fd, "t_connect");
620			TFREE(bind_ret, T_BIND);
621			TFREE(sndcall, T_CALL);
622			TFREE(rcvcall, T_CALL);
623			Uerror = SS_DIAL_FAILED;
624			fd_rmlock(fd);
625			(void) t_close(fd);
626			return (FAIL);
627		}
628	}
629	(void) alarm(0);
630	TFREE(bind_ret, T_BIND);
631	TFREE(sndcall, T_CALL);
632	TFREE(rcvcall, T_CALL);
633	if (i == CONNECT_ATTEMPTS) {
634		tfaillog(fd, "t_connect");
635		Uerror = SS_DIAL_FAILED;
636		fd_rmlock(fd);
637		(void) t_close(fd);
638		return (FAIL);
639	}
640	errno = t_errno = 0;
641	(void) strcpy(Dc, dev[D_CALLER]);
642	return (fd);
643}
644#endif /* TLI */
645