1 /* $OpenBSD: main.c,v 1.56 2024/07/19 15:28:51 bluhm 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 unveil(_PATH_GETTYTAB ".db", "r") == -1) { 177 syslog(LOG_ERR, "%s: %m", tname); 178 exit(1); 179 } 180 if (unveil("/dev", "rw") == -1) { 181 syslog(LOG_ERR, "%s: %m", tname); 182 exit(1); 183 } 184 if (unveil(_PATH_GETTY, "x") == -1) { 185 syslog(LOG_ERR, "%s: %m", tname); 186 exit(1); 187 } 188 189 gettable("default", defent); 190 gendefaults(); 191 if (argc > 1) 192 tname = argv[1]; 193 gettable(tname, tabent); 194 if (LO == NULL) 195 LO = _PATH_LOGIN; 196 if (unveil(LO, "x") == -1) { 197 syslog(LOG_ERR, "%s: %m", tname); 198 exit(1); 199 } 200 if (unveil(NULL, NULL) == -1) { 201 syslog(LOG_ERR, "%s: %m", tname); 202 exit(1); 203 } 204 strlcpy(saveLO, LO, sizeof saveLO); 205 206 /* 207 * The following is a work around for vhangup interactions 208 * which cause great problems getting window systems started. 209 * If the tty line is "-", we do the old style getty presuming 210 * that the file descriptors are already set up for us. 211 * J. Gettys - MIT Project Athena. 212 */ 213 if (argc <= 2 || strcmp(argv[2], "-") == 0) { 214 if (pledge("stdio rpath proc exec tty", NULL) == -1) { 215 syslog(LOG_ERR, "pledge: %m"); 216 exit(1); 217 } 218 219 if ((tname = ttyname(0)) == NULL) { 220 syslog(LOG_ERR, "stdin: %m"); 221 exit(1); 222 } 223 if (strlcpy(ttyn, tname, sizeof(ttyn)) >= sizeof(ttyn)) { 224 errno = ENAMETOOLONG; 225 syslog(LOG_ERR, "%s: %m", tname); 226 exit(1); 227 } 228 } else { 229 int i; 230 231 snprintf(ttyn, sizeof ttyn, "%s%s", _PATH_DEV, argv[2]); 232 if (strcmp(argv[0], "+") != 0) { 233 chown(ttyn, 0, 0); 234 chmod(ttyn, 0600); 235 revoke(ttyn); 236 /* 237 * Delay the open so DTR stays down long enough to be detected. 238 */ 239 sleep(2); 240 while ((i = open(ttyn, O_RDWR)) == -1) { 241 if ((repcnt % 10 == 0) && 242 (errno != ENXIO || !failopenlogged)) { 243 syslog(LOG_ERR, "%s: %m", ttyn); 244 closelog(); 245 failopenlogged = 1; 246 } 247 repcnt++; 248 sleep(60); 249 } 250 login_tty(i); 251 } 252 } 253 254 if (pledge("stdio rpath proc exec tty", NULL) == -1) { 255 syslog(LOG_ERR, "pledge: %m"); 256 exit(1); 257 } 258 259 /* Start with default tty settings */ 260 if (tcgetattr(0, &tmode) == -1) { 261 syslog(LOG_ERR, "%s: %m", ttyn); 262 exit(1); 263 } 264 omode = tmode; 265 266 for (;;) { 267 gettable(tname, tabent); 268 if (strcmp(LO, saveLO) != 0) { 269 /* re-exec to apply new unveil */ 270 closefrom(0); 271 execv(_PATH_GETTY, argv); 272 exit(0); 273 } 274 if (OPset || EPset || APset) 275 APset++, OPset++, EPset++; 276 setdefaults(); 277 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */ 278 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 279 280 if (IS) 281 cfsetispeed(&tmode, IS); 282 else if (SP) 283 cfsetispeed(&tmode, SP); 284 if (OS) 285 cfsetospeed(&tmode, OS); 286 else if (SP) 287 cfsetospeed(&tmode, SP); 288 setflags(0); 289 setchars(); 290 if (tcsetattr(0, TCSANOW, &tmode) == -1) { 291 syslog(LOG_ERR, "%s: %m", ttyn); 292 exit(1); 293 } 294 if (AB) { 295 tname = autobaud(); 296 continue; 297 } 298 if (PS) { 299 tname = portselector(); 300 continue; 301 } 302 if (CL && *CL) 303 putpad(CL); 304 strlcpy(globalhostname, HN, sizeof(globalhostname)); 305 if (IM && *IM) 306 putf(IM); 307 if (TO) { 308 signal(SIGALRM, dingdong); 309 alarm(TO); 310 } 311 if (getname()) { 312 int i; 313 314 oflush(); 315 alarm(0); 316 signal(SIGALRM, SIG_DFL); 317 if (name[0] == '-') { 318 xputs("user names may not start with '-'."); 319 continue; 320 } 321 if (!(upper || lower || digit)) 322 continue; 323 setflags(2); 324 if (crmod) { 325 tmode.c_iflag |= ICRNL; 326 tmode.c_oflag |= ONLCR; 327 } 328 if (UC) { 329 tmode.c_iflag |= IUCLC; 330 tmode.c_oflag |= OLCUC; 331 tmode.c_lflag |= XCASE; 332 } 333 if (lower || LC) { 334 tmode.c_iflag &= ~IUCLC; 335 tmode.c_oflag &= ~OLCUC; 336 tmode.c_lflag &= ~XCASE; 337 } 338 if (tcsetattr(0, TCSANOW, &tmode) == -1) { 339 syslog(LOG_ERR, "%s: %m", ttyn); 340 exit(1); 341 } 342 signal(SIGINT, SIG_DFL); 343 for (i = 0; environ[i] != NULL; i++) 344 env[i] = environ[i]; 345 makeenv(&env[i]); 346 347 limit.rlim_max = RLIM_INFINITY; 348 limit.rlim_cur = RLIM_INFINITY; 349 (void)setrlimit(RLIMIT_CPU, &limit); 350 execle(LO, "login", "-p", "--", name, NULL, env); 351 syslog(LOG_ERR, "%s: %m", LO); 352 exit(1); 353 } 354 alarm(0); 355 signal(SIGALRM, SIG_DFL); 356 signal(SIGINT, SIG_IGN); 357 if (NX && *NX) 358 tname = NX; 359 } 360 } 361 362 static int 363 getname(void) 364 { 365 unsigned char cs; 366 int c, r; 367 char *np; 368 369 /* 370 * Interrupt may happen if we use CBREAK mode 371 */ 372 signal(SIGINT, interrupt); 373 setflags(1); 374 prompt(); 375 if (PF > 0) { 376 oflush(); 377 sleep(PF); 378 PF = 0; 379 } 380 if (tcsetattr(0, TCSANOW, &tmode) == -1) { 381 syslog(LOG_ERR, "%s: %m", ttyn); 382 exit(1); 383 } 384 crmod = digit = lower = upper = 0; 385 np = name; 386 for (;;) { 387 oflush(); 388 r = read(STDIN_FILENO, &cs, 1); 389 if (r <= 0) { 390 if (r == -1 && errno == EINTR && interrupt_flag) { 391 interrupt_flag = 0; 392 return (0); 393 } 394 exit(0); 395 } 396 /* Handle 'printables' we cannot erase */ 397 if (cs == CTRL('L') || cs == CTRL('K')) 398 continue; 399 if (cs == '\t') 400 cs = ' '; 401 if ((c = cs&0177) == 0) 402 return (0); 403 404 if (c == EOT) 405 exit(1); 406 if (c == '\r' || c == '\n' || np >= name + sizeof name -1) { 407 putf("\r\n"); 408 break; 409 } 410 if (islower(c)) 411 lower = 1; 412 else if (isupper(c)) 413 upper = 1; 414 else if (c == ERASE || c == '\b') { 415 if (np > name) { 416 if (*--np == '\033') 417 xputs("\b\b \b\b"); 418 else if (isprint(*np)) 419 xputs("\b \b"); 420 } 421 continue; 422 } else if (c == KILL) { 423 putchr('\r'); 424 putf(LM); 425 while (np > name) { 426 if (*--np == '\033') 427 xputs(" "); 428 else if (isprint(*np)) 429 putchr(' '); 430 } 431 putchr('\r'); 432 prompt(); 433 np = name; 434 continue; 435 } else if (isdigit(c)) 436 digit++; 437 if (IG && (c <= ' ' || c > 0176)) 438 continue; 439 *np++ = c; 440 if (c == '\033') { 441 putchr('^'); 442 putchr('['); 443 } else 444 putchr(cs); 445 } 446 signal(SIGINT, SIG_IGN); 447 if (interrupt_flag) { 448 interrupt_flag = 0; 449 return (0); 450 } 451 *np = 0; 452 if (c == '\r') 453 crmod = 1; 454 return (1); 455 } 456 457 static void 458 putpad(char *s) 459 { 460 int pad = 0; 461 speed_t ospeed = cfgetospeed(&tmode); 462 463 if (isdigit((unsigned char)*s)) { 464 while (isdigit((unsigned char)*s)) { 465 pad *= 10; 466 pad += *s++ - '0'; 467 } 468 pad *= 10; 469 if (*s == '.' && isdigit((unsigned char)s[1])) { 470 pad += s[1] - '0'; 471 s += 2; 472 } 473 } 474 475 xputs(s); 476 /* 477 * If no delay needed, or output speed is 478 * not comprehensible, then don't try to delay. 479 */ 480 if (pad == 0 || ospeed <= 0) 481 return; 482 483 /* 484 * Round up by a half a character frame, and then do the delay. 485 * Too bad there are no user program accessible programmed delays. 486 * Transmitting pad characters slows many terminals down and also 487 * loads the system. 488 */ 489 pad = (pad * ospeed + 50000) / 100000; 490 while (pad--) 491 putchr(*PC); 492 } 493 494 static void 495 xputs(char *s) 496 { 497 while (*s) 498 putchr(*s++); 499 } 500 501 char outbuf[OBUFSIZ]; 502 int obufcnt = 0; 503 504 static void 505 putchr(int cc) 506 { 507 char c; 508 509 c = cc; 510 if (!NP) { 511 c |= partab[c&0177] & 0200; 512 if (OP) 513 c ^= 0200; 514 } 515 if (!UB) { 516 outbuf[obufcnt++] = c; 517 if (obufcnt >= OBUFSIZ) 518 oflush(); 519 } else 520 write(STDOUT_FILENO, &c, 1); 521 } 522 523 static void 524 oflush(void) 525 { 526 if (obufcnt) 527 write(STDOUT_FILENO, outbuf, obufcnt); 528 obufcnt = 0; 529 } 530 531 static void 532 prompt(void) 533 { 534 535 putf(LM); 536 if (CO) 537 putchr('\n'); 538 } 539 540 static void 541 putf(char *cp) 542 { 543 char *slash, db[100]; 544 time_t t; 545 546 while (*cp) { 547 if (*cp != '%') { 548 putchr(*cp++); 549 continue; 550 } 551 switch (*++cp) { 552 553 case 't': 554 slash = strrchr(ttyn, '/'); 555 if (slash == (char *) 0) 556 xputs(ttyn); 557 else 558 xputs(&slash[1]); 559 break; 560 561 case 'h': 562 xputs(globalhostname); 563 break; 564 565 case 'd': { 566 struct tm *tm; 567 time(&t); 568 if ((tm = localtime(&t)) != NULL) 569 if (strftime(db, sizeof(db), 570 "%l:%M%p on %A, %d %B %Y", tm) != 0) 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