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