1 /* $OpenBSD: main.c,v 1.19 2001/07/08 21:18:08 deraadt 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 #ifndef lint 37 static char copyright[] = 38 "@(#) Copyright (c) 1980, 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"; 40 #endif /* not lint */ 41 42 #ifndef lint 43 /*static char sccsid[] = "from: @(#)main.c 8.1 (Berkeley) 6/20/93";*/ 44 static char rcsid[] = "$OpenBSD: main.c,v 1.19 2001/07/08 21:18:08 deraadt Exp $"; 45 #endif /* not lint */ 46 47 #include <sys/param.h> 48 #include <sys/stat.h> 49 #include <termios.h> 50 #include <sys/ioctl.h> 51 #include <sys/resource.h> 52 #include <sys/utsname.h> 53 #include <errno.h> 54 #include <signal.h> 55 #include <fcntl.h> 56 #include <time.h> 57 #include <ctype.h> 58 #include <fcntl.h> 59 #include <setjmp.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <syslog.h> 63 #include <time.h> 64 #include <unistd.h> 65 #include <util.h> 66 67 #include "gettytab.h" 68 #include "pathnames.h" 69 #include "extern.h" 70 71 /* 72 * Set the amount of running time that getty should accumulate 73 * before deciding that something is wrong and exit. 74 */ 75 #define GETTY_TIMEOUT 60 /* seconds */ 76 77 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */ 78 79 #define PPP_FRAME 0x7e /* PPP Framing character */ 80 #define PPP_STATION 0xff /* "All Station" character */ 81 #define PPP_ESCAPE 0x7d /* Escape Character */ 82 #define PPP_CONTROL 0x03 /* PPP Control Field */ 83 #define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */ 84 #define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */ 85 #define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */ 86 87 struct termios tmode, omode; 88 89 int crmod, digit, lower, upper; 90 91 char hostname[MAXHOSTNAMELEN]; 92 struct utsname kerninfo; 93 char name[MAXLOGNAME]; 94 char dev[] = _PATH_DEV; 95 char ttyn[32]; 96 char *portselector(); 97 char *ttyname(); 98 99 #define OBUFSIZ 128 100 #define TABBUFSIZ 512 101 102 char defent[TABBUFSIZ]; 103 char tabent[TABBUFSIZ]; 104 105 char *env[128]; 106 107 char partab[] = { 108 0001,0201,0201,0001,0201,0001,0001,0201, 109 0202,0004,0003,0205,0005,0206,0201,0001, 110 0201,0001,0001,0201,0001,0201,0201,0001, 111 0001,0201,0201,0001,0201,0001,0001,0201, 112 0200,0000,0000,0200,0000,0200,0200,0000, 113 0000,0200,0200,0000,0200,0000,0000,0200, 114 0000,0200,0200,0000,0200,0000,0000,0200, 115 0200,0000,0000,0200,0000,0200,0200,0000, 116 0200,0000,0000,0200,0000,0200,0200,0000, 117 0000,0200,0200,0000,0200,0000,0000,0200, 118 0000,0200,0200,0000,0200,0000,0000,0200, 119 0200,0000,0000,0200,0000,0200,0200,0000, 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,0201 124 }; 125 126 #define ERASE tmode.c_cc[VERASE] 127 #define KILL tmode.c_cc[VKILL] 128 #define EOT tmode.c_cc[VEOF] 129 130 jmp_buf timeout; 131 132 static void 133 dingdong() 134 { 135 alarm(0); 136 signal(SIGALRM, SIG_DFL); 137 longjmp(timeout, 1); /* XXX signal/longjmp resource leaks */ 138 } 139 140 jmp_buf intrupt; 141 142 static void 143 interrupt() 144 { 145 146 signal(SIGINT, interrupt); 147 longjmp(intrupt, 1); 148 } 149 150 /* 151 * Action to take when getty is running too long. 152 */ 153 void 154 timeoverrun(signo) 155 int signo; 156 { 157 /* XXX signal race */ 158 syslog(LOG_ERR, "getty exiting due to excessive running time"); 159 _exit(1); 160 } 161 162 static int getname __P((void)); 163 static void oflush __P((void)); 164 static void prompt __P((void)); 165 static void putchr __P((int)); 166 static void putf __P((char *)); 167 static void putpad __P((char *)); 168 static void xputs __P((char *)); 169 170 int 171 main(argc, argv) 172 int argc; 173 char *argv[]; 174 { 175 extern char **environ; 176 char *tname; 177 int repcnt = 0, failopenlogged = 0; 178 struct rlimit limit; 179 int rval; 180 181 signal(SIGINT, SIG_IGN); 182 /* 183 signal(SIGQUIT, SIG_DFL); 184 */ 185 openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH); 186 gethostname(hostname, sizeof(hostname)); 187 if (hostname[0] == '\0') 188 strcpy(hostname, "Amnesiac"); 189 uname(&kerninfo); 190 191 /* 192 * Limit running time to deal with broken or dead lines. 193 */ 194 (void)signal(SIGXCPU, timeoverrun); 195 limit.rlim_max = RLIM_INFINITY; 196 limit.rlim_cur = GETTY_TIMEOUT; 197 (void)setrlimit(RLIMIT_CPU, &limit); 198 199 /* 200 * The following is a work around for vhangup interactions 201 * which cause great problems getting window systems started. 202 * If the tty line is "-", we do the old style getty presuming 203 * that the file descriptors are already set up for us. 204 * J. Gettys - MIT Project Athena. 205 */ 206 if (argc <= 2 || strcmp(argv[2], "-") == 0) { 207 snprintf(ttyn, sizeof ttyn, "%s", ttyname(0)); 208 } else { 209 int i; 210 211 snprintf(ttyn, sizeof ttyn, "%s%s", dev, argv[2]); 212 if (strcmp(argv[0], "+") != 0) { 213 chown(ttyn, 0, 0); 214 chmod(ttyn, 0600); 215 revoke(ttyn); 216 /* 217 * Delay the open so DTR stays down long enough to be detected. 218 */ 219 sleep(2); 220 while ((i = open(ttyn, O_RDWR)) == -1) { 221 if ((repcnt % 10 == 0) && 222 (errno != ENXIO || !failopenlogged)) { 223 syslog(LOG_ERR, "%s: %m", ttyn); 224 closelog(); 225 failopenlogged = 1; 226 } 227 repcnt++; 228 sleep(60); 229 } 230 login_tty(i); 231 } 232 } 233 234 /* Start with default tty settings */ 235 if (tcgetattr(0, &tmode) < 0) { 236 syslog(LOG_ERR, "%s: %m", ttyn); 237 exit(1); 238 } 239 omode = tmode; 240 241 gettable("default", defent); 242 gendefaults(); 243 tname = "default"; 244 if (argc > 1) 245 tname = argv[1]; 246 for (;;) { 247 int off; 248 249 gettable(tname, tabent); 250 if (OPset || EPset || APset) 251 APset++, OPset++, EPset++; 252 setdefaults(); 253 off = 0; 254 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */ 255 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 256 ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 257 258 if (IS) 259 cfsetispeed(&tmode, IS); 260 else if (SP) 261 cfsetispeed(&tmode, SP); 262 if (OS) 263 cfsetospeed(&tmode, OS); 264 else if (SP) 265 cfsetospeed(&tmode, SP); 266 setflags(0); 267 setchars(); 268 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 269 syslog(LOG_ERR, "%s: %m", ttyn); 270 exit(1); 271 } 272 if (AB) { 273 extern char *autobaud(); 274 275 tname = autobaud(); 276 continue; 277 } 278 if (PS) { 279 tname = portselector(); 280 continue; 281 } 282 if (CL && *CL) 283 putpad(CL); 284 edithost(HE); 285 if (IM && *IM) 286 putf(IM); 287 if (setjmp(timeout)) { 288 tmode.c_ispeed = tmode.c_ospeed = 0; 289 (void)tcsetattr(0, TCSANOW, &tmode); 290 exit(1); 291 } 292 if (TO) { 293 signal(SIGALRM, dingdong); 294 alarm(TO); 295 } 296 if ((rval = getname()) == 2) { 297 oflush(); 298 alarm(0); 299 signal(SIGALRM, SIG_DFL); 300 execle(PP, "ppplogin", ttyn, (char *) 0, env); 301 syslog(LOG_ERR, "%s: %m", PP); 302 exit(1); 303 } else if (rval) { 304 register int i; 305 306 oflush(); 307 alarm(0); 308 signal(SIGALRM, SIG_DFL); 309 if (name[0] == '-') { 310 xputs("user names may not start with '-'."); 311 continue; 312 } 313 if (!(upper || lower || digit)) 314 continue; 315 setflags(2); 316 if (crmod) { 317 tmode.c_iflag |= ICRNL; 318 tmode.c_oflag |= ONLCR; 319 } 320 if (upper || UC) { 321 tmode.c_iflag |= IUCLC; 322 tmode.c_oflag |= OLCUC; 323 tmode.c_lflag |= XCASE; 324 } 325 if (lower || LC) { 326 tmode.c_iflag &= ~IUCLC; 327 tmode.c_oflag &= ~OLCUC; 328 tmode.c_lflag &= ~XCASE; 329 } 330 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 331 syslog(LOG_ERR, "%s: %m", ttyn); 332 exit(1); 333 } 334 signal(SIGINT, SIG_DFL); 335 for (i = 0; environ[i] != (char *)0; i++) 336 env[i] = environ[i]; 337 makeenv(&env[i]); 338 339 limit.rlim_max = RLIM_INFINITY; 340 limit.rlim_cur = RLIM_INFINITY; 341 (void)setrlimit(RLIMIT_CPU, &limit); 342 execle(LO, "login", "-p", "--", name, (char *)0, env); 343 syslog(LOG_ERR, "%s: %m", LO); 344 exit(1); 345 } 346 alarm(0); 347 signal(SIGALRM, SIG_DFL); 348 signal(SIGINT, SIG_IGN); 349 if (NX && *NX) 350 tname = NX; 351 } 352 } 353 354 static int 355 getname() 356 { 357 register int c; 358 register char *np; 359 unsigned char cs; 360 volatile int ppp_state = 0; 361 volatile int ppp_connection = 0; 362 363 /* 364 * Interrupt may happen if we use CBREAK mode 365 */ 366 if (setjmp(intrupt)) { 367 signal(SIGINT, SIG_IGN); 368 return (0); 369 } 370 signal(SIGINT, interrupt); 371 setflags(1); 372 prompt(); 373 if (PF > 0) { 374 oflush(); 375 sleep(PF); 376 PF = 0; 377 } 378 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 379 syslog(LOG_ERR, "%s: %m", ttyn); 380 exit(1); 381 } 382 crmod = digit = lower = upper = 0; 383 np = name; 384 for (;;) { 385 oflush(); 386 if (read(STDIN_FILENO, &cs, 1) <= 0) 387 exit(0); 388 if ((c = cs&0177) == 0) 389 return (0); 390 391 /* 392 * PPP detection state machine.. 393 * Look for sequences: 394 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or 395 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC) 396 * See RFC1662. 397 * Derived from code from Michael Hancock <michaelh@cet.co.jp> 398 * and Erik 'PPP' Olson <eriko@wrq.com> 399 */ 400 if (PP && cs == PPP_FRAME) { 401 ppp_state = 1; 402 } else if (ppp_state == 1 && cs == PPP_STATION) { 403 ppp_state = 2; 404 } else if (ppp_state == 2 && cs == PPP_ESCAPE) { 405 ppp_state = 3; 406 } else if ((ppp_state == 2 && cs == PPP_CONTROL) || 407 (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { 408 ppp_state = 4; 409 } else if (ppp_state == 4 && cs == PPP_LCP_HI) { 410 ppp_state = 5; 411 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) { 412 ppp_connection = 1; 413 break; 414 } else { 415 ppp_state = 0; 416 } 417 418 if (c == EOT) 419 exit(1); 420 if (c == '\r' || c == '\n' || np >= name + sizeof name -1) { 421 putf("\r\n"); 422 break; 423 } 424 if (islower(c)) 425 lower = 1; 426 else if (isupper(c)) 427 upper = 1; 428 else if (c == ERASE || c == '#' || c == '\b') { 429 if (np > name) { 430 np--; 431 if (cfgetospeed(&tmode) >= 1200) 432 xputs("\b \b"); 433 else 434 putchr(cs); 435 } 436 continue; 437 } else if (c == KILL || c == '@') { 438 putchr(cs); 439 putchr('\r'); 440 if (cfgetospeed(&tmode) < 1200) 441 putchr('\n'); 442 /* this is the way they do it down under ... */ 443 else if (np > name) 444 xputs(" \r"); 445 prompt(); 446 np = name; 447 continue; 448 } else if (isdigit(c)) 449 digit++; 450 if (IG && (c <= ' ' || c > 0176)) 451 continue; 452 *np++ = c; 453 putchr(cs); 454 } 455 signal(SIGINT, SIG_IGN); 456 *np = 0; 457 if (c == '\r') 458 crmod = 1; 459 if (upper && !lower && !LC || UC) 460 for (np = name; *np; np++) 461 if (isupper(*np)) 462 *np = tolower(*np); 463 return (1 + ppp_connection); 464 } 465 466 static void 467 putpad(s) 468 register char *s; 469 { 470 int pad = 0; 471 speed_t ospeed = cfgetospeed(&tmode); 472 473 if (isdigit(*s)) { 474 while (isdigit(*s)) { 475 pad *= 10; 476 pad += *s++ - '0'; 477 } 478 pad *= 10; 479 if (*s == '.' && isdigit(s[1])) { 480 pad += s[1] - '0'; 481 s += 2; 482 } 483 } 484 485 xputs(s); 486 /* 487 * If no delay needed, or output speed is 488 * not comprehensible, then don't try to delay. 489 */ 490 if (pad == 0 || ospeed <= 0) 491 return; 492 493 /* 494 * Round up by a half a character frame, and then do the delay. 495 * Too bad there are no user program accessible programmed delays. 496 * Transmitting pad characters slows many terminals down and also 497 * loads the system. 498 */ 499 pad = (pad * ospeed + 50000) / 100000; 500 while (pad--) 501 putchr(*PC); 502 } 503 504 static void 505 xputs(s) 506 register char *s; 507 { 508 while (*s) 509 putchr(*s++); 510 } 511 512 char outbuf[OBUFSIZ]; 513 int obufcnt = 0; 514 515 static void 516 putchr(cc) 517 int cc; 518 { 519 char c; 520 521 c = cc; 522 if (!NP) { 523 c |= partab[c&0177] & 0200; 524 if (OP) 525 c ^= 0200; 526 } 527 if (!UB) { 528 outbuf[obufcnt++] = c; 529 if (obufcnt >= OBUFSIZ) 530 oflush(); 531 } else 532 write(STDOUT_FILENO, &c, 1); 533 } 534 535 static void 536 oflush() 537 { 538 if (obufcnt) 539 write(STDOUT_FILENO, outbuf, obufcnt); 540 obufcnt = 0; 541 } 542 543 static void 544 prompt() 545 { 546 547 putf(LM); 548 if (CO) 549 putchr('\n'); 550 } 551 552 static void 553 putf(cp) 554 register char *cp; 555 { 556 extern char editedhost[]; 557 time_t t; 558 char *slash, db[100]; 559 560 while (*cp) { 561 if (*cp != '%') { 562 putchr(*cp++); 563 continue; 564 } 565 switch (*++cp) { 566 567 case 't': 568 slash = strrchr(ttyn, '/'); 569 if (slash == (char *) 0) 570 xputs(ttyn); 571 else 572 xputs(&slash[1]); 573 break; 574 575 case 'h': 576 xputs(editedhost); 577 break; 578 579 case 'd': { 580 static char fmt[] = "%l:% %p on %A, %d %B %Y"; 581 582 fmt[4] = 'M'; /* I *hate* SCCS... */ 583 (void)time(&t); 584 (void)strftime(db, sizeof(db), fmt, localtime(&t)); 585 xputs(db); 586 break; 587 588 case 's': 589 xputs(kerninfo.sysname); 590 break; 591 592 case 'm': 593 xputs(kerninfo.machine); 594 break; 595 596 case 'r': 597 xputs(kerninfo.release); 598 break; 599 600 case 'v': 601 xputs(kerninfo.version); 602 break; 603 } 604 605 case '%': 606 putchr('%'); 607 break; 608 } 609 cp++; 610 } 611 } 612