Annotation of src/crypto/external/bsd/openssh/dist/auth.c, Revision 1.16
1.16 ! christos 1: /* $NetBSD: auth.c,v 1.15 2015/08/21 08:20:59 christos Exp $ */
1.15 christos 2: /* $OpenBSD: auth.c,v 1.113 2015/08/21 03:42:19 djm Exp $ */
1.1 christos 3: /*
4: * Copyright (c) 2000 Markus Friedl. All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25: */
26:
1.2 christos 27: #include "includes.h"
1.16 ! christos 28: __RCSID("$NetBSD: auth.c,v 1.15 2015/08/21 08:20:59 christos Exp $");
1.1 christos 29: #include <sys/types.h>
30: #include <sys/stat.h>
31:
32: #include <errno.h>
33: #include <fcntl.h>
34: #include <libgen.h>
35: #include <login_cap.h>
36: #include <paths.h>
37: #include <pwd.h>
38: #include <stdarg.h>
39: #include <stdio.h>
40: #include <string.h>
41: #include <unistd.h>
1.12 christos 42: #include <limits.h>
1.1 christos 43:
44: #include "xmalloc.h"
45: #include "match.h"
46: #include "groupaccess.h"
47: #include "log.h"
48: #include "buffer.h"
1.10 christos 49: #include "misc.h"
1.1 christos 50: #include "servconf.h"
51: #include "key.h"
52: #include "hostfile.h"
53: #include "auth.h"
54: #include "auth-options.h"
55: #include "canohost.h"
56: #include "uidswap.h"
57: #include "packet.h"
58: #ifdef GSSAPI
59: #include "ssh-gss.h"
60: #endif
1.3 adam 61: #include "authfile.h"
1.1 christos 62: #include "monitor_wrap.h"
1.12 christos 63: #include "authfile.h"
64: #include "ssherr.h"
1.8 christos 65: #include "compat.h"
1.11 christos 66: #include "pfilter.h"
1.1 christos 67:
1.2 christos 68: #ifdef HAVE_LOGIN_CAP
69: #include <login_cap.h>
70: #endif
71:
1.1 christos 72: /* import */
73: extern ServerOptions options;
74: extern int use_privsep;
75:
76: /* Debugging messages */
77: Buffer auth_debug;
78: int auth_debug_init;
79:
80: /*
81: * Check if the user is allowed to log in via ssh. If user is listed
82: * in DenyUsers or one of user's groups is listed in DenyGroups, false
83: * will be returned. If AllowUsers isn't empty and user isn't listed
84: * there, or if AllowGroups isn't empty and one of user's groups isn't
85: * listed there, false will be returned.
86: * If the user's shell is not executable, false will be returned.
87: * Otherwise true is returned.
88: */
89: int
90: allowed_user(struct passwd * pw)
91: {
1.2 christos 92: #ifdef HAVE_LOGIN_CAP
93: extern login_cap_t *lc;
94: int match_name, match_ip;
95: char *cap_hlist, *hp;
96: #endif
1.1 christos 97: struct stat st;
98: const char *hostname = NULL, *ipaddr = NULL;
99: u_int i;
100:
101: /* Shouldn't be called if pw is NULL, but better safe than sorry... */
102: if (!pw || !pw->pw_name)
103: return 0;
104:
1.2 christos 105: #ifdef HAVE_LOGIN_CAP
1.9 christos 106: hostname = get_canonical_hostname(options.use_dns);
1.2 christos 107: ipaddr = get_remote_ipaddr();
108:
109: lc = login_getclass(pw->pw_class);
110:
111: /*
112: * Check the deny list.
113: */
114: cap_hlist = login_getcapstr(lc, "host.deny", NULL, NULL);
115: if (cap_hlist != NULL) {
116: hp = strtok(cap_hlist, ",");
117: while (hp != NULL) {
1.13 christos 118: match_name = match_hostname(hostname, hp);
119: match_ip = match_hostname(ipaddr, hp);
1.2 christos 120: /*
121: * Only a positive match here causes a "deny".
122: */
123: if (match_name > 0 || match_ip > 0) {
124: free(cap_hlist);
125: login_close(lc);
126: return 0;
127: }
128: hp = strtok(NULL, ",");
129: }
130: free(cap_hlist);
131: }
132:
133: /*
134: * Check the allow list. If the allow list exists, and the
135: * remote host is not in it, the user is implicitly denied.
136: */
137: cap_hlist = login_getcapstr(lc, "host.allow", NULL, NULL);
138: if (cap_hlist != NULL) {
139: hp = strtok(cap_hlist, ",");
140: if (hp == NULL) {
141: /* Just in case there's an empty string... */
142: free(cap_hlist);
143: login_close(lc);
144: return 0;
145: }
146: while (hp != NULL) {
1.13 christos 147: match_name = match_hostname(hostname, hp);
148: match_ip = match_hostname(ipaddr, hp);
1.2 christos 149: /*
150: * Negative match causes an immediate "deny".
151: * Positive match causes us to break out
152: * of the loop (allowing a fallthrough).
153: */
154: if (match_name < 0 || match_ip < 0) {
155: free(cap_hlist);
156: login_close(lc);
157: return 0;
158: }
159: if (match_name > 0 || match_ip > 0)
160: break;
161: hp = strtok(NULL, ",");
162: }
163: free(cap_hlist);
164: if (hp == NULL) {
165: login_close(lc);
166: return 0;
167: }
168: }
169:
170: login_close(lc);
171: #endif
172:
173: #ifdef USE_PAM
174: if (!options.use_pam) {
175: #endif
176: /*
177: * password/account expiration.
178: */
179: if (pw->pw_change || pw->pw_expire) {
180: struct timeval tv;
181:
182: (void)gettimeofday(&tv, (struct timezone *)NULL);
183: if (pw->pw_expire) {
184: if (tv.tv_sec >= pw->pw_expire) {
185: logit("User %.100s not allowed because account has expired",
186: pw->pw_name);
187: return 0; /* expired */
188: }
189: }
190: #ifdef _PASSWORD_CHGNOW
191: if (pw->pw_change == _PASSWORD_CHGNOW) {
192: logit("User %.100s not allowed because password needs to be changed",
193: pw->pw_name);
194:
195: return 0; /* can't force password change (yet) */
196: }
197: #endif
198: if (pw->pw_change) {
199: if (tv.tv_sec >= pw->pw_change) {
200: logit("User %.100s not allowed because password has expired",
201: pw->pw_name);
202: return 0; /* expired */
203: }
204: }
205: }
206: #ifdef USE_PAM
207: }
208: #endif
209:
1.1 christos 210: /*
1.3 adam 211: * Deny if shell does not exist or is not executable unless we
212: * are chrooting.
1.1 christos 213: */
1.2 christos 214: /*
215: * XXX Should check to see if it is executable by the
216: * XXX requesting user. --thorpej
217: */
1.3 adam 218: if (options.chroot_directory == NULL ||
219: strcasecmp(options.chroot_directory, "none") == 0) {
220: char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
221: _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
222:
223: if (stat(shell, &st) != 0) {
224: logit("User %.100s not allowed because shell %.100s "
225: "does not exist", pw->pw_name, shell);
1.8 christos 226: free(shell);
1.3 adam 227: return 0;
228: }
229: if (S_ISREG(st.st_mode) == 0 ||
230: (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
231: logit("User %.100s not allowed because shell %.100s "
232: "is not executable", pw->pw_name, shell);
1.8 christos 233: free(shell);
1.3 adam 234: return 0;
235: }
1.8 christos 236: free(shell);
1.1 christos 237: }
1.2 christos 238: /*
239: * XXX Consider nuking {Allow,Deny}{Users,Groups}. We have the
240: * XXX login_cap(3) mechanism which covers all other types of
241: * XXX logins, too.
242: */
1.1 christos 243:
244: if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
245: options.num_deny_groups > 0 || options.num_allow_groups > 0) {
246: hostname = get_canonical_hostname(options.use_dns);
247: ipaddr = get_remote_ipaddr();
248: }
249:
250: /* Return false if user is listed in DenyUsers */
251: if (options.num_deny_users > 0) {
252: for (i = 0; i < options.num_deny_users; i++)
253: if (match_user(pw->pw_name, hostname, ipaddr,
254: options.deny_users[i])) {
255: logit("User %.100s from %.100s not allowed "
256: "because listed in DenyUsers",
257: pw->pw_name, hostname);
258: return 0;
259: }
260: }
261: /* Return false if AllowUsers isn't empty and user isn't listed there */
262: if (options.num_allow_users > 0) {
263: for (i = 0; i < options.num_allow_users; i++)
264: if (match_user(pw->pw_name, hostname, ipaddr,
265: options.allow_users[i]))
266: break;
267: /* i < options.num_allow_users iff we break for loop */
268: if (i >= options.num_allow_users) {
269: logit("User %.100s from %.100s not allowed because "
270: "not listed in AllowUsers", pw->pw_name, hostname);
271: return 0;
272: }
273: }
274: if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
275: /* Get the user's group access list (primary and supplementary) */
276: if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
277: logit("User %.100s from %.100s not allowed because "
278: "not in any group", pw->pw_name, hostname);
279: return 0;
280: }
281:
282: /* Return false if one of user's groups is listed in DenyGroups */
283: if (options.num_deny_groups > 0)
284: if (ga_match(options.deny_groups,
285: options.num_deny_groups)) {
286: ga_free();
287: logit("User %.100s from %.100s not allowed "
288: "because a group is listed in DenyGroups",
289: pw->pw_name, hostname);
290: return 0;
291: }
292: /*
293: * Return false if AllowGroups isn't empty and one of user's groups
294: * isn't listed there
295: */
296: if (options.num_allow_groups > 0)
297: if (!ga_match(options.allow_groups,
298: options.num_allow_groups)) {
299: ga_free();
300: logit("User %.100s from %.100s not allowed "
301: "because none of user's groups are listed "
302: "in AllowGroups", pw->pw_name, hostname);
303: return 0;
304: }
305: ga_free();
306: }
307: /* We found no reason not to let this user try to log on... */
308: return 1;
309: }
310:
311: void
1.8 christos 312: auth_info(Authctxt *authctxt, const char *fmt, ...)
313: {
314: va_list ap;
315: int i;
316:
317: free(authctxt->info);
318: authctxt->info = NULL;
319:
320: va_start(ap, fmt);
321: i = vasprintf(&authctxt->info, fmt, ap);
322: va_end(ap);
323:
324: if (i < 0 || authctxt->info == NULL)
325: fatal("vasprintf failed");
326: }
327:
328: void
1.7 christos 329: auth_log(Authctxt *authctxt, int authenticated, int partial,
1.8 christos 330: const char *method, const char *submethod)
1.1 christos 331: {
332: void (*authlog) (const char *fmt,...) = verbose;
1.4 christos 333: const char *authmsg;
1.1 christos 334:
335: if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
336: return;
337:
338: /* Raise logging level */
339: if (authenticated == 1 ||
340: !authctxt->valid ||
341: authctxt->failures >= options.max_authtries / 2 ||
342: strcmp(method, "password") == 0)
343: authlog = logit;
344:
345: if (authctxt->postponed)
346: authmsg = "Postponed";
1.7 christos 347: else if (partial)
348: authmsg = "Partial";
1.1 christos 349: else
350: authmsg = authenticated ? "Accepted" : "Failed";
351:
1.8 christos 352: authlog("%s %s%s%s for %s%.100s from %.200s port %d %s%s%s",
1.1 christos 353: authmsg,
354: method,
1.7 christos 355: submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
1.1 christos 356: authctxt->valid ? "" : "invalid user ",
357: authctxt->user,
358: get_remote_ipaddr(),
359: get_remote_port(),
1.8 christos 360: compat20 ? "ssh2" : "ssh1",
361: authctxt->info != NULL ? ": " : "",
362: authctxt->info != NULL ? authctxt->info : "");
1.11 christos 363: if (!authctxt->postponed)
364: pfilter_notify(!authenticated);
1.8 christos 365: free(authctxt->info);
366: authctxt->info = NULL;
1.1 christos 367: }
368:
1.10 christos 369: void
370: auth_maxtries_exceeded(Authctxt *authctxt)
371: {
1.12 christos 372: error("maximum authentication attempts exceeded for "
1.10 christos 373: "%s%.100s from %.200s port %d %s",
374: authctxt->valid ? "" : "invalid user ",
375: authctxt->user,
376: get_remote_ipaddr(),
377: get_remote_port(),
378: compat20 ? "ssh2" : "ssh1");
1.12 christos 379: packet_disconnect("Too many authentication failures");
1.10 christos 380: /* NOTREACHED */
381: }
382:
1.1 christos 383: /*
384: * Check whether root logins are disallowed.
385: */
386: int
1.4 christos 387: auth_root_allowed(const char *method)
1.1 christos 388: {
389: switch (options.permit_root_login) {
390: case PERMIT_YES:
391: return 1;
392: case PERMIT_NO_PASSWD:
1.14 christos 393: if (strcmp(method, "publickey") == 0 ||
394: strcmp(method, "hostbased") == 0 ||
1.15 christos 395: strcmp(method, "gssapi-with-mic") == 0)
1.1 christos 396: return 1;
397: break;
398: case PERMIT_FORCED_ONLY:
399: if (forced_command) {
400: logit("Root login accepted for forced command.");
401: return 1;
402: }
403: break;
404: }
405: logit("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr());
406: return 0;
407: }
408:
409:
410: /*
411: * Given a template and a passwd structure, build a filename
412: * by substituting % tokenised options. Currently, %% becomes '%',
413: * %h becomes the home directory and %u the username.
414: *
415: * This returns a buffer allocated by xmalloc.
416: */
1.5 christos 417: char *
1.1 christos 418: expand_authorized_keys(const char *filename, struct passwd *pw)
419: {
1.12 christos 420: char *file, ret[PATH_MAX];
1.1 christos 421: int i;
422:
423: file = percent_expand(filename, "h", pw->pw_dir,
424: "u", pw->pw_name, (char *)NULL);
425:
426: /*
427: * Ensure that filename starts anchored. If not, be backward
428: * compatible and prepend the '%h/'
429: */
430: if (*file == '/')
431: return (file);
432:
433: i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
434: if (i < 0 || (size_t)i >= sizeof(ret))
435: fatal("expand_authorized_keys: path too long");
1.8 christos 436: free(file);
1.1 christos 437: return (xstrdup(ret));
438: }
439:
440: char *
1.3 adam 441: authorized_principals_file(struct passwd *pw)
442: {
1.13 christos 443: if (options.authorized_principals_file == NULL)
1.3 adam 444: return NULL;
445: return expand_authorized_keys(options.authorized_principals_file, pw);
446: }
447:
1.1 christos 448: /* return ok if key exists in sysfile or userfile */
449: HostStatus
450: check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
451: const char *sysfile, const char *userfile)
452: {
453: char *user_hostfile;
454: struct stat st;
455: HostStatus host_status;
1.4 christos 456: struct hostkeys *hostkeys;
457: const struct hostkey_entry *found;
1.1 christos 458:
1.4 christos 459: hostkeys = init_hostkeys();
460: load_hostkeys(hostkeys, host, sysfile);
461: if (userfile != NULL) {
1.1 christos 462: user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
463: if (options.strict_modes &&
464: (stat(user_hostfile, &st) == 0) &&
465: ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
466: (st.st_mode & 022) != 0)) {
467: logit("Authentication refused for %.100s: "
468: "bad owner or modes for %.200s",
469: pw->pw_name, user_hostfile);
1.3 adam 470: auth_debug_add("Ignored %.200s: bad ownership or modes",
471: user_hostfile);
1.1 christos 472: } else {
473: temporarily_use_uid(pw);
1.4 christos 474: load_hostkeys(hostkeys, host, user_hostfile);
1.1 christos 475: restore_uid();
476: }
1.8 christos 477: free(user_hostfile);
1.1 christos 478: }
1.4 christos 479: host_status = check_key_in_hostkeys(hostkeys, key, &found);
480: if (host_status == HOST_REVOKED)
481: error("WARNING: revoked key for %s attempted authentication",
482: found->host);
483: else if (host_status == HOST_OK)
484: debug("%s: key for %s found at %s:%ld", __func__,
485: found->host, found->file, found->line);
486: else
487: debug("%s: key for host %s not found", __func__, host);
488:
489: free_hostkeys(hostkeys);
1.1 christos 490:
491: return host_status;
492: }
493:
494: /*
1.7 christos 495: * Check a given path for security. This is defined as all components
1.1 christos 496: * of the path to the file must be owned by either the owner of
497: * of the file or root and no directories must be group or world writable.
498: *
499: * XXX Should any specific check be done for sym links ?
500: *
1.7 christos 501: * Takes a file name, its stat information (preferably from fstat() to
502: * avoid races), the uid of the expected owner, their home directory and an
1.1 christos 503: * error buffer plus max size as arguments.
504: *
505: * Returns 0 on success and -1 on failure
506: */
1.7 christos 507: int
508: auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
509: uid_t uid, char *err, size_t errlen)
1.1 christos 510: {
1.12 christos 511: char buf[PATH_MAX], homedir[PATH_MAX];
1.1 christos 512: char *cp;
513: int comparehome = 0;
514: struct stat st;
515:
1.7 christos 516: if (realpath(name, buf) == NULL) {
517: snprintf(err, errlen, "realpath %s failed: %s", name,
1.1 christos 518: strerror(errno));
519: return -1;
520: }
1.7 christos 521: if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
1.1 christos 522: comparehome = 1;
523:
1.7 christos 524: if (!S_ISREG(stp->st_mode)) {
525: snprintf(err, errlen, "%s is not a regular file", buf);
526: return -1;
527: }
528: if ((stp->st_uid != 0 && stp->st_uid != uid) ||
529: (stp->st_mode & 022) != 0) {
1.1 christos 530: snprintf(err, errlen, "bad ownership or modes for file %s",
531: buf);
532: return -1;
533: }
534:
535: /* for each component of the canonical path, walking upwards */
536: for (;;) {
537: if ((cp = dirname(buf)) == NULL) {
538: snprintf(err, errlen, "dirname() failed");
539: return -1;
540: }
541: strlcpy(buf, cp, sizeof(buf));
542:
543: if (stat(buf, &st) < 0 ||
544: (st.st_uid != 0 && st.st_uid != uid) ||
545: (st.st_mode & 022) != 0) {
546: snprintf(err, errlen,
547: "bad ownership or modes for directory %s", buf);
548: return -1;
549: }
550:
1.3 adam 551: /* If are past the homedir then we can stop */
1.5 christos 552: if (comparehome && strcmp(homedir, buf) == 0)
1.1 christos 553: break;
1.5 christos 554:
1.1 christos 555: /*
556: * dirname should always complete with a "/" path,
557: * but we can be paranoid and check for "." too
558: */
559: if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0))
560: break;
561: }
562: return 0;
563: }
564:
1.7 christos 565: /*
566: * Version of secure_path() that accepts an open file descriptor to
567: * avoid races.
568: *
569: * Returns 0 on success and -1 on failure
570: */
571: static int
572: secure_filename(FILE *f, const char *file, struct passwd *pw,
573: char *err, size_t errlen)
574: {
575: struct stat st;
576:
577: /* check the open file to avoid races */
578: if (fstat(fileno(f), &st) < 0) {
579: snprintf(err, errlen, "cannot stat file %s: %s",
580: file, strerror(errno));
581: return -1;
582: }
583: return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
584: }
585:
1.3 adam 586: static FILE *
587: auth_openfile(const char *file, struct passwd *pw, int strict_modes,
1.4 christos 588: int log_missing, const char *file_type)
1.1 christos 589: {
590: char line[1024];
591: struct stat st;
592: int fd;
593: FILE *f;
594:
1.3 adam 595: if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
596: if (log_missing || errno != ENOENT)
597: debug("Could not open %s '%s': %s", file_type, file,
598: strerror(errno));
1.1 christos 599: return NULL;
1.3 adam 600: }
1.1 christos 601:
602: if (fstat(fd, &st) < 0) {
603: close(fd);
604: return NULL;
605: }
606: if (!S_ISREG(st.st_mode)) {
1.3 adam 607: logit("User %s %s %s is not a regular file",
608: pw->pw_name, file_type, file);
1.1 christos 609: close(fd);
610: return NULL;
611: }
612: unset_nonblock(fd);
613: if ((f = fdopen(fd, "r")) == NULL) {
614: close(fd);
615: return NULL;
616: }
1.4 christos 617: if (strict_modes &&
1.1 christos 618: secure_filename(f, file, pw, line, sizeof(line)) != 0) {
619: fclose(f);
620: logit("Authentication refused: %s", line);
1.3 adam 621: auth_debug_add("Ignored %s: %s", file_type, line);
1.1 christos 622: return NULL;
623: }
624:
625: return f;
626: }
627:
1.3 adam 628:
629: FILE *
630: auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
631: {
632: return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
633: }
634:
635: FILE *
636: auth_openprincipals(const char *file, struct passwd *pw, int strict_modes)
637: {
638: return auth_openfile(file, pw, strict_modes, 0,
639: "authorized principals");
640: }
641:
1.1 christos 642: struct passwd *
643: getpwnamallow(const char *user)
644: {
1.2 christos 645: #ifdef HAVE_LOGIN_CAP
646: extern login_cap_t *lc;
647: #ifdef BSD_AUTH
648: auth_session_t *as;
649: #endif
650: #endif
1.1 christos 651: struct passwd *pw;
1.6 christos 652: struct connection_info *ci = get_connection_info(1, options.use_dns);
1.1 christos 653:
1.6 christos 654: ci->user = user;
655: parse_server_match_config(&options, ci);
1.1 christos 656:
657: pw = getpwnam(user);
658: if (pw == NULL) {
1.16 ! christos 659: pfilter_notify(1);
1.1 christos 660: logit("Invalid user %.100s from %.100s",
661: user, get_remote_ipaddr());
662: return (NULL);
663: }
664: if (!allowed_user(pw))
665: return (NULL);
1.2 christos 666: #ifdef HAVE_LOGIN_CAP
1.1 christos 667: if ((lc = login_getclass(pw->pw_class)) == NULL) {
668: debug("unable to get login class: %s", user);
669: return (NULL);
670: }
1.2 christos 671: #ifdef BSD_AUTH
1.1 christos 672: if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
673: auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
674: debug("Approval failure for %s", user);
675: pw = NULL;
676: }
677: if (as != NULL)
678: auth_close(as);
1.2 christos 679: #endif
680: #endif
1.1 christos 681: if (pw != NULL)
682: return (pwcopy(pw));
683: return (NULL);
684: }
685:
1.3 adam 686: /* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
687: int
688: auth_key_is_revoked(Key *key)
689: {
1.12 christos 690: char *fp = NULL;
691: int r;
1.3 adam 692:
693: if (options.revoked_keys_file == NULL)
694: return 0;
1.12 christos 695: if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
696: SSH_FP_DEFAULT)) == NULL) {
697: r = SSH_ERR_ALLOC_FAIL;
698: error("%s: fingerprint key: %s", __func__, ssh_err(r));
699: goto out;
700: }
701:
702: r = sshkey_check_revoked(key, options.revoked_keys_file);
703: switch (r) {
1.7 christos 704: case 0:
1.12 christos 705: break; /* not revoked */
706: case SSH_ERR_KEY_REVOKED:
707: error("Authentication key %s %s revoked by file %s",
708: sshkey_type(key), fp, options.revoked_keys_file);
709: goto out;
1.7 christos 710: default:
1.12 christos 711: error("Error checking authentication key %s %s in "
712: "revoked keys file %s: %s", sshkey_type(key), fp,
713: options.revoked_keys_file, ssh_err(r));
714: goto out;
1.7 christos 715: }
1.12 christos 716:
717: /* Success */
718: r = 0;
719:
720: out:
721: free(fp);
722: return r == 0 ? 0 : 1;
1.3 adam 723: }
724:
1.1 christos 725: void
726: auth_debug_add(const char *fmt,...)
727: {
728: char buf[1024];
729: va_list args;
730:
731: if (!auth_debug_init)
732: return;
733:
734: va_start(args, fmt);
735: vsnprintf(buf, sizeof(buf), fmt, args);
736: va_end(args);
737: buffer_put_cstring(&auth_debug, buf);
738: }
739:
740: void
741: auth_debug_send(void)
742: {
743: char *msg;
744:
745: if (!auth_debug_init)
746: return;
747: while (buffer_len(&auth_debug)) {
748: msg = buffer_get_string(&auth_debug, NULL);
749: packet_send_debug("%s", msg);
1.8 christos 750: free(msg);
1.1 christos 751: }
752: }
753:
754: void
755: auth_debug_reset(void)
756: {
757: if (auth_debug_init)
758: buffer_clear(&auth_debug);
759: else {
760: buffer_init(&auth_debug);
761: auth_debug_init = 1;
762: }
763: }
764:
765: struct passwd *
766: fakepw(void)
767: {
768: static struct passwd fake;
1.4 christos 769: static char nouser[] = "NOUSER";
770: static char nonexist[] = "/nonexist";
1.1 christos 771:
772: memset(&fake, 0, sizeof(fake));
1.4 christos 773: fake.pw_name = nouser;
774: fake.pw_passwd = __UNCONST(
775: "$2a$06$r3.juUaHZDlIbQaO2dS9FuYxL1W9M81R1Tc92PoSNmzvpEqLkLGrK");
776: fake.pw_gecos = nouser;
1.1 christos 777: fake.pw_uid = (uid_t)-1;
778: fake.pw_gid = (gid_t)-1;
1.4 christos 779: fake.pw_class = __UNCONST("");
780: fake.pw_dir = nonexist;
781: fake.pw_shell = nonexist;
1.1 christos 782:
783: return (&fake);
784: }
CVSweb <webmaster@jp.NetBSD.org>