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 35 static 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";*/ 42 static char rcsid[] = "$Id: main.c,v 1.13 1994/09/18 00:14:39 mycroft Exp $"; 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <sys/termios.h> 48 #include <sys/ioctl.h> 49 #include <sys/resource.h> 50 #include <sys/utsname.h> 51 #include <signal.h> 52 #include <fcntl.h> 53 #include <time.h> 54 #include <ctype.h> 55 #include <fcntl.h> 56 #include <setjmp.h> 57 #include <signal.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <syslog.h> 61 #include <time.h> 62 #include <unistd.h> 63 64 #include "gettytab.h" 65 #include "pathnames.h" 66 #include "extern.h" 67 68 /* 69 * Set the amount of running time that getty should accumulate 70 * before deciding that something is wrong and exit. 71 */ 72 #define GETTY_TIMEOUT 60 /* seconds */ 73 74 struct termios tmode, omode; 75 76 int crmod, digit, lower, upper; 77 78 char hostname[MAXHOSTNAMELEN]; 79 struct utsname kerninfo; 80 char name[16]; 81 char dev[] = _PATH_DEV; 82 char ttyn[32]; 83 char *portselector(); 84 char *ttyname(); 85 86 #define OBUFSIZ 128 87 #define TABBUFSIZ 512 88 89 char defent[TABBUFSIZ]; 90 char tabent[TABBUFSIZ]; 91 92 char *env[128]; 93 94 char partab[] = { 95 0001,0201,0201,0001,0201,0001,0001,0201, 96 0202,0004,0003,0205,0005,0206,0201,0001, 97 0201,0001,0001,0201,0001,0201,0201,0001, 98 0001,0201,0201,0001,0201,0001,0001,0201, 99 0200,0000,0000,0200,0000,0200,0200,0000, 100 0000,0200,0200,0000,0200,0000,0000,0200, 101 0000,0200,0200,0000,0200,0000,0000,0200, 102 0200,0000,0000,0200,0000,0200,0200,0000, 103 0200,0000,0000,0200,0000,0200,0200,0000, 104 0000,0200,0200,0000,0200,0000,0000,0200, 105 0000,0200,0200,0000,0200,0000,0000,0200, 106 0200,0000,0000,0200,0000,0200,0200,0000, 107 0000,0200,0200,0000,0200,0000,0000,0200, 108 0200,0000,0000,0200,0000,0200,0200,0000, 109 0200,0000,0000,0200,0000,0200,0200,0000, 110 0000,0200,0200,0000,0200,0000,0000,0201 111 }; 112 113 #define ERASE tmode.c_cc[VERASE] 114 #define KILL tmode.c_cc[VKILL] 115 #define EOT tmode.c_cc[VEOF] 116 117 jmp_buf timeout; 118 119 static void 120 dingdong() 121 { 122 123 alarm(0); 124 signal(SIGALRM, SIG_DFL); 125 longjmp(timeout, 1); 126 } 127 128 jmp_buf intrupt; 129 130 static void 131 interrupt() 132 { 133 134 signal(SIGINT, interrupt); 135 longjmp(intrupt, 1); 136 } 137 138 /* 139 * Action to take when getty is running too long. 140 */ 141 void 142 timeoverrun(signo) 143 int signo; 144 { 145 146 syslog(LOG_ERR, "getty exiting due to excessive running time\n"); 147 exit(1); 148 } 149 150 static int getname __P((void)); 151 static void oflush __P((void)); 152 static void prompt __P((void)); 153 static void putchr __P((int)); 154 static void putf __P((char *)); 155 static void putpad __P((char *)); 156 static void puts __P((char *)); 157 158 int 159 main(argc, argv) 160 int argc; 161 char *argv[]; 162 { 163 extern char **environ; 164 char *tname; 165 long allflags; 166 int repcnt = 0; 167 struct rlimit limit; 168 169 signal(SIGINT, SIG_IGN); 170 /* 171 signal(SIGQUIT, SIG_DFL); 172 */ 173 openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH); 174 gethostname(hostname, sizeof(hostname)); 175 if (hostname[0] == '\0') 176 strcpy(hostname, "Amnesiac"); 177 uname(&kerninfo); 178 179 /* 180 * Limit running time to deal with broken or dead lines. 181 */ 182 (void)signal(SIGXCPU, timeoverrun); 183 limit.rlim_max = RLIM_INFINITY; 184 limit.rlim_cur = GETTY_TIMEOUT; 185 (void)setrlimit(RLIMIT_CPU, &limit); 186 187 /* 188 * The following is a work around for vhangup interactions 189 * which cause great problems getting window systems started. 190 * If the tty line is "-", we do the old style getty presuming 191 * that the file descriptors are already set up for us. 192 * J. Gettys - MIT Project Athena. 193 */ 194 if (argc <= 2 || strcmp(argv[2], "-") == 0) 195 strcpy(ttyn, ttyname(0)); 196 else { 197 int i; 198 199 strcpy(ttyn, dev); 200 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev)); 201 if (strcmp(argv[0], "+") != 0) { 202 chown(ttyn, 0, 0); 203 chmod(ttyn, 0600); 204 revoke(ttyn); 205 /* 206 * Delay the open so DTR stays down long enough to be detected. 207 */ 208 sleep(2); 209 while ((i = open(ttyn, O_RDWR)) == -1) { 210 if (repcnt % 10 == 0) { 211 syslog(LOG_ERR, "%s: %m", ttyn); 212 closelog(); 213 } 214 repcnt++; 215 sleep(60); 216 } 217 login_tty(i); 218 } 219 } 220 221 /* Start with default tty settings */ 222 if (tcgetattr(0, &tmode) < 0) { 223 syslog(LOG_ERR, "%s: %m", ttyn); 224 exit(1); 225 } 226 omode = tmode; 227 228 gettable("default", defent); 229 gendefaults(); 230 tname = "default"; 231 if (argc > 1) 232 tname = argv[1]; 233 for (;;) { 234 int off; 235 236 gettable(tname, tabent); 237 if (OPset || EPset || APset) 238 APset++, OPset++, EPset++; 239 setdefaults(); 240 off = 0; 241 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */ 242 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 243 ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 244 245 if (IS) 246 cfsetispeed(&tmode, IS); 247 else if (SP) 248 cfsetispeed(&tmode, SP); 249 if (OS) 250 cfsetospeed(&tmode, OS); 251 else if (SP) 252 cfsetospeed(&tmode, SP); 253 setflags(0); 254 setchars(); 255 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 256 syslog(LOG_ERR, "%s: %m", ttyn); 257 exit(1); 258 } 259 if (AB) { 260 extern char *autobaud(); 261 262 tname = autobaud(); 263 continue; 264 } 265 if (PS) { 266 tname = portselector(); 267 continue; 268 } 269 if (CL && *CL) 270 putpad(CL); 271 edithost(HE); 272 if (IM && *IM) 273 putf(IM); 274 if (setjmp(timeout)) { 275 tmode.c_ispeed = tmode.c_ospeed = 0; 276 (void)tcsetattr(0, TCSANOW, &tmode); 277 exit(1); 278 } 279 if (TO) { 280 signal(SIGALRM, dingdong); 281 alarm(TO); 282 } 283 if (getname()) { 284 register int i; 285 286 oflush(); 287 alarm(0); 288 signal(SIGALRM, SIG_DFL); 289 if (name[0] == '-') { 290 puts("user names may not start with '-'."); 291 continue; 292 } 293 if (!(upper || lower || digit)) 294 continue; 295 setflags(2); 296 if (crmod) { 297 tmode.c_iflag |= ICRNL; 298 tmode.c_oflag |= ONLCR; 299 } 300 #if XXX 301 if (upper || UC) 302 tmode.sg_flags |= LCASE; 303 if (lower || LC) 304 tmode.sg_flags &= ~LCASE; 305 #endif 306 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 307 syslog(LOG_ERR, "%s: %m", ttyn); 308 exit(1); 309 } 310 signal(SIGINT, SIG_DFL); 311 for (i = 0; environ[i] != (char *)0; i++) 312 env[i] = environ[i]; 313 makeenv(&env[i]); 314 315 limit.rlim_max = RLIM_INFINITY; 316 limit.rlim_cur = RLIM_INFINITY; 317 (void)setrlimit(RLIMIT_CPU, &limit); 318 execle(LO, "login", "-p", name, (char *) 0, env); 319 syslog(LOG_ERR, "%s: %m", LO); 320 exit(1); 321 } 322 alarm(0); 323 signal(SIGALRM, SIG_DFL); 324 signal(SIGINT, SIG_IGN); 325 if (NX && *NX) 326 tname = NX; 327 } 328 } 329 330 static int 331 getname() 332 { 333 register int c; 334 register char *np; 335 char cs; 336 337 /* 338 * Interrupt may happen if we use CBREAK mode 339 */ 340 if (setjmp(intrupt)) { 341 signal(SIGINT, SIG_IGN); 342 return (0); 343 } 344 signal(SIGINT, interrupt); 345 setflags(1); 346 prompt(); 347 if (PF > 0) { 348 oflush(); 349 sleep(PF); 350 PF = 0; 351 } 352 if (tcsetattr(0, TCSANOW, &tmode) < 0) { 353 syslog(LOG_ERR, "%s: %m", ttyn); 354 exit(1); 355 } 356 crmod = digit = lower = upper = 0; 357 np = name; 358 for (;;) { 359 oflush(); 360 if (read(STDIN_FILENO, &cs, 1) <= 0) 361 exit(0); 362 if ((c = cs&0177) == 0) 363 return (0); 364 if (c == EOT) 365 exit(1); 366 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) { 367 putf("\r\n"); 368 break; 369 } 370 if (islower(c)) 371 lower = 1; 372 else if (isupper(c)) 373 upper = 1; 374 else if (c == ERASE || c == '#' || c == '\b') { 375 if (np > name) { 376 np--; 377 if (cfgetospeed(&tmode) >= 1200) 378 puts("\b \b"); 379 else 380 putchr(cs); 381 } 382 continue; 383 } else if (c == KILL || c == '@') { 384 putchr(cs); 385 putchr('\r'); 386 if (cfgetospeed(&tmode) < 1200) 387 putchr('\n'); 388 /* this is the way they do it down under ... */ 389 else if (np > name) 390 puts(" \r"); 391 prompt(); 392 np = name; 393 continue; 394 } else if (isdigit(c)) 395 digit++; 396 if (IG && (c <= ' ' || c > 0176)) 397 continue; 398 *np++ = c; 399 putchr(cs); 400 } 401 signal(SIGINT, SIG_IGN); 402 *np = 0; 403 if (c == '\r') 404 crmod = 1; 405 if (upper && !lower && !LC || UC) 406 for (np = name; *np; np++) 407 if (isupper(*np)) 408 *np = tolower(*np); 409 return (1); 410 } 411 412 static void 413 putpad(s) 414 register char *s; 415 { 416 register pad = 0; 417 speed_t ospeed = cfgetospeed(&tmode); 418 419 if (isdigit(*s)) { 420 while (isdigit(*s)) { 421 pad *= 10; 422 pad += *s++ - '0'; 423 } 424 pad *= 10; 425 if (*s == '.' && isdigit(s[1])) { 426 pad += s[1] - '0'; 427 s += 2; 428 } 429 } 430 431 puts(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 puts(s) 452 register char *s; 453 { 454 while (*s) 455 putchr(*s++); 456 } 457 458 char outbuf[OBUFSIZ]; 459 int obufcnt = 0; 460 461 static void 462 putchr(cc) 463 int cc; 464 { 465 char c; 466 467 c = cc; 468 if (!NP) { 469 c |= partab[c&0177] & 0200; 470 if (OP) 471 c ^= 0200; 472 } 473 if (!UB) { 474 outbuf[obufcnt++] = c; 475 if (obufcnt >= OBUFSIZ) 476 oflush(); 477 } else 478 write(STDOUT_FILENO, &c, 1); 479 } 480 481 static void 482 oflush() 483 { 484 if (obufcnt) 485 write(STDOUT_FILENO, outbuf, obufcnt); 486 obufcnt = 0; 487 } 488 489 static void 490 prompt() 491 { 492 493 putf(LM); 494 if (CO) 495 putchr('\n'); 496 } 497 498 static void 499 putf(cp) 500 register char *cp; 501 { 502 extern char editedhost[]; 503 time_t t; 504 char *slash, db[100]; 505 506 while (*cp) { 507 if (*cp != '%') { 508 putchr(*cp++); 509 continue; 510 } 511 switch (*++cp) { 512 513 case 't': 514 slash = strrchr(ttyn, '/'); 515 if (slash == (char *) 0) 516 puts(ttyn); 517 else 518 puts(&slash[1]); 519 break; 520 521 case 'h': 522 puts(editedhost); 523 break; 524 525 case 'd': { 526 static char fmt[] = "%l:% %p on %A, %d %B %Y"; 527 528 fmt[4] = 'M'; /* I *hate* SCCS... */ 529 (void)time(&t); 530 (void)strftime(db, sizeof(db), fmt, localtime(&t)); 531 puts(db); 532 break; 533 534 case 's': 535 puts(kerninfo.sysname); 536 break; 537 538 case 'm': 539 puts(kerninfo.machine); 540 break; 541 542 case 'r': 543 puts(kerninfo.release); 544 break; 545 546 case 'v': 547 puts(kerninfo.version); 548 break; 549 } 550 551 case '%': 552 putchr('%'); 553 break; 554 } 555 cp++; 556 } 557 } 558