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