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