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