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