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