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