Annotation of src/usr.bin/ssh/auth2.c, Revision 1.8.2.2
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.8.2.2 ! jason 24:
1.1 markus 25: #include "includes.h"
1.8.2.2 ! jason 26: RCSID("$OpenBSD: auth2.c,v 1.20 2000/10/14 12:16:56 markus Exp $");
1.1 markus 27:
28: #include <openssl/dsa.h>
29: #include <openssl/rsa.h>
30: #include <openssl/evp.h>
31:
32: #include "xmalloc.h"
33: #include "rsa.h"
34: #include "ssh.h"
35: #include "pty.h"
36: #include "packet.h"
37: #include "buffer.h"
38: #include "servconf.h"
39: #include "compat.h"
40: #include "channels.h"
41: #include "bufaux.h"
42: #include "ssh2.h"
43: #include "auth.h"
44: #include "session.h"
45: #include "dispatch.h"
46: #include "auth.h"
47: #include "key.h"
48: #include "kex.h"
49:
50: #include "dsa.h"
51: #include "uidswap.h"
1.8.2.1 jason 52: #include "auth-options.h"
1.1 markus 53:
54: /* import */
55: extern ServerOptions options;
56: extern unsigned char *session_id2;
57: extern int session_id2_len;
58:
1.8.2.2 ! jason 59: static Authctxt *x_authctxt = NULL;
! 60: static int one = 1;
! 61:
! 62: typedef struct Authmethod Authmethod;
! 63: struct Authmethod {
! 64: char *name;
! 65: int (*userauth)(Authctxt *authctxt);
! 66: int *enabled;
! 67: };
! 68:
1.1 markus 69: /* protocol */
70:
1.8.2.2 ! jason 71: void input_service_request(int type, int plen, void *ctxt);
! 72: void input_userauth_request(int type, int plen, void *ctxt);
! 73: void protocol_error(int type, int plen, void *ctxt);
1.1 markus 74:
75:
76: /* helper */
1.8.2.2 ! jason 77: Authmethod *authmethod_lookup(const char *name);
! 78: struct passwd *pwcopy(struct passwd *pw);
1.1 markus 79: int user_dsa_key_allowed(struct passwd *pw, Key *key);
1.8.2.2 ! jason 80: char *authmethods_get(void);
1.1 markus 81:
1.8.2.2 ! jason 82: /* auth */
! 83: int userauth_none(Authctxt *authctxt);
! 84: int userauth_passwd(Authctxt *authctxt);
! 85: int userauth_pubkey(Authctxt *authctxt);
! 86: int userauth_kbdint(Authctxt *authctxt);
! 87:
! 88: Authmethod authmethods[] = {
! 89: {"none",
! 90: userauth_none,
! 91: &one},
! 92: {"publickey",
! 93: userauth_pubkey,
! 94: &options.dsa_authentication},
! 95: {"keyboard-interactive",
! 96: userauth_kbdint,
! 97: &options.kbd_interactive_authentication},
! 98: {"password",
! 99: userauth_passwd,
! 100: &options.password_authentication},
! 101: {NULL, NULL, NULL}
1.1 markus 102: };
103:
104: /*
1.8.2.2 ! jason 105: * loop until authctxt->success == TRUE
1.1 markus 106: */
107:
108: void
109: do_authentication2()
110: {
1.8.2.2 ! jason 111: Authctxt *authctxt = xmalloc(sizeof(*authctxt));
! 112: memset(authctxt, 'a', sizeof(*authctxt));
! 113: authctxt->valid = 0;
! 114: authctxt->attempt = 0;
! 115: authctxt->success = 0;
! 116: x_authctxt = authctxt; /*XXX*/
! 117:
1.5 djm 118: #ifdef KRB4
1.8.2.2 ! jason 119: /* turn off kerberos, not supported by SSH2 */
1.4 markus 120: options.kerberos_authentication = 0;
1.5 djm 121: #endif
1.1 markus 122: dispatch_init(&protocol_error);
123: dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
1.8.2.2 ! jason 124: dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
1.1 markus 125: do_authenticated2();
126: }
127:
128: void
1.8.2.2 ! jason 129: protocol_error(int type, int plen, void *ctxt)
1.1 markus 130: {
131: log("auth: protocol error: type %d plen %d", type, plen);
132: packet_start(SSH2_MSG_UNIMPLEMENTED);
133: packet_put_int(0);
134: packet_send();
135: packet_write_wait();
136: }
137:
138: void
1.8.2.2 ! jason 139: input_service_request(int type, int plen, void *ctxt)
1.1 markus 140: {
1.8.2.2 ! jason 141: Authctxt *authctxt = ctxt;
1.1 markus 142: unsigned int len;
143: int accept = 0;
144: char *service = packet_get_string(&len);
145: packet_done();
146:
1.8.2.2 ! jason 147: if (authctxt == NULL)
! 148: fatal("input_service_request: no authctxt");
! 149:
1.1 markus 150: if (strcmp(service, "ssh-userauth") == 0) {
1.8.2.2 ! jason 151: if (!authctxt->success) {
1.1 markus 152: accept = 1;
153: /* now we can handle user-auth requests */
154: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
155: }
156: }
157: /* XXX all other service requests are denied */
158:
159: if (accept) {
160: packet_start(SSH2_MSG_SERVICE_ACCEPT);
161: packet_put_cstring(service);
162: packet_send();
163: packet_write_wait();
164: } else {
165: debug("bad service request %s", service);
166: packet_disconnect("bad service request %s", service);
167: }
168: xfree(service);
169: }
170:
171: void
1.8.2.2 ! jason 172: input_userauth_request(int type, int plen, void *ctxt)
1.1 markus 173: {
1.8.2.2 ! jason 174: Authctxt *authctxt = ctxt;
! 175: Authmethod *m = NULL;
! 176: char *user, *service, *method;
1.1 markus 177: int authenticated = 0;
178:
1.8.2.2 ! jason 179: if (authctxt == NULL)
! 180: fatal("input_userauth_request: no authctxt");
! 181: if (authctxt->attempt++ >= AUTH_FAIL_MAX)
1.1 markus 182: packet_disconnect("too many failed userauth_requests");
183:
1.8.2.2 ! jason 184: user = packet_get_string(NULL);
! 185: service = packet_get_string(NULL);
! 186: method = packet_get_string(NULL);
1.1 markus 187: debug("userauth-request for user %s service %s method %s", user, service, method);
1.8.2.2 ! jason 188: debug("attempt #%d", authctxt->attempt);
1.1 markus 189:
1.8.2.2 ! jason 190: if (authctxt->attempt == 1) {
! 191: /* setup auth context */
! 192: struct passwd *pw = NULL;
! 193: setproctitle("%s", user);
! 194: pw = getpwnam(user);
! 195: if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
! 196: authctxt->pw = pwcopy(pw);
! 197: authctxt->valid = 1;
! 198: debug2("input_userauth_request: setting up authctxt for %s", user);
! 199: } else {
! 200: log("input_userauth_request: illegal user %s", user);
1.1 markus 201: }
1.8.2.2 ! jason 202: authctxt->user = xstrdup(user);
! 203: authctxt->service = xstrdup(service);
! 204: } else if (authctxt->valid) {
! 205: if (strcmp(user, authctxt->user) != 0 ||
! 206: strcmp(service, authctxt->service) != 0) {
! 207: log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)",
! 208: user, service, authctxt->user, authctxt->service);
! 209: authctxt->valid = 0;
! 210: }
! 211: }
! 212:
! 213: m = authmethod_lookup(method);
! 214: if (m != NULL) {
! 215: debug2("input_userauth_request: try method %s", method);
! 216: authenticated = m->userauth(authctxt);
! 217: } else {
! 218: debug2("input_userauth_request: unsupported method %s", method);
1.1 markus 219: }
1.8.2.2 ! jason 220: if (!authctxt->valid && authenticated == 1) {
! 221: log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method);
! 222: authenticated = 0;
! 223: }
! 224:
! 225: /* Special handling for root */
! 226: if (authenticated == 1 &&
! 227: authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) {
1.3 markus 228: authenticated = 0;
1.8.2.2 ! jason 229: log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
1.3 markus 230: }
231:
1.8.2.2 ! jason 232: /* Log before sending the reply */
! 233: userauth_log(authctxt, authenticated, method);
! 234: userauth_reply(authctxt, authenticated);
! 235:
! 236: xfree(service);
! 237: xfree(user);
! 238: xfree(method);
! 239: }
! 240:
! 241:
! 242: void
! 243: userauth_log(Authctxt *authctxt, int authenticated, char *method)
! 244: {
! 245: void (*authlog) (const char *fmt,...) = verbose;
! 246: char *user = NULL, *authmsg = NULL;
! 247:
1.6 markus 248: /* Raise logging level */
249: if (authenticated == 1 ||
1.8.2.2 ! jason 250: !authctxt->valid ||
! 251: authctxt->attempt >= AUTH_FAIL_LOG ||
1.6 markus 252: strcmp(method, "password") == 0)
253: authlog = log;
254:
255: if (authenticated == 1) {
256: authmsg = "Accepted";
257: } else if (authenticated == 0) {
258: authmsg = "Failed";
259: } else {
260: authmsg = "Postponed";
261: }
1.8.2.2 ! jason 262:
! 263: if (authctxt->valid) {
! 264: user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user;
! 265: } else {
! 266: user = "NOUSER";
! 267: }
! 268:
1.6 markus 269: authlog("%s %s for %.200s from %.200s port %d ssh2",
1.8.2.2 ! jason 270: authmsg,
! 271: method,
! 272: user,
! 273: get_remote_ipaddr(),
! 274: get_remote_port());
! 275: }
1.6 markus 276:
1.8.2.2 ! jason 277: void
! 278: userauth_reply(Authctxt *authctxt, int authenticated)
! 279: {
1.3 markus 280: /* XXX todo: check if multiple auth methods are needed */
1.1 markus 281: if (authenticated == 1) {
282: /* turn off userauth */
283: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
284: packet_start(SSH2_MSG_USERAUTH_SUCCESS);
285: packet_send();
286: packet_write_wait();
287: /* now we can break out */
1.8.2.2 ! jason 288: authctxt->success = 1;
1.1 markus 289: } else if (authenticated == 0) {
1.8.2.2 ! jason 290: char *methods = authmethods_get();
1.1 markus 291: packet_start(SSH2_MSG_USERAUTH_FAILURE);
1.8.2.2 ! jason 292: packet_put_cstring(methods);
! 293: packet_put_char(0); /* XXX partial success, unused */
1.1 markus 294: packet_send();
295: packet_write_wait();
1.8.2.2 ! jason 296: xfree(methods);
! 297: } else {
! 298: /* do nothing, we did already send a reply */
1.1 markus 299: }
300: }
301:
302: int
1.8.2.2 ! jason 303: userauth_none(Authctxt *authctxt)
1.1 markus 304: {
1.8.2.2 ! jason 305: /* disable method "none", only allowed one time */
! 306: Authmethod *m = authmethod_lookup("none");
! 307: if (m != NULL)
! 308: m->enabled = NULL;
1.1 markus 309: packet_done();
1.8.2.2 ! jason 310: return authctxt->valid ? auth_password(authctxt->pw, "") : 0;
1.1 markus 311: }
1.8.2.2 ! jason 312:
1.1 markus 313: int
1.8.2.2 ! jason 314: userauth_passwd(Authctxt *authctxt)
1.1 markus 315: {
316: char *password;
317: int authenticated = 0;
318: int change;
319: unsigned int len;
320: change = packet_get_char();
321: if (change)
322: log("password change not supported");
323: password = packet_get_string(&len);
324: packet_done();
1.8.2.2 ! jason 325: if (authctxt->valid &&
! 326: auth_password(authctxt->pw, password) == 1)
1.1 markus 327: authenticated = 1;
328: memset(password, 0, len);
329: xfree(password);
330: return authenticated;
331: }
1.8.2.2 ! jason 332:
! 333: int
! 334: userauth_kbdint(Authctxt *authctxt)
! 335: {
! 336: int authenticated = 0;
! 337: char *lang = NULL;
! 338: char *devs = NULL;
! 339:
! 340: lang = packet_get_string(NULL);
! 341: devs = packet_get_string(NULL);
! 342: packet_done();
! 343:
! 344: debug("keyboard-interactive language %s devs %s", lang, devs);
! 345: #ifdef SKEY
! 346: /* XXX hardcoded, we should look at devs */
! 347: if (options.skey_authentication != 0)
! 348: authenticated = auth2_skey(authctxt);
! 349: #endif
! 350: xfree(lang);
! 351: xfree(devs);
! 352: return authenticated;
! 353: }
! 354:
1.1 markus 355: int
1.8.2.2 ! jason 356: userauth_pubkey(Authctxt *authctxt)
1.1 markus 357: {
358: Buffer b;
359: Key *key;
360: char *pkalg, *pkblob, *sig;
361: unsigned int alen, blen, slen;
362: int have_sig;
363: int authenticated = 0;
364:
1.8.2.2 ! jason 365: if (!authctxt->valid) {
! 366: debug2("userauth_pubkey: disabled because of invalid user");
1.8 markus 367: return 0;
368: }
1.1 markus 369: have_sig = packet_get_char();
370: pkalg = packet_get_string(&alen);
371: if (strcmp(pkalg, KEX_DSS) != 0) {
372: log("bad pkalg %s", pkalg); /*XXX*/
1.8.2.2 ! jason 373: xfree(pkalg);
1.1 markus 374: return 0;
375: }
376: pkblob = packet_get_string(&blen);
377: key = dsa_key_from_blob(pkblob, blen);
1.2 markus 378: if (key != NULL) {
379: if (have_sig) {
380: sig = packet_get_string(&slen);
381: packet_done();
382: buffer_init(&b);
1.8.2.2 ! jason 383: if (datafellows & SSH_OLD_SESSIONID) {
1.8.2.1 jason 384: buffer_append(&b, session_id2, session_id2_len);
1.8.2.2 ! jason 385: } else {
! 386: buffer_put_string(&b, session_id2, session_id2_len);
1.8.2.1 jason 387: }
388: /* reconstruct packet */
1.2 markus 389: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.8.2.2 ! jason 390: buffer_put_cstring(&b, authctxt->user);
1.8.2.1 jason 391: buffer_put_cstring(&b,
392: datafellows & SSH_BUG_PUBKEYAUTH ?
393: "ssh-userauth" :
1.8.2.2 ! jason 394: authctxt->service);
1.8.2.1 jason 395: buffer_put_cstring(&b, "publickey");
396: buffer_put_char(&b, have_sig);
397: buffer_put_cstring(&b, KEX_DSS);
398: buffer_put_string(&b, pkblob, blen);
1.1 markus 399: #ifdef DEBUG_DSS
1.2 markus 400: buffer_dump(&b);
1.1 markus 401: #endif
1.2 markus 402: /* test for correct signature */
1.8.2.2 ! jason 403: if (user_dsa_key_allowed(authctxt->pw, key) &&
1.2 markus 404: dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
405: authenticated = 1;
406: buffer_clear(&b);
407: xfree(sig);
408: } else {
1.8.2.2 ! jason 409: debug("test whether pkalg/pkblob are acceptable");
1.2 markus 410: packet_done();
1.8.2.2 ! jason 411:
1.2 markus 412: /* XXX fake reply and always send PK_OK ? */
1.6 markus 413: /*
414: * XXX this allows testing whether a user is allowed
415: * to login: if you happen to have a valid pubkey this
416: * message is sent. the message is NEVER sent at all
417: * if a user is not allowed to login. is this an
418: * issue? -markus
419: */
1.8.2.2 ! jason 420: if (user_dsa_key_allowed(authctxt->pw, key)) {
1.2 markus 421: packet_start(SSH2_MSG_USERAUTH_PK_OK);
422: packet_put_string(pkalg, alen);
423: packet_put_string(pkblob, blen);
424: packet_send();
425: packet_write_wait();
426: authenticated = -1;
427: }
1.1 markus 428: }
1.8.2.2 ! jason 429: if (authenticated != 1)
! 430: auth_clear_options();
1.2 markus 431: key_free(key);
1.1 markus 432: }
433: xfree(pkalg);
434: xfree(pkblob);
435: return authenticated;
436: }
437:
1.8.2.2 ! jason 438: /* get current user */
1.1 markus 439:
440: struct passwd*
441: auth_get_user(void)
442: {
1.8.2.2 ! jason 443: return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
1.1 markus 444: }
445:
1.8.2.2 ! jason 446: #define DELIM ","
! 447:
! 448: char *
! 449: authmethods_get(void)
1.1 markus 450: {
1.8.2.2 ! jason 451: Authmethod *method = NULL;
! 452: unsigned int size = 0;
! 453: char *list;
1.1 markus 454:
1.8.2.2 ! jason 455: for (method = authmethods; method->name != NULL; method++) {
! 456: if (strcmp(method->name, "none") == 0)
! 457: continue;
! 458: if (method->enabled != NULL && *(method->enabled) != 0) {
! 459: if (size != 0)
! 460: size += strlen(DELIM);
! 461: size += strlen(method->name);
1.1 markus 462: }
1.8.2.2 ! jason 463: }
! 464: size++; /* trailing '\0' */
! 465: list = xmalloc(size);
! 466: list[0] = '\0';
! 467:
! 468: for (method = authmethods; method->name != NULL; method++) {
! 469: if (strcmp(method->name, "none") == 0)
! 470: continue;
! 471: if (method->enabled != NULL && *(method->enabled) != 0) {
! 472: if (list[0] != '\0')
! 473: strlcat(list, DELIM, size);
! 474: strlcat(list, method->name, size);
1.1 markus 475: }
476: }
1.8.2.2 ! jason 477: return list;
! 478: }
! 479:
! 480: Authmethod *
! 481: authmethod_lookup(const char *name)
! 482: {
! 483: Authmethod *method = NULL;
! 484: if (name != NULL)
! 485: for (method = authmethods; method->name != NULL; method++)
! 486: if (method->enabled != NULL &&
! 487: *(method->enabled) != 0 &&
! 488: strcmp(name, method->name) == 0)
! 489: return method;
! 490: debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
! 491: return NULL;
1.1 markus 492: }
493:
494: /* return 1 if user allows given key */
495: int
496: user_dsa_key_allowed(struct passwd *pw, Key *key)
497: {
498: char line[8192], file[1024];
499: int found_key = 0;
500: unsigned int bits = -1;
501: FILE *f;
502: unsigned long linenum = 0;
503: struct stat st;
504: Key *found;
505:
1.8.2.2 ! jason 506: if (pw == NULL)
! 507: return 0;
! 508:
1.1 markus 509: /* Temporarily use the user's uid. */
510: temporarily_use_uid(pw->pw_uid);
511:
512: /* The authorized keys. */
513: snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
514: SSH_USER_PERMITTED_KEYS2);
515:
516: /* Fail quietly if file does not exist */
517: if (stat(file, &st) < 0) {
518: /* Restore the privileged uid. */
519: restore_uid();
520: return 0;
521: }
522: /* Open the file containing the authorized keys. */
523: f = fopen(file, "r");
524: if (!f) {
525: /* Restore the privileged uid. */
526: restore_uid();
527: return 0;
528: }
529: if (options.strict_modes) {
530: int fail = 0;
531: char buf[1024];
532: /* Check open file in order to avoid open/stat races */
533: if (fstat(fileno(f), &st) < 0 ||
534: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
535: (st.st_mode & 022) != 0) {
1.8.2.2 ! jason 536: snprintf(buf, sizeof buf,
! 537: "%s authentication refused for %.100s: "
! 538: "bad ownership or modes for '%s'.",
! 539: key_type(key), pw->pw_name, file);
1.1 markus 540: fail = 1;
541: } else {
542: /* Check path to SSH_USER_PERMITTED_KEYS */
543: int i;
544: static const char *check[] = {
545: "", SSH_USER_DIR, NULL
546: };
547: for (i = 0; check[i]; i++) {
548: snprintf(line, sizeof line, "%.500s/%.100s",
549: pw->pw_dir, check[i]);
550: if (stat(line, &st) < 0 ||
551: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
552: (st.st_mode & 022) != 0) {
553: snprintf(buf, sizeof buf,
1.8.2.2 ! jason 554: "%s authentication refused for %.100s: "
1.1 markus 555: "bad ownership or modes for '%s'.",
1.8.2.2 ! jason 556: key_type(key), pw->pw_name, line);
1.1 markus 557: fail = 1;
558: break;
559: }
560: }
561: }
562: if (fail) {
563: fclose(f);
1.8.2.1 jason 564: log("%s",buf);
1.1 markus 565: restore_uid();
566: return 0;
567: }
568: }
569: found_key = 0;
1.8.2.2 ! jason 570: found = key_new(key->type);
1.1 markus 571:
572: while (fgets(line, sizeof(line), f)) {
1.8.2.1 jason 573: char *cp, *options = NULL;
1.1 markus 574: linenum++;
575: /* Skip leading whitespace, empty and comment lines. */
576: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
577: ;
578: if (!*cp || *cp == '\n' || *cp == '#')
579: continue;
1.8.2.1 jason 580:
1.1 markus 581: bits = key_read(found, &cp);
1.8.2.1 jason 582: if (bits == 0) {
583: /* no key? check if there are options for this key */
584: int quoted = 0;
585: options = cp;
586: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
587: if (*cp == '\\' && cp[1] == '"')
588: cp++; /* Skip both */
589: else if (*cp == '"')
590: quoted = !quoted;
591: }
592: /* Skip remaining whitespace. */
593: for (; *cp == ' ' || *cp == '\t'; cp++)
594: ;
595: bits = key_read(found, &cp);
596: if (bits == 0) {
597: /* still no key? advance to next line*/
598: continue;
599: }
600: }
601: if (key_equal(found, key) &&
602: auth_parse_options(pw, options, linenum) == 1) {
1.1 markus 603: found_key = 1;
604: debug("matching key found: file %s, line %ld",
605: file, linenum);
606: break;
607: }
608: }
609: restore_uid();
610: fclose(f);
611: key_free(found);
612: return found_key;
1.8.2.2 ! jason 613: }
! 614:
! 615: struct passwd *
! 616: pwcopy(struct passwd *pw)
! 617: {
! 618: struct passwd *copy = xmalloc(sizeof(*copy));
! 619: memset(copy, 0, sizeof(*copy));
! 620: copy->pw_name = xstrdup(pw->pw_name);
! 621: copy->pw_passwd = xstrdup(pw->pw_passwd);
! 622: copy->pw_uid = pw->pw_uid;
! 623: copy->pw_gid = pw->pw_gid;
! 624: copy->pw_class = xstrdup(pw->pw_class);
! 625: copy->pw_dir = xstrdup(pw->pw_dir);
! 626: copy->pw_shell = xstrdup(pw->pw_shell);
! 627: return copy;
1.1 markus 628: }