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