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