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