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