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