1 /* $NetBSD: main.c,v 1.65 2016/03/17 00:21:04 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.65 2016/03/17 00:21:04 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/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; 187 volatile int first_time = 1; 188 struct rlimit limit; 189 struct passwd *pw; 190 int rval; 191 /* this is used past the siglongjmp, so make sure it is not cached 192 in registers that might become invalid. */ 193 volatile int uugetty = 0; 194 const char * volatile tname = "default"; 195 196 (void)signal(SIGINT, SIG_IGN); 197 openlog("getty", LOG_PID, LOG_AUTH); 198 (void)gethostname(hostname, sizeof(hostname)); 199 hostname[sizeof(hostname) - 1] = '\0'; 200 if (hostname[0] == '\0') 201 (void)strlcpy(hostname, "Amnesiac", sizeof(hostname)); 202 (void)uname(&kerninfo); 203 204 progname = getprogname(); 205 if (progname[0] == 'u' && progname[1] == 'u') 206 uugetty = 1; 207 208 /* 209 * Find id of uucp login (if present) so we can chown tty properly. 210 */ 211 if (uugetty && (pw = getpwnam("uucp"))) 212 ttyowner = pw->pw_uid; 213 else 214 ttyowner = 0; 215 216 /* 217 * Limit running time to deal with broken or dead lines. 218 */ 219 (void)signal(SIGXCPU, timeoverrun); 220 limit.rlim_max = RLIM_INFINITY; 221 limit.rlim_cur = GETTY_TIMEOUT; 222 (void)setrlimit(RLIMIT_CPU, &limit); 223 224 /* 225 * The following is a work around for vhangup interactions 226 * which cause great problems getting window systems started. 227 * If the tty line is "-", we do the old style getty presuming 228 * that the file descriptors are already set up for us. 229 * J. Gettys - MIT Project Athena. 230 */ 231 if (argc <= 2 || strcmp(argv[2], "-") == 0) { 232 (void)strlcpy(ttyn, ttyname(0), sizeof(ttyn)); 233 } 234 else { 235 int i; 236 237 rawttyn = argv[2]; 238 (void)strlcpy(ttyn, dev, sizeof(ttyn)); 239 (void)strlcat(ttyn, argv[2], sizeof(ttyn)); 240 if (uugetty) { 241 (void)chown(ttyn, ttyowner, 0); 242 (void)strlcpy(lockfile, _PATH_LOCK, 243 sizeof(lockfile)); 244 (void)strlcat(lockfile, argv[2], 245 sizeof(lockfile)); 246 /* 247 * wait for lockfiles to go away before we try 248 * to open 249 */ 250 if (pidlock(lockfile, 0, 0, 0) != 0) { 251 syslog(LOG_ERR, 252 "%s: can't create lockfile", ttyn); 253 exit(1); 254 } 255 (void)unlink(lockfile); 256 } 257 if (strcmp(argv[0], "+") != 0) { 258 (void)chown(ttyn, ttyowner, 0); 259 (void)chmod(ttyn, 0600); 260 (void)revoke(ttyn); 261 if (ttyaction(ttyn, "getty", "root")) 262 syslog(LOG_WARNING, "%s: ttyaction failed", 263 ttyn); 264 /* 265 * Delay the open so DTR stays down long enough 266 * to be detected. 267 */ 268 (void)sleep(2); 269 while ((i = open(ttyn, O_RDWR)) == -1) { 270 if ((repcnt % 10 == 0) && 271 (errno != ENXIO || !failopenlogged)) { 272 syslog(LOG_WARNING, "%s: %m", ttyn); 273 closelog(); 274 failopenlogged = 1; 275 } 276 repcnt++; 277 (void)sleep(60); 278 } 279 if (uugetty && pidlock(lockfile, 0, 0, 0) != 0) { 280 syslog(LOG_ERR, "%s: can't create lockfile", 281 ttyn); 282 exit(1); 283 } 284 if (uugetty) 285 (void)chown(lockfile, ttyowner, 0); 286 (void)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 if (argc > 1) 300 tname = argv[1]; 301 for (;;) { 302 int off; 303 304 rval = 0; 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 (void)ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 312 (void)ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 313 314 if (IS) 315 (void)cfsetispeed(&tmode, (speed_t)IS); 316 else if (SP) 317 (void)cfsetispeed(&tmode, (speed_t)SP); 318 if (OS) 319 (void)cfsetospeed(&tmode, (speed_t)OS); 320 else if (SP) 321 (void)cfsetospeed(&tmode, (speed_t)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 (CS) 337 clearscreen(); 338 if (CL && *CL) 339 putpad(CL); 340 edithost(HE); 341 342 /* 343 * If this is the first time through this, and an 344 * issue file has been given, then send it. 345 */ 346 if (first_time != 0 && IF != NULL) { 347 char buf[_POSIX2_LINE_MAX]; 348 FILE *fp; 349 350 if ((fp = fopen(IF, "r")) != NULL) { 351 while (fgets(buf, sizeof(buf) - 1, fp) != NULL) 352 putf(buf); 353 (void)fclose(fp); 354 } 355 } 356 first_time = 0; 357 358 if (IM && *IM) 359 putf(IM); 360 oflush(); 361 if (sigsetjmp(timeout, 1)) { 362 tmode.c_ispeed = tmode.c_ospeed = 0; 363 (void)tcsetattr(0, TCSANOW, &tmode); 364 exit(1); 365 } 366 if (TO) { 367 (void)signal(SIGALRM, dingdong); 368 (void)alarm((unsigned int)TO); 369 } 370 if (NN) { 371 name[0] = '\0'; 372 lower = 1; 373 upper = digit_or_punc = 0; 374 } else if (AL) { 375 const char *p = AL; 376 char *q = name; 377 378 while (*p && q < &name[sizeof name - 1]) { 379 if (isupper((unsigned char)*p)) 380 upper = 1; 381 else if (islower((unsigned char)*p)) 382 lower = 1; 383 else if (isdigit((unsigned char)*p)) 384 digit_or_punc = 1; 385 *q++ = *p++; 386 } 387 } else if ((rval = getname()) == 2) { 388 setflags(2); 389 (void)execle(PP, "ppplogin", ttyn, (char *) 0, env); 390 syslog(LOG_ERR, "%s: %m", PP); 391 exit(1); 392 } 393 394 if (rval || AL || NN) { 395 int i; 396 397 oflush(); 398 (void)alarm(0); 399 (void)signal(SIGALRM, SIG_DFL); 400 if (name[0] == '-') { 401 xputs("user names may not start with '-'."); 402 continue; 403 } 404 if (!(upper || lower || digit_or_punc)) 405 continue; 406 setflags(2); 407 if (crmod) { 408 tmode.c_iflag |= ICRNL; 409 tmode.c_oflag |= ONLCR; 410 } 411 #if XXX 412 if (upper || UC) 413 tmode.sg_flags |= LCASE; 414 if (lower || LC) 415 tmode.sg_flags &= ~LCASE; 416 #endif 417 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 418 syslog(LOG_ERR, "%s: %m", ttyn); 419 exit(1); 420 } 421 (void)signal(SIGINT, SIG_DFL); 422 for (i = 0; envp[i] != NULL; i++) 423 env[i] = envp[i]; 424 makeenv(&env[i]); 425 426 limit.rlim_max = RLIM_INFINITY; 427 limit.rlim_cur = RLIM_INFINITY; 428 (void)setrlimit(RLIMIT_CPU, &limit); 429 if (NN) 430 (void)execle(LO, "login", AL ? "-fp" : "-p", 431 NULL, env); 432 else 433 (void)execle(LO, "login", AL ? "-fp" : "-p", 434 "--", name, NULL, env); 435 syslog(LOG_ERR, "%s: %m", LO); 436 exit(1); 437 } 438 (void)alarm(0); 439 (void)signal(SIGALRM, SIG_DFL); 440 (void)signal(SIGINT, SIG_IGN); 441 if (NX && *NX) 442 tname = NX; 443 if (uugetty) 444 (void)unlink(lockfile); 445 } 446 } 447 448 static int 449 getname(void) 450 { 451 int c; 452 char *np; 453 unsigned char cs; 454 int ppp_state, ppp_connection; 455 456 /* 457 * Interrupt may happen if we use CBREAK mode 458 */ 459 if (sigsetjmp(intrupt, 1)) { 460 (void)signal(SIGINT, SIG_IGN); 461 return (0); 462 } 463 (void)signal(SIGINT, interrupt); 464 setflags(1); 465 prompt(); 466 if (PF > 0) { 467 oflush(); 468 (void)sleep((unsigned int)PF); 469 PF = 0; 470 } 471 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 472 syslog(LOG_ERR, "%s: %m", ttyn); 473 exit(1); 474 } 475 crmod = digit_or_punc = lower = upper = 0; 476 ppp_state = ppp_connection = 0; 477 np = name; 478 for (;;) { 479 oflush(); 480 if (read(STDIN_FILENO, &cs, 1) <= 0) 481 exit(0); 482 if ((c = cs&0177) == 0) 483 return (0); 484 485 /* 486 * PPP detection state machine.. 487 * Look for sequences: 488 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or 489 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC) 490 * See RFC1662. 491 * Derived from code from Michael Hancock <michaelh@cet.co.jp> 492 * and Erik 'PPP' Olson <eriko@wrq.com> 493 */ 494 if (PP && cs == PPP_FRAME) { 495 ppp_state = 1; 496 } else if (ppp_state == 1 && cs == PPP_STATION) { 497 ppp_state = 2; 498 } else if (ppp_state == 2 && cs == PPP_ESCAPE) { 499 ppp_state = 3; 500 } else if ((ppp_state == 2 && cs == PPP_CONTROL) || 501 (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { 502 ppp_state = 4; 503 } else if (ppp_state == 4 && cs == PPP_LCP_HI) { 504 ppp_state = 5; 505 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) { 506 ppp_connection = 1; 507 break; 508 } else { 509 ppp_state = 0; 510 } 511 512 if (c == EOT) 513 exit(1); 514 if (c == '\r' || c == '\n' || 515 np >= &name[LOGIN_NAME_MAX - 1]) { 516 *np = '\0'; 517 putf("\r\n"); 518 break; 519 } 520 if (islower(c)) 521 lower = 1; 522 else if (isupper(c)) 523 upper = 1; 524 else if (c == ERASE || c == '#' || c == '\b') { 525 if (np > name) { 526 np--; 527 if (cfgetospeed(&tmode) >= 1200) 528 xputs("\b \b"); 529 else 530 putchr(cs); 531 } 532 continue; 533 } else if (c == KILL || c == '@') { 534 putchr(cs); 535 putchr('\r'); 536 if (cfgetospeed(&tmode) < 1200) 537 putchr('\n'); 538 /* this is the way they do it down under ... */ 539 else if (np > name) 540 xputs( 541 " \r"); 542 prompt(); 543 np = name; 544 continue; 545 } else if (isdigit(c) || c == '_') 546 digit_or_punc = 1; 547 if (IG && (c <= ' ' || c > 0176)) 548 continue; 549 *np++ = c; 550 putchr(cs); 551 552 /* 553 * An MS-Windows direct connect PPP "client" won't send its 554 * first PPP packet until we respond to its "CLIENT" poll 555 * with a CRLF sequence. We cater to yet another broken 556 * implementation of a previously-standard protocol... 557 */ 558 *np = '\0'; 559 if (strstr(name, "CLIENT")) 560 putf("\r\n"); 561 } 562 (void)signal(SIGINT, SIG_IGN); 563 *np = 0; 564 if (c == '\r') 565 crmod = 1; 566 if ((upper && !lower && !LC) || UC) 567 for (np = name; *np; np++) 568 *np = tolower((unsigned char)*np); 569 return (1 + ppp_connection); 570 } 571 572 static void 573 xputs(const char *s) 574 { 575 while (*s) 576 putchr(*s++); 577 } 578 579 char outbuf[OBUFSIZ]; 580 size_t obufcnt = 0; 581 582 static int 583 putchr(int cc) 584 { 585 unsigned char c; 586 587 c = cc; 588 if (!NP) { 589 c |= partab[c&0177] & 0200; 590 if (OP) 591 c ^= 0200; 592 } 593 if (!UB) { 594 outbuf[obufcnt++] = c; 595 if (obufcnt >= OBUFSIZ) 596 oflush(); 597 return 1; 598 } 599 return write(STDOUT_FILENO, &c, 1); 600 } 601 602 static void 603 oflush(void) 604 { 605 if (obufcnt) 606 (void)write(STDOUT_FILENO, outbuf, obufcnt); 607 obufcnt = 0; 608 } 609 610 static void 611 prompt(void) 612 { 613 614 putf(LM); 615 if (CO) 616 putchr('\n'); 617 } 618 619 static void 620 putf(const char *cp) 621 { 622 time_t t; 623 char *slash, db[100]; 624 625 while (*cp) { 626 if (*cp != '%') { 627 putchr(*cp++); 628 continue; 629 } 630 switch (*++cp) { 631 632 case 't': 633 if ((slash = strstr(ttyn, "/pts/")) == NULL) 634 slash = strrchr(ttyn, '/'); 635 if (slash == NULL) 636 xputs(ttyn); 637 else 638 xputs(&slash[1]); 639 break; 640 641 case 'h': 642 xputs(editedhost); 643 break; 644 645 case 'd': 646 (void)time(&t); 647 (void)strftime(db, sizeof(db), 648 "%l:%M%p on %A, %d %B %Y", localtime(&t)); 649 xputs(db); 650 break; 651 652 case 's': 653 xputs(kerninfo.sysname); 654 break; 655 656 case 'm': 657 xputs(kerninfo.machine); 658 break; 659 660 case 'r': 661 xputs(kerninfo.release); 662 break; 663 664 case 'v': 665 xputs(kerninfo.version); 666 break; 667 668 case '%': 669 putchr('%'); 670 break; 671 } 672 if (*cp) 673 cp++; 674 } 675 } 676 677 static void 678 clearscreen(void) 679 { 680 struct ttyent *typ; 681 int err; 682 683 if (rawttyn == NULL) 684 return; 685 686 typ = getttynam(rawttyn); 687 688 if ((typ == NULL) || (typ->ty_type == NULL) || 689 (typ->ty_type[0] == 0)) 690 return; 691 692 if (setupterm(typ->ty_type, 0, &err) == ERR) 693 return; 694 695 if (clear_screen) 696 putpad(clear_screen); 697 698 del_curterm(cur_term); 699 cur_term = NULL; 700 } 701