1 /* $NetBSD: lock.c,v 1.33 2013/10/18 20:47:06 christos Exp $ */
4 * Copyright (c) 1980, 1987, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/cdefs.h>
37 __COPYRIGHT("@(#) Copyright (c) 1980, 1987, 1993\
38 The Regents of the University of California. All rights reserved.");
43 static char sccsid
[] = "@(#)lock.c 8.1 (Berkeley) 6/6/93";
45 __RCSID("$NetBSD: lock.c,v 1.33 2013/10/18 20:47:06 christos Exp $");
49 * Lock a terminal up until the given key is entered, until the root
50 * password is entered, or the given interval times out.
52 * Timeout interval is by default TIMEOUT, it can be changed with
53 * an argument of the form -time where time is in minutes
56 #include <sys/param.h>
72 #include <security/pam_appl.h>
73 #include <security/openpam.h> /* for openpam_ttyconv() */
83 int main(int, char **);
85 static void bye(int) __dead
;
87 static void quit(int) __dead
;
89 static int skey_auth(const char *);
92 static struct timeval timeout
;
93 static struct timeval zerotime
;
94 static struct termios tty
, ntty
;
95 static int notimeout
; /* no timeout at all */
96 static long nexttime
; /* keep the timeout time */
99 main(int argc
, char **argv
)
102 struct timeval timval
;
103 struct itimerval ntimer
, otimer
;
110 uid_t uid
= getuid();
111 char hostname
[MAXHOSTNAMELEN
+ 1], s
[BUFSIZ
], s1
[BUFSIZ
];
113 pam_handle_t
*pamh
= NULL
;
114 static const struct pam_conv pamc
= { &openpam_ttyconv
, NULL
};
120 if ((pw
= getpwuid(getuid())) == NULL
)
121 errx(1, "unknown uid %lu.", (u_long
)uid
);
124 sectimeout
= TIMEOUT
;
127 while ((ch
= getopt(argc
, argv
, "npt:")) != -1)
134 if (((sectimeout
= strtol(optarg
, &ap
, 0)) == LONG_MAX
135 || sectimeout
== LONG_MIN
)
137 err(1, "illegal timeout value: %s", optarg
);
138 if (optarg
== ap
|| *ap
|| sectimeout
<= 0)
139 errx(1, "illegal timeout value: %s", optarg
);
140 if (sectimeout
>= INT_MAX
/ 60)
141 errx(1, "too large timeout value: %ld",
147 mypw
= strdup(pw
->pw_passwd
);
154 (void)fprintf(stderr
,
155 "usage: %s [-np] [-t timeout]\n", getprogname());
159 #if defined(USE_PAM) || defined(SKEY)
160 if (! usemine
) { /* -p with PAM or S/key needs privs */
162 if (setuid(uid
) == -1) /* discard privs */
163 err(1, "setuid failed");
164 #if defined(USE_PAM) || defined(SKEY)
168 timeout
.tv_sec
= (int)sectimeout
* 60;
170 if (tcgetattr(STDIN_FILENO
, &tty
) < 0) /* get information for header */
171 err(1, "tcgetattr failed");
172 gethostname(hostname
, sizeof(hostname
));
173 hostname
[sizeof(hostname
) - 1] = '\0';
174 if (!(ttynam
= ttyname(STDIN_FILENO
)))
175 err(1, "ttyname failed");
176 if (gettimeofday(&timval
, NULL
) == -1)
177 err(1, "gettimeofday failed");
178 curtime
= timval
.tv_sec
;
179 nexttime
= timval
.tv_sec
+ ((int)sectimeout
* 60);
180 timp
= localtime(&curtime
);
188 if (signal(SIGINT
, quit
) == SIG_ERR
)
189 err(1, "signal failed");
190 if (signal(SIGQUIT
, quit
) == SIG_ERR
)
191 err(1, "signal failed");
192 ntty
= tty
; ntty
.c_lflag
&= ~ECHO
;
193 if (tcsetattr(STDIN_FILENO
, TCSADRAIN
, &ntty
) == -1)
197 /* get key and check again */
198 (void)printf("Key: ");
199 if (!fgets(s
, sizeof(s
), stdin
) || *s
== '\n')
201 (void)printf("\nAgain: ");
203 * Don't need EOF test here, if we get EOF, then s1 != s
204 * and the right things will happen.
206 (void)fgets(s1
, sizeof(s1
), stdin
);
209 (void)printf("\alock: passwords didn't match.\n");
210 (void)tcsetattr(STDIN_FILENO
, TCSADRAIN
, &tty
);
220 pam_err
= pam_start("lock", pw
->pw_name
, &pamc
, &pamh
);
221 if (pam_err
!= PAM_SUCCESS
)
222 err(1, "pam_start: %s", pam_strerror(NULL
, pam_err
));
226 /* set signal handlers */
227 if (signal(SIGINT
, hi
) == SIG_ERR
)
228 err(1, "signal failed");
229 if (signal(SIGQUIT
, hi
) == SIG_ERR
)
230 err(1, "signal failed");
231 if (signal(SIGTSTP
, hi
) == SIG_ERR
)
232 err(1, "signal failed");
235 if (signal(SIGALRM
, hi
) == SIG_ERR
)
236 err(1, "signal failed");
237 (void)printf("lock: %s on %s. no timeout.\n"
238 "time now is %.20s%s%s",
239 ttynam
, hostname
, ap
, tzn
, ap
+ 19);
242 if (signal(SIGALRM
, bye
) == SIG_ERR
)
243 err(1, "signal failed");
245 ntimer
.it_interval
= zerotime
;
246 ntimer
.it_value
= timeout
;
247 if (setitimer(ITIMER_REAL
, &ntimer
, &otimer
) == -1)
248 err(1, "setitimer failed");
251 (void)printf("lock: %s on %s. timeout in %ld minutes\n"
252 "time now is %.20s%s%s",
253 ttynam
, hostname
, sectimeout
, ap
, tzn
, ap
+ 19);
259 pam_err
= pam_authenticate(pamh
, 0);
260 if (pam_err
== PAM_SUCCESS
)
265 (void)printf("Key: ");
266 if (!fgets(s
, sizeof(s
), stdin
)) {
273 s
[strlen(s
) - 1] = '\0';
275 if (strcasecmp(s
, "s/key") == 0) {
276 if (skey_auth(pw
->pw_name
))
280 if (!strcmp(mypw
, crypt(s
, mypw
)))
287 (void)printf("\a\n");
289 if (tcsetattr(STDIN_FILENO
, TCSADRAIN
, &ntty
) == -1
291 err(1, "tcsetattr failed");
295 (void)pam_end(pamh
, pam_err
);
305 * We can't use libskey's skey_authenticate() since it
306 * handles signals in a way that's inappropriate
307 * for our needs. Instead we roll our own.
310 skey_auth(const char *user
)
316 if (!skey_haskey(user
) && (ask
= skey_keyinfo(user
))) {
317 (void)printf("\n[%s]\nResponse: ", ask
);
318 if (!fgets(s
, sizeof(s
), stdin
) || *s
== '\n')
321 s
[strlen(s
) - 1] = '\0';
322 if (skey_passcheck(user
, s
) != -1)
326 (void)printf("Sorry, you have no s/key.\n");
334 struct timeval timval
;
337 (void)printf("lock: type in the unlock key.\n");
339 if (gettimeofday(&timval
, NULL
) == -1)
340 err(1, "gettimeofday failed");
341 (void)printf("lock: type in the unlock key. "
342 "timeout in %lld:%lld minutes\n",
343 (long long)(nexttime
- timval
.tv_sec
) / 60,
344 (long long)(nexttime
- timval
.tv_sec
) % 60);
352 (void)tcsetattr(STDIN_FILENO
, TCSADRAIN
, &tty
);
359 (void)tcsetattr(STDIN_FILENO
, TCSADRAIN
, &tty
);
360 (void)printf("lock: timeout\n");