main.c revision 21120
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.11 1996/11/13 01:06:40 pst 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 296 /* if a delay was specified then sleep for that 297 number of seconds before writing the initial prompt */ 298 if(DE) 299 sleep(DE); 300 301 if (IM && *IM) 302 putf(IM); 303 if (setjmp(timeout)) { 304 cfsetispeed(&tmode, B0); 305 cfsetospeed(&tmode, B0); 306 (void)tcsetattr(0, TCSANOW, &tmode); 307 exit(1); 308 } 309 if (TO) { 310 signal(SIGALRM, dingdong); 311 alarm(TO); 312 } 313 if ((rval = getname()) == 2) { 314 execle(PP, "ppplogin", ttyn, (char *) 0, env); 315 syslog(LOG_ERR, "%s: %m", PP); 316 exit(1); 317 } else if (rval) { 318 register int i; 319 320 oflush(); 321 alarm(0); 322 signal(SIGALRM, SIG_DFL); 323 if (name[0] == '-') { 324 puts("user names may not start with '-'."); 325 continue; 326 } 327 if (!(upper || lower || digit)) 328 continue; 329 setflags(2); 330 if (crmod) { 331 tmode.c_iflag |= ICRNL; 332 tmode.c_oflag |= ONLCR; 333 } 334#if REALLY_OLD_TTYS 335 if (upper || UC) 336 tmode.sg_flags |= LCASE; 337 if (lower || LC) 338 tmode.sg_flags &= ~LCASE; 339#endif 340 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 341 syslog(LOG_ERR, "%s: %m", ttyn); 342 exit(1); 343 } 344 signal(SIGINT, SIG_DFL); 345 for (i = 0; environ[i] != (char *)0; i++) 346 env[i] = environ[i]; 347 makeenv(&env[i]); 348 349 limit.rlim_max = RLIM_INFINITY; 350 limit.rlim_cur = RLIM_INFINITY; 351 (void)setrlimit(RLIMIT_CPU, &limit); 352 execle(LO, "login", "-p", name, (char *) 0, env); 353 syslog(LOG_ERR, "%s: %m", LO); 354 exit(1); 355 } 356 alarm(0); 357 signal(SIGALRM, SIG_DFL); 358 signal(SIGINT, SIG_IGN); 359 if (NX && *NX) 360 tname = NX; 361 } 362} 363 364static int 365getname() 366{ 367 register int c; 368 register char *np; 369 unsigned char cs; 370 int ppp_state; 371 int ppp_connection = 0; 372 373 /* 374 * Interrupt may happen if we use CBREAK mode 375 */ 376 if (setjmp(intrupt)) { 377 signal(SIGINT, SIG_IGN); 378 return (0); 379 } 380 signal(SIGINT, interrupt); 381 setflags(1); 382 prompt(); 383 oflush(); 384 if (PF > 0) { 385 sleep(PF); 386 PF = 0; 387 } 388 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 389 syslog(LOG_ERR, "%s: %m", ttyn); 390 exit(1); 391 } 392 crmod = digit = lower = upper = 0; 393 np = name; 394 for (;;) { 395 oflush(); 396 if (read(STDIN_FILENO, &cs, 1) <= 0) 397 exit(0); 398 if ((c = cs&0177) == 0) 399 return (0); 400 401 /* PPP detection state machine.. 402 Look for sequences: 403 PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or 404 PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC) 405 See RFC1662. 406 Derived from code from Michael Hancock, <michaelh@cet.co.jp> 407 and Erik 'PPP' Olson, <eriko@wrq.com> 408 */ 409 410 if (PP && (cs == PPP_FRAME)) { 411 ppp_state = 1; 412 } else if (ppp_state == 1 && cs == PPP_STATION) { 413 ppp_state = 2; 414 } else if (ppp_state == 2 && cs == PPP_ESCAPE) { 415 ppp_state = 3; 416 } else if ((ppp_state == 2 && cs == PPP_CONTROL) 417 || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { 418 ppp_state = 4; 419 } else if (ppp_state == 4 && cs == PPP_LCP_HI) { 420 ppp_state = 5; 421 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) { 422 ppp_connection = 1; 423 break; 424 } else { 425 ppp_state = 0; 426 } 427 428 if (c == EOT || c == CTRL('d')) 429 exit(1); 430 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) { 431 putf("\r\n"); 432 break; 433 } 434 if (islower(c)) 435 lower = 1; 436 else if (isupper(c)) 437 upper = 1; 438 else if (c == ERASE || c == '\b' || c == 0177) { 439 if (np > name) { 440 np--; 441 if (cfgetospeed(&tmode) >= 1200) 442 puts("\b \b"); 443 else 444 putchr(cs); 445 } 446 continue; 447 } else if (c == KILL || c == CTRL('u')) { 448 putchr('\r'); 449 if (cfgetospeed(&tmode) < 1200) 450 putchr('\n'); 451 /* this is the way they do it down under ... */ 452 else if (np > name) 453 puts(" \r"); 454 prompt(); 455 np = name; 456 continue; 457 } else if (isdigit(c)) 458 digit++; 459 if (IG && (c <= ' ' || c > 0176)) 460 continue; 461 *np++ = c; 462 putchr(cs); 463 } 464 signal(SIGINT, SIG_IGN); 465 *np = 0; 466 if (c == '\r') 467 crmod = 1; 468 if ((upper && !lower && !LC) || UC) 469 for (np = name; *np; np++) 470 if (isupper(*np)) 471 *np = tolower(*np); 472 return (1 + ppp_connection); 473} 474 475static void 476putpad(s) 477 register const char *s; 478{ 479 register pad = 0; 480 speed_t ospeed = cfgetospeed(&tmode); 481 482 if (isdigit(*s)) { 483 while (isdigit(*s)) { 484 pad *= 10; 485 pad += *s++ - '0'; 486 } 487 pad *= 10; 488 if (*s == '.' && isdigit(s[1])) { 489 pad += s[1] - '0'; 490 s += 2; 491 } 492 } 493 494 puts(s); 495 /* 496 * If no delay needed, or output speed is 497 * not comprehensible, then don't try to delay. 498 */ 499 if (pad == 0 || ospeed <= 0) 500 return; 501 502 /* 503 * Round up by a half a character frame, and then do the delay. 504 * Too bad there are no user program accessible programmed delays. 505 * Transmitting pad characters slows many terminals down and also 506 * loads the system. 507 */ 508 pad = (pad * ospeed + 50000) / 100000; 509 while (pad--) 510 putchr(*PC); 511} 512 513static void 514puts(s) 515 register const char *s; 516{ 517 while (*s) 518 putchr(*s++); 519} 520 521char outbuf[OBUFSIZ]; 522int obufcnt = 0; 523 524static void 525putchr(cc) 526 int cc; 527{ 528 char c; 529 530 c = cc; 531 if (!NP) { 532 c |= partab[c&0177] & 0200; 533 if (OP) 534 c ^= 0200; 535 } 536 if (!UB) { 537 outbuf[obufcnt++] = c; 538 if (obufcnt >= OBUFSIZ) 539 oflush(); 540 } else 541 write(STDOUT_FILENO, &c, 1); 542} 543 544static void 545oflush() 546{ 547 if (obufcnt) 548 write(STDOUT_FILENO, outbuf, obufcnt); 549 obufcnt = 0; 550} 551 552static void 553prompt() 554{ 555 556 putf(LM); 557 if (CO) 558 putchr('\n'); 559} 560 561static void 562putf(cp) 563 register const char *cp; 564{ 565 extern char editedhost[]; 566 time_t t; 567 char *slash, db[100]; 568 569 while (*cp) { 570 if (*cp != '%') { 571 putchr(*cp++); 572 continue; 573 } 574 switch (*++cp) { 575 576 case 't': 577 slash = strrchr(ttyn, '/'); 578 if (slash == (char *) 0) 579 puts(ttyn); 580 else 581 puts(&slash[1]); 582 break; 583 584 case 'h': 585 puts(editedhost); 586 break; 587 588 case 'd': { 589 t = (time_t)0; 590 (void)time(&t); 591 if (Lo) 592 (void)setlocale(LC_TIME, Lo); 593 (void)strftime(db, sizeof(db), "%+", localtime(&t)); 594 puts(db); 595 break; 596 597 case 's': 598 puts(kerninfo.sysname); 599 break; 600 601 case 'm': 602 puts(kerninfo.machine); 603 break; 604 605 case 'r': 606 puts(kerninfo.release); 607 break; 608 609 case 'v': 610 puts(kerninfo.version); 611 break; 612 } 613 614 case '%': 615 putchr('%'); 616 break; 617 } 618 cp++; 619 } 620} 621