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 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 gettable("default", defent); 228 gendefaults(); 229 tname = "default"; 230 if (argc > 1) 231 tname = argv[1]; 232 for (;;) { 233 int off; 234 235 gettable(tname, tabent); 236 if (OPset || EPset || APset) 237 APset++, OPset++, EPset++; 238 setdefaults(); 239 off = 0; 240 ioctl(0, TIOCFLUSH, &off); /* clear out the crap */ 241 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */ 242 ioctl(0, FIOASYNC, &off); /* ditto for async mode */ 243 if (IS) 244 tmode.sg_ispeed = speed(IS); 245 else if (SP) 246 tmode.sg_ispeed = speed(SP); 247 if (OS) 248 tmode.sg_ospeed = speed(OS); 249 else if (SP) 250 tmode.sg_ospeed = speed(SP); 251 tmode.sg_flags = setflags(0); 252 ioctl(0, TIOCSETP, &tmode); 253 setchars(); 254 ioctl(0, TIOCSETC, &tc); 255 if (HC) 256 ioctl(0, TIOCHPCL, 0); 257 if (AB) { 258 extern char *autobaud(); 259 260 tname = autobaud(); 261 continue; 262 } 263 if (PS) { 264 tname = portselector(); 265 continue; 266 } 267 if (CL && *CL) 268 putpad(CL); 269 edithost(HE); 270 if (IM && *IM) 271 putf(IM); 272 if (setjmp(timeout)) { 273 tmode.sg_ispeed = tmode.sg_ospeed = 0; 274 ioctl(0, TIOCSETP, &tmode); 275 exit(1); 276 } 277 if (TO) { 278 signal(SIGALRM, dingdong); 279 alarm(TO); 280 } 281 if (getname()) { 282 register int i; 283 284 oflush(); 285 alarm(0); 286 signal(SIGALRM, SIG_DFL); 287 if (name[0] == '-') { 288 puts("user names may not start with '-'."); 289 continue; 290 } 291 if (!(upper || lower || digit)) 292 continue; 293 allflags = setflags(2); 294 tmode.sg_flags = allflags & 0xffff; 295 allflags >>= 16; 296 if (crmod || NL) 297 tmode.sg_flags |= CRMOD; 298 if (upper || UC) 299 tmode.sg_flags |= LCASE; 300 if (lower || LC) 301 tmode.sg_flags &= ~LCASE; 302 ioctl(0, TIOCSETP, &tmode); 303 ioctl(0, TIOCSLTC, <c); 304 ioctl(0, TIOCLSET, &allflags); 305 signal(SIGINT, SIG_DFL); 306 for (i = 0; environ[i] != (char *)0; i++) 307 env[i] = environ[i]; 308 makeenv(&env[i]); 309 310 /* 311 * this is what login was doing anyway. 312 * soon we rewrite getty completely. 313 */ 314 set_ttydefaults(0); 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 tmode.sg_flags = setflags(0); 346 ioctl(0, TIOCSETP, &tmode); 347 tmode.sg_flags = setflags(1); 348 prompt(); 349 if (PF > 0) { 350 oflush(); 351 sleep(PF); 352 PF = 0; 353 } 354 ioctl(0, TIOCSETP, &tmode); 355 crmod = digit = lower = upper = 0; 356 np = name; 357 for (;;) { 358 oflush(); 359 if (read(STDIN_FILENO, &cs, 1) <= 0) 360 exit(0); 361 if ((c = cs&0177) == 0) 362 return (0); 363 if (c == EOT) 364 exit(1); 365 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) { 366 putf("\r\n"); 367 break; 368 } 369 if (islower(c)) 370 lower = 1; 371 else if (isupper(c)) 372 upper = 1; 373 else if (c == ERASE || c == '#' || c == '\b') { 374 if (np > name) { 375 np--; 376 if (tmode.sg_ospeed >= B1200) 377 puts("\b \b"); 378 else 379 putchr(cs); 380 } 381 continue; 382 } else if (c == KILL || c == '@') { 383 putchr(cs); 384 putchr('\r'); 385 if (tmode.sg_ospeed < B1200) 386 putchr('\n'); 387 /* this is the way they do it down under ... */ 388 else if (np > name) 389 puts(" \r"); 390 prompt(); 391 np = name; 392 continue; 393 } else if (isdigit(c)) 394 digit++; 395 if (IG && (c <= ' ' || c > 0176)) 396 continue; 397 *np++ = c; 398 putchr(cs); 399 } 400 signal(SIGINT, SIG_IGN); 401 *np = 0; 402 if (c == '\r') 403 crmod = 1; 404 if (upper && !lower && !LC || UC) 405 for (np = name; *np; np++) 406 if (isupper(*np)) 407 *np = tolower(*np); 408 return (1); 409 } 410 411 static 412 short tmspc10[] = { 413 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15 414 }; 415 416 static void 417 putpad(s) 418 register char *s; 419 { 420 register pad = 0; 421 register mspc10; 422 423 if (isdigit(*s)) { 424 while (isdigit(*s)) { 425 pad *= 10; 426 pad += *s++ - '0'; 427 } 428 pad *= 10; 429 if (*s == '.' && isdigit(s[1])) { 430 pad += s[1] - '0'; 431 s += 2; 432 } 433 } 434 435 puts(s); 436 /* 437 * If no delay needed, or output speed is 438 * not comprehensible, then don't try to delay. 439 */ 440 if (pad == 0) 441 return; 442 if (tmode.sg_ospeed <= 0 || 443 tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0])) 444 return; 445 446 /* 447 * Round up by a half a character frame, and then do the delay. 448 * Too bad there are no user program accessible programmed delays. 449 * Transmitting pad characters slows many terminals down and also 450 * loads the system. 451 */ 452 mspc10 = tmspc10[tmode.sg_ospeed]; 453 pad += mspc10 / 2; 454 for (pad /= mspc10; pad > 0; pad--) 455 putchr(*PC); 456 } 457 458 static void 459 puts(s) 460 register char *s; 461 { 462 while (*s) 463 putchr(*s++); 464 } 465 466 char outbuf[OBUFSIZ]; 467 int obufcnt = 0; 468 469 static void 470 putchr(cc) 471 int cc; 472 { 473 char c; 474 475 c = cc; 476 if (!NP) { 477 c |= partab[c&0177] & 0200; 478 if (OP) 479 c ^= 0200; 480 } 481 if (!UB) { 482 outbuf[obufcnt++] = c; 483 if (obufcnt >= OBUFSIZ) 484 oflush(); 485 } else 486 write(STDOUT_FILENO, &c, 1); 487 } 488 489 static void 490 oflush() 491 { 492 if (obufcnt) 493 write(STDOUT_FILENO, outbuf, obufcnt); 494 obufcnt = 0; 495 } 496 497 static void 498 prompt() 499 { 500 501 putf(LM); 502 if (CO) 503 putchr('\n'); 504 } 505 506 static void 507 putf(cp) 508 register char *cp; 509 { 510 extern char editedhost[]; 511 time_t t; 512 char *slash, db[100]; 513 514 while (*cp) { 515 if (*cp != '%') { 516 putchr(*cp++); 517 continue; 518 } 519 switch (*++cp) { 520 521 case 't': 522 slash = strrchr(ttyn, '/'); 523 if (slash == (char *) 0) 524 puts(ttyn); 525 else 526 puts(&slash[1]); 527 break; 528 529 case 'h': 530 puts(editedhost); 531 break; 532 533 case 'd': { 534 static char fmt[] = "%l:% %P on %A, %d %B %Y"; 535 536 fmt[4] = 'M'; /* I *hate* SCCS... */ 537 (void)time(&t); 538 (void)strftime(db, sizeof(db), fmt, localtime(&t)); 539 puts(db); 540 break; 541 } 542 543 case '%': 544 putchr('%'); 545 break; 546 } 547 cp++; 548 } 549 } 550