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