tools/llvm: Do not build with symbols
[minix3.git] / libexec / getty / main.c
blob1ca4502599f15d4ce92e9ccbb86b6c3a2eade9be
1 /* $NetBSD: main.c,v 1.64 2013/08/12 13:54:33 joerg Exp $ */
3 /*-
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
32 #include <sys/cdefs.h>
34 #ifndef lint
35 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
36 The Regents of the University of California. All rights reserved.");
37 #endif /* not lint */
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 */
47 #include <sys/param.h>
48 #include <sys/ioctl.h>
49 #include <sys/resource.h>
50 #include <sys/utsname.h>
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>
70 #include "gettytab.h"
71 #include "pathnames.h"
72 #include "extern.h"
74 extern char editedhost[];
77 * Set the amount of running time that getty should accumulate
78 * before deciding that something is wrong and exit.
80 #define GETTY_TIMEOUT 60 /* seconds */
82 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
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 */
92 struct termios tmode, omode;
94 int crmod, digit_or_punc, lower, upper;
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;
105 #define OBUFSIZ 128
106 #define TABBUFSIZ 512
108 char defent[TABBUFSIZ];
109 char tabent[TABBUFSIZ];
111 char *env[128];
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
132 #define ERASE tmode.c_cc[VERASE]
133 #define KILL tmode.c_cc[VKILL]
134 #define EOT tmode.c_cc[VEOF]
136 static void clearscreen(void);
138 sigjmp_buf timeout;
140 __dead static void
141 /*ARGSUSED*/
142 dingdong(int signo)
145 (void)alarm(0);
146 (void)signal(SIGALRM, SIG_DFL);
147 siglongjmp(timeout, 1);
150 sigjmp_buf intrupt;
152 __dead static void
153 /*ARGSUSED*/
154 interrupt(int signo)
157 (void)signal(SIGINT, interrupt);
158 siglongjmp(intrupt, 1);
161 #if !defined(__minix)
163 * Action to take when getty is running too long.
165 __dead static void
166 /*ARGSUSED*/
167 timeoverrun(int signo)
170 syslog(LOG_ERR, "getty exiting due to excessive running time");
171 exit(1);
173 #endif /* !defined(__minix) */
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 *);
182 #define putpad(s) tputs(s, 1, putchr)
185 main(int argc, char *argv[], char *envp[])
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";
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);
205 progname = getprogname();
206 if (progname[0] == 'u' && progname[1] == 'u')
207 uugetty = 1;
210 * Find id of uucp login (if present) so we can chown tty properly.
212 if (uugetty && (pw = getpwnam("uucp")))
213 ttyowner = pw->pw_uid;
214 else
215 ttyowner = 0;
218 * Limit running time to deal with broken or dead lines.
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);
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.
234 if (argc <= 2 || strcmp(argv[2], "-") == 0) {
235 (void)strlcpy(ttyn, ttyname(0), sizeof(ttyn));
237 else {
238 int i;
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));
250 * wait for lockfiles to go away before we try
251 * to open
253 if (pidlock(lockfile, 0, 0, 0) != 0) {
254 syslog(LOG_ERR,
255 "%s: can't create lockfile", ttyn);
256 exit(1);
258 (void)unlink(lockfile);
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);
270 * Delay the open so DTR stays down long enough
271 * to be detected.
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;
281 repcnt++;
282 (void)sleep(60);
284 if (uugetty && pidlock(lockfile, 0, 0, 0) != 0) {
285 syslog(LOG_ERR, "%s: can't create lockfile",
286 ttyn);
287 exit(1);
289 if (uugetty)
290 (void)chown(lockfile, ttyowner, 0);
291 (void)login_tty(i);
295 /* Start with default tty settings */
296 if (tcgetattr(0, &tmode) < 0) {
297 syslog(LOG_ERR, "%s: %m", ttyn);
298 exit(1);
300 omode = tmode;
302 gettable("default", defent);
303 gendefaults();
304 if (argc > 1)
305 tname = argv[1];
306 for (;;) {
307 int off;
309 rval = 0;
310 gettable(tname, tabent);
311 if (OPset || EPset || APset)
312 APset++, OPset++, EPset++;
313 setdefaults();
314 off = 0;
315 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */
316 #ifndef __minix
317 (void)ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */
318 (void)ioctl(0, FIOASYNC, &off); /* ditto for async mode */
319 #endif /* !defined(__minix) */
321 if (IS)
322 (void)cfsetispeed(&tmode, (speed_t)IS);
323 else if (SP)
324 (void)cfsetispeed(&tmode, (speed_t)SP);
325 if (OS)
326 (void)cfsetospeed(&tmode, (speed_t)OS);
327 else if (SP)
328 (void)cfsetospeed(&tmode, (speed_t)SP);
329 setflags(0);
330 setchars();
331 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
332 syslog(LOG_ERR, "%s: %m", ttyn);
333 exit(1);
335 if (AB) {
336 tname = autobaud();
337 continue;
339 if (PS) {
340 tname = portselector();
341 continue;
343 if (CS)
344 clearscreen();
345 if (CL && *CL)
346 putpad(CL);
347 edithost(HE);
350 * If this is the first time through this, and an
351 * issue file has been given, then send it.
353 if (first_time != 0 && IF != NULL) {
354 char buf[_POSIX2_LINE_MAX];
355 FILE *fp;
357 if ((fp = fopen(IF, "r")) != NULL) {
358 while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
359 putf(buf);
360 (void)fclose(fp);
363 first_time = 0;
365 if (IM && *IM)
366 putf(IM);
367 oflush();
368 if (sigsetjmp(timeout, 1)) {
369 tmode.c_ispeed = tmode.c_ospeed = 0;
370 (void)tcsetattr(0, TCSANOW, &tmode);
371 exit(1);
373 if (TO) {
374 (void)signal(SIGALRM, dingdong);
375 (void)alarm((unsigned int)TO);
377 if (NN) {
378 name[0] = '\0';
379 lower = 1;
380 upper = digit_or_punc = 0;
381 } else if (AL) {
382 const char *p = AL;
383 char *q = name;
385 while (*p && q < &name[sizeof name - 1]) {
386 if (isupper((unsigned char)*p))
387 upper = 1;
388 else if (islower((unsigned char)*p))
389 lower = 1;
390 else if (isdigit((unsigned char)*p))
391 digit_or_punc = 1;
392 *q++ = *p++;
394 } else if ((rval = getname()) == 2) {
395 setflags(2);
396 (void)execle(PP, "ppplogin", ttyn, (char *) 0, env);
397 syslog(LOG_ERR, "%s: %m", PP);
398 exit(1);
401 if (rval || AL || NN) {
402 int i;
404 oflush();
405 (void)alarm(0);
406 (void)signal(SIGALRM, SIG_DFL);
407 if (name[0] == '-') {
408 xputs("user names may not start with '-'.");
409 continue;
411 if (!(upper || lower || digit_or_punc))
412 continue;
413 setflags(2);
414 if (crmod) {
415 tmode.c_iflag |= ICRNL;
416 tmode.c_oflag |= ONLCR;
418 #if XXX
419 if (upper || UC)
420 tmode.sg_flags |= LCASE;
421 if (lower || LC)
422 tmode.sg_flags &= ~LCASE;
423 #endif
424 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
425 syslog(LOG_ERR, "%s: %m", ttyn);
426 exit(1);
428 (void)signal(SIGINT, SIG_DFL);
429 for (i = 0; envp[i] != NULL; i++)
430 env[i] = envp[i];
431 makeenv(&env[i]);
433 limit.rlim_max = RLIM_INFINITY;
434 limit.rlim_cur = RLIM_INFINITY;
435 (void)setrlimit(RLIMIT_CPU, &limit);
436 if (NN)
437 (void)execle(LO, "login", AL ? "-fp" : "-p",
438 NULL, env);
439 else
440 (void)execle(LO, "login", AL ? "-fp" : "-p",
441 "--", name, NULL, env);
442 syslog(LOG_ERR, "%s: %m", LO);
443 exit(1);
445 (void)alarm(0);
446 (void)signal(SIGALRM, SIG_DFL);
447 (void)signal(SIGINT, SIG_IGN);
448 if (NX && *NX)
449 tname = NX;
450 if (uugetty)
451 (void)unlink(lockfile);
455 static int
456 getname(void)
458 int c;
459 char *np;
460 unsigned char cs;
461 int ppp_state, ppp_connection;
464 * Interrupt may happen if we use CBREAK mode
466 if (sigsetjmp(intrupt, 1)) {
467 (void)signal(SIGINT, SIG_IGN);
468 return (0);
470 (void)signal(SIGINT, interrupt);
471 setflags(1);
472 prompt();
473 if (PF > 0) {
474 oflush();
475 (void)sleep((unsigned int)PF);
476 PF = 0;
478 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
479 syslog(LOG_ERR, "%s: %m", ttyn);
480 exit(1);
482 crmod = digit_or_punc = lower = upper = 0;
483 ppp_state = ppp_connection = 0;
484 np = name;
485 for (;;) {
486 oflush();
487 if (read(STDIN_FILENO, &cs, 1) <= 0)
488 exit(0);
489 if ((c = cs&0177) == 0)
490 return (0);
493 * PPP detection state machine..
494 * Look for sequences:
495 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
496 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
497 * See RFC1662.
498 * Derived from code from Michael Hancock <michaelh@cet.co.jp>
499 * and Erik 'PPP' Olson <eriko@wrq.com>
501 if (PP && cs == PPP_FRAME) {
502 ppp_state = 1;
503 } else if (ppp_state == 1 && cs == PPP_STATION) {
504 ppp_state = 2;
505 } else if (ppp_state == 2 && cs == PPP_ESCAPE) {
506 ppp_state = 3;
507 } else if ((ppp_state == 2 && cs == PPP_CONTROL) ||
508 (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
509 ppp_state = 4;
510 } else if (ppp_state == 4 && cs == PPP_LCP_HI) {
511 ppp_state = 5;
512 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
513 ppp_connection = 1;
514 break;
515 } else {
516 ppp_state = 0;
519 if (c == EOT)
520 exit(1);
521 if (c == '\r' || c == '\n' ||
522 np >= &name[LOGIN_NAME_MAX - 1]) {
523 *np = '\0';
524 putf("\r\n");
525 break;
527 if (islower(c))
528 lower = 1;
529 else if (isupper(c))
530 upper = 1;
531 else if (c == ERASE || c == '#' || c == '\b') {
532 if (np > name) {
533 np--;
534 if (cfgetospeed(&tmode) >= 1200)
535 xputs("\b \b");
536 else
537 putchr(cs);
539 continue;
540 } else if (c == KILL || c == '@') {
541 putchr(cs);
542 putchr('\r');
543 if (cfgetospeed(&tmode) < 1200)
544 putchr('\n');
545 /* this is the way they do it down under ... */
546 else if (np > name)
547 xputs(
548 " \r");
549 prompt();
550 np = name;
551 continue;
552 } else if (isdigit(c) || c == '_')
553 digit_or_punc = 1;
554 if (IG && (c <= ' ' || c > 0176))
555 continue;
556 *np++ = c;
557 putchr(cs);
560 * An MS-Windows direct connect PPP "client" won't send its
561 * first PPP packet until we respond to its "CLIENT" poll
562 * with a CRLF sequence. We cater to yet another broken
563 * implementation of a previously-standard protocol...
565 *np = '\0';
566 if (strstr(name, "CLIENT"))
567 putf("\r\n");
569 (void)signal(SIGINT, SIG_IGN);
570 *np = 0;
571 if (c == '\r')
572 crmod = 1;
573 if ((upper && !lower && !LC) || UC)
574 for (np = name; *np; np++)
575 *np = tolower((unsigned char)*np);
576 return (1 + ppp_connection);
579 static void
580 xputs(const char *s)
582 while (*s)
583 putchr(*s++);
586 char outbuf[OBUFSIZ];
587 size_t obufcnt = 0;
589 static int
590 putchr(int cc)
592 unsigned char c;
594 c = cc;
595 if (!NP) {
596 c |= partab[c&0177] & 0200;
597 if (OP)
598 c ^= 0200;
600 if (!UB) {
601 outbuf[obufcnt++] = c;
602 if (obufcnt >= OBUFSIZ)
603 oflush();
604 return 1;
606 return write(STDOUT_FILENO, &c, 1);
609 static void
610 oflush(void)
612 if (obufcnt)
613 (void)write(STDOUT_FILENO, outbuf, obufcnt);
614 obufcnt = 0;
617 static void
618 prompt(void)
621 putf(LM);
622 if (CO)
623 putchr('\n');
626 static void
627 putf(const char *cp)
629 time_t t;
630 char *slash, db[100];
632 while (*cp) {
633 if (*cp != '%') {
634 putchr(*cp++);
635 continue;
637 switch (*++cp) {
639 case 't':
640 if ((slash = strstr(ttyn, "/pts/")) == NULL)
641 slash = strrchr(ttyn, '/');
642 if (slash == NULL)
643 xputs(ttyn);
644 else
645 xputs(&slash[1]);
646 break;
648 case 'h':
649 xputs(editedhost);
650 break;
652 case 'd':
653 (void)time(&t);
654 (void)strftime(db, sizeof(db),
655 "%l:%M%p on %A, %d %B %Y", localtime(&t));
656 xputs(db);
657 break;
659 case 's':
660 xputs(kerninfo.sysname);
661 break;
663 case 'm':
664 xputs(kerninfo.machine);
665 break;
667 case 'r':
668 xputs(kerninfo.release);
669 break;
671 case 'v':
672 xputs(kerninfo.version);
673 break;
675 case '%':
676 putchr('%');
677 break;
679 if (*cp)
680 cp++;
684 static void
685 clearscreen(void)
687 struct ttyent *typ;
688 int err;
690 if (rawttyn == NULL)
691 return;
693 typ = getttynam(rawttyn);
695 if ((typ == NULL) || (typ->ty_type == NULL) ||
696 (typ->ty_type[0] == 0))
697 return;
699 if (setupterm(typ->ty_type, 0, &err) == ERR)
700 return;
702 if (clear_screen)
703 putpad(clear_screen);
705 del_curterm(cur_term);
706 cur_term = NULL;