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