Annotation of src/usr.bin/ssh/auth2.c, Revision 1.37
1.1 markus 1: /*
2: * Copyright (c) 2000 Markus Friedl. All rights reserved.
3: *
4: * Redistribution and use in source and binary forms, with or without
5: * modification, are permitted provided that the following conditions
6: * are met:
7: * 1. Redistributions of source code must retain the above copyright
8: * notice, this list of conditions and the following disclaimer.
9: * 2. Redistributions in binary form must reproduce the above copyright
10: * notice, this list of conditions and the following disclaimer in the
11: * documentation and/or other materials provided with the distribution.
12: *
13: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23: */
1.14 deraadt 24:
1.1 markus 25: #include "includes.h"
1.37 ! markus 26: RCSID("$OpenBSD: auth2.c,v 1.36 2001/02/04 15:32:22 stevesk Exp $");
1.1 markus 27:
28: #include <openssl/evp.h>
29:
1.32 markus 30: #include "ssh2.h"
1.1 markus 31: #include "xmalloc.h"
32: #include "rsa.h"
33: #include "pty.h"
34: #include "packet.h"
35: #include "buffer.h"
1.32 markus 36: #include "log.h"
1.1 markus 37: #include "servconf.h"
38: #include "compat.h"
39: #include "channels.h"
40: #include "bufaux.h"
41: #include "auth.h"
42: #include "session.h"
43: #include "dispatch.h"
44: #include "key.h"
1.32 markus 45: #include "cipher.h"
46: #include "kex.h"
1.29 markus 47: #include "pathnames.h"
1.1 markus 48: #include "uidswap.h"
1.10 markus 49: #include "auth-options.h"
1.1 markus 50:
51: /* import */
52: extern ServerOptions options;
1.23 markus 53: extern u_char *session_id2;
1.1 markus 54: extern int session_id2_len;
55:
1.18 markus 56: static Authctxt *x_authctxt = NULL;
57: static int one = 1;
58:
59: typedef struct Authmethod Authmethod;
60: struct Authmethod {
61: char *name;
62: int (*userauth)(Authctxt *authctxt);
63: int *enabled;
64: };
65:
1.1 markus 66: /* protocol */
67:
1.15 markus 68: void input_service_request(int type, int plen, void *ctxt);
69: void input_userauth_request(int type, int plen, void *ctxt);
70: void protocol_error(int type, int plen, void *ctxt);
1.1 markus 71:
72: /* helper */
1.18 markus 73: Authmethod *authmethod_lookup(const char *name);
74: struct passwd *pwcopy(struct passwd *pw);
1.21 markus 75: int user_key_allowed(struct passwd *pw, Key *key);
1.18 markus 76: char *authmethods_get(void);
1.1 markus 77:
1.18 markus 78: /* auth */
1.25 markus 79: void userauth_banner(void);
1.18 markus 80: int userauth_none(Authctxt *authctxt);
81: int userauth_passwd(Authctxt *authctxt);
82: int userauth_pubkey(Authctxt *authctxt);
83: int userauth_kbdint(Authctxt *authctxt);
84:
85: Authmethod authmethods[] = {
86: {"none",
87: userauth_none,
88: &one},
89: {"publickey",
90: userauth_pubkey,
1.21 markus 91: &options.pubkey_authentication},
1.18 markus 92: {"keyboard-interactive",
93: userauth_kbdint,
94: &options.kbd_interactive_authentication},
95: {"password",
96: userauth_passwd,
97: &options.password_authentication},
98: {NULL, NULL, NULL}
1.1 markus 99: };
100:
101: /*
1.18 markus 102: * loop until authctxt->success == TRUE
1.1 markus 103: */
104:
105: void
106: do_authentication2()
107: {
1.28 markus 108: Authctxt *authctxt = authctxt_new();
109:
1.18 markus 110: x_authctxt = authctxt; /*XXX*/
111:
1.34 markus 112: /* challenge-reponse is implemented via keyboard interactive */
113: if (options.challenge_reponse_authentication)
114: options.kbd_interactive_authentication = 1;
115:
1.1 markus 116: dispatch_init(&protocol_error);
117: dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
1.18 markus 118: dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
1.28 markus 119: do_authenticated2(authctxt);
1.1 markus 120: }
121:
122: void
1.15 markus 123: protocol_error(int type, int plen, void *ctxt)
1.1 markus 124: {
125: log("auth: protocol error: type %d plen %d", type, plen);
126: packet_start(SSH2_MSG_UNIMPLEMENTED);
127: packet_put_int(0);
128: packet_send();
129: packet_write_wait();
130: }
131:
132: void
1.15 markus 133: input_service_request(int type, int plen, void *ctxt)
1.1 markus 134: {
1.18 markus 135: Authctxt *authctxt = ctxt;
1.23 markus 136: u_int len;
1.1 markus 137: int accept = 0;
138: char *service = packet_get_string(&len);
139: packet_done();
140:
1.18 markus 141: if (authctxt == NULL)
142: fatal("input_service_request: no authctxt");
143:
1.1 markus 144: if (strcmp(service, "ssh-userauth") == 0) {
1.18 markus 145: if (!authctxt->success) {
1.1 markus 146: accept = 1;
147: /* now we can handle user-auth requests */
148: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
149: }
150: }
151: /* XXX all other service requests are denied */
152:
153: if (accept) {
154: packet_start(SSH2_MSG_SERVICE_ACCEPT);
155: packet_put_cstring(service);
156: packet_send();
157: packet_write_wait();
158: } else {
159: debug("bad service request %s", service);
160: packet_disconnect("bad service request %s", service);
161: }
162: xfree(service);
163: }
164:
165: void
1.15 markus 166: input_userauth_request(int type, int plen, void *ctxt)
1.1 markus 167: {
1.18 markus 168: Authctxt *authctxt = ctxt;
169: Authmethod *m = NULL;
1.28 markus 170: char *user, *service, *method, *style = NULL;
1.1 markus 171: int authenticated = 0;
172:
1.18 markus 173: if (authctxt == NULL)
174: fatal("input_userauth_request: no authctxt");
1.1 markus 175:
1.18 markus 176: user = packet_get_string(NULL);
177: service = packet_get_string(NULL);
178: method = packet_get_string(NULL);
1.1 markus 179: debug("userauth-request for user %s service %s method %s", user, service, method);
1.24 markus 180: debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
1.1 markus 181:
1.28 markus 182: if ((style = strchr(user, ':')) != NULL)
183: *style++ = 0;
184:
1.36 stevesk 185: if (authctxt->attempt++ == 0) {
1.18 markus 186: /* setup auth context */
187: struct passwd *pw = NULL;
188: setproctitle("%s", user);
189: pw = getpwnam(user);
190: if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
191: authctxt->pw = pwcopy(pw);
192: authctxt->valid = 1;
193: debug2("input_userauth_request: setting up authctxt for %s", user);
194: } else {
195: log("input_userauth_request: illegal user %s", user);
196: }
197: authctxt->user = xstrdup(user);
198: authctxt->service = xstrdup(service);
1.28 markus 199: authctxt->style = style ? xstrdup(style) : NULL; /* currently unused */
1.18 markus 200: } else if (authctxt->valid) {
201: if (strcmp(user, authctxt->user) != 0 ||
202: strcmp(service, authctxt->service) != 0) {
203: log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)",
204: user, service, authctxt->user, authctxt->service);
205: authctxt->valid = 0;
1.1 markus 206: }
207: }
1.28 markus 208: /* reset state */
209: dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, &protocol_error);
210: authctxt->postponed = 0;
1.18 markus 211:
1.28 markus 212: /* try to authenticate user */
1.18 markus 213: m = authmethod_lookup(method);
214: if (m != NULL) {
215: debug2("input_userauth_request: try method %s", method);
216: authenticated = m->userauth(authctxt);
217: }
1.28 markus 218: if (!authctxt->valid && authenticated)
219: fatal("INTERNAL ERROR: authenticated invalid user %s",
220: authctxt->user);
1.18 markus 221:
222: /* Special handling for root */
1.28 markus 223: if (authenticated && authctxt->pw->pw_uid == 0 && !auth_root_allowed())
1.3 markus 224: authenticated = 0;
225:
1.18 markus 226: /* Log before sending the reply */
1.28 markus 227: auth_log(authctxt, authenticated, method, " ssh2");
228:
229: if (!authctxt->postponed)
230: userauth_reply(authctxt, authenticated);
1.18 markus 231:
232: xfree(service);
233: xfree(user);
234: xfree(method);
235: }
236:
1.25 markus 237: void
238: userauth_banner(void)
239: {
240: struct stat st;
241: char *banner = NULL;
242: off_t len, n;
243: int fd;
244:
245: if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
246: return;
247: if ((fd = open(options.banner, O_RDONLY)) < 0) {
248: error("userauth_banner: open %s failed: %s",
249: options.banner, strerror(errno));
250: return;
251: }
252: if (fstat(fd, &st) < 0)
253: goto done;
254: len = st.st_size;
255: banner = xmalloc(len + 1);
256: if ((n = read(fd, banner, len)) < 0)
257: goto done;
258: banner[n] = '\0';
259: packet_start(SSH2_MSG_USERAUTH_BANNER);
260: packet_put_cstring(banner);
261: packet_put_cstring(""); /* language, unused */
262: packet_send();
263: debug("userauth_banner: sent");
264: done:
265: if (banner)
266: xfree(banner);
267: close(fd);
268: return;
269: }
1.18 markus 270:
1.36 stevesk 271: void
1.18 markus 272: userauth_reply(Authctxt *authctxt, int authenticated)
273: {
1.24 markus 274: char *methods;
1.28 markus 275:
1.3 markus 276: /* XXX todo: check if multiple auth methods are needed */
1.28 markus 277: if (authenticated) {
1.1 markus 278: /* turn off userauth */
279: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
280: packet_start(SSH2_MSG_USERAUTH_SUCCESS);
281: packet_send();
282: packet_write_wait();
283: /* now we can break out */
1.18 markus 284: authctxt->success = 1;
1.28 markus 285: } else {
286: if (authctxt->failures++ > AUTH_FAIL_MAX)
1.36 stevesk 287: packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
1.24 markus 288: methods = authmethods_get();
1.1 markus 289: packet_start(SSH2_MSG_USERAUTH_FAILURE);
1.18 markus 290: packet_put_cstring(methods);
291: packet_put_char(0); /* XXX partial success, unused */
1.1 markus 292: packet_send();
293: packet_write_wait();
1.18 markus 294: xfree(methods);
1.1 markus 295: }
296: }
297:
298: int
1.18 markus 299: userauth_none(Authctxt *authctxt)
1.1 markus 300: {
1.18 markus 301: /* disable method "none", only allowed one time */
302: Authmethod *m = authmethod_lookup("none");
303: if (m != NULL)
304: m->enabled = NULL;
1.1 markus 305: packet_done();
1.25 markus 306: userauth_banner();
1.18 markus 307: return authctxt->valid ? auth_password(authctxt->pw, "") : 0;
1.1 markus 308: }
1.18 markus 309:
1.1 markus 310: int
1.18 markus 311: userauth_passwd(Authctxt *authctxt)
1.1 markus 312: {
313: char *password;
314: int authenticated = 0;
315: int change;
1.23 markus 316: u_int len;
1.1 markus 317: change = packet_get_char();
318: if (change)
319: log("password change not supported");
320: password = packet_get_string(&len);
321: packet_done();
1.18 markus 322: if (authctxt->valid &&
323: auth_password(authctxt->pw, password) == 1)
1.1 markus 324: authenticated = 1;
325: memset(password, 0, len);
326: xfree(password);
327: return authenticated;
328: }
1.18 markus 329:
330: int
331: userauth_kbdint(Authctxt *authctxt)
332: {
333: int authenticated = 0;
334: char *lang = NULL;
335: char *devs = NULL;
336:
337: lang = packet_get_string(NULL);
338: devs = packet_get_string(NULL);
339: packet_done();
340:
341: debug("keyboard-interactive language %s devs %s", lang, devs);
1.28 markus 342:
1.34 markus 343: if (options.challenge_reponse_authentication)
344: authenticated = auth2_challenge(authctxt, devs);
1.28 markus 345:
1.18 markus 346: xfree(lang);
347: xfree(devs);
348: return authenticated;
349: }
350:
1.1 markus 351: int
1.18 markus 352: userauth_pubkey(Authctxt *authctxt)
1.1 markus 353: {
354: Buffer b;
355: Key *key;
356: char *pkalg, *pkblob, *sig;
1.23 markus 357: u_int alen, blen, slen;
1.21 markus 358: int have_sig, pktype;
1.1 markus 359: int authenticated = 0;
360:
1.18 markus 361: if (!authctxt->valid) {
362: debug2("userauth_pubkey: disabled because of invalid user");
1.8 markus 363: return 0;
364: }
1.1 markus 365: have_sig = packet_get_char();
1.22 markus 366: if (datafellows & SSH_BUG_PKAUTH) {
367: debug2("userauth_pubkey: SSH_BUG_PKAUTH");
368: /* no explicit pkalg given */
369: pkblob = packet_get_string(&blen);
370: buffer_init(&b);
371: buffer_append(&b, pkblob, blen);
372: /* so we have to extract the pkalg from the pkblob */
373: pkalg = buffer_get_string(&b, &alen);
374: buffer_free(&b);
375: } else {
376: pkalg = packet_get_string(&alen);
377: pkblob = packet_get_string(&blen);
378: }
1.21 markus 379: pktype = key_type_from_name(pkalg);
380: if (pktype == KEY_UNSPEC) {
1.22 markus 381: /* this is perfectly legal */
382: log("userauth_pubkey: unsupported public key algorithm: %s", pkalg);
1.1 markus 383: xfree(pkalg);
1.22 markus 384: xfree(pkblob);
1.1 markus 385: return 0;
386: }
1.21 markus 387: key = key_from_blob(pkblob, blen);
1.2 markus 388: if (key != NULL) {
389: if (have_sig) {
390: sig = packet_get_string(&slen);
391: packet_done();
392: buffer_init(&b);
1.20 markus 393: if (datafellows & SSH_OLD_SESSIONID) {
394: buffer_append(&b, session_id2, session_id2_len);
395: } else {
1.11 markus 396: buffer_put_string(&b, session_id2, session_id2_len);
397: }
1.9 markus 398: /* reconstruct packet */
1.2 markus 399: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.18 markus 400: buffer_put_cstring(&b, authctxt->user);
1.9 markus 401: buffer_put_cstring(&b,
1.22 markus 402: datafellows & SSH_BUG_PKSERVICE ?
1.9 markus 403: "ssh-userauth" :
1.18 markus 404: authctxt->service);
1.22 markus 405: if (datafellows & SSH_BUG_PKAUTH) {
406: buffer_put_char(&b, have_sig);
407: } else {
408: buffer_put_cstring(&b, "publickey");
409: buffer_put_char(&b, have_sig);
410: buffer_put_cstring(&b, key_ssh_name(key));
411: }
1.9 markus 412: buffer_put_string(&b, pkblob, blen);
1.21 markus 413: #ifdef DEBUG_PK
1.2 markus 414: buffer_dump(&b);
1.1 markus 415: #endif
1.2 markus 416: /* test for correct signature */
1.21 markus 417: if (user_key_allowed(authctxt->pw, key) &&
418: key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
1.2 markus 419: authenticated = 1;
420: buffer_clear(&b);
421: xfree(sig);
422: } else {
1.18 markus 423: debug("test whether pkalg/pkblob are acceptable");
1.2 markus 424: packet_done();
1.18 markus 425:
1.2 markus 426: /* XXX fake reply and always send PK_OK ? */
1.6 markus 427: /*
428: * XXX this allows testing whether a user is allowed
429: * to login: if you happen to have a valid pubkey this
430: * message is sent. the message is NEVER sent at all
431: * if a user is not allowed to login. is this an
432: * issue? -markus
433: */
1.21 markus 434: if (user_key_allowed(authctxt->pw, key)) {
1.2 markus 435: packet_start(SSH2_MSG_USERAUTH_PK_OK);
436: packet_put_string(pkalg, alen);
437: packet_put_string(pkblob, blen);
438: packet_send();
439: packet_write_wait();
440: authenticated = -1;
441: }
1.1 markus 442: }
1.17 markus 443: if (authenticated != 1)
444: auth_clear_options();
1.2 markus 445: key_free(key);
1.1 markus 446: }
1.21 markus 447: debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
1.1 markus 448: xfree(pkalg);
449: xfree(pkblob);
450: return authenticated;
451: }
452:
1.18 markus 453: /* get current user */
1.1 markus 454:
455: struct passwd*
456: auth_get_user(void)
457: {
1.18 markus 458: return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
1.1 markus 459: }
460:
1.18 markus 461: #define DELIM ","
462:
463: char *
464: authmethods_get(void)
1.1 markus 465: {
1.18 markus 466: Authmethod *method = NULL;
1.23 markus 467: u_int size = 0;
1.18 markus 468: char *list;
1.1 markus 469:
1.18 markus 470: for (method = authmethods; method->name != NULL; method++) {
471: if (strcmp(method->name, "none") == 0)
472: continue;
473: if (method->enabled != NULL && *(method->enabled) != 0) {
474: if (size != 0)
475: size += strlen(DELIM);
476: size += strlen(method->name);
1.1 markus 477: }
1.18 markus 478: }
479: size++; /* trailing '\0' */
480: list = xmalloc(size);
481: list[0] = '\0';
482:
483: for (method = authmethods; method->name != NULL; method++) {
484: if (strcmp(method->name, "none") == 0)
485: continue;
486: if (method->enabled != NULL && *(method->enabled) != 0) {
487: if (list[0] != '\0')
488: strlcat(list, DELIM, size);
489: strlcat(list, method->name, size);
1.1 markus 490: }
491: }
1.18 markus 492: return list;
493: }
494:
495: Authmethod *
496: authmethod_lookup(const char *name)
497: {
498: Authmethod *method = NULL;
499: if (name != NULL)
500: for (method = authmethods; method->name != NULL; method++)
501: if (method->enabled != NULL &&
502: *(method->enabled) != 0 &&
503: strcmp(name, method->name) == 0)
504: return method;
505: debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
506: return NULL;
1.1 markus 507: }
508:
509: /* return 1 if user allows given key */
510: int
1.21 markus 511: user_key_allowed(struct passwd *pw, Key *key)
1.1 markus 512: {
1.31 markus 513: char line[8192], file[MAXPATHLEN];
1.1 markus 514: int found_key = 0;
515: FILE *f;
1.23 markus 516: u_long linenum = 0;
1.1 markus 517: struct stat st;
518: Key *found;
519:
1.18 markus 520: if (pw == NULL)
521: return 0;
522:
1.1 markus 523: /* Temporarily use the user's uid. */
524: temporarily_use_uid(pw->pw_uid);
525:
526: /* The authorized keys. */
527: snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
1.29 markus 528: _PATH_SSH_USER_PERMITTED_KEYS2);
1.1 markus 529:
530: /* Fail quietly if file does not exist */
531: if (stat(file, &st) < 0) {
532: /* Restore the privileged uid. */
533: restore_uid();
534: return 0;
535: }
536: /* Open the file containing the authorized keys. */
537: f = fopen(file, "r");
538: if (!f) {
539: /* Restore the privileged uid. */
540: restore_uid();
541: return 0;
542: }
543: if (options.strict_modes) {
544: int fail = 0;
545: char buf[1024];
546: /* Check open file in order to avoid open/stat races */
547: if (fstat(fileno(f), &st) < 0 ||
548: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
549: (st.st_mode & 022) != 0) {
1.16 markus 550: snprintf(buf, sizeof buf,
551: "%s authentication refused for %.100s: "
552: "bad ownership or modes for '%s'.",
553: key_type(key), pw->pw_name, file);
1.1 markus 554: fail = 1;
555: } else {
1.29 markus 556: /* Check path to _PATH_SSH_USER_PERMITTED_KEYS */
1.1 markus 557: int i;
558: static const char *check[] = {
1.29 markus 559: "", _PATH_SSH_USER_DIR, NULL
1.1 markus 560: };
561: for (i = 0; check[i]; i++) {
562: snprintf(line, sizeof line, "%.500s/%.100s",
563: pw->pw_dir, check[i]);
564: if (stat(line, &st) < 0 ||
565: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
566: (st.st_mode & 022) != 0) {
567: snprintf(buf, sizeof buf,
1.16 markus 568: "%s authentication refused for %.100s: "
1.1 markus 569: "bad ownership or modes for '%s'.",
1.16 markus 570: key_type(key), pw->pw_name, line);
1.1 markus 571: fail = 1;
572: break;
573: }
574: }
575: }
576: if (fail) {
577: fclose(f);
1.12 todd 578: log("%s",buf);
1.1 markus 579: restore_uid();
580: return 0;
581: }
582: }
583: found_key = 0;
1.16 markus 584: found = key_new(key->type);
1.1 markus 585:
586: while (fgets(line, sizeof(line), f)) {
1.10 markus 587: char *cp, *options = NULL;
1.1 markus 588: linenum++;
589: /* Skip leading whitespace, empty and comment lines. */
590: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
591: ;
592: if (!*cp || *cp == '\n' || *cp == '#')
593: continue;
1.10 markus 594:
1.21 markus 595: if (key_read(found, &cp) == -1) {
1.10 markus 596: /* no key? check if there are options for this key */
597: int quoted = 0;
1.21 markus 598: debug2("user_key_allowed: check options: '%s'", cp);
1.10 markus 599: options = cp;
600: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
601: if (*cp == '\\' && cp[1] == '"')
602: cp++; /* Skip both */
603: else if (*cp == '"')
604: quoted = !quoted;
605: }
606: /* Skip remaining whitespace. */
607: for (; *cp == ' ' || *cp == '\t'; cp++)
608: ;
1.21 markus 609: if (key_read(found, &cp) == -1) {
610: debug2("user_key_allowed: advance: '%s'", cp);
1.10 markus 611: /* still no key? advance to next line*/
612: continue;
613: }
614: }
615: if (key_equal(found, key) &&
1.30 markus 616: auth_parse_options(pw, options, file, linenum) == 1) {
1.1 markus 617: found_key = 1;
618: debug("matching key found: file %s, line %ld",
619: file, linenum);
620: break;
621: }
622: }
623: restore_uid();
624: fclose(f);
625: key_free(found);
626: return found_key;
627: }