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