Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[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.2 2003/06/17 04:29:28 dillon 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(argc, argv)
83         int argc;
84         char **argv;
85 {
86         struct passwd *pw;
87         struct timeval timval;
88         time_t timval_sec;
89         struct itimerval ntimer, otimer;
90         struct tm *timp;
91         int ch, failures, sectimeout, usemine, vtylock;
92         char *ap, *mypw, *ttynam, *tzn;
93         char hostname[MAXHOSTNAMELEN], s[BUFSIZ], s1[BUFSIZ];
94
95         openlog("lock", LOG_ODELAY, LOG_AUTH);
96
97         sectimeout = TIMEOUT;
98         mypw = NULL;
99         usemine = 0;
100         no_timeout = 0;
101         vtylock = 0;
102         while ((ch = getopt(argc, argv, "npt:v")) != -1)
103                 switch((char)ch) {
104                 case 't':
105                         if ((sectimeout = atoi(optarg)) <= 0)
106                                 errx(1, "illegal timeout value");
107                         break;
108                 case 'p':
109                         usemine = 1;
110                         if (!(pw = getpwuid(getuid())))
111                                 errx(1, "unknown uid %d", getuid());
112                         mypw = strdup(pw->pw_passwd);
113                         break;
114                 case 'n':
115                         no_timeout = 1;
116                         break;
117                 case 'v':
118                         vtylock = 1;
119                         break;
120                 case '?':
121                 default:
122                         usage();
123                 }
124         timeout.tv_sec = sectimeout * 60;
125
126         setuid(getuid());               /* discard privs */
127
128         if (ioctl(0, TIOCGETP, &tty))   /* get information for header */
129                 exit(1);
130         gethostname(hostname, sizeof(hostname));
131         if (!(ttynam = ttyname(0)))
132                 errx(1, "not a terminal?");
133         if (gettimeofday(&timval, (struct timezone *)NULL))
134                 err(1, "gettimeofday");
135         nexttime = timval.tv_sec + (sectimeout * 60);
136         timval_sec = timval.tv_sec;
137         timp = localtime(&timval_sec);
138         ap = asctime(timp);
139         tzn = timp->tm_zone;
140
141         (void)signal(SIGINT, quit);
142         (void)signal(SIGQUIT, quit);
143         ntty = tty; ntty.sg_flags &= ~ECHO;
144         (void)ioctl(0, TIOCSETP, &ntty);
145
146         if (!mypw) {
147                 /* get key and check again */
148                 (void)printf("Key: ");
149                 if (!fgets(s, sizeof(s), stdin) || *s == '\n')
150                         quit(0);
151                 (void)printf("\nAgain: ");
152                 /*
153                  * Don't need EOF test here, if we get EOF, then s1 != s
154                  * and the right things will happen.
155                  */
156                 (void)fgets(s1, sizeof(s1), stdin);
157                 (void)putchar('\n');
158                 if (strcmp(s1, s)) {
159                         (void)printf("\07lock: passwords didn't match.\n");
160                         ioctl(0, TIOCSETP, &tty);
161                         exit(1);
162                 }
163                 s[0] = '\0';
164                 mypw = s1;
165         }
166
167         /* set signal handlers */
168         (void)signal(SIGINT, hi);
169         (void)signal(SIGQUIT, hi);
170         (void)signal(SIGTSTP, hi);
171         (void)signal(SIGALRM, bye);
172
173         ntimer.it_interval = zerotime;
174         ntimer.it_value = timeout;
175         if (!no_timeout)
176                 setitimer(ITIMER_REAL, &ntimer, &otimer);
177         if (vtylock) {
178                 /*
179                  * If this failed, we want to err out; warn isn't good
180                  * enough, since we don't want the user to think that
181                  * everything is nice and locked because they got a
182                  * "Key:" prompt.
183                  */
184                 if (ioctl(0, VT_LOCKSWITCH, &vtylock) == -1) {
185                         (void)ioctl(0, TIOCSETP, &tty);
186                         err(1, "locking vty");
187                 }
188                 vtyunlock = 0x2;
189         }
190
191         /* header info */
192         (void)printf("lock: %s on %s.", ttynam, hostname);
193         if (no_timeout)
194                 (void)printf(" no timeout.");
195         else
196                 (void)printf(" timeout in %d minute%s.", sectimeout,
197                     sectimeout != 1 ? "s" : "");
198         if (vtylock)
199                 (void)printf(" vty locked.");
200         (void)printf("\ntime now is %.20s%s%s", ap, tzn, ap + 19);
201
202         failures = 0;
203
204         for (;;) {
205                 (void)printf("Key: ");
206                 if (!fgets(s, sizeof(s), stdin)) {
207                         clearerr(stdin);
208                         hi(0);
209                         continue;
210                 }
211                 if (usemine) {
212                         s[strlen(s) - 1] = '\0';
213                         if (!strcmp(mypw, crypt(s, mypw)))
214                                 break;
215                 }
216                 else if (!strcmp(s, s1))
217                         break;
218                 (void)printf("\07\n");
219                 failures++;
220                 if (getuid() == 0)
221                     syslog(LOG_NOTICE, "%d ROOT UNLOCK FAILURE%s (%s on %s)",
222                         failures, failures > 1 ? "S": "", ttynam, hostname);
223                 if (ioctl(0, TIOCGETP, &ntty))
224                         exit(1);
225                 sleep(1);               /* to discourage guessing */
226         }
227         if (getuid() == 0)
228                 syslog(LOG_NOTICE, "ROOT UNLOCK ON hostname %s port %s",
229                     hostname, ttynam);
230         quit(0);
231         return(0); /* not reached */
232 }
233
234
235 static void
236 usage()
237 {
238         (void)fprintf(stderr, "usage: lock [-npv] [-t timeout]\n");
239         exit(1);
240 }
241
242 void
243 hi(int signo __unused)
244 {
245         struct timeval timval;
246
247         if (!gettimeofday(&timval, (struct timezone *)NULL)) {
248                 (void)printf("lock: type in the unlock key. ");
249                 if (no_timeout) {
250                         (void)putchar('\n');
251                 } else {
252                         (void)printf("timeout in %ld:%ld minutes\n",
253                             (nexttime - timval.tv_sec) / 60,
254                             (nexttime - timval.tv_sec) % 60);
255                 }
256         }
257 }
258
259 void
260 quit(int signo __unused)
261 {
262         (void)putchar('\n');
263         (void)ioctl(0, TIOCSETP, &tty);
264         if (vtyunlock)
265                 (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock);
266         exit(0);
267 }
268
269 void
270 bye(int signo __unused)
271 {
272         if (!no_timeout) {
273                 (void)ioctl(0, TIOCSETP, &tty);
274                 if (vtyunlock)
275                         (void)ioctl(0, VT_LOCKSWITCH, &vtyunlock);
276                 (void)printf("lock: timeout\n");
277                 exit(1);
278         }
279 }