xref: /illumos-gate/usr/src/lib/libnsl/dial/callers.c (revision 7c478bd9)
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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright 2004 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 #include <rpc/trace.h>
35 
36 #ifdef BSD4_2
37 #include <netdb.h>
38 #include <netinet/in.h>
39 #include <sys/socket.h>
40 #endif
41 #ifdef UNET
42 #include  "UNET/unetio.h"
43 #include  "UNET/tcp.h"
44 #endif
45 
46 
47 EXTERN void alarmtr();
48 EXTERN jmp_buf Sjbuf;
49 EXTERN char *fdig(), *strecpy();
50 EXTERN int interface();
51 EXTERN int fd_mklock(), fd_cklock(), chat(), getdialline();
52 EXTERN void fixline(), fd_rmlock();
53 static void translate();
54 static int gdial();
55 EXTERN int	Modemctrl;
56 EXTERN unsigned connecttime;
57 EXTERN int (*Setup)();
58 
59 extern int	_fcntl(int, int, ...);
60 
61 /*
62  *	to add a new caller:
63  *	declare the function that knows how to call on the device,
64  *	add a line to the callers table giving the name of the device
65  *	(from Devices file) and the name of the function
66  *	add the function to the end of this file
67  */
68 
69 #ifdef DIAL801
70 EXTERN int	dial801();
71 EXTERN int	open801();
72 #endif
73 
74 #ifdef DATAKIT
75 EXTERN int	dkcall();
76 #endif /* DATAKIT */
77 
78 #ifdef V8
79 int	Dialout();
80 #endif
81 
82 #ifdef TCP
83 GLOBAL int	unetcall();
84 GLOBAL int	tcpcall();
85 #endif /* TCP */
86 
87 #ifdef SYTEK
88 int	sytcall();
89 #endif /* SYTEK */
90 
91 #ifdef TLI
92 EXTERN int	tlicall();
93 #endif /* TLI */
94 
95 static struct caller Caller[] = {
96 
97 #ifdef DIAL801
98 	{"801",		dial801},
99 	{"212",		dial801},
100 #endif /* DIAL801 */
101 
102 #ifdef V8
103 	{"Dialout",	Dialout},	/* ditto but using dialout(III) */
104 #endif
105 
106 #ifdef TCP
107 #ifdef BSD4_2
108 	{"TCP",		tcpcall},	/* 4.2BSD sockets */
109 #else /* !BSD4_2 */
110 #ifdef UNET
111 	{"TCP",		unetcall},	/* 3com implementation of tcp */
112 	{"Unetserver",	unetcall},
113 #endif /* UNET */
114 #endif /* BSD4_2 */
115 #endif /* TCP */
116 
117 #ifdef DATAKIT
118 	{"DK",		dkcall},	/* standard AT&T DATAKIT VCS caller */
119 #endif /* DATAKIT */
120 
121 #ifdef SYTEK
122 	{"Sytek",	sytcall},	/* untested but should work */
123 #endif /* SYTEK */
124 
125 #ifdef TLI
126 	{"TLI",		tlicall},	/* AT&T Transport Layer Interface */
127 #ifdef TLIS
128 	{"TLIS",	tlicall},	/* AT&T Transport Layer Interface */
129 #endif /*  TLIS  */
130 #endif /* TLI */
131 
132 	{NULL, 		NULL}		/* this line must be last */
133 };
134 
135 /*
136  *	exphone - expand phone number for given prefix and number
137  *
138  *	return code - none
139  */
140 
141 static void
142 exphone(in, out)
143 char *in, *out;
144 {
145 	FILE *fn;
146 	char pre[MAXPH], npart[MAXPH], tpre[MAXPH], p[MAXPH];
147 	char buf[BUFSIZ];
148 	char *s1;
149 
150 	trace1(TR_exphone, 0);
151 	if (!isalpha(*in)) {
152 		(void) strcpy(out, in);
153 		trace1(TR_exphone, 1);
154 		return;
155 	}
156 
157 	s1=pre;
158 	while (isalpha(*in))
159 		*s1++ = *in++;
160 	*s1 = NULLCHAR;
161 	s1 = npart;
162 	while (*in != NULLCHAR)
163 		*s1++ = *in++;
164 	*s1 = NULLCHAR;
165 
166 	tpre[0] = NULLCHAR;
167 	fn = fopen(DIALCODES, "r");
168 	if (fn != NULL) {
169 		while (fgets(buf, BUFSIZ, fn)) {
170 			if (sscanf(buf, "%s%s", p, tpre) < 1)
171 				continue;
172 			if (EQUALS(p, pre))
173 				break;
174 			tpre[0] = NULLCHAR;
175 		}
176 		fclose(fn);
177 	}
178 
179 	(void) strcpy(out, tpre);
180 	(void) strcat(out, npart);
181 	trace1(TR_exphone, 1);
182 	return;
183 }
184 
185 /*
186  * repphone - Replace \D and \T sequences in arg with phone
187  * expanding and translating as appropriate.
188  */
189 static char *
190 repphone(arg, phone, trstr)
191 register char *arg, *phone, *trstr;
192 {
193 	static char *pbuf;	/* dynamically allocated below */
194 	register char *fp, *tp;
195 
196 	trace1(TR_repphone, 0);
197 	if (pbuf == NULL) {
198 		pbuf = (char *)malloc(2*(MAXPH+2));
199 		if (pbuf == NULL)
200 			return (arg);
201 	}
202 	for (tp=pbuf; *arg; arg++) {
203 		if (*arg != '\\') {
204 			*tp++ = *arg;
205 			continue;
206 		} else {
207 			switch (*(arg+1)) {
208 			case 'T':
209 				exphone(phone, tp);
210 				translate(trstr, tp);
211 				for (; *tp; tp++)
212 				    ;
213 				arg++;
214 				break;
215 			case 'D':
216 				for (fp=phone; *tp = *fp++; tp++)
217 				    ;
218 				arg++;
219 				break;
220 			default:
221 				*tp++ = *arg;
222 				break;
223 			}
224 		}
225 	}
226 	*tp = '\0';
227 	trace1(TR_repphone, 1);
228 	return (pbuf);
229 }
230 
231 static u_int saved_mode;
232 static char saved_dcname[20];
233 
234 /*
235  * processdev - Process a line from the Devices file
236  *
237  * return codes:
238  *	file descriptor  -  succeeded
239  *	FAIL  -  failed
240  */
241 GLOBAL int
242 processdev(flds, dev)
243 register char *flds[], *dev[];
244 {
245 	int dcf = -1;
246 	register struct caller	*ca;
247 	char *args[D_MAX+1], dcname[20];
248 	register char **sdev;
249 	EXTERN int pop_push();
250 	EXTERN void  setdevcfg();
251 	int nullfd;
252 	char *phonecl;			/* clear phone string */
253 	char phoneex[2*(MAXPH+2)];	/* expanded phone string */
254 	EXTERN void ttygenbrk();
255 	struct termio tty_orig;
256 	int ret_orig = -1;
257 
258 	trace1(TR_processdev, 0);
259 	sdev = dev;
260 	/*	set up default "break" routine	*/
261 	genbrk = ttygenbrk;
262 
263 	/*	initialize Devconfig info	*/
264 	DEBUG(5, "processdev: calling setdevcfg(%s, ", Progname);
265 	DEBUG(5, "%s)\n", flds[F_TYPE]);
266 	setdevcfg(Progname, flds[F_TYPE]);
267 
268 	for (ca = Caller; ca->CA_type != NULL; ca++) {
269 		/* This will find built-in caller functions */
270 		if (EQUALS(ca->CA_type, dev[D_CALLER])) {
271 			DEBUG(5, "Internal caller type %s\n", dev[D_CALLER]);
272 			if (dev[D_ARG] == NULL) {
273 				/* if NULL - assume translate */
274 				dev[D_ARG+1] = NULL;	/* needed for for loop later to mark the end */
275 				dev[D_ARG] = "\\T";
276 			}
277 			dev[D_ARG] = repphone(dev[D_ARG], flds[F_PHONE], "");
278 			if ((dcf = (*(ca->CA_caller))(flds, dev)) < 0) {
279 				trace1(TR_processdev, 1);
280 				return (dcf) ;
281 			}
282 			if (interface(ca->CA_type)) {
283 				DEBUG(5, "interface(%s) failed", ca->CA_type);
284 				Uerror = SS_DEVICE_FAILED;
285 				/*	restore vanilla unix interface	*/
286 				(void)interface("UNIX");
287 				trace1(TR_processdev, 1);
288 				return (FAIL);
289 			}
290 			dev += 2; /* Skip to next CALLER and ARG */
291 			break;
292 		}
293 	}
294 	if (dcf == -1) {
295 		/* Here if not a built-in caller function */
296 
297 		/* We do locking (file and advisory) after open	*/
298 
299 		/*
300 		 * Open the line
301 		 */
302 		if (*dev[D_LINE] != '/') {
303 			(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
304 		} else {
305 			(void) strcpy(dcname, dev[D_LINE]);
306 		}
307 		/* take care of the possible partial open fd */
308 		(void) close(nullfd = open("/", O_RDONLY));
309 		if (setjmp(Sjbuf)) {
310 			(void) close(nullfd);
311 			DEBUG(1, "generic open timeout\n%s", "");
312 			logent("generic open", "TIMEOUT");
313 			Uerror = SS_CANT_ACCESS_DEVICE;
314 			goto bad;
315 		}
316 		(void) signal(SIGALRM, alarmtr);
317 		(void) alarm(10);
318 		if (Modemctrl) {
319 			DEBUG(7, "opening with O_NDELAY set\n%s", "");
320 			dcf = open(dcname, (O_RDWR | O_NDELAY) );
321 			saved_mode = O_RDWR | O_NDELAY;
322 		} else {
323 			dcf = open(dcname, O_RDWR );
324 			saved_mode = O_RDWR;
325 		}
326 		strcpy(saved_dcname, dcname);
327 		(void) alarm(0);
328 		if (dcf < 0) {
329 			DEBUG(1, "generic open failed, errno = %d\n", errno);
330 			(void) close(nullfd);
331 			logent("generic open", "FAILED");
332 			Uerror = SS_CANT_ACCESS_DEVICE;
333 			goto bad;
334 		}
335 
336 		/* check locks BEFORE modifying the stream */
337 
338 		if (fd_mklock(dcf) != SUCCESS) {
339 			DEBUG(1, "failed to lock device %s\n", dcname);
340 			Uerror = SS_LOCKED_DEVICE;
341 			goto bad;
342 		}
343 
344 		if (Modemctrl) {
345 			DEBUG(7, "clear O_NDELAY\n%s", "");
346 			if (_fcntl(dcf, F_SETFL,
347 				(_fcntl(dcf, F_GETFL, 0) & ~O_NDELAY)) < 0) {
348 				DEBUG(7, "clear O_NDELAY failed, errno %d\n", errno);
349 				Uerror = SS_DEVICE_FAILED;
350 				goto bad;
351 			}
352 		}
353 	}
354 
355 	if ((*Setup)(MASTER, &dcf, &dcf)) {
356 		/*	any device|system lock files we should remove?	*/
357 		DEBUG(5, "MASTER Setup failed%s", "");
358 		Uerror = SS_DEVICE_FAILED;
359 		goto bad;
360 	}
361 
362 	/* configure any requested streams modules */
363 	if (!pop_push(dcf)) {
364 		DEBUG(5, "STREAMS module configuration failed%s\n","");
365 		Uerror = SS_DEVICE_FAILED;
366 		goto bad;
367 	}
368 
369 	/* save initial state of line in case script fails */
370 	ret_orig = ioctl(dcf, TCGETA, &tty_orig);
371 
372 	/* use sdev[] since dev[] is incremented for internal callers */
373 	fixline(dcf, atoi(fdig(sdev[D_CLASS])), D_DIRECT);
374 
375 	/*
376 	 * Now loop through the remaining callers and chat
377 	 * according to scripts in dialers file.
378 	 */
379 	for (; dev[D_CALLER] != NULL; dev += 2) {
380 		register int w;
381 		/*
382 		 * Scan Dialers file to find an entry
383 		 */
384 		if ((w = gdial(dev[D_CALLER], args, D_MAX)) < 1) {
385 			logent("generic call to gdial", "FAILED");
386 			Uerror = SS_CANT_ACCESS_DEVICE;
387 			goto bad;
388 		}
389 		if (w <= 2)	/* do nothing - no chat */
390 			break;
391 		/*
392 		 * Translate the phone number
393 		 */
394 		if (dev[D_ARG] == NULL) {
395 			/* if NULL - assume no translation */
396 			dev[D_ARG+1] = NULL; /* needed for for loop to mark the end */
397 			dev[D_ARG] = "\\D";
398 		}
399 
400 		phonecl = repphone(dev[D_ARG], flds[F_PHONE], args[1]);
401 		exphone(phonecl, phoneex);
402 		translate(args[1], phoneex);
403 		/*
404 		 * Chat
405 		 */
406 		if (chat(w-2, &args[2], dcf, phonecl, phoneex) != SUCCESS) {
407 			CDEBUG(5, "\nCHAT gdial(%s) FAILED\n", dev[D_CALLER]);
408 			Uerror = SS_CHAT_FAILED;
409 			goto bad;
410 		}
411 	}
412 	/*
413 	 * Success at last!
414 	 */
415 	strcpy(Dc, sdev[D_LINE]);
416 	trace1(TR_processdev, 1);
417 	return (dcf);
418 bad:
419 	if (dcf >= 0) {
420 		/* reset line settings if we got them in the beginning */
421 		if (ret_orig == 0)
422 			(void) ioctl(dcf, TCSETAW, &tty_orig);
423 		fd_rmlock(dcf);
424 		(void)close(dcf);
425 	}
426 	/*	restore vanilla unix interface	*/
427 	(void)interface("UNIX");
428 	trace1(TR_processdev, 1);
429 	return (FAIL);
430 }
431 
432 /*
433  * clear_hup()	clear the hangup state of the given device
434  */
435 GLOBAL int
436 clear_hup(dcf)
437 int dcf;
438 {
439 	int ndcf;
440 	if ((ndcf = open(saved_dcname, saved_mode)) < 0) {
441 		return (FAIL);
442 	}
443 	if (ndcf != dcf) {
444 		close(ndcf);
445 	}
446 	return (SUCCESS);
447 }
448 
449 
450 /*
451  * translate the pairs of characters present in the first
452  * string whenever the first of the pair appears in the second
453  * string.
454  */
455 static void
456 translate(ttab, str)
457 register char *ttab, *str;
458 {
459 	register char *s;
460 	trace1(TR_translate, 0);
461 
462 	for (;*ttab && *(ttab+1); ttab += 2)
463 		for (s=str;*s;s++)
464 			if (*ttab == *s)
465 				*s = *(ttab+1);
466 	trace1(TR_translate, 1);
467 	return;
468 }
469 
470 #define MAXLINE	512
471 /*
472  * Get the information about the dialer.
473  * gdial(type, arps, narps)
474  *	type	-> type of dialer (e.g., penril)
475  *	arps	-> array of pointers returned by gdial
476  *	narps	-> number of elements in array returned by gdial
477  * Return value:
478  *	-1	-> Can't open DIALERFILE
479  *	0	-> requested type not found
480  *	>0	-> success - number of fields filled in
481  */
482 static int
483 gdial(type, arps, narps)
484 register char *type, *arps[];
485 register int narps;
486 {
487 	static char *info;	/* dynamically allocated MAXLINE */
488 	int na;
489 	EXTERN void dialreset();
490 	EXTERN char * currdial();
491 
492 	trace2(TR_gdial, 0, narps);
493 	DEBUG(2, "gdial(%s) called\n", type);
494 	if (info == NULL) {
495 		info = (char *)malloc(MAXLINE);
496 		if (info == NULL) {
497 			DEBUG(1, "malloc failed for info in gdial\n", 0);
498 			return (0);
499 		}
500 	}
501 	while (getdialline(info, MAXLINE)) {
502 		if ((info[0] == '#') || (info[0] == ' ') ||
503 		    (info[0] == '\t') || (info[0] == '\n'))
504 			continue;
505 		if ((na = getargs(info, arps, narps)) == 0)
506 			continue;
507 		if (EQUALS(arps[0], type)) {
508 		    DEBUG(5, "Trying caller script '%s'", type);
509 		    DEBUG(5, " from '%s'.\n", currdial());
510 		    dialreset();
511 		    bsfix(arps);
512 		    trace2(TR_gdial, 1, narps);
513 		    return (na);
514 		}
515 	}
516 	DEBUG(1, "%s not found in Dialers file\n", type);
517 	dialreset();
518 	trace2(TR_gdial, 1, narps);
519 	return (0);
520 }
521 
522 
523 #ifdef DATAKIT
524 
525 /*
526  *	dkcall(flds, dev)	make a DATAKIT VCS connection
527  *				  DATAKIT VCS is a trademark of AT&T
528  *
529  *	return codes:
530  *		>0 - file number - ok
531  *		FAIL - failed
532  */
533 
534 #include "dk.h"
535 EXTERN int dkdial();
536 
537 /*ARGSUSED*/
538 GLOBAL int
539 dkcall(flds, dev)
540 char *flds[], *dev[];
541 {
542 	register fd;
543 #ifdef V8
544 	extern int cdkp_ld;
545 #endif
546 
547 	char	dialstring[64];
548 	EXTERN	void dkbreak();
549 
550 	trace1(TR_dkcall, 0);
551 	strcpy(dialstring, dev[D_ARG]);
552 	DEBUG(4, "dkcall(%s)\n", dialstring);
553 
554 
555 #ifdef V8
556 	if (setjmp(Sjbuf)) {
557 		Uerror = SS_DIAL_FAILED;
558 		trace1(TR_dkcall, 1);
559 		return (FAIL);
560 	}
561 
562 	(void) signal(SIGALRM, alarmtr);
563 	(void) alarm(connecttime);
564 	DEBUG(4, "tdkdial(%s", flds[F_PHONE]);
565 	DEBUG(4, ", %d)\n", atoi(dev[D_CLASS]));
566     	if ((fd = tdkdial(flds[F_PHONE], atoi(dev[D_CLASS]))) >= 0)
567 	    if (dkproto(fd, cdkp_ld) < 0)
568 	       {
569 	    	close(fd);
570 	    	fd = -1;
571 	       }
572 	(void) alarm(0);
573 #else
574 	fd = dkdial(dialstring);
575 #endif
576 
577 	(void) strcpy(Dc, "DK");
578 	if (fd < 0) {
579 		Uerror = SS_DIAL_FAILED;
580 		trace1(TR_dkcall, 1);
581 		return (FAIL);
582 	}
583 	else {
584 		genbrk = dkbreak;
585 		trace1(TR_dkcall, 1);
586 		return (fd);
587 	}
588 }
589 
590 #endif /* DATAKIT */
591 
592 #ifdef TCP
593 
594 /*
595  *	tcpcall(flds, dev)	make ethernet/socket connection
596  *
597  *	return codes:
598  *		>0 - file number - ok
599  *		FAIL - failed
600  */
601 
602 #ifndef BSD4_2
603 /*ARGSUSED*/
604 GLOBAL int
605 tcpcall(flds, dev)
606 char	*flds[], *dev[];
607 {
608 	trace1(TR_tcpcall, 0);
609 	Uerror = SS_NO_DEVICE;
610 	trace1(TR_tcpcall, 1);
611 	return (FAIL);
612 }
613 #else /* BSD4_2 */
614 GLOBAL int
615 tcpcall(flds, dev)
616 char *flds[], *dev[];
617 {
618 	int ret;
619 	short port;
620 	struct servent *sp;
621 	struct hostent *hp;
622 	struct sockaddr_in sin;
623 
624 	trace1(TR_tcpcall, 0);
625 	port = atoi(dev[D_ARG]);
626 	if (port == 0) {
627 		sp = getservbyname("uucp", "tcp");
628 		ASSERT(sp != NULL, "No uucp server", 0, 0);
629 		port = sp->s_port;
630 	}
631 	else port = htons(port);
632 	hp = gethostbyname(flds[F_NAME]);
633 	if (hp == NULL) {
634 		logent("tcpopen", "no such host");
635 		Uerror = SS_NO_DEVICE;
636 		trace1(TR_tcpcall, 1);
637 		return (FAIL);
638 	}
639 	DEBUG(4, "tcpdial host %s, ", flds[F_NAME]);
640 	DEBUG(4, "port %d\n", ntohs(port));
641 
642 	ret = socket(AF_INET, SOCK_STREAM, 0);
643 	if (ret < 0) {
644 		char *errstr;
645 
646 		if ((errstr = strerror(errno)) != (char *) NULL) {
647 			DEBUG(5, "no socket: %s\n", errstr);
648 			logent("no socket", errstr);
649 		}
650 		else {
651 			DEBUG(5, "no socket, errno %d\n", errno);
652 			logent("tcpopen", "NO SOCKET");
653 		}
654 		Uerror = SS_NO_DEVICE;
655 		trace1(TR_tcpcall, 1);
656 		return (FAIL);
657 	}
658 	sin.sin_family = hp->h_addrtype;
659 	bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
660 	sin.sin_port = port;
661 	if (setjmp(Sjbuf)) {
662 		DEBUG(4, "timeout tcpopen\n%s", "");
663 		logent("tcpopen", "TIMEOUT");
664 		Uerror = SS_NO_DEVICE;
665 		trace1(TR_tcpcall, 1);
666 		return (FAIL);
667 	}
668 	(void) signal(SIGALRM, alarmtr);
669 	(void) alarm(connecttime);
670 	DEBUG(7, "family: %d\n", sin.sin_family);
671 	DEBUG(7, "port: %d\n", sin.sin_port);
672 	DEBUG(7, "addr: %08x\n",*((int *) &sin.sin_addr));
673 	if (connect(ret, (caddr_t)&sin, sizeof (sin)) < 0) {
674 		char *errstr;
675 
676 		(void) alarm(0);
677 		(void) close(ret);
678 		if ((errstr = strerror(errno)) != (char *) NULL) {
679 			DEBUG(5, "connect failed: %s\n", errstr);
680 			logent("connect failed", errstr);
681 		}
682 		else {
683 			DEBUG(5, "connect failed, errno %d\n", errno);
684 			logent("tcpopen", "CONNECT FAILED");
685 		}
686 		Uerror = SS_NO_DEVICE;
687 		trace1(TR_tcpcall, 1);
688 		return (FAIL);
689 	}
690 	(void) signal(SIGPIPE, SIG_IGN);  /* watch out for broken ipc link...*/
691 	(void) alarm(0);
692 	(void) strcpy(Dc, "IPC");
693 	trace1(TR_tcpcall, 1);
694  	return (ret);
695 }
696 
697 #endif /* BSD4_2 */
698 
699 /*
700  *	unetcall(flds, dev)	make ethernet connection
701  *
702  *	return codes:
703  *		>0 - file number - ok
704  *		FAIL - failed
705  */
706 
707 #ifndef UNET
708 GLOBAL int
709 unetcall(flds, dev)
710 char	*flds[], *dev[];
711 {
712 	trace1(TR_unetcall, 0);
713 	Uerror = SS_NO_DEVICE;
714 	trace1(TR_unetcall, 1);
715  	return (FAIL);
716 }
717 #else /* UNET */
718 GLOBAL int
719 unetcall(flds, dev)
720 char *flds[], *dev[];
721 {
722 	int ret;
723 	int port;
724 
725 	trace1(TR_unetcall, 0);
726 	port = atoi(dev[D_ARG]);
727 	DEBUG(4, "unetdial host %s, ", flds[F_NAME]);
728 	DEBUG(4, "port %d\n", port);
729 	(void) alarm(connecttime);
730 	ret = tcpopen(flds[F_NAME], port, 0, TO_ACTIVE, "rw");
731 	(void) alarm(0);
732 	endhnent();
733 	if (ret < 0) {
734 		DEBUG(5, "tcpopen failed: errno %d\n", errno);
735 		Uerror = SS_DIAL_FAILED;
736 		trace1(TR_unetcall, 1);
737 		return (FAIL);
738 	}
739 	(void) strcpy(Dc, "UNET");
740 	trace1(TR_unetcall, 1);
741 	return (ret);
742 }
743 #endif /* UNET */
744 
745 #endif /* TCP */
746 
747 #ifdef SYTEK
748 
749 /*
750  *	sytcall(flds, dev)	make a sytek connection
751  *
752  *	return codes:
753  *		>0 - file number - ok
754  *		FAIL - failed
755  */
756 
757 /*ARGSUSED*/
758 GLOBAL int
759 sytcall(flds, dev)
760 char *flds[], *dev[];
761 {
762 	int dcr, dcr2, nullfd, ret;
763 	char dcname[20], command[BUFSIZ];
764 
765 
766 	trace1(TR_sytcall, 0);
767 	(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
768 	DEBUG(4, "dc - %s, ", dcname);
769 	dcr = open(dcname, O_WRONLY|O_NDELAY);
770 	if (dcr < 0) {
771 		Uerror = SS_DIAL_FAILED;
772 		DEBUG(4, "OPEN FAILED %s\n", dcname);
773 		trace1(TR_sytcall, 1);
774 		return (FAIL);
775 	}
776 	if (fd_mklock(dcr) != SUCCESS) {
777 		(void)close(dcr);
778 		DEBUG(1, "failed to lock device %s\n", dcname);
779 		Uerror = SS_LOCKED_DEVICE;
780 		trace1(TR_sytcall, 1);
781 		return (FAIL);
782 	}
783 
784 	sytfixline(dcr, atoi(fdig(dev[D_CLASS])), D_DIRECT);
785 	(void) sleep(2);
786 	DEBUG(4, "Calling Sytek unit %s\n", dev[D_ARG]);
787 	(void) sprintf(command,"\r\rcall %s\r", dev[D_ARG]);
788 	ret = (*Write)(dcr, command, strlen(command));
789 	(void) sleep(1);
790 	DEBUG(4, "COM1 return = %d\n", ret);
791 	sytfix2line(dcr);
792 	(void) close(nullfd = open("/", O_RDONLY));
793 	(void) signal(SIGALRM, alarmtr);
794 	if (setjmp(Sjbuf)) {
795 		DEBUG(4, "timeout sytek open\n%s", "");
796 		(void) close(nullfd);
797 		(void) close(dcr2);
798 		fd_rmlock(dcr);
799 		(void) close(dcr);
800 		Uerror = SS_DIAL_FAILED;
801 		trace1(TR_sytcall, 1);
802 		return (FAIL);
803 	}
804 	(void) alarm(10);
805 	dcr2 = open(dcname,O_RDWR);
806 	(void) alarm(0);
807 	fd_rmlock(dcr);
808 	(void) close(dcr);
809 	if (dcr2 < 0) {
810 		DEBUG(4, "OPEN 2 FAILED %s\n", dcname);
811 		Uerror = SS_DIAL_FAILED;
812 		(void) close(nullfd);	/* kernel might think dc2 is open */
813 		trace1(TR_sytcall, 1);
814 		return (FAIL);
815 	}
816 	if (fd_mklock(dcr2) != SUCCESS) {
817 		(void)close(dcr2);
818 		DEBUG(1, "failed to lock device %s\n", dcname);
819 		Uerror = SS_LOCKED_DEVICE;
820 		trace1(TR_sytcall, 1);
821 		return (FAIL);
822 	}
823 	trace1(TR_sytcall, 1);
824 	return (dcr2);
825 }
826 
827 #endif /* SYTEK */
828 
829 #ifdef DIAL801
830 
831 /*
832  *	dial801(flds, dev)	dial remote machine on 801/801
833  *	char *flds[], *dev[];
834  *
835  *	return codes:
836  *		file descriptor  -  succeeded
837  *		FAIL  -  failed
838  *
839  *	unfortunately, open801() is different for usg and non-usg
840  */
841 
842 /*ARGSUSED*/
843 GLOBAL int
844 dial801(flds, dev)
845 char *flds[], *dev[];
846 {
847 	char dcname[20], dnname[20], phone[MAXPH+2];
848 	int dcf = -1, speed;
849 
850 	trace1(TR_dial801, 0);
851 	(void) sprintf(dnname, "/dev/%s", dev[D_CALLDEV]);
852 	(void) sprintf(phone, "%s%s", dev[D_ARG]   , ACULAST);
853 	(void) sprintf(dcname, "/dev/%s", dev[D_LINE]);
854 	CDEBUG(1, "Use Port %s, ", dcname);
855 	DEBUG(4, "acu - %s, ", dnname);
856 	VERBOSE("Trying modem - %s, ", dcname);	/* for cu */
857 	VERBOSE("acu - %s, ", dnname);	/* for cu */
858 	if (getuid()==0 || GRPCHK(getgid())) {
859 		CDEBUG(1, "Phone Number  %s\n", phone);
860 		/* In cu, only give out the phone number to trusted people. */
861 		VERBOSE("calling  %s:  ", phone);	/* for cu */
862 	}
863 	speed = atoi(fdig(dev[D_CLASS]));
864 	dcf = open801(dcname, dnname, phone, speed);
865 	if (dcf >= 0) {
866 	        if (fd_mklock(dcf) != SUCCESS) {
867 			(void) close(dcf);
868 			DEBUG(5, "fd_mklock line %s failed\n", dev[D_LINE]);
869 			Uerror = SS_LOCKED_DEVICE;
870 			trace1(TR_dial801, 1);
871 			return (FAIL);
872 		}
873 		fixline(dcf, speed, D_ACU);
874 		(void) strcpy(Dc, dev[D_LINE]);	/* for later unlock() */
875 		VERBOSE("SUCCEEDED\n%s", "");
876 	} else {
877 		VERBOSE("FAILED\n%s", "");
878 	}
879 	trace1(TR_dial801, 1);
880 	return (dcf);
881 }
882 
883 
884 #ifndef ATTSV
885 /*ARGSUSED*/
886 GLOBAL int
887 open801(dcname, dnname, phone, speed)
888 char *dcname, *dnname, *phone;
889 {
890 	int nw, lt, dcf = -1, nullfd, dnf = -1;
891 	pid_t w_ret, pid = -1;
892 	unsigned timelim;
893 
894 	trace1(TR_open801, 0);
895 	if ((dnf = open(dnname, O_WRONLY)) < 0) {
896 		DEBUG(5, "can't open %s\n", dnname);
897 		Uerror = SS_CANT_ACCESS_DEVICE;
898 		trace1(TR_open801, 1);
899 		return (FAIL);
900 	}
901 	DEBUG(5, "%s is open\n", dnname);
902 
903 	(void) close(nullfd = open("/dev/null", O_RDONLY));/* partial open hack */
904 	if (setjmp(Sjbuf)) {
905 		DEBUG(4, "timeout modem open\n%s", "");
906 		(void) close(nullfd);
907 		(void) close(dcf);
908 		(void) close(dnf);
909 		logent("801 open", "TIMEOUT");
910 		if (pid > 0) {
911 			kill(pid, 9);
912 			wait((int *) 0);
913 		}
914 		Uerror = SS_DIAL_FAILED;
915 		trace1(TR_open801, 1);
916 		return (FAIL);
917 	}
918 	(void) signal(SIGALRM, alarmtr);
919 	timelim = 5 * strlen(phone);
920 	(void) alarm(timelim < connecttime ? connecttime : timelim);
921 	if ((pid = fork()) == 0) {
922 		sleep(2);
923 		nw = (*Write)(dnf, phone, lt = strlen(phone));
924 		if (nw != lt) {
925 			DEBUG(4, "ACU write error %d\n", errno);
926 			logent("ACU write", "FAILED");
927 			trace1(TR_open801, 1);
928 			exit(1);
929 		}
930 		DEBUG(4, "ACU write ok\n%s", "");
931 		trace1(TR_open801, 1);
932 		exit(0);
933 	}
934 	/*  open line - will return on carrier */
935 	dcf = open(dcname, O_RDWR);
936 
937 	DEBUG(4, "dcf is %d\n", dcf);
938 	if (dcf < 0) {	/* handle like a timeout */
939 		(void) alarm(0);
940 		longjmp(Sjbuf, 1);
941 	}
942 
943 	/* modem is open */
944 	while ((w_ret = wait(&lt)) != pid)
945 		if (w_ret == -1 && errno != EINTR) {
946 			DEBUG(4, "Wait failed errno=%d\n", errno);
947 			(void) close(dcf);
948 			(void) close(dnf);
949 			Uerror = SS_DIAL_FAILED;
950 			trace1(TR_open801, 1);
951 			return (FAIL);
952 		}
953 	(void) alarm(0);
954 
955 	(void) close(dnf);	/* no reason to keep the 801 open */
956 	if (lt != 0) {
957 		DEBUG(4, "Fork Stat %o\n", lt);
958 		(void) close(dcf);
959 		Uerror = SS_DIAL_FAILED;
960 		trace1(TR_open801, 1);
961 		return (FAIL);
962 	}
963 	trace1(TR_open801, 1);
964 	return (dcf);
965 }
966 
967 #else /* ATTSV */
968 
969 GLOBAL int
970 open801(dcname, dnname, phone, speed)
971 char *dcname, *dnname, *phone;
972 {
973 	int nw, lt, dcf = -1, nullfd, dnf = -1, ret;
974 	unsigned timelim;
975 
976 	trace1(TR_open801, 0);
977 	(void) close(nullfd = open("/", O_RDONLY));	/* partial open hack */
978 	if (setjmp(Sjbuf)) {
979 		DEBUG(4, "DN write %s\n", "timeout");
980 		(void) close(dnf);
981 		(void) close(dcf);
982 		(void) close(nullfd);
983 		Uerror = SS_DIAL_FAILED;
984 		trace1(TR_open801, 1);
985 		return (FAIL);
986 	}
987 	(void) signal(SIGALRM, alarmtr);
988 	timelim = 5 * strlen(phone);
989 	(void) alarm(timelim < connecttime ? connecttime : timelim);
990 
991 	if ((dnf = open(dnname, O_WRONLY)) < 0) {
992 		DEBUG(5, "can't open %s\n", dnname);
993 		Uerror = SS_CANT_ACCESS_DEVICE;
994 		trace1(TR_open801, 1);
995 		return (FAIL);
996 	}
997 	DEBUG(5, "%s is open\n", dnname);
998 	if (fd_mklock(dnf) != SUCCESS) {
999 		(void)close(dnf);
1000 		DEBUG(1, "failed to lock device %s\n", dnname);
1001 		Uerror = SS_LOCKED_DEVICE;
1002 	}
1003 	if ((dcf = open(dcname, O_RDWR | O_NDELAY)) < 0) {
1004 		DEBUG(5, "can't open %s\n", dcname);
1005 		Uerror = SS_CANT_ACCESS_DEVICE;
1006 		trace1(TR_open801, 1);
1007 		return (FAIL);
1008 	}
1009 	if (fd_mklock(dcf) != SUCCESS) {
1010 		(void)close(dcf);
1011 		DEBUG(1, "failed to lock device %s\n", dcname);
1012 		Uerror = SS_LOCKED_DEVICE;
1013 		trace1(TR_open801, 1);
1014 		return (FAIL);
1015 	}
1016 
1017 	DEBUG(4, "dcf is %d\n", dcf);
1018 	fixline(dcf, speed, D_ACU);
1019 	nw = (*Write)(dnf, phone, lt = strlen(phone));
1020 	if (nw != lt) {
1021 		(void) alarm(0);
1022 		DEBUG(4, "ACU write error %d\n", errno);
1023 		(void) close(dnf);
1024 		(void) close(dcf);
1025 		Uerror = SS_DIAL_FAILED;
1026 		trace1(TR_open801, 1);
1027 		return (FAIL);
1028 	} else
1029 		DEBUG(4, "ACU write ok\n%s", "");
1030 
1031 	(void) close(dnf);
1032 	(void) close(nullfd = open("/", O_RDONLY));	/* partial open hack */
1033 	ret = open(dcname, O_RDWR);  /* wait for carrier  */
1034 	(void) alarm(0);
1035 	(void) close(ret);	/* close 2nd modem open() */
1036 	if (ret < 0) {		/* open() interrupted by alarm */
1037 		DEBUG(4, "Line open %s\n", "failed");
1038 		Uerror = SS_DIAL_FAILED;
1039 		(void) close(nullfd);		/* close partially opened modem */
1040 		trace1(TR_open801, 1);
1041 		return (FAIL);
1042 	}
1043 	(void) _fcntl(dcf,F_SETFL, _fcntl(dcf, F_GETFL, 0) & ~O_NDELAY);
1044 	trace1(TR_open801, 1);
1045 	return (dcf);
1046 }
1047 #endif /* ATTSV */
1048 
1049 #endif /* DIAL801 */
1050 
1051 #ifdef V8
1052 GLOBAL int
1053 Dialout(flds)
1054 char *flds[];
1055 {
1056     int fd;
1057     char phone[MAXPH+2];
1058 
1059 
1060     trace1(TR_Dialout, 0);
1061     exphone(flds[F_PHONE], phone);
1062 
1063     DEBUG(4, "call dialout(%s", phone);
1064     DEBUG(4, ", %s)\n", dev[D_CLASS]);
1065     fd = dialout(phone, dev[D_CLASS]);
1066     if (fd == -1)
1067 	Uerror = SS_NO_DEVICE;
1068     if (fd == -3)
1069 	Uerror = SS_DIAL_FAILED;
1070     if (fd == -9)
1071 	Uerror = SS_DEVICE_FAILED;
1072 
1073     (void) strcpy(Dc, "Dialout");
1074 
1075     trace1(TR_Dialout, 1);
1076     return (fd);
1077 }
1078 #endif /* V8 */
1079 
1080 #ifdef TLI
1081 /*
1082  *
1083  * AT&T Transport Layer Interface
1084  *
1085  * expected in Devices
1086  *	TLI line1 - - TLI
1087  * or
1088  *	TLIS line1 - - TLIS
1089  *
1090  */
1091 
1092 #include <tiuser.h>
1093 
1094 #if defined(__STDC__)
1095 EXTERN void tfaillog(int fd, const char *s);
1096 #else
1097 EXTERN void tfaillog();
1098 #endif
1099 
1100 char *t_alloc();
1101 int t_bind(), t_close(), t_connect(), t_free(), t_look(), t_open(), t_rcvdis();
1102 
1103 #define	CONNECT_ATTEMPTS	3
1104 #define	TFREE(p, type)	if ((p)) t_free((char *)(p), (type))
1105 
1106 /*
1107  * returns fd to remote uucp daemon
1108  */
1109 /*ARGSUSED*/
1110 GLOBAL int
1111 tlicall(flds, dev)
1112 char *flds[];
1113 char *dev[];
1114 {
1115 	char		addrbuf[ BUFSIZ ];
1116 	char		devname[MAXNAMESIZE];
1117 	int		fd;
1118 	register int	i, j;
1119 	struct t_bind	*bind_ret = 0;
1120 	struct t_info	tinfo;
1121 	struct t_call	*sndcall = 0, *rcvcall = 0;
1122 
1123 	EXTERN struct netbuf	*stoa();
1124 
1125         trace1(TR_tlicall, 0);
1126 	if (dev[D_LINE][0] != '/') {
1127 		/*	dev holds device name relative to /dev	*/
1128 		sprintf(devname, "/dev/%s", dev[D_LINE]);
1129 	} else {
1130 		/*	dev holds full path name of device	*/
1131 		strcpy(devname, dev[D_LINE]);
1132 	}
1133 	/* gimme local transport endpoint */
1134 	errno = t_errno = 0;
1135 	if (setjmp(Sjbuf)) {
1136 		DEBUG(1, "t_open timeout\n%s", "");
1137 		logent("t_open", "TIMEOUT");
1138 		Uerror = SS_NO_DEVICE;
1139         	trace1(TR_tlicall, 1);
1140 		return (FAIL);
1141 	}
1142 	(void) signal(SIGALRM, alarmtr);
1143 	(void) alarm(5);
1144 	fd = t_open(devname, O_RDWR, &tinfo);
1145 	(void) alarm(0);
1146 	if (fd < 0) {
1147 		tfaillog(fd, "t_open");
1148 		Uerror = SS_NO_DEVICE;
1149         	trace1(TR_tlicall, 1);
1150 		return (FAIL);
1151 	}
1152 	if (fd_mklock(fd) != SUCCESS) {
1153 		(void)t_close(fd);
1154 		DEBUG(1, "tlicall: failed to lock device %s\n", devname);
1155 		Uerror = SS_LOCKED_DEVICE;
1156         	trace1(TR_tlicall, 1);
1157 		return (FAIL);
1158 	}
1159 
1160 	/* allocate tli structures	*/
1161 	errno = t_errno = 0;
1162 	if ((bind_ret = (struct t_bind *)t_alloc(fd, T_BIND, T_ALL)) ==
1163 	    (struct t_bind *)NULL
1164 	|| (sndcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) ==
1165 	    (struct t_call *)NULL
1166 	|| (rcvcall = (struct t_call *)t_alloc(fd, T_CALL, T_ALL)) ==
1167 	    (struct t_call *)NULL) {
1168 		tfaillog(fd, "t_alloc");
1169 		TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1170 		TFREE(rcvcall, T_CALL);
1171 		Uerror = SS_NO_DEVICE;
1172         	trace1(TR_tlicall, 1);
1173 		return (FAIL);
1174 	}
1175 
1176 	/* bind */
1177 	errno = t_errno = 0;
1178 	if (t_bind(fd, (struct t_bind *) 0, bind_ret) < 0) {
1179 		tfaillog(fd, "t_bind");
1180 		TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1181 		TFREE(rcvcall, T_CALL);
1182 		Uerror = SS_NO_DEVICE;
1183 		fd_rmlock(fd);
1184 		(void) t_close(fd);
1185         	trace1(TR_tlicall, 1);
1186 		return (FAIL);
1187 	}
1188 	DEBUG(5, "tlicall: bound to %s\n", bind_ret->addr.buf);
1189 
1190 	/*
1191 	 * Prepare to connect.
1192 	 *
1193 	 * If address begins with "\x", "\X", "\o", or "\O",
1194 	 * assume is hexadecimal or octal address and use stoa()
1195 	 * to convert it.
1196 	 *
1197 	 * Else is usual uucico address -- only \N's left to process.
1198 	 * Walk thru connection address, changing \N's to NULLCHARs.
1199 	 * Note:  If a NULLCHAR must be part of the connection address,
1200 	 * it must be overtly included in the address.  One recommended
1201 	 * way is to do it in the Devices file, thusly:
1202 	 *		Netname /dev/netport - - TLI \D\000
1203 	 * bsfix() turns \000 into \N and then the loop below makes it a
1204 	 * real, included-in-the-length null-byte.
1205 	 *
1206 	 * The DEBUG must print the strecpy'd address (so that
1207 	 * non-printables will have been replaced with C escapes).
1208 	 */
1209 
1210 	DEBUG(5, "t_connect to addr \"%s\"\n",
1211 		strecpy(addrbuf, dev[D_ARG], "\\"));
1212 
1213 	if (dev[D_ARG][0] == '\\' &&
1214 	(dev[D_ARG][1] == 'x' || dev[D_ARG][1] == 'X'
1215 	|| dev[D_ARG][1] == 'o' || dev[D_ARG][1] == 'O')) {
1216 		if (stoa(dev[D_ARG], &(sndcall->addr)) == (struct netbuf *)NULL) {
1217 			DEBUG(5, "tlicall: stoa failed\n%s", "");
1218 			logent("tlicall", "string-to-address failed");
1219 			TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1220 			TFREE(rcvcall, T_CALL);
1221 			Uerror = SS_NO_DEVICE;
1222 			fd_rmlock(fd);
1223 			(void) t_close(fd);
1224         		trace1(TR_tlicall, 1);
1225 			return (FAIL);
1226 		}
1227 	} else {
1228 		for (i = j = 0; i < BUFSIZ && dev[D_ARG][i] != NULLCHAR;
1229 		++i, ++j) {
1230 			if (dev[D_ARG][i] == '\\'  &&  dev[D_ARG][i+1] == 'N') {
1231 				addrbuf[j] = NULLCHAR;
1232 				++i;
1233 			}
1234 			else {
1235 				addrbuf[j] = dev[D_ARG][i];
1236 			}
1237 		}
1238 		sndcall->addr.buf = addrbuf;
1239 		sndcall->addr.len = j;
1240 	}
1241 
1242 	if (setjmp(Sjbuf)) {
1243 		DEBUG(4, "timeout tlicall\n%s", "");
1244 		logent("tlicall", "TIMEOUT");
1245 		TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1246 		TFREE(rcvcall, T_CALL);
1247 		Uerror = SS_NO_DEVICE;
1248 		fd_rmlock(fd);
1249 		(void) t_close(fd);
1250         	trace1(TR_tlicall, 1);
1251 		return (FAIL);
1252 	}
1253 	(void) signal(SIGALRM, alarmtr);
1254 	(void) alarm(connecttime);
1255 
1256 	/* connect to the service -- some listeners can't handle */
1257 	/* multiple connect requests, so try it a few times */
1258 	errno = t_errno = 0;
1259 	for (i = 0; i < CONNECT_ATTEMPTS; ++i) {
1260 		if (t_connect(fd, sndcall, rcvcall) == 0)
1261 			break;
1262 		if ((t_errno == TLOOK) && (t_look(fd) == T_DISCONNECT)) {
1263 			t_rcvdis(fd,NULL);
1264 			(void) alarm(0);
1265 		} else {
1266 			(void) alarm(0);
1267 			tfaillog(fd, "t_connect");
1268 			TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1269 			TFREE(rcvcall, T_CALL);
1270 			Uerror = SS_DIAL_FAILED;
1271 			fd_rmlock(fd);
1272 			(void) t_close(fd);
1273         		trace1(TR_tlicall, 1);
1274 			return (FAIL);
1275 		}
1276 	}
1277 	(void) alarm(0);
1278 	TFREE(bind_ret, T_BIND);TFREE(sndcall, T_CALL);
1279 	TFREE(rcvcall, T_CALL);
1280 	if (i == CONNECT_ATTEMPTS) {
1281 		tfaillog(fd, "t_connect");
1282 		Uerror = SS_DIAL_FAILED;
1283 		fd_rmlock(fd);
1284 		(void) t_close(fd);
1285         	trace1(TR_tlicall, 1);
1286 		return (FAIL);
1287 	}
1288 	errno = t_errno = 0;
1289 	(void) strcpy(Dc, dev[D_CALLER]);
1290         trace1(TR_tlicall, 1);
1291 	return (fd);
1292 }
1293 #endif /* TLI */
1294