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