auth.c revision 318402
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: stable/11/crypto/openssh/auth.c 318402 2017-05-17 14:28:01Z lidl $");
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 */
81extern ServerOptions options;
82extern int use_privsep;
83extern Buffer loginmsg;
84extern struct passwd *privsep_pw;
85
86/* Debugging messages */
87Buffer auth_debug;
88int 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 */
99int
100allowed_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
258void
259auth_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
275void
276auth_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		if (authenticated)
299			BLACKLIST_NOTIFY(BLACKLIST_AUTH_OK, "ssh");
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
336void
337auth_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 */
353int
354auth_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 */
384char *
385expand_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
407char *
408authorized_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 */
416HostStatus
417check_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 */
474int
475auth_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 */
538static int
539secure_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
553static FILE *
554auth_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
596FILE *
597auth_openkeyfile(const char *file, struct passwd *pw, int strict_modes)
598{
599	return auth_openfile(file, pw, strict_modes, 1, "authorized keys");
600}
601
602FILE *
603auth_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
609struct passwd *
610getpwnamallow(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_BAD_USER, user);
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 */
682int
683auth_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
720void
721auth_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
735void
736auth_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
749void
750auth_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
760struct passwd *
761fakepw(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}
782