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