1 /*- 2 * Copyright (c) 1980, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char copyright[] = 36 "@(#) Copyright (c) 1980, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 /*static char sccsid[] = "from: @(#)main.c 8.1 (Berkeley) 6/20/93";*/ 42 static char rcsid[] = "$Id: main.c,v 1.20 1997/06/03 12:56:47 davidn Exp $"; 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <sys/ioctl.h> 48 #include <sys/resource.h> 49 #include <sys/ttydefaults.h> 50 #include <sys/utsname.h> 51 #include <errno.h> 52 #include <signal.h> 53 #include <fcntl.h> 54 #include <time.h> 55 #include <ctype.h> 56 #include <fcntl.h> 57 #include <libutil.h> 58 #include <locale.h> 59 #include <setjmp.h> 60 #include <signal.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <syslog.h> 64 #include <termios.h> 65 #include <time.h> 66 #include <unistd.h> 67 68 #include "gettytab.h" 69 #include "pathnames.h" 70 #include "extern.h" 71 72 /* 73 * Set the amount of running time that getty should accumulate 74 * before deciding that something is wrong and exit. 75 */ 76 #define GETTY_TIMEOUT 60 /* seconds */ 77 78 #undef CTRL 79 #define CTRL(x) (x&037) 80 81 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */ 82 83 #define PPP_FRAME 0x7e /* PPP Framing character */ 84 #define PPP_STATION 0xff /* "All Station" character */ 85 #define PPP_ESCAPE 0x7d /* Escape Character */ 86 #define PPP_CONTROL 0x03 /* PPP Control Field */ 87 #define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */ 88 #define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */ 89 #define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */ 90 91 struct termios tmode, omode; 92 93 int crmod, digit, lower, upper; 94 95 char hostname[MAXHOSTNAMELEN]; 96 char name[MAXLOGNAME*3]; 97 char dev[] = _PATH_DEV; 98 char ttyn[32]; 99 100 #define OBUFSIZ 128 101 #define TABBUFSIZ 512 102 103 char defent[TABBUFSIZ]; 104 char tabent[TABBUFSIZ]; 105 106 char *env[128]; 107 108 char partab[] = { 109 0001,0201,0201,0001,0201,0001,0001,0201, 110 0202,0004,0003,0205,0005,0206,0201,0001, 111 0201,0001,0001,0201,0001,0201,0201,0001, 112 0001,0201,0201,0001,0201,0001,0001,0201, 113 0200,0000,0000,0200,0000,0200,0200,0000, 114 0000,0200,0200,0000,0200,0000,0000,0200, 115 0000,0200,0200,0000,0200,0000,0000,0200, 116 0200,0000,0000,0200,0000,0200,0200,0000, 117 0200,0000,0000,0200,0000,0200,0200,0000, 118 0000,0200,0200,0000,0200,0000,0000,0200, 119 0000,0200,0200,0000,0200,0000,0000,0200, 120 0200,0000,0000,0200,0000,0200,0200,0000, 121 0000,0200,0200,0000,0200,0000,0000,0200, 122 0200,0000,0000,0200,0000,0200,0200,0000, 123 0200,0000,0000,0200,0000,0200,0200,0000, 124 0000,0200,0200,0000,0200,0000,0000,0201 125 }; 126 127 #define ERASE tmode.c_cc[VERASE] 128 #define KILL tmode.c_cc[VKILL] 129 #define EOT tmode.c_cc[VEOF] 130 131 static void dingdong __P((int)); 132 static int getname __P((void)); 133 static void interrupt __P((int)); 134 static void oflush __P((void)); 135 static void prompt __P((void)); 136 static void putchr __P((int)); 137 static void putf __P((const char *)); 138 static void putpad __P((const char *)); 139 static void puts __P((const char *)); 140 static void timeoverrun __P((int)); 141 static char *getline __P((int)); 142 static void setttymode __P((const char *, int)); 143 static void setdefttymode __P((const char *)); 144 static int opentty __P((const char *, int)); 145 146 int main __P((int, char **)); 147 148 jmp_buf timeout; 149 150 static void 151 dingdong(signo) 152 int signo; 153 { 154 alarm(0); 155 longjmp(timeout, 1); 156 } 157 158 jmp_buf intrupt; 159 160 static void 161 interrupt(signo) 162 int signo; 163 { 164 longjmp(intrupt, 1); 165 } 166 167 /* 168 * Action to take when getty is running too long. 169 */ 170 static void 171 timeoverrun(signo) 172 int signo; 173 { 174 175 syslog(LOG_ERR, "getty exiting due to excessive running time\n"); 176 exit(1); 177 } 178 179 int 180 main(argc, argv) 181 int argc; 182 char **argv; 183 { 184 extern char **environ; 185 const char *tname; 186 int first_sleep = 1, first_time = 1; 187 struct rlimit limit; 188 int rval; 189 190 signal(SIGINT, SIG_IGN); 191 signal(SIGQUIT, SIG_IGN); 192 193 openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH); 194 gethostname(hostname, sizeof(hostname)); 195 if (hostname[0] == '\0') 196 strcpy(hostname, "Amnesiac"); 197 198 /* 199 * Limit running time to deal with broken or dead lines. 200 */ 201 (void)signal(SIGXCPU, timeoverrun); 202 limit.rlim_max = RLIM_INFINITY; 203 limit.rlim_cur = GETTY_TIMEOUT; 204 (void)setrlimit(RLIMIT_CPU, &limit); 205 206 gettable("default", defent); 207 gendefaults(); 208 tname = "default"; 209 if (argc > 1) 210 tname = argv[1]; 211 212 /* 213 * The following is a work around for vhangup interactions 214 * which cause great problems getting window systems started. 215 * If the tty line is "-", we do the old style getty presuming 216 * that the file descriptors are already set up for us. 217 * J. Gettys - MIT Project Athena. 218 */ 219 if (argc <= 2 || strcmp(argv[2], "-") == 0) 220 strcpy(ttyn, ttyname(STDIN_FILENO)); 221 else { 222 strcpy(ttyn, dev); 223 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev)); 224 if (strcmp(argv[0], "+") != 0) { 225 chown(ttyn, 0, 0); 226 chmod(ttyn, 0600); 227 revoke(ttyn); 228 229 gettable(tname, tabent); 230 231 /* Init modem sequence has been specified 232 */ 233 if (IC) { 234 if (!opentty(ttyn, O_RDWR|O_NONBLOCK)) 235 exit(1); 236 setdefttymode(tname); 237 if (getty_chat(IC, CT, DC) > 0) { 238 syslog(LOG_ERR, "modem init problem on %s", ttyn); 239 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 240 exit(1); 241 } 242 } 243 244 if (AC) { 245 int i, rfds; 246 struct timeval timeout; 247 248 if (!opentty(ttyn, O_RDWR|O_NONBLOCK)) 249 exit(1); 250 setdefttymode(tname); 251 rfds = 1 << 0; /* FD_SET */ 252 timeout.tv_sec = RT; 253 timeout.tv_usec = 0; 254 i = select(32, (fd_set*)&rfds, (fd_set*)NULL, 255 (fd_set*)NULL, RT ? &timeout : NULL); 256 if (i < 0) { 257 syslog(LOG_ERR, "select %s: %m", ttyn); 258 } else if (i == 0) { 259 syslog(LOG_NOTICE, "recycle tty %s", ttyn); 260 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 261 exit(0); /* recycle for init */ 262 } 263 i = getty_chat(AC, CT, DC); 264 if (i > 0) { 265 syslog(LOG_ERR, "modem answer problem on %s", ttyn); 266 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 267 exit(1); 268 } 269 } else { /* blocking open */ 270 if (!opentty(ttyn, O_RDWR)) 271 exit(1); 272 } 273 } 274 } 275 276 /* Start with default tty settings */ 277 if (tcgetattr(STDIN_FILENO, &tmode) < 0) { 278 syslog(LOG_ERR, "tcgetattr %s: %m", ttyn); 279 exit(1); 280 } 281 /* 282 * Don't rely on the driver too much, and initialize crucial 283 * things according to <sys/ttydefaults.h>. Avoid clobbering 284 * the c_cc[] settings however, the console drivers might wish 285 * to leave their idea of the preferred VERASE key value 286 * there. 287 */ 288 tmode.c_iflag = TTYDEF_IFLAG; 289 tmode.c_oflag = TTYDEF_OFLAG; 290 tmode.c_lflag = TTYDEF_LFLAG; 291 tmode.c_cflag = TTYDEF_CFLAG; 292 omode = tmode; 293 294 for (;;) { 295 296 /* 297 * if a delay was specified then sleep for that 298 * number of seconds before writing the initial prompt 299 */ 300 if (first_sleep && DE) { 301 sleep(DE); 302 /* remove any noise */ 303 (void)tcflush(STDIN_FILENO, TCIOFLUSH); 304 } 305 first_sleep = 0; 306 307 setttymode(tname, 0); 308 if (AB) { 309 tname = autobaud(); 310 continue; 311 } 312 if (PS) { 313 tname = portselector(); 314 continue; 315 } 316 if (CL && *CL) 317 putpad(CL); 318 edithost(HE); 319 320 /* if this is the first time through this, and an 321 issue file has been given, then send it */ 322 if (first_time && IF) { 323 int fd; 324 325 if ((fd = open(IF, O_RDONLY)) != -1) { 326 char * cp; 327 328 while ((cp = getline(fd)) != NULL) { 329 putf(cp); 330 } 331 close(fd); 332 } 333 } 334 first_time = 0; 335 336 if (IM && *IM) 337 putf(IM); 338 if (setjmp(timeout)) { 339 cfsetispeed(&tmode, B0); 340 cfsetospeed(&tmode, B0); 341 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); 342 exit(1); 343 } 344 if (TO) { 345 signal(SIGALRM, dingdong); 346 alarm(TO); 347 } 348 if ((rval = getname()) == 2) { 349 oflush(); 350 alarm(0); 351 execle(PP, "ppplogin", ttyn, (char *) 0, env); 352 syslog(LOG_ERR, "%s: %m", PP); 353 exit(1); 354 } else if (rval) { 355 register int i; 356 357 oflush(); 358 alarm(0); 359 signal(SIGALRM, SIG_DFL); 360 if (name[0] == '-') { 361 puts("user names may not start with '-'."); 362 continue; 363 } 364 if (!(upper || lower || digit)) 365 continue; 366 setflags(2); 367 if (crmod) { 368 tmode.c_iflag |= ICRNL; 369 tmode.c_oflag |= ONLCR; 370 } 371 #if REALLY_OLD_TTYS 372 if (upper || UC) 373 tmode.sg_flags |= LCASE; 374 if (lower || LC) 375 tmode.sg_flags &= ~LCASE; 376 #endif 377 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { 378 syslog(LOG_ERR, "tcsetattr %s: %m", ttyn); 379 exit(1); 380 } 381 signal(SIGINT, SIG_DFL); 382 for (i = 0; environ[i] != (char *)0; i++) 383 env[i] = environ[i]; 384 makeenv(&env[i]); 385 386 limit.rlim_max = RLIM_INFINITY; 387 limit.rlim_cur = RLIM_INFINITY; 388 (void)setrlimit(RLIMIT_CPU, &limit); 389 execle(LO, "login", "-p", name, (char *) 0, env); 390 syslog(LOG_ERR, "%s: %m", LO); 391 exit(1); 392 } 393 alarm(0); 394 signal(SIGALRM, SIG_DFL); 395 signal(SIGINT, SIG_IGN); 396 if (NX && *NX) 397 tname = NX; 398 } 399 } 400 401 static int 402 opentty(const char *ttyn, int flags) 403 { 404 int i, j = 0; 405 int failopenlogged = 0; 406 407 while (j < 10 && (i = open(ttyn, flags)) == -1) 408 { 409 if (((j % 10) == 0) && (errno != ENXIO || !failopenlogged)) { 410 syslog(LOG_ERR, "open %s: %m", ttyn); 411 failopenlogged = 1; 412 } 413 j++; 414 sleep(60); 415 } 416 if (i == -1) { 417 syslog(LOG_ERR, "open %s: %m", ttyn); 418 return 0; 419 } 420 else { 421 login_tty(i); 422 return 1; 423 } 424 } 425 426 static void 427 setdefttymode(tname) 428 const char * tname; 429 { 430 if (tcgetattr(STDIN_FILENO, &tmode) < 0) { 431 syslog(LOG_ERR, "tcgetattr %s: %m", ttyn); 432 exit(1); 433 } 434 tmode.c_iflag = TTYDEF_IFLAG; 435 tmode.c_oflag = TTYDEF_OFLAG; 436 tmode.c_lflag = TTYDEF_LFLAG; 437 tmode.c_cflag = TTYDEF_CFLAG; 438 omode = tmode; 439 setttymode(tname, 1); 440 } 441 442 static void 443 setttymode(tname, raw) 444 const char * tname; 445 int raw; 446 { 447 int off = 0; 448 449 gettable(tname, tabent); 450 if (OPset || EPset || APset) 451 APset++, OPset++, EPset++; 452 setdefaults(); 453 (void)tcflush(STDIN_FILENO, TCIOFLUSH); /* clear out the crap */ 454 ioctl(STDIN_FILENO, FIONBIO, &off); /* turn off non-blocking mode */ 455 ioctl(STDIN_FILENO, FIOASYNC, &off); /* ditto for async mode */ 456 457 if (IS) 458 cfsetispeed(&tmode, speed(IS)); 459 else if (SP) 460 cfsetispeed(&tmode, speed(SP)); 461 if (OS) 462 cfsetospeed(&tmode, speed(OS)); 463 else if (SP) 464 cfsetospeed(&tmode, speed(SP)); 465 setflags(0); 466 setchars(); 467 if (raw) 468 cfmakeraw(&tmode); 469 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { 470 syslog(LOG_ERR, "tcsetattr %s: %m", ttyn); 471 exit(1); 472 } 473 } 474 475 476 static int 477 getname() 478 { 479 register int c; 480 register char *np; 481 unsigned char cs; 482 int ppp_state = 0; 483 int ppp_connection = 0; 484 485 /* 486 * Interrupt may happen if we use CBREAK mode 487 */ 488 if (setjmp(intrupt)) { 489 signal(SIGINT, SIG_IGN); 490 return (0); 491 } 492 signal(SIGINT, interrupt); 493 setflags(1); 494 prompt(); 495 oflush(); 496 if (PF > 0) { 497 sleep(PF); 498 PF = 0; 499 } 500 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { 501 syslog(LOG_ERR, "%s: %m", ttyn); 502 exit(1); 503 } 504 crmod = digit = lower = upper = 0; 505 np = name; 506 for (;;) { 507 oflush(); 508 if (read(STDIN_FILENO, &cs, 1) <= 0) 509 exit(0); 510 if ((c = cs&0177) == 0) 511 return (0); 512 513 /* PPP detection state machine.. 514 Look for sequences: 515 PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or 516 PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC) 517 See RFC1662. 518 Derived from code from Michael Hancock, <michaelh@cet.co.jp> 519 and Erik 'PPP' Olson, <eriko@wrq.com> 520 */ 521 522 if (PP && (cs == PPP_FRAME)) { 523 ppp_state = 1; 524 } else if (ppp_state == 1 && cs == PPP_STATION) { 525 ppp_state = 2; 526 } else if (ppp_state == 2 && cs == PPP_ESCAPE) { 527 ppp_state = 3; 528 } else if ((ppp_state == 2 && cs == PPP_CONTROL) 529 || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { 530 ppp_state = 4; 531 } else if (ppp_state == 4 && cs == PPP_LCP_HI) { 532 ppp_state = 5; 533 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) { 534 ppp_connection = 1; 535 break; 536 } else { 537 ppp_state = 0; 538 } 539 540 if (c == EOT || c == CTRL('d')) 541 exit(1); 542 if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) { 543 putf("\r\n"); 544 break; 545 } 546 if (islower(c)) 547 lower = 1; 548 else if (isupper(c)) 549 upper = 1; 550 else if (c == ERASE || c == '\b' || c == 0177) { 551 if (np > name) { 552 np--; 553 if (cfgetospeed(&tmode) >= 1200) 554 puts("\b \b"); 555 else 556 putchr(cs); 557 } 558 continue; 559 } else if (c == KILL || c == CTRL('u')) { 560 putchr('\r'); 561 if (cfgetospeed(&tmode) < 1200) 562 putchr('\n'); 563 /* this is the way they do it down under ... */ 564 else if (np > name) 565 puts(" \r"); 566 prompt(); 567 np = name; 568 continue; 569 } else if (isdigit(c)) 570 digit++; 571 if (IG && (c <= ' ' || c > 0176)) 572 continue; 573 *np++ = c; 574 putchr(cs); 575 } 576 signal(SIGINT, SIG_IGN); 577 *np = 0; 578 if (c == '\r') 579 crmod = 1; 580 if ((upper && !lower && !LC) || UC) 581 for (np = name; *np; np++) 582 if (isupper(*np)) 583 *np = tolower(*np); 584 return (1 + ppp_connection); 585 } 586 587 static void 588 putpad(s) 589 register const char *s; 590 { 591 register pad = 0; 592 speed_t ospeed = cfgetospeed(&tmode); 593 594 if (isdigit(*s)) { 595 while (isdigit(*s)) { 596 pad *= 10; 597 pad += *s++ - '0'; 598 } 599 pad *= 10; 600 if (*s == '.' && isdigit(s[1])) { 601 pad += s[1] - '0'; 602 s += 2; 603 } 604 } 605 606 puts(s); 607 /* 608 * If no delay needed, or output speed is 609 * not comprehensible, then don't try to delay. 610 */ 611 if (pad == 0 || ospeed <= 0) 612 return; 613 614 /* 615 * Round up by a half a character frame, and then do the delay. 616 * Too bad there are no user program accessible programmed delays. 617 * Transmitting pad characters slows many terminals down and also 618 * loads the system. 619 */ 620 pad = (pad * ospeed + 50000) / 100000; 621 while (pad--) 622 putchr(*PC); 623 } 624 625 static void 626 puts(s) 627 register const char *s; 628 { 629 while (*s) 630 putchr(*s++); 631 } 632 633 char outbuf[OBUFSIZ]; 634 int obufcnt = 0; 635 636 static void 637 putchr(cc) 638 int cc; 639 { 640 char c; 641 642 c = cc; 643 if (!NP) { 644 c |= partab[c&0177] & 0200; 645 if (OP) 646 c ^= 0200; 647 } 648 if (!UB) { 649 outbuf[obufcnt++] = c; 650 if (obufcnt >= OBUFSIZ) 651 oflush(); 652 } else 653 write(STDOUT_FILENO, &c, 1); 654 } 655 656 static void 657 oflush() 658 { 659 if (obufcnt) 660 write(STDOUT_FILENO, outbuf, obufcnt); 661 obufcnt = 0; 662 } 663 664 static void 665 prompt() 666 { 667 668 putf(LM); 669 if (CO) 670 putchr('\n'); 671 } 672 673 674 static char * 675 getline(fd) 676 int fd; 677 { 678 int i = 0; 679 static char linebuf[512]; 680 681 /* 682 * This is certainly slow, but it avoids having to include 683 * stdio.h unnecessarily. Issue files should be small anyway. 684 */ 685 while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) { 686 if (linebuf[i] == '\n') { 687 /* Don't rely on newline mode, assume raw */ 688 linebuf[i++] = '\r'; 689 linebuf[i++] = '\n'; 690 linebuf[i] = '\0'; 691 return linebuf; 692 } 693 ++i; 694 } 695 linebuf[i] = '\0'; 696 return i ? linebuf : 0; 697 } 698 699 static void 700 putf(cp) 701 register const char *cp; 702 { 703 extern char editedhost[]; 704 time_t t; 705 char *slash, db[100]; 706 707 static struct utsname kerninfo; 708 709 if (!*kerninfo.sysname) 710 uname(&kerninfo); 711 712 while (*cp) { 713 if (*cp != '%') { 714 putchr(*cp++); 715 continue; 716 } 717 switch (*++cp) { 718 719 case 't': 720 slash = strrchr(ttyn, '/'); 721 if (slash == (char *) 0) 722 puts(ttyn); 723 else 724 puts(&slash[1]); 725 break; 726 727 case 'h': 728 puts(editedhost); 729 break; 730 731 case 'd': { 732 t = (time_t)0; 733 (void)time(&t); 734 if (Lo) 735 (void)setlocale(LC_TIME, Lo); 736 (void)strftime(db, sizeof(db), "%+", localtime(&t)); 737 puts(db); 738 break; 739 740 case 's': 741 puts(kerninfo.sysname); 742 break; 743 744 case 'm': 745 puts(kerninfo.machine); 746 break; 747 748 case 'r': 749 puts(kerninfo.release); 750 break; 751 752 case 'v': 753 puts(kerninfo.version); 754 break; 755 } 756 757 case '%': 758 putchr('%'); 759 break; 760 } 761 cp++; 762 } 763 } 764