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