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