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