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