auth2-pubkey.c revision 295367
1/* $OpenBSD: auth2-pubkey.c,v 1.53 2015/06/15 18:44:22 jsing 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
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/wait.h>
31
32#include <errno.h>
33#include <fcntl.h>
34#ifdef HAVE_PATHS_H
35# include <paths.h>
36#endif
37#include <pwd.h>
38#include <signal.h>
39#include <stdio.h>
40#include <stdarg.h>
41#include <string.h>
42#include <time.h>
43#include <unistd.h>
44#include <limits.h>
45
46#include "xmalloc.h"
47#include "ssh.h"
48#include "ssh2.h"
49#include "packet.h"
50#include "buffer.h"
51#include "log.h"
52#include "misc.h"
53#include "servconf.h"
54#include "compat.h"
55#include "key.h"
56#include "hostfile.h"
57#include "auth.h"
58#include "pathnames.h"
59#include "uidswap.h"
60#include "auth-options.h"
61#include "canohost.h"
62#ifdef GSSAPI
63#include "ssh-gss.h"
64#endif
65#include "monitor_wrap.h"
66#include "authfile.h"
67#include "match.h"
68#include "ssherr.h"
69#include "channels.h" /* XXX for session.h */
70#include "session.h" /* XXX for child_set_env(); refactor? */
71
72/* import */
73extern ServerOptions options;
74extern u_char *session_id2;
75extern u_int session_id2_len;
76
77static int
78userauth_pubkey(Authctxt *authctxt)
79{
80	Buffer b;
81	Key *key = NULL;
82	char *pkalg, *userstyle;
83	u_char *pkblob, *sig;
84	u_int alen, blen, slen;
85	int have_sig, pktype;
86	int authenticated = 0;
87
88	if (!authctxt->valid) {
89		debug2("userauth_pubkey: disabled because of invalid user");
90		return 0;
91	}
92	have_sig = packet_get_char();
93	if (datafellows & SSH_BUG_PKAUTH) {
94		debug2("userauth_pubkey: SSH_BUG_PKAUTH");
95		/* no explicit pkalg given */
96		pkblob = packet_get_string(&blen);
97		buffer_init(&b);
98		buffer_append(&b, pkblob, blen);
99		/* so we have to extract the pkalg from the pkblob */
100		pkalg = buffer_get_string(&b, &alen);
101		buffer_free(&b);
102	} else {
103		pkalg = packet_get_string(&alen);
104		pkblob = packet_get_string(&blen);
105	}
106	pktype = key_type_from_name(pkalg);
107	if (pktype == KEY_UNSPEC) {
108		/* this is perfectly legal */
109		logit("userauth_pubkey: unsupported public key algorithm: %s",
110		    pkalg);
111		goto done;
112	}
113	key = key_from_blob(pkblob, blen);
114	if (key == NULL) {
115		error("userauth_pubkey: cannot decode key: %s", pkalg);
116		goto done;
117	}
118	if (key->type != pktype) {
119		error("userauth_pubkey: type mismatch for decoded key "
120		    "(received %d, expected %d)", key->type, pktype);
121		goto done;
122	}
123	if (key_type_plain(key->type) == KEY_RSA &&
124	    (datafellows & SSH_BUG_RSASIGMD5) != 0) {
125		logit("Refusing RSA key because client uses unsafe "
126		    "signature scheme");
127		goto done;
128	}
129	if (auth2_userkey_already_used(authctxt, key)) {
130		logit("refusing previously-used %s key", key_type(key));
131		goto done;
132	}
133	if (match_pattern_list(sshkey_ssh_name(key),
134	    options.pubkey_key_types, 0) != 1) {
135		logit("%s: key type %s not in PubkeyAcceptedKeyTypes",
136		    __func__, sshkey_ssh_name(key));
137		goto done;
138	}
139
140	if (have_sig) {
141		sig = packet_get_string(&slen);
142		packet_check_eom();
143		buffer_init(&b);
144		if (datafellows & SSH_OLD_SESSIONID) {
145			buffer_append(&b, session_id2, session_id2_len);
146		} else {
147			buffer_put_string(&b, session_id2, session_id2_len);
148		}
149		/* reconstruct packet */
150		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
151		xasprintf(&userstyle, "%s%s%s", authctxt->user,
152		    authctxt->style ? ":" : "",
153		    authctxt->style ? authctxt->style : "");
154		buffer_put_cstring(&b, userstyle);
155		free(userstyle);
156		buffer_put_cstring(&b,
157		    datafellows & SSH_BUG_PKSERVICE ?
158		    "ssh-userauth" :
159		    authctxt->service);
160		if (datafellows & SSH_BUG_PKAUTH) {
161			buffer_put_char(&b, have_sig);
162		} else {
163			buffer_put_cstring(&b, "publickey");
164			buffer_put_char(&b, have_sig);
165			buffer_put_cstring(&b, pkalg);
166		}
167		buffer_put_string(&b, pkblob, blen);
168#ifdef DEBUG_PK
169		buffer_dump(&b);
170#endif
171		pubkey_auth_info(authctxt, key, NULL);
172
173		/* test for correct signature */
174		authenticated = 0;
175		if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
176		    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
177		    buffer_len(&b))) == 1) {
178			authenticated = 1;
179			/* Record the successful key to prevent reuse */
180			auth2_record_userkey(authctxt, key);
181			key = NULL; /* Don't free below */
182		}
183		buffer_free(&b);
184		free(sig);
185	} else {
186		debug("test whether pkalg/pkblob are acceptable");
187		packet_check_eom();
188
189		/* XXX fake reply and always send PK_OK ? */
190		/*
191		 * XXX this allows testing whether a user is allowed
192		 * to login: if you happen to have a valid pubkey this
193		 * message is sent. the message is NEVER sent at all
194		 * if a user is not allowed to login. is this an
195		 * issue? -markus
196		 */
197		if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) {
198			packet_start(SSH2_MSG_USERAUTH_PK_OK);
199			packet_put_string(pkalg, alen);
200			packet_put_string(pkblob, blen);
201			packet_send();
202			packet_write_wait();
203			authctxt->postponed = 1;
204		}
205	}
206	if (authenticated != 1)
207		auth_clear_options();
208done:
209	debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
210	if (key != NULL)
211		key_free(key);
212	free(pkalg);
213	free(pkblob);
214	return authenticated;
215}
216
217void
218pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
219{
220	char *fp, *extra;
221	va_list ap;
222	int i;
223
224	extra = NULL;
225	if (fmt != NULL) {
226		va_start(ap, fmt);
227		i = vasprintf(&extra, fmt, ap);
228		va_end(ap);
229		if (i < 0 || extra == NULL)
230			fatal("%s: vasprintf failed", __func__);
231	}
232
233	if (key_is_cert(key)) {
234		fp = sshkey_fingerprint(key->cert->signature_key,
235		    options.fingerprint_hash, SSH_FP_DEFAULT);
236		auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s",
237		    key_type(key), key->cert->key_id,
238		    (unsigned long long)key->cert->serial,
239		    key_type(key->cert->signature_key),
240		    fp == NULL ? "(null)" : fp,
241		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
242		free(fp);
243	} else {
244		fp = sshkey_fingerprint(key, options.fingerprint_hash,
245		    SSH_FP_DEFAULT);
246		auth_info(authctxt, "%s %s%s%s", key_type(key),
247		    fp == NULL ? "(null)" : fp,
248		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
249		free(fp);
250	}
251	free(extra);
252}
253
254/*
255 * Splits 's' into an argument vector. Handles quoted string and basic
256 * escape characters (\\, \", \'). Caller must free the argument vector
257 * and its members.
258 */
259static int
260split_argv(const char *s, int *argcp, char ***argvp)
261{
262	int r = SSH_ERR_INTERNAL_ERROR;
263	int argc = 0, quote, i, j;
264	char *arg, **argv = xcalloc(1, sizeof(*argv));
265
266	*argvp = NULL;
267	*argcp = 0;
268
269	for (i = 0; s[i] != '\0'; i++) {
270		/* Skip leading whitespace */
271		if (s[i] == ' ' || s[i] == '\t')
272			continue;
273
274		/* Start of a token */
275		quote = 0;
276		if (s[i] == '\\' &&
277		    (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\'))
278			i++;
279		else if (s[i] == '\'' || s[i] == '"')
280			quote = s[i++];
281
282		argv = xreallocarray(argv, (argc + 2), sizeof(*argv));
283		arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1);
284		argv[argc] = NULL;
285
286		/* Copy the token in, removing escapes */
287		for (j = 0; s[i] != '\0'; i++) {
288			if (s[i] == '\\') {
289				if (s[i + 1] == '\'' ||
290				    s[i + 1] == '\"' ||
291				    s[i + 1] == '\\') {
292					i++; /* Skip '\' */
293					arg[j++] = s[i];
294				} else {
295					/* Unrecognised escape */
296					arg[j++] = s[i];
297				}
298			} else if (quote == 0 && (s[i] == ' ' || s[i] == '\t'))
299				break; /* done */
300			else if (quote != 0 && s[i] == quote)
301				break; /* done */
302			else
303				arg[j++] = s[i];
304		}
305		if (s[i] == '\0') {
306			if (quote != 0) {
307				/* Ran out of string looking for close quote */
308				r = SSH_ERR_INVALID_FORMAT;
309				goto out;
310			}
311			break;
312		}
313	}
314	/* Success */
315	*argcp = argc;
316	*argvp = argv;
317	argc = 0;
318	argv = NULL;
319	r = 0;
320 out:
321	if (argc != 0 && argv != NULL) {
322		for (i = 0; i < argc; i++)
323			free(argv[i]);
324		free(argv);
325	}
326	return r;
327}
328
329/*
330 * Reassemble an argument vector into a string, quoting and escaping as
331 * necessary. Caller must free returned string.
332 */
333static char *
334assemble_argv(int argc, char **argv)
335{
336	int i, j, ws, r;
337	char c, *ret;
338	struct sshbuf *buf, *arg;
339
340	if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL)
341		fatal("%s: sshbuf_new failed", __func__);
342
343	for (i = 0; i < argc; i++) {
344		ws = 0;
345		sshbuf_reset(arg);
346		for (j = 0; argv[i][j] != '\0'; j++) {
347			r = 0;
348			c = argv[i][j];
349			switch (c) {
350			case ' ':
351			case '\t':
352				ws = 1;
353				r = sshbuf_put_u8(arg, c);
354				break;
355			case '\\':
356			case '\'':
357			case '"':
358				if ((r = sshbuf_put_u8(arg, '\\')) != 0)
359					break;
360				/* FALLTHROUGH */
361			default:
362				r = sshbuf_put_u8(arg, c);
363				break;
364			}
365			if (r != 0)
366				fatal("%s: sshbuf_put_u8: %s",
367				    __func__, ssh_err(r));
368		}
369		if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) ||
370		    (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) ||
371		    (r = sshbuf_putb(buf, arg)) != 0 ||
372		    (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0))
373			fatal("%s: buffer error: %s", __func__, ssh_err(r));
374	}
375	if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL)
376		fatal("%s: malloc failed", __func__);
377	memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf));
378	ret[sshbuf_len(buf)] = '\0';
379	sshbuf_free(buf);
380	sshbuf_free(arg);
381	return ret;
382}
383
384/*
385 * Runs command in a subprocess. Returns pid on success and a FILE* to the
386 * subprocess' stdout or 0 on failure.
387 * NB. "command" is only used for logging.
388 */
389static pid_t
390subprocess(const char *tag, struct passwd *pw, const char *command,
391    int ac, char **av, FILE **child)
392{
393	FILE *f;
394	struct stat st;
395	int devnull, p[2], i;
396	pid_t pid;
397	char *cp, errmsg[512];
398	u_int envsize;
399	char **child_env;
400
401	*child = NULL;
402
403	debug3("%s: %s command \"%s\" running as %s", __func__,
404	    tag, command, pw->pw_name);
405
406	/* Verify the path exists and is safe-ish to execute */
407	if (*av[0] != '/') {
408		error("%s path is not absolute", tag);
409		return 0;
410	}
411	temporarily_use_uid(pw);
412	if (stat(av[0], &st) < 0) {
413		error("Could not stat %s \"%s\": %s", tag,
414		    av[0], strerror(errno));
415		restore_uid();
416		return 0;
417	}
418	if (auth_secure_path(av[0], &st, NULL, 0,
419	    errmsg, sizeof(errmsg)) != 0) {
420		error("Unsafe %s \"%s\": %s", tag, av[0], errmsg);
421		restore_uid();
422		return 0;
423	}
424
425	/*
426	 * Run the command; stderr is left in place, stdout is the
427	 * authorized_keys output.
428	 */
429	if (pipe(p) != 0) {
430		error("%s: pipe: %s", tag, strerror(errno));
431		restore_uid();
432		return 0;
433	}
434
435	/*
436	 * Don't want to call this in the child, where it can fatal() and
437	 * run cleanup_exit() code.
438	 */
439	restore_uid();
440
441	switch ((pid = fork())) {
442	case -1: /* error */
443		error("%s: fork: %s", tag, strerror(errno));
444		close(p[0]);
445		close(p[1]);
446		return 0;
447	case 0: /* child */
448		/* Prepare a minimal environment for the child. */
449		envsize = 5;
450		child_env = xcalloc(sizeof(*child_env), envsize);
451		child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH);
452		child_set_env(&child_env, &envsize, "USER", pw->pw_name);
453		child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name);
454		child_set_env(&child_env, &envsize, "HOME", pw->pw_dir);
455		if ((cp = getenv("LANG")) != NULL)
456			child_set_env(&child_env, &envsize, "LANG", cp);
457
458		for (i = 0; i < NSIG; i++)
459			signal(i, SIG_DFL);
460
461		if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
462			error("%s: open %s: %s", tag, _PATH_DEVNULL,
463			    strerror(errno));
464			_exit(1);
465		}
466		/* Keep stderr around a while longer to catch errors */
467		if (dup2(devnull, STDIN_FILENO) == -1 ||
468		    dup2(p[1], STDOUT_FILENO) == -1) {
469			error("%s: dup2: %s", tag, strerror(errno));
470			_exit(1);
471		}
472		closefrom(STDERR_FILENO + 1);
473
474		/* Don't use permanently_set_uid() here to avoid fatal() */
475		if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
476			error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid,
477			    strerror(errno));
478			_exit(1);
479		}
480		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
481			error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid,
482			    strerror(errno));
483			_exit(1);
484		}
485		/* stdin is pointed to /dev/null at this point */
486		if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
487			error("%s: dup2: %s", tag, strerror(errno));
488			_exit(1);
489		}
490
491		execve(av[0], av, child_env);
492		error("%s exec \"%s\": %s", tag, command, strerror(errno));
493		_exit(127);
494	default: /* parent */
495		break;
496	}
497
498	close(p[1]);
499	if ((f = fdopen(p[0], "r")) == NULL) {
500		error("%s: fdopen: %s", tag, strerror(errno));
501		close(p[0]);
502		/* Don't leave zombie child */
503		kill(pid, SIGTERM);
504		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
505			;
506		return 0;
507	}
508	/* Success */
509	debug3("%s: %s pid %ld", __func__, tag, (long)pid);
510	*child = f;
511	return pid;
512}
513
514/* Returns 0 if pid exited cleanly, non-zero otherwise */
515static int
516exited_cleanly(pid_t pid, const char *tag, const char *cmd)
517{
518	int status;
519
520	while (waitpid(pid, &status, 0) == -1) {
521		if (errno != EINTR) {
522			error("%s: waitpid: %s", tag, strerror(errno));
523			return -1;
524		}
525	}
526	if (WIFSIGNALED(status)) {
527		error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status));
528		return -1;
529	} else if (WEXITSTATUS(status) != 0) {
530		error("%s %s failed, status %d", tag, cmd, WEXITSTATUS(status));
531		return -1;
532	}
533	return 0;
534}
535
536static int
537match_principals_option(const char *principal_list, struct sshkey_cert *cert)
538{
539	char *result;
540	u_int i;
541
542	/* XXX percent_expand() sequences for authorized_principals? */
543
544	for (i = 0; i < cert->nprincipals; i++) {
545		if ((result = match_list(cert->principals[i],
546		    principal_list, NULL)) != NULL) {
547			debug3("matched principal from key options \"%.100s\"",
548			    result);
549			free(result);
550			return 1;
551		}
552	}
553	return 0;
554}
555
556static int
557process_principals(FILE *f, char *file, struct passwd *pw,
558    struct sshkey_cert *cert)
559{
560	char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
561	u_long linenum = 0;
562	u_int i;
563
564	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
565		/* Skip leading whitespace. */
566		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
567			;
568		/* Skip blank and comment lines. */
569		if ((ep = strchr(cp, '#')) != NULL)
570			*ep = '\0';
571		if (!*cp || *cp == '\n')
572			continue;
573		/* Trim trailing whitespace. */
574		ep = cp + strlen(cp) - 1;
575		while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
576			*ep-- = '\0';
577		/*
578		 * If the line has internal whitespace then assume it has
579		 * key options.
580		 */
581		line_opts = NULL;
582		if ((ep = strrchr(cp, ' ')) != NULL ||
583		    (ep = strrchr(cp, '\t')) != NULL) {
584			for (; *ep == ' ' || *ep == '\t'; ep++)
585				;
586			line_opts = cp;
587			cp = ep;
588		}
589		for (i = 0; i < cert->nprincipals; i++) {
590			if (strcmp(cp, cert->principals[i]) == 0) {
591				debug3("%s:%lu: matched principal \"%.100s\"",
592				    file == NULL ? "(command)" : file,
593				    linenum, cert->principals[i]);
594				if (auth_parse_options(pw, line_opts,
595				    file, linenum) != 1)
596					continue;
597				return 1;
598			}
599		}
600	}
601	return 0;
602}
603
604static int
605match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
606{
607	FILE *f;
608	int success;
609
610	temporarily_use_uid(pw);
611	debug("trying authorized principals file %s", file);
612	if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
613		restore_uid();
614		return 0;
615	}
616	success = process_principals(f, file, pw, cert);
617	fclose(f);
618	restore_uid();
619	return success;
620}
621
622/*
623 * Checks whether principal is allowed in output of command.
624 * returns 1 if the principal is allowed or 0 otherwise.
625 */
626static int
627match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert)
628{
629	FILE *f = NULL;
630	int ok, found_principal = 0;
631	struct passwd *pw;
632	int i, ac = 0, uid_swapped = 0;
633	pid_t pid;
634	char *tmp, *username = NULL, *command = NULL, **av = NULL;
635	void (*osigchld)(int);
636
637	if (options.authorized_principals_command == NULL)
638		return 0;
639	if (options.authorized_principals_command_user == NULL) {
640		error("No user for AuthorizedPrincipalsCommand specified, "
641		    "skipping");
642		return 0;
643	}
644
645	/*
646	 * NB. all returns later this function should go via "out" to
647	 * ensure the original SIGCHLD handler is restored properly.
648	 */
649	osigchld = signal(SIGCHLD, SIG_DFL);
650
651	/* Prepare and verify the user for the command */
652	username = percent_expand(options.authorized_principals_command_user,
653	    "u", user_pw->pw_name, (char *)NULL);
654	pw = getpwnam(username);
655	if (pw == NULL) {
656		error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
657		    username, strerror(errno));
658		goto out;
659	}
660
661	/* Turn the command into an argument vector */
662	if (split_argv(options.authorized_principals_command, &ac, &av) != 0) {
663		error("AuthorizedPrincipalsCommand \"%s\" contains "
664		    "invalid quotes", command);
665		goto out;
666	}
667	if (ac == 0) {
668		error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments",
669		    command);
670		goto out;
671	}
672	for (i = 1; i < ac; i++) {
673		tmp = percent_expand(av[i],
674		    "u", user_pw->pw_name,
675		    "h", user_pw->pw_dir,
676		    (char *)NULL);
677		if (tmp == NULL)
678			fatal("%s: percent_expand failed", __func__);
679		free(av[i]);
680		av[i] = tmp;
681	}
682	/* Prepare a printable command for logs, etc. */
683	command = assemble_argv(ac, av);
684
685	if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
686	    ac, av, &f)) == 0)
687		goto out;
688
689	uid_swapped = 1;
690	temporarily_use_uid(pw);
691
692	ok = process_principals(f, NULL, pw, cert);
693
694	if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0)
695		goto out;
696
697	/* Read completed successfully */
698	found_principal = ok;
699 out:
700	if (f != NULL)
701		fclose(f);
702	signal(SIGCHLD, osigchld);
703	for (i = 0; i < ac; i++)
704		free(av[i]);
705	free(av);
706	if (uid_swapped)
707		restore_uid();
708	free(command);
709	free(username);
710	return found_principal;
711}
712/*
713 * Checks whether key is allowed in authorized_keys-format file,
714 * returns 1 if the key is allowed or 0 otherwise.
715 */
716static int
717check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
718{
719	char line[SSH_MAX_PUBKEY_BYTES];
720	const char *reason;
721	int found_key = 0;
722	u_long linenum = 0;
723	Key *found;
724	char *fp;
725
726	found_key = 0;
727
728	found = NULL;
729	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
730		char *cp, *key_options = NULL;
731		if (found != NULL)
732			key_free(found);
733		found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
734		auth_clear_options();
735
736		/* Skip leading whitespace, empty and comment lines. */
737		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
738			;
739		if (!*cp || *cp == '\n' || *cp == '#')
740			continue;
741
742		if (key_read(found, &cp) != 1) {
743			/* no key?  check if there are options for this key */
744			int quoted = 0;
745			debug2("user_key_allowed: check options: '%s'", cp);
746			key_options = cp;
747			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
748				if (*cp == '\\' && cp[1] == '"')
749					cp++;	/* Skip both */
750				else if (*cp == '"')
751					quoted = !quoted;
752			}
753			/* Skip remaining whitespace. */
754			for (; *cp == ' ' || *cp == '\t'; cp++)
755				;
756			if (key_read(found, &cp) != 1) {
757				debug2("user_key_allowed: advance: '%s'", cp);
758				/* still no key?  advance to next line*/
759				continue;
760			}
761		}
762		if (key_is_cert(key)) {
763			if (!key_equal(found, key->cert->signature_key))
764				continue;
765			if (auth_parse_options(pw, key_options, file,
766			    linenum) != 1)
767				continue;
768			if (!key_is_cert_authority)
769				continue;
770			if ((fp = sshkey_fingerprint(found,
771			    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
772				continue;
773			debug("matching CA found: file %s, line %lu, %s %s",
774			    file, linenum, key_type(found), fp);
775			/*
776			 * If the user has specified a list of principals as
777			 * a key option, then prefer that list to matching
778			 * their username in the certificate principals list.
779			 */
780			if (authorized_principals != NULL &&
781			    !match_principals_option(authorized_principals,
782			    key->cert)) {
783				reason = "Certificate does not contain an "
784				    "authorized principal";
785 fail_reason:
786				free(fp);
787				error("%s", reason);
788				auth_debug_add("%s", reason);
789				continue;
790			}
791			if (key_cert_check_authority(key, 0, 0,
792			    authorized_principals == NULL ? pw->pw_name : NULL,
793			    &reason) != 0)
794				goto fail_reason;
795			if (auth_cert_options(key, pw) != 0) {
796				free(fp);
797				continue;
798			}
799			verbose("Accepted certificate ID \"%s\" "
800			    "signed by %s CA %s via %s", key->cert->key_id,
801			    key_type(found), fp, file);
802			free(fp);
803			found_key = 1;
804			break;
805		} else if (key_equal(found, key)) {
806			if (auth_parse_options(pw, key_options, file,
807			    linenum) != 1)
808				continue;
809			if (key_is_cert_authority)
810				continue;
811			if ((fp = sshkey_fingerprint(found,
812			    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
813				continue;
814			debug("matching key found: file %s, line %lu %s %s",
815			    file, linenum, key_type(found), fp);
816			free(fp);
817			found_key = 1;
818			break;
819		}
820	}
821	if (found != NULL)
822		key_free(found);
823	if (!found_key)
824		debug2("key not found");
825	return found_key;
826}
827
828/* Authenticate a certificate key against TrustedUserCAKeys */
829static int
830user_cert_trusted_ca(struct passwd *pw, Key *key)
831{
832	char *ca_fp, *principals_file = NULL;
833	const char *reason;
834	int ret = 0, found_principal = 0, use_authorized_principals;
835
836	if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
837		return 0;
838
839	if ((ca_fp = sshkey_fingerprint(key->cert->signature_key,
840	    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
841		return 0;
842
843	if (sshkey_in_file(key->cert->signature_key,
844	    options.trusted_user_ca_keys, 1, 0) != 0) {
845		debug2("%s: CA %s %s is not listed in %s", __func__,
846		    key_type(key->cert->signature_key), ca_fp,
847		    options.trusted_user_ca_keys);
848		goto out;
849	}
850	/*
851	 * If AuthorizedPrincipals is in use, then compare the certificate
852	 * principals against the names in that file rather than matching
853	 * against the username.
854	 */
855	if ((principals_file = authorized_principals_file(pw)) != NULL) {
856		if (match_principals_file(principals_file, pw, key->cert))
857			found_principal = 1;
858	}
859	/* Try querying command if specified */
860	if (!found_principal && match_principals_command(pw, key->cert))
861		found_principal = 1;
862	/* If principals file or command is specified, then require a match */
863	use_authorized_principals = principals_file != NULL ||
864            options.authorized_principals_command != NULL;
865	if (!found_principal && use_authorized_principals) {
866		reason = "Certificate does not contain an authorized principal";
867 fail_reason:
868		error("%s", reason);
869		auth_debug_add("%s", reason);
870		goto out;
871	}
872	if (key_cert_check_authority(key, 0, 1,
873	    use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
874		goto fail_reason;
875	if (auth_cert_options(key, pw) != 0)
876		goto out;
877
878	verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s",
879	    key->cert->key_id, key_type(key->cert->signature_key), ca_fp,
880	    options.trusted_user_ca_keys);
881	ret = 1;
882
883 out:
884	free(principals_file);
885	free(ca_fp);
886	return ret;
887}
888
889/*
890 * Checks whether key is allowed in file.
891 * returns 1 if the key is allowed or 0 otherwise.
892 */
893static int
894user_key_allowed2(struct passwd *pw, Key *key, char *file)
895{
896	FILE *f;
897	int found_key = 0;
898
899	/* Temporarily use the user's uid. */
900	temporarily_use_uid(pw);
901
902	debug("trying public key file %s", file);
903	if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
904		found_key = check_authkeys_file(f, file, key, pw);
905		fclose(f);
906	}
907
908	restore_uid();
909	return found_key;
910}
911
912/*
913 * Checks whether key is allowed in output of command.
914 * returns 1 if the key is allowed or 0 otherwise.
915 */
916static int
917user_key_command_allowed2(struct passwd *user_pw, Key *key)
918{
919	FILE *f = NULL;
920	int r, ok, found_key = 0;
921	struct passwd *pw;
922	int i, uid_swapped = 0, ac = 0;
923	pid_t pid;
924	char *username = NULL, *key_fp = NULL, *keytext = NULL;
925	char *tmp, *command = NULL, **av = NULL;
926	void (*osigchld)(int);
927
928	if (options.authorized_keys_command == NULL)
929		return 0;
930	if (options.authorized_keys_command_user == NULL) {
931		error("No user for AuthorizedKeysCommand specified, skipping");
932		return 0;
933	}
934
935	/*
936	 * NB. all returns later this function should go via "out" to
937	 * ensure the original SIGCHLD handler is restored properly.
938	 */
939	osigchld = signal(SIGCHLD, SIG_DFL);
940
941	/* Prepare and verify the user for the command */
942	username = percent_expand(options.authorized_keys_command_user,
943	    "u", user_pw->pw_name, (char *)NULL);
944	pw = getpwnam(username);
945	if (pw == NULL) {
946		error("AuthorizedKeysCommandUser \"%s\" not found: %s",
947		    username, strerror(errno));
948		goto out;
949	}
950
951	/* Prepare AuthorizedKeysCommand */
952	if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash,
953	    SSH_FP_DEFAULT)) == NULL) {
954		error("%s: sshkey_fingerprint failed", __func__);
955		goto out;
956	}
957	if ((r = sshkey_to_base64(key, &keytext)) != 0) {
958		error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
959		goto out;
960	}
961
962	/* Turn the command into an argument vector */
963	if (split_argv(options.authorized_keys_command, &ac, &av) != 0) {
964		error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
965		    command);
966		goto out;
967	}
968	if (ac == 0) {
969		error("AuthorizedKeysCommand \"%s\" yielded no arguments",
970		    command);
971		goto out;
972	}
973	for (i = 1; i < ac; i++) {
974		tmp = percent_expand(av[i],
975		    "u", user_pw->pw_name,
976		    "h", user_pw->pw_dir,
977		    "t", sshkey_ssh_name(key),
978		    "f", key_fp,
979		    "k", keytext,
980		    (char *)NULL);
981		if (tmp == NULL)
982			fatal("%s: percent_expand failed", __func__);
983		free(av[i]);
984		av[i] = tmp;
985	}
986	/* Prepare a printable command for logs, etc. */
987	command = assemble_argv(ac, av);
988
989	/*
990	 * If AuthorizedKeysCommand was run without arguments
991	 * then fall back to the old behaviour of passing the
992	 * target username as a single argument.
993	 */
994	if (ac == 1) {
995		av = xreallocarray(av, ac + 2, sizeof(*av));
996		av[1] = xstrdup(user_pw->pw_name);
997		av[2] = NULL;
998		/* Fix up command too, since it is used in log messages */
999		free(command);
1000		xasprintf(&command, "%s %s", av[0], av[1]);
1001	}
1002
1003	if ((pid = subprocess("AuthorizedKeysCommand", pw, command,
1004	    ac, av, &f)) == 0)
1005		goto out;
1006
1007	uid_swapped = 1;
1008	temporarily_use_uid(pw);
1009
1010	ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
1011
1012	if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0)
1013		goto out;
1014
1015	/* Read completed successfully */
1016	found_key = ok;
1017 out:
1018	if (f != NULL)
1019		fclose(f);
1020	signal(SIGCHLD, osigchld);
1021	for (i = 0; i < ac; i++)
1022		free(av[i]);
1023	free(av);
1024	if (uid_swapped)
1025		restore_uid();
1026	free(command);
1027	free(username);
1028	free(key_fp);
1029	free(keytext);
1030	return found_key;
1031}
1032
1033/*
1034 * Check whether key authenticates and authorises the user.
1035 */
1036int
1037user_key_allowed(struct passwd *pw, Key *key, int auth_attempt)
1038{
1039	u_int success, i;
1040	char *file;
1041
1042	if (auth_key_is_revoked(key))
1043		return 0;
1044	if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
1045		return 0;
1046
1047	success = user_cert_trusted_ca(pw, key);
1048	if (success)
1049		return success;
1050
1051	success = user_key_command_allowed2(pw, key);
1052	if (success > 0)
1053		return success;
1054
1055	for (i = 0; !success && i < options.num_authkeys_files; i++) {
1056
1057		if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
1058			continue;
1059		file = expand_authorized_keys(
1060		    options.authorized_keys_files[i], pw);
1061
1062		success = user_key_allowed2(pw, key, file);
1063		free(file);
1064	}
1065
1066	return success;
1067}
1068
1069/* Records a public key in the list of previously-successful keys */
1070void
1071auth2_record_userkey(Authctxt *authctxt, struct sshkey *key)
1072{
1073	struct sshkey **tmp;
1074
1075	if (authctxt->nprev_userkeys >= INT_MAX ||
1076	    (tmp = reallocarray(authctxt->prev_userkeys,
1077	    authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL)
1078		fatal("%s: reallocarray failed", __func__);
1079	authctxt->prev_userkeys = tmp;
1080	authctxt->prev_userkeys[authctxt->nprev_userkeys] = key;
1081	authctxt->nprev_userkeys++;
1082}
1083
1084/* Checks whether a key has already been used successfully for authentication */
1085int
1086auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key)
1087{
1088	u_int i;
1089
1090	for (i = 0; i < authctxt->nprev_userkeys; i++) {
1091		if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) {
1092			return 1;
1093		}
1094	}
1095	return 0;
1096}
1097
1098Authmethod method_pubkey = {
1099	"publickey",
1100	userauth_pubkey,
1101	&options.pubkey_authentication
1102};
1103