1 /* $OpenBSD: main.c,v 1.34 2014/11/19 13:35:37 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/param.h> 33 #include <sys/stat.h> 34 #include <termios.h> 35 #include <sys/ioctl.h> 36 #include <sys/resource.h> 37 #include <sys/utsname.h> 38 #include <errno.h> 39 #include <signal.h> 40 #include <fcntl.h> 41 #include <time.h> 42 #include <ctype.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <syslog.h> 46 #include <stdio.h> 47 #include <unistd.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[MAXHOSTNAMELEN]; 75 struct utsname kerninfo; 76 char name[MAXLOGNAME]; 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 snprintf(ttyn, sizeof ttyn, "%s", ttyname(0)); 189 } else { 190 int i; 191 192 snprintf(ttyn, sizeof ttyn, "%s%s", dev, argv[2]); 193 if (strcmp(argv[0], "+") != 0) { 194 chown(ttyn, 0, 0); 195 chmod(ttyn, 0600); 196 revoke(ttyn); 197 /* 198 * Delay the open so DTR stays down long enough to be detected. 199 */ 200 sleep(2); 201 while ((i = open(ttyn, O_RDWR)) == -1) { 202 if ((repcnt % 10 == 0) && 203 (errno != ENXIO || !failopenlogged)) { 204 syslog(LOG_ERR, "%s: %m", ttyn); 205 closelog(); 206 failopenlogged = 1; 207 } 208 repcnt++; 209 sleep(60); 210 } 211 login_tty(i); 212 } 213 } 214 215 /* Start with default tty settings */ 216 if (tcgetattr(0, &tmode) < 0) { 217 syslog(LOG_ERR, "%s: %m", ttyn); 218 exit(1); 219 } 220 omode = tmode; 221 222 gettable("default", defent); 223 gendefaults(); 224 tname = "default"; 225 if (argc > 1) 226 tname = argv[1]; 227 for (;;) { 228 int off; 229 230 gettable(tname, tabent); 231 if (OPset || EPset || APset) 232 APset++, OPset++, EPset++; 233 setdefaults(); 234 off = 0; 235 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */ 236 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 237 ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 238 239 if (IS) 240 cfsetispeed(&tmode, IS); 241 else if (SP) 242 cfsetispeed(&tmode, SP); 243 if (OS) 244 cfsetospeed(&tmode, OS); 245 else if (SP) 246 cfsetospeed(&tmode, SP); 247 setflags(0); 248 setchars(); 249 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 250 syslog(LOG_ERR, "%s: %m", ttyn); 251 exit(1); 252 } 253 if (AB) { 254 tname = autobaud(); 255 continue; 256 } 257 if (PS) { 258 tname = portselector(); 259 continue; 260 } 261 if (CL && *CL) 262 putpad(CL); 263 edithost(HE); 264 if (IM && *IM) 265 putf(IM); 266 if (TO) { 267 signal(SIGALRM, dingdong); 268 alarm(TO); 269 } 270 if ((rval = getname()) == 2) { 271 oflush(); 272 alarm(0); 273 signal(SIGALRM, SIG_DFL); 274 execle(PP, "ppplogin", ttyn, (char *) 0, env); 275 syslog(LOG_ERR, "%s: %m", PP); 276 exit(1); 277 } else if (rval) { 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] != (char *)0; 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, (char *)0, 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 int ppp_state = 0, ppp_connection = 0; 332 unsigned char cs; 333 int c, r; 334 char *np; 335 336 /* 337 * Interrupt may happen if we use CBREAK mode 338 */ 339 signal(SIGINT, interrupt); 340 setflags(1); 341 prompt(); 342 if (PF > 0) { 343 oflush(); 344 sleep(PF); 345 PF = 0; 346 } 347 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 348 syslog(LOG_ERR, "%s: %m", ttyn); 349 exit(1); 350 } 351 crmod = digit = lower = upper = 0; 352 np = name; 353 for (;;) { 354 oflush(); 355 r = read(STDIN_FILENO, &cs, 1); 356 if (r <= 0) { 357 if (r == -1 && errno == EINTR && interrupt_flag) { 358 interrupt_flag = 0; 359 return (0); 360 } 361 exit(0); 362 } 363 if ((c = cs&0177) == 0) 364 return (0); 365 366 /* 367 * PPP detection state machine.. 368 * Look for sequences: 369 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or 370 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC) 371 * See RFC1662. 372 * Derived from code from Michael Hancock <michaelh@cet.co.jp> 373 * and Erik 'PPP' Olson <eriko@wrq.com> 374 */ 375 if (PP && cs == PPP_FRAME) { 376 ppp_state = 1; 377 } else if (ppp_state == 1 && cs == PPP_STATION) { 378 ppp_state = 2; 379 } else if (ppp_state == 2 && cs == PPP_ESCAPE) { 380 ppp_state = 3; 381 } else if ((ppp_state == 2 && cs == PPP_CONTROL) || 382 (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { 383 ppp_state = 4; 384 } else if (ppp_state == 4 && cs == PPP_LCP_HI) { 385 ppp_state = 5; 386 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) { 387 ppp_connection = 1; 388 break; 389 } else { 390 ppp_state = 0; 391 } 392 393 if (c == EOT) 394 exit(1); 395 if (c == '\r' || c == '\n' || np >= name + sizeof name -1) { 396 putf("\r\n"); 397 break; 398 } 399 if (islower(c)) 400 lower = 1; 401 else if (isupper(c)) 402 upper = 1; 403 else if (c == ERASE || c == '#' || c == '\b') { 404 if (np > name) { 405 np--; 406 if (cfgetospeed(&tmode) >= 1200) 407 xputs("\b \b"); 408 else 409 putchr(cs); 410 } 411 continue; 412 } else if (c == KILL || c == '@') { 413 putchr(cs); 414 putchr('\r'); 415 if (cfgetospeed(&tmode) < 1200) 416 putchr('\n'); 417 /* this is the way they do it down under ... */ 418 else if (np > name) 419 xputs(" \r"); 420 prompt(); 421 np = name; 422 continue; 423 } else if (isdigit(c)) 424 digit++; 425 if (IG && (c <= ' ' || c > 0176)) 426 continue; 427 *np++ = c; 428 putchr(cs); 429 } 430 signal(SIGINT, SIG_IGN); 431 if (interrupt_flag) { 432 interrupt_flag = 0; 433 return (0); 434 } 435 *np = 0; 436 if (c == '\r') 437 crmod = 1; 438 return (1 + ppp_connection); 439 } 440 441 static void 442 putpad(char *s) 443 { 444 int pad = 0; 445 speed_t ospeed = cfgetospeed(&tmode); 446 447 if (isdigit((unsigned char)*s)) { 448 while (isdigit((unsigned char)*s)) { 449 pad *= 10; 450 pad += *s++ - '0'; 451 } 452 pad *= 10; 453 if (*s == '.' && isdigit((unsigned char)s[1])) { 454 pad += s[1] - '0'; 455 s += 2; 456 } 457 } 458 459 xputs(s); 460 /* 461 * If no delay needed, or output speed is 462 * not comprehensible, then don't try to delay. 463 */ 464 if (pad == 0 || ospeed <= 0) 465 return; 466 467 /* 468 * Round up by a half a character frame, and then do the delay. 469 * Too bad there are no user program accessible programmed delays. 470 * Transmitting pad characters slows many terminals down and also 471 * loads the system. 472 */ 473 pad = (pad * ospeed + 50000) / 100000; 474 while (pad--) 475 putchr(*PC); 476 } 477 478 static void 479 xputs(char *s) 480 { 481 while (*s) 482 putchr(*s++); 483 } 484 485 char outbuf[OBUFSIZ]; 486 int obufcnt = 0; 487 488 static void 489 putchr(int cc) 490 { 491 char c; 492 493 c = cc; 494 if (!NP) { 495 c |= partab[c&0177] & 0200; 496 if (OP) 497 c ^= 0200; 498 } 499 if (!UB) { 500 outbuf[obufcnt++] = c; 501 if (obufcnt >= OBUFSIZ) 502 oflush(); 503 } else 504 write(STDOUT_FILENO, &c, 1); 505 } 506 507 static void 508 oflush(void) 509 { 510 if (obufcnt) 511 write(STDOUT_FILENO, outbuf, obufcnt); 512 obufcnt = 0; 513 } 514 515 static void 516 prompt(void) 517 { 518 519 putf(LM); 520 if (CO) 521 putchr('\n'); 522 } 523 524 static void 525 putf(char *cp) 526 { 527 extern char editedhost[]; 528 char *slash, db[100]; 529 time_t t; 530 531 while (*cp) { 532 if (*cp != '%') { 533 putchr(*cp++); 534 continue; 535 } 536 switch (*++cp) { 537 538 case 't': 539 slash = strrchr(ttyn, '/'); 540 if (slash == (char *) 0) 541 xputs(ttyn); 542 else 543 xputs(&slash[1]); 544 break; 545 546 case 'h': 547 xputs(editedhost); 548 break; 549 550 case 'd': { 551 (void)time(&t); 552 (void)strftime(db, sizeof(db), 553 "%l:%M%p on %A, %d %B %Y", localtime(&t)); 554 xputs(db); 555 break; 556 } 557 558 case 's': 559 xputs(kerninfo.sysname); 560 break; 561 562 case 'm': 563 xputs(kerninfo.machine); 564 break; 565 566 case 'r': 567 xputs(kerninfo.release); 568 break; 569 570 case 'v': 571 xputs(kerninfo.version); 572 break; 573 574 case '%': 575 putchr('%'); 576 break; 577 } 578 cp++; 579 } 580 } 581