1 /* $NetBSD: main.c,v 1.24 1997/11/18 21:29:11 thorpej 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 38 #ifndef lint 39 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"); 41 #endif /* not lint */ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "from: @(#)main.c 8.1 (Berkeley) 6/20/93"; 46 #else 47 __RCSID("$NetBSD: main.c,v 1.24 1997/11/18 21:29:11 thorpej Exp $"); 48 #endif 49 #endif /* not lint */ 50 51 #include <sys/param.h> 52 #include <sys/stat.h> 53 #include <termios.h> 54 #include <sys/ioctl.h> 55 #include <sys/resource.h> 56 #include <sys/utsname.h> 57 58 #include <errno.h> 59 #include <fcntl.h> 60 #include <time.h> 61 #include <ctype.h> 62 #include <fcntl.h> 63 #include <pwd.h> 64 #include <setjmp.h> 65 #include <signal.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <syslog.h> 69 #include <time.h> 70 #include <unistd.h> 71 #include <util.h> 72 73 #include "gettytab.h" 74 #include "pathnames.h" 75 #include "extern.h" 76 77 extern char *__progname; 78 79 /* 80 * Set the amount of running time that getty should accumulate 81 * before deciding that something is wrong and exit. 82 */ 83 #define GETTY_TIMEOUT 60 /* seconds */ 84 85 struct termios tmode, omode; 86 87 int crmod, digit, lower, upper; 88 89 char hostname[MAXHOSTNAMELEN]; 90 struct utsname kerninfo; 91 char name[16]; 92 char dev[] = _PATH_DEV; 93 char ttyn[32]; 94 char lockfile[512]; 95 uid_t ttyowner; 96 97 #define OBUFSIZ 128 98 #define TABBUFSIZ 512 99 100 char defent[TABBUFSIZ]; 101 char tabent[TABBUFSIZ]; 102 103 char *env[128]; 104 105 char partab[] = { 106 0001,0201,0201,0001,0201,0001,0001,0201, 107 0202,0004,0003,0205,0005,0206,0201,0001, 108 0201,0001,0001,0201,0001,0201,0201,0001, 109 0001,0201,0201,0001,0201,0001,0001,0201, 110 0200,0000,0000,0200,0000,0200,0200,0000, 111 0000,0200,0200,0000,0200,0000,0000,0200, 112 0000,0200,0200,0000,0200,0000,0000,0200, 113 0200,0000,0000,0200,0000,0200,0200,0000, 114 0200,0000,0000,0200,0000,0200,0200,0000, 115 0000,0200,0200,0000,0200,0000,0000,0200, 116 0000,0200,0200,0000,0200,0000,0000,0200, 117 0200,0000,0000,0200,0000,0200,0200,0000, 118 0000,0200,0200,0000,0200,0000,0000,0200, 119 0200,0000,0000,0200,0000,0200,0200,0000, 120 0200,0000,0000,0200,0000,0200,0200,0000, 121 0000,0200,0200,0000,0200,0000,0000,0201 122 }; 123 124 #define ERASE tmode.c_cc[VERASE] 125 #define KILL tmode.c_cc[VKILL] 126 #define EOT tmode.c_cc[VEOF] 127 128 static void dingdong __P((int)); 129 static void interrupt __P((int)); 130 void timeoverrun __P((int)); 131 132 jmp_buf timeout; 133 134 static void 135 dingdong(signo) 136 int signo; 137 { 138 139 alarm(0); 140 signal(SIGALRM, SIG_DFL); 141 longjmp(timeout, 1); 142 } 143 144 jmp_buf intrupt; 145 146 static void 147 interrupt(signo) 148 int signo; 149 { 150 151 signal(SIGINT, interrupt); 152 longjmp(intrupt, 1); 153 } 154 155 /* 156 * Action to take when getty is running too long. 157 */ 158 void 159 timeoverrun(signo) 160 int signo; 161 { 162 163 syslog(LOG_ERR, "getty exiting due to excessive running time\n"); 164 exit(1); 165 } 166 167 int main __P((int, char **)); 168 static int getname __P((void)); 169 static void oflush __P((void)); 170 static void prompt __P((void)); 171 static void putchr __P((int)); 172 static void putf __P((const char *)); 173 static void putpad __P((const char *)); 174 static void xputs __P((const char *)); 175 176 int 177 main(argc, argv) 178 int argc; 179 char *argv[]; 180 { 181 extern char **environ; 182 char *tname; 183 int repcnt = 0, failopenlogged = 0, uugetty = 0; 184 struct rlimit limit; 185 struct passwd *pw; 186 187 #ifdef __GNUC__ 188 (void)&tname; /* XXX gcc -Wall */ 189 #endif 190 191 signal(SIGINT, SIG_IGN); 192 /* 193 signal(SIGQUIT, SIG_DFL); 194 */ 195 openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH); 196 gethostname(hostname, sizeof(hostname)); 197 if (hostname[0] == '\0') 198 strcpy(hostname, "Amnesiac"); 199 uname(&kerninfo); 200 201 if (__progname[0] == 'u' && __progname[1] == 'u') 202 uugetty = 1; 203 204 /* 205 * Find id of uucp login (if present) so we can chown tty properly. 206 */ 207 if (uugetty && (pw = getpwnam("uucp"))) 208 ttyowner = pw->pw_uid; 209 else 210 ttyowner = 0; 211 212 /* 213 * Limit running time to deal with broken or dead lines. 214 */ 215 (void)signal(SIGXCPU, timeoverrun); 216 limit.rlim_max = RLIM_INFINITY; 217 limit.rlim_cur = GETTY_TIMEOUT; 218 (void)setrlimit(RLIMIT_CPU, &limit); 219 220 /* 221 * The following is a work around for vhangup interactions 222 * which cause great problems getting window systems started. 223 * If the tty line is "-", we do the old style getty presuming 224 * that the file descriptors are already set up for us. 225 * J. Gettys - MIT Project Athena. 226 */ 227 if (argc <= 2 || strcmp(argv[2], "-") == 0) { 228 strncpy(ttyn, ttyname(0), 32); 229 ttyn[31] = (char)NULL; 230 } 231 else { 232 int i; 233 234 strcpy(ttyn, dev); 235 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev)); 236 237 if (uugetty) { 238 chown(ttyn, ttyowner, 0); 239 strcpy(lockfile, _PATH_LOCK); 240 strncat(lockfile, argv[2], sizeof(lockfile)-sizeof(_PATH_LOCK)); 241 /* wait for lockfiles to go away before we try to open */ 242 if ( pidlock(lockfile, 0, 0, 0) != 0 ) { 243 syslog(LOG_ERR, "%s: can't create lockfile", ttyn); 244 exit(1); 245 } 246 unlink(lockfile); 247 } 248 if (strcmp(argv[0], "+") != 0) { 249 chown(ttyn, ttyowner, 0); 250 chmod(ttyn, 0600); 251 revoke(ttyn); 252 if (ttyaction(ttyn, "getty", "root")) 253 syslog(LOG_ERR,"%s: ttyaction failed", ttyn); 254 /* 255 * Delay the open so DTR stays down long enough to be detected. 256 */ 257 sleep(2); 258 while ((i = open(ttyn, O_RDWR)) == -1) { 259 if ((repcnt % 10 == 0) && 260 (errno != ENXIO || !failopenlogged)) { 261 syslog(LOG_ERR, "%s: %m", ttyn); 262 closelog(); 263 failopenlogged = 1; 264 } 265 repcnt++; 266 sleep(60); 267 } 268 if (uugetty && pidlock(lockfile, 0, 0, 0) != 0) { 269 syslog(LOG_ERR, "%s: can't create lockfile", ttyn); 270 exit(1); 271 } 272 (void) chown(lockfile, ttyowner, 0); 273 login_tty(i); 274 } 275 } 276 277 /* Start with default tty settings */ 278 if (tcgetattr(0, &tmode) < 0) { 279 syslog(LOG_ERR, "%s: %m", ttyn); 280 exit(1); 281 } 282 omode = tmode; 283 284 gettable("default", defent); 285 gendefaults(); 286 tname = "default"; 287 if (argc > 1) 288 tname = argv[1]; 289 for (;;) { 290 int off; 291 292 gettable(tname, tabent); 293 if (OPset || EPset || APset) 294 APset++, OPset++, EPset++; 295 setdefaults(); 296 off = 0; 297 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */ 298 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 299 ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 300 301 if (IS) 302 cfsetispeed(&tmode, IS); 303 else if (SP) 304 cfsetispeed(&tmode, SP); 305 if (OS) 306 cfsetospeed(&tmode, OS); 307 else if (SP) 308 cfsetospeed(&tmode, SP); 309 setflags(0); 310 setchars(); 311 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 312 syslog(LOG_ERR, "%s: %m", ttyn); 313 exit(1); 314 } 315 if (AB) { 316 tname = autobaud(); 317 continue; 318 } 319 if (PS) { 320 tname = portselector(); 321 continue; 322 } 323 if (CL && *CL) 324 putpad(CL); 325 edithost(HE); 326 if (IM && *IM) 327 putf(IM); 328 if (setjmp(timeout)) { 329 tmode.c_ispeed = tmode.c_ospeed = 0; 330 (void)tcsetattr(0, TCSANOW, &tmode); 331 exit(1); 332 } 333 if (TO) { 334 signal(SIGALRM, dingdong); 335 alarm(TO); 336 } 337 if (getname()) { 338 register int i; 339 340 oflush(); 341 alarm(0); 342 signal(SIGALRM, SIG_DFL); 343 if (name[0] == '-') { 344 xputs("user names may not start with '-'."); 345 continue; 346 } 347 if (!(upper || lower || digit)) 348 continue; 349 setflags(2); 350 if (crmod) { 351 tmode.c_iflag |= ICRNL; 352 tmode.c_oflag |= ONLCR; 353 } 354 #if XXX 355 if (upper || UC) 356 tmode.sg_flags |= LCASE; 357 if (lower || LC) 358 tmode.sg_flags &= ~LCASE; 359 #endif 360 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 361 syslog(LOG_ERR, "%s: %m", ttyn); 362 exit(1); 363 } 364 signal(SIGINT, SIG_DFL); 365 for (i = 0; environ[i] != (char *)0; i++) 366 env[i] = environ[i]; 367 makeenv(&env[i]); 368 369 limit.rlim_max = RLIM_INFINITY; 370 limit.rlim_cur = RLIM_INFINITY; 371 (void)setrlimit(RLIMIT_CPU, &limit); 372 execle(LO, "login", "-p", "--", name, (char *)0, env); 373 syslog(LOG_ERR, "%s: %m", LO); 374 exit(1); 375 } 376 alarm(0); 377 signal(SIGALRM, SIG_DFL); 378 signal(SIGINT, SIG_IGN); 379 if (NX && *NX) 380 tname = NX; 381 unlink(lockfile); 382 } 383 } 384 385 static int 386 getname() 387 { 388 register int c; 389 register char *np; 390 char cs; 391 392 /* 393 * Interrupt may happen if we use CBREAK mode 394 */ 395 if (setjmp(intrupt)) { 396 signal(SIGINT, SIG_IGN); 397 return (0); 398 } 399 signal(SIGINT, interrupt); 400 setflags(1); 401 prompt(); 402 if (PF > 0) { 403 oflush(); 404 sleep(PF); 405 PF = 0; 406 } 407 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 408 syslog(LOG_ERR, "%s: %m", ttyn); 409 exit(1); 410 } 411 crmod = digit = lower = upper = 0; 412 np = name; 413 for (;;) { 414 oflush(); 415 if (read(STDIN_FILENO, &cs, 1) <= 0) 416 exit(0); 417 if ((c = cs&0177) == 0) 418 return (0); 419 if (c == EOT) 420 exit(1); 421 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) { 422 putf("\r\n"); 423 break; 424 } 425 if (islower(c)) 426 lower = 1; 427 else if (isupper(c)) 428 upper = 1; 429 else if (c == ERASE || c == '#' || c == '\b') { 430 if (np > name) { 431 np--; 432 if (cfgetospeed(&tmode) >= 1200) 433 xputs("\b \b"); 434 else 435 putchr(cs); 436 } 437 continue; 438 } else if (c == KILL || c == '@') { 439 putchr(cs); 440 putchr('\r'); 441 if (cfgetospeed(&tmode) < 1200) 442 putchr('\n'); 443 /* this is the way they do it down under ... */ 444 else if (np > name) 445 xputs( 446 " \r"); 447 prompt(); 448 np = name; 449 continue; 450 } else if (isdigit(c)) 451 digit++; 452 if (IG && (c <= ' ' || c > 0176)) 453 continue; 454 *np++ = c; 455 putchr(cs); 456 } 457 signal(SIGINT, SIG_IGN); 458 *np = 0; 459 if (c == '\r') 460 crmod = 1; 461 if ((upper && !lower && !LC) || UC) 462 for (np = name; *np; np++) 463 if (isupper(*np)) 464 *np = tolower(*np); 465 return (1); 466 } 467 468 static void 469 putpad(s) 470 register const char *s; 471 { 472 register pad = 0; 473 speed_t ospeed = cfgetospeed(&tmode); 474 475 if (isdigit(*s)) { 476 while (isdigit(*s)) { 477 pad *= 10; 478 pad += *s++ - '0'; 479 } 480 pad *= 10; 481 if (*s == '.' && isdigit(s[1])) { 482 pad += s[1] - '0'; 483 s += 2; 484 } 485 } 486 487 xputs(s); 488 /* 489 * If no delay needed, or output speed is 490 * not comprehensible, then don't try to delay. 491 */ 492 if (pad == 0 || ospeed <= 0) 493 return; 494 495 /* 496 * Round up by a half a character frame, and then do the delay. 497 * Too bad there are no user program accessible programmed delays. 498 * Transmitting pad characters slows many terminals down and also 499 * loads the system. 500 */ 501 pad = (pad * ospeed + 50000) / 100000; 502 while (pad--) 503 putchr(*PC); 504 } 505 506 static void 507 xputs(s) 508 register const char *s; 509 { 510 while (*s) 511 putchr(*s++); 512 } 513 514 char outbuf[OBUFSIZ]; 515 int obufcnt = 0; 516 517 static void 518 putchr(cc) 519 int cc; 520 { 521 char c; 522 523 c = cc; 524 if (!NP) { 525 c |= partab[c&0177] & 0200; 526 if (OP) 527 c ^= 0200; 528 } 529 if (!UB) { 530 outbuf[obufcnt++] = c; 531 if (obufcnt >= OBUFSIZ) 532 oflush(); 533 } else 534 write(STDOUT_FILENO, &c, 1); 535 } 536 537 static void 538 oflush() 539 { 540 if (obufcnt) 541 write(STDOUT_FILENO, outbuf, obufcnt); 542 obufcnt = 0; 543 } 544 545 static void 546 prompt() 547 { 548 549 putf(LM); 550 if (CO) 551 putchr('\n'); 552 } 553 554 static void 555 putf(cp) 556 register const char *cp; 557 { 558 extern char editedhost[]; 559 time_t t; 560 char *slash, db[100]; 561 562 while (*cp) { 563 if (*cp != '%') { 564 putchr(*cp++); 565 continue; 566 } 567 switch (*++cp) { 568 569 case 't': 570 slash = strrchr(ttyn, '/'); 571 if (slash == (char *) 0) 572 xputs(ttyn); 573 else 574 xputs(&slash[1]); 575 break; 576 577 case 'h': 578 xputs(editedhost); 579 break; 580 581 case 'd': { 582 static char fmt[] = "%l:% %p on %A, %d %B %Y"; 583 584 fmt[4] = 'M'; /* I *hate* SCCS... */ 585 (void)time(&t); 586 (void)strftime(db, sizeof(db), fmt, localtime(&t)); 587 xputs(db); 588 break; 589 590 case 's': 591 xputs(kerninfo.sysname); 592 break; 593 594 case 'm': 595 xputs(kerninfo.machine); 596 break; 597 598 case 'r': 599 xputs(kerninfo.release); 600 break; 601 602 case 'v': 603 xputs(kerninfo.version); 604 break; 605 } 606 607 case '%': 608 putchr('%'); 609 break; 610 } 611 cp++; 612 } 613 } 614