cf/largefile.m4: Fix build with autoconf-2.72
[heimdal.git] / appl / otp / otp.c
blobdeb7d303c66b031f8a94e7b863d52918679cec8f
1 /*
2 * Copyright (c) 1995-1997, 1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * 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.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "otp_locl.h"
35 #include <getarg.h>
37 RCSID("$Id$");
39 static int listp;
40 static int deletep;
41 static int openp;
42 static int renewp;
43 static char* alg_string;
44 static char *user;
45 static int version_flag;
46 static int help_flag;
48 struct getargs args[] = {
49 { "list", 'l', arg_flag, &listp, "list OTP status", NULL },
50 { "delete", 'd', arg_flag, &deletep, "delete OTP", NULL },
51 { "open", 'o', arg_flag, &openp, "open a locked OTP", NULL },
52 { "renew", 'r', arg_flag, &renewp, "securely renew OTP", NULL },
53 { "hash", 'f', arg_string, &alg_string,
54 "hash algorithm (md4, md5, or sha)", "algorithm"},
55 { "user", 'u', arg_string, &user,
56 "user other than current user (root only)", "user" },
57 { "version", 0, arg_flag, &version_flag, NULL, NULL },
58 { "help", 'h', arg_flag, &help_flag, NULL, NULL }
61 int num_args = sizeof(args) / sizeof(args[0]);
63 static void
64 usage(int code)
66 arg_printusage(args, num_args, NULL, "[num seed]");
67 exit(code);
71 * Renew the OTP for a user.
72 * The pass-phrase is not required (RFC 1938/8.0)
75 static int
76 renew (int argc, char **argv, OtpAlgorithm *alg, char *inuser)
78 OtpContext newctx, *ctx;
79 char prompt[128];
80 char pw[64];
81 void *dbm;
82 int ret;
84 newctx.alg = alg;
85 newctx.user = inuser;
86 newctx.n = atoi (argv[0]);
87 strlcpy (newctx.seed, argv[1], sizeof(newctx.seed));
88 strlwr(newctx.seed);
89 snprintf (prompt, sizeof(prompt),
90 "[ otp-%s %u %s ]",
91 newctx.alg->name,
92 newctx.n,
93 newctx.seed);
94 if (UI_UTIL_read_pw_string (pw, sizeof(pw), prompt, 0) == 0 &&
95 otp_parse (newctx.key, pw, alg) == 0) {
96 ctx = &newctx;
97 ret = 0;
98 } else
99 return 1;
101 dbm = otp_db_open ();
102 if (dbm == NULL) {
103 warnx ("otp_db_open failed");
104 return 1;
106 otp_put (dbm, ctx);
107 otp_db_close (dbm);
108 return ret;
112 * Return 0 if the user could enter the next OTP.
113 * I would rather have returned !=0 but it's shell-like here around.
116 static int
117 verify_user_otp(char *username)
119 OtpContext ctx;
120 char passwd[OTP_MAX_PASSPHRASE + 1];
121 char ss[256];
122 char *prompt = NULL;
124 if (otp_challenge (&ctx, username, ss, sizeof(ss)) != 0) {
125 warnx("no otp challenge found for %s", username);
126 return 1;
129 if (asprintf(&prompt, "%s's %s Password: ", username, ss) == -1 ||
130 prompt == NULL)
131 err(1, "out of memory");
132 if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)) {
133 free(prompt);
134 return 1;
136 free(prompt);
137 return otp_verify_user (&ctx, passwd);
141 * Set the OTP for a user
144 static int
145 set (int argc, char **argv, OtpAlgorithm *alg, char *inuser)
147 void *db;
148 OtpContext ctx;
149 char pw[OTP_MAX_PASSPHRASE + 1];
150 int ret;
151 int i;
153 ctx.alg = alg;
154 ctx.user = strdup (inuser);
155 if (ctx.user == NULL)
156 err (1, "out of memory");
158 ctx.n = atoi (argv[0]);
159 strlcpy (ctx.seed, argv[1], sizeof(ctx.seed));
160 strlwr(ctx.seed);
161 do {
162 if (UI_UTIL_read_pw_string (pw, sizeof(pw), "Pass-phrase: ",
163 UI_UTIL_FLAG_VERIFY))
164 return 1;
165 if (strlen (pw) < OTP_MIN_PASSPHRASE)
166 printf ("Too short pass-phrase. Use at least %d characters\n",
167 OTP_MIN_PASSPHRASE);
168 } while(strlen(pw) < OTP_MIN_PASSPHRASE);
169 ctx.alg->init (ctx.key, pw, ctx.seed);
170 for (i = 0; i < ctx.n; ++i)
171 ctx.alg->next (ctx.key);
172 db = otp_db_open ();
173 if(db == NULL) {
174 free (ctx.user);
175 err (1, "otp_db_open failed");
177 ret = otp_put (db, &ctx);
178 otp_db_close (db);
179 free (ctx.user);
180 return ret;
184 * Delete otp of user from the database
187 static int
188 delete_otp (int argc, char **argv, char *inuser)
190 void *db;
191 OtpContext ctx;
192 int ret;
194 db = otp_db_open ();
195 if(db == NULL)
196 errx (1, "otp_db_open failed");
198 ctx.user = inuser;
199 ret = otp_delete(db, &ctx);
200 otp_db_close (db);
201 return ret;
205 * Tell whether the user has an otp
208 static int
209 has_an_otp(char *inuser)
211 void *db;
212 OtpContext ctx;
213 int ret;
215 db = otp_db_open ();
216 if(db == NULL) {
217 warnx ("otp_db_open failed");
218 return 0; /* if no db no otp! */
221 ctx.user = inuser;
222 ret = otp_simple_get(db, &ctx);
224 otp_db_close (db);
225 return !ret;
229 * Get and print out the otp entry for some user
232 static void
233 print_otp_entry_for_name (void *db, char *inuser)
235 OtpContext ctx;
237 ctx.user = inuser;
238 if (!otp_simple_get(db, &ctx)) {
239 fprintf(stdout,
240 "%s\totp-%s %d %s",
241 ctx.user, ctx.alg->name, ctx.n, ctx.seed);
242 if (ctx.lock_time)
243 fprintf(stdout,
244 "\tlocked since %s",
245 ctime(&ctx.lock_time));
246 else
247 fprintf(stdout, "\n");
251 static int
252 open_otp (int argc, char **argv, char *inuser)
254 void *db;
255 OtpContext ctx;
256 int ret;
258 db = otp_db_open ();
259 if (db == NULL)
260 errx (1, "otp_db_open failed");
262 ctx.user = inuser;
263 ret = otp_simple_get (db, &ctx);
264 if (ret == 0)
265 ret = otp_put (db, &ctx);
266 otp_db_close (db);
267 return ret;
271 * Print otp entries for one or all users
274 static int
275 list_otps (int argc, char **argv, char *inuser)
277 void *db;
278 struct passwd *pw;
280 db = otp_db_open ();
281 if(db == NULL)
282 errx (1, "otp_db_open failed");
284 if (inuser)
285 print_otp_entry_for_name(db, inuser);
286 else
287 /* scans all users... so as to get a deterministic order */
288 while ((pw = getpwent()))
289 print_otp_entry_for_name(db, pw->pw_name);
291 otp_db_close (db);
292 return 0;
296 main (int argc, char **argv)
298 int defaultp = 0;
299 int uid = getuid();
300 OtpAlgorithm *alg = otp_find_alg (OTP_ALG_DEFAULT);
301 int optidx = 0;
302 char userbuf[128];
304 setprogname (argv[0]);
305 if(getarg(args, num_args, argc, argv, &optidx))
306 usage(1);
307 if(help_flag)
308 usage(0);
309 if(version_flag) {
310 print_version(NULL);
311 exit(0);
314 if(deletep && uid != 0)
315 errx (1, "Only root can delete OTPs");
316 if(alg_string) {
317 alg = otp_find_alg (alg_string);
318 if (alg == NULL)
319 errx (1, "Unknown algorithm: %s", alg_string);
321 if (user && uid != 0)
322 errx (1, "Only root can use `-u'");
323 argc -= optidx;
324 argv += optidx;
326 if (!(listp || deletep || renewp || openp))
327 defaultp = 1;
329 if ( listp + deletep + renewp + defaultp + openp != 1)
330 usage(1); /* one of -d or -l or -r or none */
332 if(deletep || openp || listp) {
333 if(argc != 0)
334 errx(1, "delete, open, and list requires no arguments");
335 } else {
336 if(argc != 2)
337 errx(1, "setup, and renew requires `num', and `seed'");
339 if (listp)
340 return list_otps (argc, argv, user);
342 if (user == NULL) {
343 user = roken_get_username(userbuf, sizeof(userbuf));
344 if (user == NULL)
345 err (1, "You don't exist");
349 * users other that root must provide the next OTP to update the sequence.
350 * it avoids someone to use a pending session to change an OTP sequence.
351 * see RFC 1938/8.0.
353 if (uid != 0 && (defaultp || renewp)) {
354 if (!has_an_otp(user)) {
355 errx (1, "Only root can set an initial OTP");
356 } else { /* Check the next OTP (RFC 1938/8.0: SHOULD) */
357 if (verify_user_otp(user) != 0) {
358 errx (1, "User authentication failed");
363 if (deletep)
364 return delete_otp (argc, argv, user);
365 else if (renewp)
366 return renew (argc, argv, alg, user);
367 else if (openp)
368 return open_otp (argc, argv, user);
369 else
370 return set (argc, argv, alg, user);