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