Remove the evil inline ==> rpcgen_inline CPP hack, rename the variable
[dragonfly.git] / usr.bin / lock / lock.c
1 /*
2  * Copyright (c) 1980, 1987, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Bob Toxen.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * @(#) Copyright (c) 1980, 1987, 1993 The Regents of the University of California.  All rights reserved.
37  * @(#)lock.c   8.1 (Berkeley) 6/6/93
38  * $FreeBSD: src/usr.bin/lock/lock.c,v 1.8.2.1 2002/09/15 22:32:56 dd Exp $
39  * $DragonFly: src/usr.bin/lock/lock.c,v 1.3 2003/10/04 20:36:47 hmp Exp $
40  */
41
42 /*
43  * Lock a terminal up until the given key is entered or the given
44  * interval times out.
45  *
46  * Timeout interval is by default TIMEOUT, it can be changed with
47  * an argument of the form -time where time is in minutes
48  */
49
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <sys/time.h>
53 #include <sys/signal.h>
54 #include <sys/consio.h>
55 #include <err.h>
56 #include <ctype.h>
57 #include <pwd.h>
58 #include <sgtty.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <syslog.h>
63 #include <unistd.h>
64 #include <varargs.h>
65
66 #define TIMEOUT 15
67
68 void quit(int);
69 void bye(int);
70 void hi(int);
71 static void usage(void);
72
73 struct timeval  timeout;
74 struct timeval  zerotime;
75 struct sgttyb   tty, ntty;
76 long    nexttime;                       /* keep the timeout time */
77 int            no_timeout;                     /* lock terminal forever */
78 int     vtyunlock;                      /* Unlock flag and code. */
79
80 /*ARGSUSED*/
81 int
82 main(int argc, char **argv)
83 {
84         struct passwd *pw;
85         struct timeval timval;
86         time_t timval_sec;
87         struct itimerval ntimer, otimer;
88         struct tm *timp;
89         int ch, failures, sectimeout, usemine, vtylock;
90         char *ap, *mypw, *ttynam, *tzn;
91         char hostname[MAXHOSTNAMELEN], s[BUFSIZ], s1[BUFSIZ];
92
93         openlog("lock", LOG_ODELAY, LOG_AUTH);
94
95         sectimeout = TIMEOUT;
96         mypw = NULL;
97         usemine = 0;
98         no_timeout = 0;
99         vtylock = 0;
100         while ((ch = getopt(argc, argv, "npt:v")) != -1)
101                 switch((char)ch) {
102                 case 't':
103                         if ((sectimeout = atoi(optarg)) <= 0)
104                                 errx(1, "illegal timeout value");
105                         break;
106                 case 'p':
107                         usemine = 1;
108                         if (!(pw = getpwuid(getuid())))
109                                 errx(1, "unknown uid %d", getuid());
110                         mypw = strdup(pw->pw_passwd);
111                         break;
112                 case 'n':
113                         no_timeout = 1;
114                         break;
115                 case 'v':
116                         vtylock = 1;
117                         break;
118                 case '?':
119                 default:
120                         usage();
121                 }
122         timeout.tv_sec = sectimeout * 60;
123
124         setuid(getuid());               /* discard privs */
125
126         if (ioctl(0, TIOCGETP, &tty))   /* get information for header */
127                 exit(1);
128         gethostname(hostname, sizeof(hostname));
129         if (!(ttynam = ttyname(0)))
130                 errx(1, "not a terminal?");
131         if (gettimeofday(&timval, (struct timezone *)NULL))
132                 err(1, "gettimeofday");
133         nexttime = timval.tv_sec + (sectimeout * 60);
134         timval_sec = timval.tv_sec;
135         timp = localtime(&timval_sec);
136         ap = asctime(timp);
137         tzn = timp->tm_zone;
138
139         (void)signal(SIGINT, quit);
140         (void)signal(SIGQUIT, quit);
141         ntty = tty; ntty.sg_flags &= ~ECHO;
142         (void)ioctl(0, TIOCSETP, &ntty);
143
144         if (!mypw) {
145                 /* get key and check again */
146                 (void)printf("Key: ");
147                 if (!fgets(s, sizeof(s), stdin) || *s == '\n')
148                         quit(0);
149                 (void)printf("\nAgain: ");
150                 /*
151                  * Don't need EOF test here, if we get EOF, then s1 != s
152                  * and the right things will happen.
153                  */
154                 (void)fgets(s1, sizeof(s1), stdin);
155                 (void)putchar('\n');
156                 if (strcmp(s1, s)) {
157                         (void)printf("\07lock: passwords didn't match.\n");
158                         ioctl(0, TIOCSETP, &tty);
159                         exit(1);
160                 }
161                 s[0] = '\0';
162                 mypw = s1;
163         }
164
165         /* set signal handlers */
166         (void)signal(SIGINT, hi);
167         (void)signal(SIGQUIT, hi);
168         (void)signal(SIGTSTP, hi);
169         (void)signal(SIGALRM, bye);
170
171         ntimer.it_interval = zerotime;
172         ntimer.it_value = timeout;
173         if (!no_timeout)
174                 setitimer(ITIMER_REAL, &ntimer, &otimer);
175         if (vtylock) {
176                 /*
177                  * If this failed, we want to err out; warn isn't good
178                  * enough, since we don't want the user to think that
179                  * everything is nice and locked because they got a
180                  * "Key:" prompt.
181                  */
182                 if (ioctl(0, VT_LOCKSWITCH, &vtylock) == -1) {
183                         (void)ioctl(0, TIOCSETP, &tty);
184                         err(1, "locking vty");
185                 }
186                 vtyunlock = 0x2;
187         }
188
189         /* header info */
190         (void)printf("lock: %s on %s.", ttynam, hostname);
191         if (no_timeout)
192                 (void)printf(" no timeout.");
193         else
194                 (void)printf(" timeout in %d minute%s.", sectimeout,
195                     sectimeout != 1 ? "s" : "");
196         if (vtylock)
197                 (void)printf(" vty locked.");
198         (void)printf("\ntime now is %.20s%s%s", ap, tzn, ap + 19);
199
200         failures = 0;
201
202         for (;;) {
203                 (void)printf("Key: ");
204                 if (!fgets(s, sizeof(s), stdin)) {
205                         clearerr(stdin);
206                         hi(0);
207                         continue;
208                 }
209                 if (usemine) {
210                         s[strlen(s) - 1] = '\0';
211                         if (!strcmp(mypw, crypt(s, mypw)))
212                                 break;
213                 }
214                 else if (!strcmp(s, s1))
215                         break;
216                 (void)printf("\07\n");
217                 failures++;
218                 if (getuid() == 0)
219                     syslog(LOG_NOTICE, "%d ROOT UNLOCK FAILURE%s (%s on %s)",
220                         failures, failures > 1 ? "S": "", ttynam, hostname);
221                 if (ioctl(0, TIOCGETP, &ntty))
222                         exit(1);
223                 sleep(1);               /* to discourage guessing */
224         }
225         if (getuid() == 0)
226                 syslog(LOG_NOTICE, "ROOT UNLOCK ON hostname %s port %s",
227                     hostname, ttynam);
228         quit(0);
229         return(0); /* not reached */
230 }
231
232
233 static void
234 usage(void)
235 {
236         (void)fprintf(stderr, "usage: lock [-npv] [-t timeout]\n");
237         exit(1);
238 }
239
240 void
241 hi(int signo __unused)
242 {
243         struct timeval timval;
244
245         if (!gettimeofday(&timval, (struct timezone *)NULL)) {
246                 (void)printf("lock: type in the unlock key. ");
247                 if (no_timeout) {
248                         (void)putchar('\n');
249                 } else {
250                         (void)printf("timeout in %ld:%ld minutes\n",
251                             (nexttime - timval.tv_sec) / 60,
252                             (nexttime - timval.tv_sec) % 60);
253                 }
254         }
255 }
256
257 void
258 quit(int signo __unused)
259 {
260         (void)putchar('\n');
261         (void)ioctl(0, TIOCSETP, &tty);
262         if (vtyunlock)
263                 (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock);
264         exit(0);
265 }
266
267 void
268 bye(int signo __unused)
269 {
270         if (!no_timeout) {
271                 (void)ioctl(0, TIOCSETP, &tty);
272                 if (vtyunlock)
273                         (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock);
274                 (void)printf("lock: timeout\n");
275                 exit(1);
276         }
277 }