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