1 /* $NetBSD: lock.c,v 1.30 2008/07/21 14:19:23 lukem 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.30 2008/07/21 14:19:23 lukem 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
;
108 char *ap
, *mypw
, *ttynam
;
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
};
118 if ((pw
= getpwuid(getuid())) == NULL
)
119 errx(1, "unknown uid %lu.", (u_long
)uid
);
122 sectimeout
= TIMEOUT
;
126 while ((ch
= getopt(argc
, argv
, "npt:")) != -1)
133 if (((sectimeout
= strtol(optarg
, &ap
, 0)) == LONG_MAX
134 || sectimeout
== LONG_MIN
)
136 err(1, "illegal timeout value: %s", optarg
);
137 if (optarg
== ap
|| *ap
|| sectimeout
<= 0)
138 errx(1, "illegal timeout value: %s", optarg
);
139 if (sectimeout
>= INT_MAX
/ 60)
140 errx(1, "too large timeout value: %ld",
146 mypw
= strdup(pw
->pw_passwd
);
153 (void)fprintf(stderr
,
154 "usage: %s [-np] [-t timeout]\n", getprogname());
158 #if defined(USE_PAM) || defined(SKEY)
159 if (! usemine
) { /* -p with PAM or S/key needs privs */
161 if (setuid(uid
) == -1) /* discard privs */
162 err(1, "setuid failed");
163 #if defined(USE_PAM) || defined(SKEY)
167 timeout
.tv_sec
= (int)sectimeout
* 60;
169 if (tcgetattr(STDIN_FILENO
, &tty
) < 0) /* get information for header */
170 err(1, "tcgetattr failed");
171 gethostname(hostname
, sizeof(hostname
));
172 hostname
[sizeof(hostname
) - 1] = '\0';
173 if (!(ttynam
= ttyname(STDIN_FILENO
)))
174 err(1, "ttyname failed");
175 if (gettimeofday(&timval
, NULL
) == -1)
176 err(1, "gettimeofday failed");
177 curtime
= timval
.tv_sec
;
178 nexttime
= timval
.tv_sec
+ ((int)sectimeout
* 60);
179 timp
= localtime(&curtime
);
187 if (signal(SIGINT
, quit
) == SIG_ERR
)
188 err(1, "signal failed");
189 if (signal(SIGQUIT
, quit
) == SIG_ERR
)
190 err(1, "signal failed");
191 ntty
= tty
; ntty
.c_lflag
&= ~ECHO
;
192 if (tcsetattr(STDIN_FILENO
, TCSADRAIN
, &ntty
) == -1)
196 /* get key and check again */
197 (void)printf("Key: ");
198 if (!fgets(s
, sizeof(s
), stdin
) || *s
== '\n')
200 (void)printf("\nAgain: ");
202 * Don't need EOF test here, if we get EOF, then s1 != s
203 * and the right things will happen.
205 (void)fgets(s1
, sizeof(s1
), stdin
);
208 (void)printf("\alock: passwords didn't match.\n");
209 (void)tcsetattr(STDIN_FILENO
, TCSADRAIN
, &tty
);
217 pam_err
= pam_start("lock", pw
->pw_name
, &pamc
, &pamh
);
218 if (pam_err
!= PAM_SUCCESS
)
219 err(1, "pam_start: %s", pam_strerror(NULL
, pam_err
));
223 /* set signal handlers */
224 if (signal(SIGINT
, hi
) == SIG_ERR
)
225 err(1, "signal failed");
226 if (signal(SIGQUIT
, hi
) == SIG_ERR
)
227 err(1, "signal failed");
228 if (signal(SIGTSTP
, hi
) == SIG_ERR
)
229 err(1, "signal failed");
232 if (signal(SIGALRM
, hi
) == SIG_ERR
)
233 err(1, "signal failed");
234 (void)printf("lock: %s on %s. no timeout.\n"
235 "time now is %.20s%s%s",
236 ttynam
, hostname
, ap
, tzn
, ap
+ 19);
239 if (signal(SIGALRM
, bye
) == SIG_ERR
)
240 err(1, "signal failed");
242 ntimer
.it_interval
= zerotime
;
243 ntimer
.it_value
= timeout
;
244 if (setitimer(ITIMER_REAL
, &ntimer
, &otimer
) == -1)
245 err(1, "setitimer failed");
248 (void)printf("lock: %s on %s. timeout in %ld minutes\n"
249 "time now is %.20s%s%s",
250 ttynam
, hostname
, sectimeout
, ap
, tzn
, ap
+ 19);
256 pam_err
= pam_authenticate(pamh
, 0);
257 if (pam_err
== PAM_SUCCESS
)
262 (void)printf("Key: ");
263 if (!fgets(s
, sizeof(s
), stdin
)) {
270 s
[strlen(s
) - 1] = '\0';
272 if (strcasecmp(s
, "s/key") == 0) {
273 if (skey_auth(pw
->pw_name
))
277 if (!strcmp(mypw
, crypt(s
, mypw
)))
284 (void)printf("\a\n");
286 if (tcsetattr(STDIN_FILENO
, TCSADRAIN
, &ntty
) == -1
288 err(1, "tcsetattr failed");
292 (void)pam_end(pamh
, pam_err
);
302 * We can't use libskey's skey_authenticate() since it
303 * handles signals in a way that's inappropriate
304 * for our needs. Instead we roll our own.
307 skey_auth(const char *user
)
313 if (!skey_haskey(user
) && (ask
= skey_keyinfo(user
))) {
314 (void)printf("\n[%s]\nResponse: ", ask
);
315 if (!fgets(s
, sizeof(s
), stdin
) || *s
== '\n')
318 s
[strlen(s
) - 1] = '\0';
319 if (skey_passcheck(user
, s
) != -1)
323 (void)printf("Sorry, you have no s/key.\n");
332 struct timeval timval
;
335 (void)printf("lock: type in the unlock key.\n");
337 if (gettimeofday(&timval
, NULL
) == -1)
338 err(1, "gettimeofday failed");
339 (void)printf("lock: type in the unlock key. "
340 "timeout in %lld:%lld minutes\n",
341 (long long)(nexttime
- timval
.tv_sec
) / 60,
342 (long long)(nexttime
- timval
.tv_sec
) % 60);
350 (void)tcsetattr(STDIN_FILENO
, TCSADRAIN
, &tty
);
357 (void)tcsetattr(STDIN_FILENO
, TCSADRAIN
, &tty
);
358 (void)printf("lock: timeout\n");