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 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 * 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 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 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 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 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 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