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