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