main.c revision 1.65 1 /* $NetBSD: main.c,v 1.65 2016/03/17 00:21:04 christos 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.65 2016/03/17 00:21:04 christos 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 sigjmp_buf timeout;
139
140 __dead static void
141 /*ARGSUSED*/
142 dingdong(int signo)
143 {
144
145 (void)alarm(0);
146 (void)signal(SIGALRM, SIG_DFL);
147 siglongjmp(timeout, 1);
148 }
149
150 sigjmp_buf intrupt;
151
152 __dead static void
153 /*ARGSUSED*/
154 interrupt(int signo)
155 {
156
157 (void)signal(SIGINT, interrupt);
158 siglongjmp(intrupt, 1);
159 }
160
161 /*
162 * Action to take when getty is running too long.
163 */
164 __dead 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 int repcnt = 0, failopenlogged = 0;
187 volatile int first_time = 1;
188 struct rlimit limit;
189 struct passwd *pw;
190 int rval;
191 /* this is used past the siglongjmp, so make sure it is not cached
192 in registers that might become invalid. */
193 volatile int uugetty = 0;
194 const char * volatile tname = "default";
195
196 (void)signal(SIGINT, SIG_IGN);
197 openlog("getty", LOG_PID, LOG_AUTH);
198 (void)gethostname(hostname, sizeof(hostname));
199 hostname[sizeof(hostname) - 1] = '\0';
200 if (hostname[0] == '\0')
201 (void)strlcpy(hostname, "Amnesiac", sizeof(hostname));
202 (void)uname(&kerninfo);
203
204 progname = getprogname();
205 if (progname[0] == 'u' && progname[1] == 'u')
206 uugetty = 1;
207
208 /*
209 * Find id of uucp login (if present) so we can chown tty properly.
210 */
211 if (uugetty && (pw = getpwnam("uucp")))
212 ttyowner = pw->pw_uid;
213 else
214 ttyowner = 0;
215
216 /*
217 * Limit running time to deal with broken or dead lines.
218 */
219 (void)signal(SIGXCPU, timeoverrun);
220 limit.rlim_max = RLIM_INFINITY;
221 limit.rlim_cur = GETTY_TIMEOUT;
222 (void)setrlimit(RLIMIT_CPU, &limit);
223
224 /*
225 * The following is a work around for vhangup interactions
226 * which cause great problems getting window systems started.
227 * If the tty line is "-", we do the old style getty presuming
228 * that the file descriptors are already set up for us.
229 * J. Gettys - MIT Project Athena.
230 */
231 if (argc <= 2 || strcmp(argv[2], "-") == 0) {
232 (void)strlcpy(ttyn, ttyname(0), sizeof(ttyn));
233 }
234 else {
235 int i;
236
237 rawttyn = argv[2];
238 (void)strlcpy(ttyn, dev, sizeof(ttyn));
239 (void)strlcat(ttyn, argv[2], sizeof(ttyn));
240 if (uugetty) {
241 (void)chown(ttyn, ttyowner, 0);
242 (void)strlcpy(lockfile, _PATH_LOCK,
243 sizeof(lockfile));
244 (void)strlcat(lockfile, argv[2],
245 sizeof(lockfile));
246 /*
247 * wait for lockfiles to go away before we try
248 * to open
249 */
250 if (pidlock(lockfile, 0, 0, 0) != 0) {
251 syslog(LOG_ERR,
252 "%s: can't create lockfile", ttyn);
253 exit(1);
254 }
255 (void)unlink(lockfile);
256 }
257 if (strcmp(argv[0], "+") != 0) {
258 (void)chown(ttyn, ttyowner, 0);
259 (void)chmod(ttyn, 0600);
260 (void)revoke(ttyn);
261 if (ttyaction(ttyn, "getty", "root"))
262 syslog(LOG_WARNING, "%s: ttyaction failed",
263 ttyn);
264 /*
265 * Delay the open so DTR stays down long enough
266 * to be detected.
267 */
268 (void)sleep(2);
269 while ((i = open(ttyn, O_RDWR)) == -1) {
270 if ((repcnt % 10 == 0) &&
271 (errno != ENXIO || !failopenlogged)) {
272 syslog(LOG_WARNING, "%s: %m", ttyn);
273 closelog();
274 failopenlogged = 1;
275 }
276 repcnt++;
277 (void)sleep(60);
278 }
279 if (uugetty && pidlock(lockfile, 0, 0, 0) != 0) {
280 syslog(LOG_ERR, "%s: can't create lockfile",
281 ttyn);
282 exit(1);
283 }
284 if (uugetty)
285 (void)chown(lockfile, ttyowner, 0);
286 (void)login_tty(i);
287 }
288 }
289
290 /* Start with default tty settings */
291 if (tcgetattr(0, &tmode) < 0) {
292 syslog(LOG_ERR, "%s: %m", ttyn);
293 exit(1);
294 }
295 omode = tmode;
296
297 gettable("default", defent);
298 gendefaults();
299 if (argc > 1)
300 tname = argv[1];
301 for (;;) {
302 int off;
303
304 rval = 0;
305 gettable(tname, tabent);
306 if (OPset || EPset || APset)
307 APset++, OPset++, EPset++;
308 setdefaults();
309 off = 0;
310 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */
311 (void)ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */
312 (void)ioctl(0, FIOASYNC, &off); /* ditto for async mode */
313
314 if (IS)
315 (void)cfsetispeed(&tmode, (speed_t)IS);
316 else if (SP)
317 (void)cfsetispeed(&tmode, (speed_t)SP);
318 if (OS)
319 (void)cfsetospeed(&tmode, (speed_t)OS);
320 else if (SP)
321 (void)cfsetospeed(&tmode, (speed_t)SP);
322 setflags(0);
323 setchars();
324 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
325 syslog(LOG_ERR, "%s: %m", ttyn);
326 exit(1);
327 }
328 if (AB) {
329 tname = autobaud();
330 continue;
331 }
332 if (PS) {
333 tname = portselector();
334 continue;
335 }
336 if (CS)
337 clearscreen();
338 if (CL && *CL)
339 putpad(CL);
340 edithost(HE);
341
342 /*
343 * If this is the first time through this, and an
344 * issue file has been given, then send it.
345 */
346 if (first_time != 0 && IF != NULL) {
347 char buf[_POSIX2_LINE_MAX];
348 FILE *fp;
349
350 if ((fp = fopen(IF, "r")) != NULL) {
351 while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
352 putf(buf);
353 (void)fclose(fp);
354 }
355 }
356 first_time = 0;
357
358 if (IM && *IM)
359 putf(IM);
360 oflush();
361 if (sigsetjmp(timeout, 1)) {
362 tmode.c_ispeed = tmode.c_ospeed = 0;
363 (void)tcsetattr(0, TCSANOW, &tmode);
364 exit(1);
365 }
366 if (TO) {
367 (void)signal(SIGALRM, dingdong);
368 (void)alarm((unsigned int)TO);
369 }
370 if (NN) {
371 name[0] = '\0';
372 lower = 1;
373 upper = digit_or_punc = 0;
374 } else if (AL) {
375 const char *p = AL;
376 char *q = name;
377
378 while (*p && q < &name[sizeof name - 1]) {
379 if (isupper((unsigned char)*p))
380 upper = 1;
381 else if (islower((unsigned char)*p))
382 lower = 1;
383 else if (isdigit((unsigned char)*p))
384 digit_or_punc = 1;
385 *q++ = *p++;
386 }
387 } else if ((rval = getname()) == 2) {
388 setflags(2);
389 (void)execle(PP, "ppplogin", ttyn, (char *) 0, env);
390 syslog(LOG_ERR, "%s: %m", PP);
391 exit(1);
392 }
393
394 if (rval || AL || NN) {
395 int i;
396
397 oflush();
398 (void)alarm(0);
399 (void)signal(SIGALRM, SIG_DFL);
400 if (name[0] == '-') {
401 xputs("user names may not start with '-'.");
402 continue;
403 }
404 if (!(upper || lower || digit_or_punc))
405 continue;
406 setflags(2);
407 if (crmod) {
408 tmode.c_iflag |= ICRNL;
409 tmode.c_oflag |= ONLCR;
410 }
411 #if XXX
412 if (upper || UC)
413 tmode.sg_flags |= LCASE;
414 if (lower || LC)
415 tmode.sg_flags &= ~LCASE;
416 #endif
417 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
418 syslog(LOG_ERR, "%s: %m", ttyn);
419 exit(1);
420 }
421 (void)signal(SIGINT, SIG_DFL);
422 for (i = 0; envp[i] != NULL; i++)
423 env[i] = envp[i];
424 makeenv(&env[i]);
425
426 limit.rlim_max = RLIM_INFINITY;
427 limit.rlim_cur = RLIM_INFINITY;
428 (void)setrlimit(RLIMIT_CPU, &limit);
429 if (NN)
430 (void)execle(LO, "login", AL ? "-fp" : "-p",
431 NULL, env);
432 else
433 (void)execle(LO, "login", AL ? "-fp" : "-p",
434 "--", name, NULL, env);
435 syslog(LOG_ERR, "%s: %m", LO);
436 exit(1);
437 }
438 (void)alarm(0);
439 (void)signal(SIGALRM, SIG_DFL);
440 (void)signal(SIGINT, SIG_IGN);
441 if (NX && *NX)
442 tname = NX;
443 if (uugetty)
444 (void)unlink(lockfile);
445 }
446 }
447
448 static int
449 getname(void)
450 {
451 int c;
452 char *np;
453 unsigned char cs;
454 int ppp_state, ppp_connection;
455
456 /*
457 * Interrupt may happen if we use CBREAK mode
458 */
459 if (sigsetjmp(intrupt, 1)) {
460 (void)signal(SIGINT, SIG_IGN);
461 return (0);
462 }
463 (void)signal(SIGINT, interrupt);
464 setflags(1);
465 prompt();
466 if (PF > 0) {
467 oflush();
468 (void)sleep((unsigned int)PF);
469 PF = 0;
470 }
471 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
472 syslog(LOG_ERR, "%s: %m", ttyn);
473 exit(1);
474 }
475 crmod = digit_or_punc = lower = upper = 0;
476 ppp_state = ppp_connection = 0;
477 np = name;
478 for (;;) {
479 oflush();
480 if (read(STDIN_FILENO, &cs, 1) <= 0)
481 exit(0);
482 if ((c = cs&0177) == 0)
483 return (0);
484
485 /*
486 * PPP detection state machine..
487 * Look for sequences:
488 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
489 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
490 * See RFC1662.
491 * Derived from code from Michael Hancock <michaelh (at) cet.co.jp>
492 * and Erik 'PPP' Olson <eriko (at) wrq.com>
493 */
494 if (PP && cs == PPP_FRAME) {
495 ppp_state = 1;
496 } else if (ppp_state == 1 && cs == PPP_STATION) {
497 ppp_state = 2;
498 } else if (ppp_state == 2 && cs == PPP_ESCAPE) {
499 ppp_state = 3;
500 } else if ((ppp_state == 2 && cs == PPP_CONTROL) ||
501 (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
502 ppp_state = 4;
503 } else if (ppp_state == 4 && cs == PPP_LCP_HI) {
504 ppp_state = 5;
505 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
506 ppp_connection = 1;
507 break;
508 } else {
509 ppp_state = 0;
510 }
511
512 if (c == EOT)
513 exit(1);
514 if (c == '\r' || c == '\n' ||
515 np >= &name[LOGIN_NAME_MAX - 1]) {
516 *np = '\0';
517 putf("\r\n");
518 break;
519 }
520 if (islower(c))
521 lower = 1;
522 else if (isupper(c))
523 upper = 1;
524 else if (c == ERASE || c == '#' || c == '\b') {
525 if (np > name) {
526 np--;
527 if (cfgetospeed(&tmode) >= 1200)
528 xputs("\b \b");
529 else
530 putchr(cs);
531 }
532 continue;
533 } else if (c == KILL || c == '@') {
534 putchr(cs);
535 putchr('\r');
536 if (cfgetospeed(&tmode) < 1200)
537 putchr('\n');
538 /* this is the way they do it down under ... */
539 else if (np > name)
540 xputs(
541 " \r");
542 prompt();
543 np = name;
544 continue;
545 } else if (isdigit(c) || c == '_')
546 digit_or_punc = 1;
547 if (IG && (c <= ' ' || c > 0176))
548 continue;
549 *np++ = c;
550 putchr(cs);
551
552 /*
553 * An MS-Windows direct connect PPP "client" won't send its
554 * first PPP packet until we respond to its "CLIENT" poll
555 * with a CRLF sequence. We cater to yet another broken
556 * implementation of a previously-standard protocol...
557 */
558 *np = '\0';
559 if (strstr(name, "CLIENT"))
560 putf("\r\n");
561 }
562 (void)signal(SIGINT, SIG_IGN);
563 *np = 0;
564 if (c == '\r')
565 crmod = 1;
566 if ((upper && !lower && !LC) || UC)
567 for (np = name; *np; np++)
568 *np = tolower((unsigned char)*np);
569 return (1 + ppp_connection);
570 }
571
572 static void
573 xputs(const char *s)
574 {
575 while (*s)
576 putchr(*s++);
577 }
578
579 char outbuf[OBUFSIZ];
580 size_t obufcnt = 0;
581
582 static int
583 putchr(int cc)
584 {
585 unsigned char c;
586
587 c = cc;
588 if (!NP) {
589 c |= partab[c&0177] & 0200;
590 if (OP)
591 c ^= 0200;
592 }
593 if (!UB) {
594 outbuf[obufcnt++] = c;
595 if (obufcnt >= OBUFSIZ)
596 oflush();
597 return 1;
598 }
599 return write(STDOUT_FILENO, &c, 1);
600 }
601
602 static void
603 oflush(void)
604 {
605 if (obufcnt)
606 (void)write(STDOUT_FILENO, outbuf, obufcnt);
607 obufcnt = 0;
608 }
609
610 static void
611 prompt(void)
612 {
613
614 putf(LM);
615 if (CO)
616 putchr('\n');
617 }
618
619 static void
620 putf(const char *cp)
621 {
622 time_t t;
623 char *slash, db[100];
624
625 while (*cp) {
626 if (*cp != '%') {
627 putchr(*cp++);
628 continue;
629 }
630 switch (*++cp) {
631
632 case 't':
633 if ((slash = strstr(ttyn, "/pts/")) == NULL)
634 slash = strrchr(ttyn, '/');
635 if (slash == NULL)
636 xputs(ttyn);
637 else
638 xputs(&slash[1]);
639 break;
640
641 case 'h':
642 xputs(editedhost);
643 break;
644
645 case 'd':
646 (void)time(&t);
647 (void)strftime(db, sizeof(db),
648 "%l:%M%p on %A, %d %B %Y", localtime(&t));
649 xputs(db);
650 break;
651
652 case 's':
653 xputs(kerninfo.sysname);
654 break;
655
656 case 'm':
657 xputs(kerninfo.machine);
658 break;
659
660 case 'r':
661 xputs(kerninfo.release);
662 break;
663
664 case 'v':
665 xputs(kerninfo.version);
666 break;
667
668 case '%':
669 putchr('%');
670 break;
671 }
672 if (*cp)
673 cp++;
674 }
675 }
676
677 static void
678 clearscreen(void)
679 {
680 struct ttyent *typ;
681 int err;
682
683 if (rawttyn == NULL)
684 return;
685
686 typ = getttynam(rawttyn);
687
688 if ((typ == NULL) || (typ->ty_type == NULL) ||
689 (typ->ty_type[0] == 0))
690 return;
691
692 if (setupterm(typ->ty_type, 0, &err) == ERR)
693 return;
694
695 if (clear_screen)
696 putpad(clear_screen);
697
698 del_curterm(cur_term);
699 cur_term = NULL;
700 }
701