auth2-pubkey.c revision 1.10
1/*	$NetBSD: auth2-pubkey.c,v 1.10 2014/10/19 16:30:58 christos Exp $	*/
2/* $OpenBSD: auth2-pubkey.c,v 1.41 2014/07/15 15:54:14 millert Exp $ */
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
27#include "includes.h"
28__RCSID("$NetBSD: auth2-pubkey.c,v 1.10 2014/10/19 16:30:58 christos Exp $");
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/wait.h>
32
33#include <errno.h>
34#include <fcntl.h>
35#include <paths.h>
36#include <pwd.h>
37#include <signal.h>
38#include <stdio.h>
39#include <stdarg.h>
40#include <string.h>
41#include <time.h>
42#include <unistd.h>
43
44#include "xmalloc.h"
45#include "ssh.h"
46#include "ssh2.h"
47#include "packet.h"
48#include "buffer.h"
49#include "log.h"
50#include "misc.h"
51#include "servconf.h"
52#include "compat.h"
53#include "key.h"
54#include "hostfile.h"
55#include "auth.h"
56#include "pathnames.h"
57#include "uidswap.h"
58#include "auth-options.h"
59#include "canohost.h"
60#ifdef GSSAPI
61#include "ssh-gss.h"
62#endif
63#include "monitor_wrap.h"
64#include "authfile.h"
65#include "match.h"
66
67#ifdef WITH_LDAP_PUBKEY
68#include "ldapauth.h"
69#endif
70
71/* import */
72extern ServerOptions options;
73extern u_char *session_id2;
74extern u_int session_id2_len;
75
76static int
77userauth_pubkey(Authctxt *authctxt)
78{
79	Buffer b;
80	Key *key = NULL;
81	char *pkalg, *userstyle;
82	u_char *pkblob, *sig;
83	u_int alen, blen, slen;
84	int have_sig, pktype;
85	int authenticated = 0;
86
87	if (!authctxt->valid) {
88		debug2("userauth_pubkey: disabled because of invalid user");
89		return 0;
90	}
91	have_sig = packet_get_char();
92	if (datafellows & SSH_BUG_PKAUTH) {
93		debug2("userauth_pubkey: SSH_BUG_PKAUTH");
94		/* no explicit pkalg given */
95		pkblob = packet_get_string(&blen);
96		buffer_init(&b);
97		buffer_append(&b, pkblob, blen);
98		/* so we have to extract the pkalg from the pkblob */
99		pkalg = buffer_get_string(&b, &alen);
100		buffer_free(&b);
101	} else {
102		pkalg = packet_get_string(&alen);
103		pkblob = packet_get_string(&blen);
104	}
105	pktype = key_type_from_name(pkalg);
106	if (pktype == KEY_UNSPEC) {
107		/* this is perfectly legal */
108		logit("userauth_pubkey: unsupported public key algorithm: %s",
109		    pkalg);
110		goto done;
111	}
112	key = key_from_blob(pkblob, blen);
113	if (key == NULL) {
114		error("userauth_pubkey: cannot decode key: %s", pkalg);
115		goto done;
116	}
117	if (key->type != pktype) {
118		error("userauth_pubkey: type mismatch for decoded key "
119		    "(received %d, expected %d)", key->type, pktype);
120		goto done;
121	}
122	if (key_type_plain(key->type) == KEY_RSA &&
123	    (datafellows & SSH_BUG_RSASIGMD5) != 0) {
124		logit("Refusing RSA key because client uses unsafe "
125		    "signature scheme");
126		goto done;
127	}
128	if (have_sig) {
129		sig = packet_get_string(&slen);
130		packet_check_eom();
131		buffer_init(&b);
132		if (datafellows & SSH_OLD_SESSIONID) {
133			buffer_append(&b, session_id2, session_id2_len);
134		} else {
135			buffer_put_string(&b, session_id2, session_id2_len);
136		}
137		/* reconstruct packet */
138		buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
139		xasprintf(&userstyle, "%s%s%s", authctxt->user,
140		    authctxt->style ? ":" : "",
141		    authctxt->style ? authctxt->style : "");
142		buffer_put_cstring(&b, userstyle);
143		free(userstyle);
144		buffer_put_cstring(&b,
145		    datafellows & SSH_BUG_PKSERVICE ?
146		    "ssh-userauth" :
147		    authctxt->service);
148		if (datafellows & SSH_BUG_PKAUTH) {
149			buffer_put_char(&b, have_sig);
150		} else {
151			buffer_put_cstring(&b, "publickey");
152			buffer_put_char(&b, have_sig);
153			buffer_put_cstring(&b, pkalg);
154		}
155		buffer_put_string(&b, pkblob, blen);
156#ifdef DEBUG_PK
157		buffer_dump(&b);
158#endif
159		pubkey_auth_info(authctxt, key, NULL);
160
161		/* test for correct signature */
162		authenticated = 0;
163		if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
164		    PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
165		    buffer_len(&b))) == 1)
166			authenticated = 1;
167		buffer_free(&b);
168		free(sig);
169	} else {
170		debug("test whether pkalg/pkblob are acceptable");
171		packet_check_eom();
172
173		/* XXX fake reply and always send PK_OK ? */
174		/*
175		 * XXX this allows testing whether a user is allowed
176		 * to login: if you happen to have a valid pubkey this
177		 * message is sent. the message is NEVER sent at all
178		 * if a user is not allowed to login. is this an
179		 * issue? -markus
180		 */
181		if (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
182			packet_start(SSH2_MSG_USERAUTH_PK_OK);
183			packet_put_string(pkalg, alen);
184			packet_put_string(pkblob, blen);
185			packet_send();
186			packet_write_wait();
187			authctxt->postponed = 1;
188		}
189	}
190	if (authenticated != 1)
191		auth_clear_options();
192done:
193	debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
194	if (key != NULL)
195		key_free(key);
196	free(pkalg);
197	free(pkblob);
198	return authenticated;
199}
200
201void
202pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
203{
204	char *fp, *extra;
205	va_list ap;
206	int i;
207
208	extra = NULL;
209	if (fmt != NULL) {
210		va_start(ap, fmt);
211		i = vasprintf(&extra, fmt, ap);
212		va_end(ap);
213		if (i < 0 || extra == NULL)
214			fatal("%s: vasprintf failed", __func__);
215	}
216
217	if (key_is_cert(key)) {
218		fp = key_fingerprint(key->cert->signature_key,
219		    SSH_FP_MD5, SSH_FP_HEX);
220		auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s",
221		    key_type(key), key->cert->key_id,
222		    (unsigned long long)key->cert->serial,
223		    key_type(key->cert->signature_key), fp,
224		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
225		free(fp);
226	} else {
227		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
228		auth_info(authctxt, "%s %s%s%s", key_type(key), fp,
229		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
230		free(fp);
231	}
232	free(extra);
233}
234
235static int
236match_principals_option(const char *principal_list, struct sshkey_cert *cert)
237{
238	char *result;
239	u_int i;
240
241	/* XXX percent_expand() sequences for authorized_principals? */
242
243	for (i = 0; i < cert->nprincipals; i++) {
244		if ((result = match_list(cert->principals[i],
245		    principal_list, NULL)) != NULL) {
246			debug3("matched principal from key options \"%.100s\"",
247			    result);
248			free(result);
249			return 1;
250		}
251	}
252	return 0;
253}
254
255static int
256match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
257{
258	FILE *f;
259	char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
260	u_long linenum = 0;
261	u_int i;
262
263	temporarily_use_uid(pw);
264	debug("trying authorized principals file %s", file);
265	if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
266		restore_uid();
267		return 0;
268	}
269	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
270		/* Skip leading whitespace. */
271		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
272			;
273		/* Skip blank and comment lines. */
274		if ((ep = strchr(cp, '#')) != NULL)
275			*ep = '\0';
276		if (!*cp || *cp == '\n')
277			continue;
278		/* Trim trailing whitespace. */
279		ep = cp + strlen(cp) - 1;
280		while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
281			*ep-- = '\0';
282		/*
283		 * If the line has internal whitespace then assume it has
284		 * key options.
285		 */
286		line_opts = NULL;
287		if ((ep = strrchr(cp, ' ')) != NULL ||
288		    (ep = strrchr(cp, '\t')) != NULL) {
289			for (; *ep == ' ' || *ep == '\t'; ep++)
290				;
291			line_opts = cp;
292			cp = ep;
293		}
294		for (i = 0; i < cert->nprincipals; i++) {
295			if (strcmp(cp, cert->principals[i]) == 0) {
296				debug3("matched principal \"%.100s\" "
297				    "from file \"%s\" on line %lu",
298				    cert->principals[i], file, linenum);
299				if (auth_parse_options(pw, line_opts,
300				    file, linenum) != 1)
301					continue;
302				fclose(f);
303				restore_uid();
304				return 1;
305			}
306		}
307	}
308	fclose(f);
309	restore_uid();
310	return 0;
311}
312
313/*
314 * Checks whether key is allowed in authorized_keys-format file,
315 * returns 1 if the key is allowed or 0 otherwise.
316 */
317static int
318check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
319{
320	char line[SSH_MAX_PUBKEY_BYTES];
321	const char *reason;
322	int found_key = 0;
323	u_long linenum = 0;
324	Key *found;
325	char *fp;
326#ifdef WITH_LDAP_PUBKEY
327	ldap_key_t * k;
328	unsigned int i = 0;
329#endif
330
331#ifdef WITH_LDAP_PUBKEY
332	found_key = 0;
333	/* allocate a new key type */
334	found = key_new(key->type);
335
336	/* first check if the options is enabled, then try.. */
337	if (options.lpk.on) {
338	    debug("[LDAP] trying LDAP first uid=%s",pw->pw_name);
339	    if (ldap_ismember(&options.lpk, pw->pw_name) > 0) {
340		if ((k = ldap_getuserkey(&options.lpk, pw->pw_name)) != NULL) {
341		    /* Skip leading whitespace, empty and comment lines. */
342		    for (i = 0 ; i < k->num ; i++) {
343			/* dont forget if multiple keys to reset options */
344			char *cp, *xoptions = NULL;
345
346			for (cp = (char *)k->keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++)
347			    ;
348			if (!*cp || *cp == '\n' || *cp == '#')
349			    continue;
350
351			if (key_read(found, &cp) != 1) {
352			    /* no key?  check if there are options for this key */
353			    int quoted = 0;
354			    debug2("[LDAP] user_key_allowed: check options: '%s'", cp);
355			    xoptions = cp;
356			    for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
357				if (*cp == '\\' && cp[1] == '"')
358				    cp++;	/* Skip both */
359				else if (*cp == '"')
360				    quoted = !quoted;
361			    }
362			    /* Skip remaining whitespace. */
363			    for (; *cp == ' ' || *cp == '\t'; cp++)
364				;
365			    if (key_read(found, &cp) != 1) {
366				debug2("[LDAP] user_key_allowed: advance: '%s'", cp);
367				/* still no key?  advance to next line*/
368				continue;
369			    }
370			}
371
372			if (key_equal(found, key) &&
373				auth_parse_options(pw, xoptions, file, linenum) == 1) {
374			    found_key = 1;
375			    debug("[LDAP] matching key found");
376			    fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
377			    verbose("[LDAP] Found matching %s key: %s", key_type(found), fp);
378
379			    /* restoring memory */
380			    ldap_keys_free(k);
381			    free(fp);
382			    restore_uid();
383			    key_free(found);
384			    return found_key;
385			    break;
386			}
387		    }/* end of LDAP for() */
388		} else {
389		    logit("[LDAP] no keys found for '%s'!", pw->pw_name);
390		}
391	    } else {
392		logit("[LDAP] '%s' is not in '%s'", pw->pw_name, options.lpk.sgroup);
393	    }
394	}
395#endif
396	debug("trying public key file %s", file);
397	f = auth_openkeyfile(file, pw, options.strict_modes);
398
399	if (!f) {
400		restore_uid();
401		return 0;
402	}
403
404	found_key = 0;
405
406	found = NULL;
407	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
408		char *cp, *key_options = NULL;
409		if (found != NULL)
410			key_free(found);
411		found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
412		auth_clear_options();
413
414		/* Skip leading whitespace, empty and comment lines. */
415		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
416			;
417		if (!*cp || *cp == '\n' || *cp == '#')
418			continue;
419
420		if (key_read(found, &cp) != 1) {
421			/* no key?  check if there are options for this key */
422			int quoted = 0;
423			debug2("user_key_allowed: check options: '%s'", cp);
424			key_options = cp;
425			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
426				if (*cp == '\\' && cp[1] == '"')
427					cp++;	/* Skip both */
428				else if (*cp == '"')
429					quoted = !quoted;
430			}
431			/* Skip remaining whitespace. */
432			for (; *cp == ' ' || *cp == '\t'; cp++)
433				;
434			if (key_read(found, &cp) != 1) {
435				debug2("user_key_allowed: advance: '%s'", cp);
436				/* still no key?  advance to next line*/
437				continue;
438			}
439		}
440		if (key_is_cert(key)) {
441			if (!key_equal(found, key->cert->signature_key))
442				continue;
443			if (auth_parse_options(pw, key_options, file,
444			    linenum) != 1)
445				continue;
446			if (!key_is_cert_authority)
447				continue;
448			fp = key_fingerprint(found, SSH_FP_MD5,
449			    SSH_FP_HEX);
450			debug("matching CA found: file %s, line %lu, %s %s",
451			    file, linenum, key_type(found), fp);
452			/*
453			 * If the user has specified a list of principals as
454			 * a key option, then prefer that list to matching
455			 * their username in the certificate principals list.
456			 */
457			if (authorized_principals != NULL &&
458			    !match_principals_option(authorized_principals,
459			    key->cert)) {
460				reason = "Certificate does not contain an "
461				    "authorized principal";
462 fail_reason:
463				free(fp);
464				error("%s", reason);
465				auth_debug_add("%s", reason);
466				continue;
467			}
468			if (key_cert_check_authority(key, 0, 0,
469			    authorized_principals == NULL ? pw->pw_name : NULL,
470			    &reason) != 0)
471				goto fail_reason;
472			if (auth_cert_options(key, pw) != 0) {
473				free(fp);
474				continue;
475			}
476			verbose("Accepted certificate ID \"%s\" "
477			    "signed by %s CA %s via %s", key->cert->key_id,
478			    key_type(found), fp, file);
479			free(fp);
480			found_key = 1;
481			break;
482		} else if (key_equal(found, key)) {
483			if (auth_parse_options(pw, key_options, file,
484			    linenum) != 1)
485				continue;
486			if (key_is_cert_authority)
487				continue;
488			found_key = 1;
489			fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
490			debug("matching key found: file %s, line %lu %s %s",
491			    file, linenum, key_type(found), fp);
492			free(fp);
493			break;
494		}
495	}
496	if (found != NULL)
497		key_free(found);
498	if (!found_key)
499		debug2("key not found");
500	return found_key;
501}
502
503/* Authenticate a certificate key against TrustedUserCAKeys */
504static int
505user_cert_trusted_ca(struct passwd *pw, Key *key)
506{
507	char *ca_fp, *principals_file = NULL;
508	const char *reason;
509	int ret = 0;
510
511	if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL)
512		return 0;
513
514	ca_fp = key_fingerprint(key->cert->signature_key,
515	    SSH_FP_MD5, SSH_FP_HEX);
516
517	if (key_in_file(key->cert->signature_key,
518	    options.trusted_user_ca_keys, 1) != 1) {
519		debug2("%s: CA %s %s is not listed in %s", __func__,
520		    key_type(key->cert->signature_key), ca_fp,
521		    options.trusted_user_ca_keys);
522		goto out;
523	}
524	/*
525	 * If AuthorizedPrincipals is in use, then compare the certificate
526	 * principals against the names in that file rather than matching
527	 * against the username.
528	 */
529	if ((principals_file = authorized_principals_file(pw)) != NULL) {
530		if (!match_principals_file(principals_file, pw, key->cert)) {
531			reason = "Certificate does not contain an "
532			    "authorized principal";
533 fail_reason:
534			error("%s", reason);
535			auth_debug_add("%s", reason);
536			goto out;
537		}
538	}
539	if (key_cert_check_authority(key, 0, 1,
540	    principals_file == NULL ? pw->pw_name : NULL, &reason) != 0)
541		goto fail_reason;
542	if (auth_cert_options(key, pw) != 0)
543		goto out;
544
545	verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s",
546	    key->cert->key_id, key_type(key->cert->signature_key), ca_fp,
547	    options.trusted_user_ca_keys);
548	ret = 1;
549
550 out:
551	free(principals_file);
552	free(ca_fp);
553	return ret;
554}
555
556/*
557 * Checks whether key is allowed in file.
558 * returns 1 if the key is allowed or 0 otherwise.
559 */
560static int
561user_key_allowed2(struct passwd *pw, Key *key, char *file)
562{
563	FILE *f;
564	int found_key = 0;
565
566	/* Temporarily use the user's uid. */
567	temporarily_use_uid(pw);
568
569	debug("trying public key file %s", file);
570	if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
571		found_key = check_authkeys_file(f, file, key, pw);
572		fclose(f);
573	}
574
575	restore_uid();
576	return found_key;
577}
578
579/*
580 * Checks whether key is allowed in output of command.
581 * returns 1 if the key is allowed or 0 otherwise.
582 */
583static int
584user_key_command_allowed2(struct passwd *user_pw, Key *key)
585{
586	FILE *f;
587	int ok, found_key = 0;
588	struct passwd *pw;
589	struct stat st;
590	int status, devnull, p[2], i;
591	pid_t pid;
592	char *username, errmsg[512];
593
594	if (options.authorized_keys_command == NULL ||
595	    options.authorized_keys_command[0] != '/')
596		return 0;
597
598	if (options.authorized_keys_command_user == NULL) {
599		error("No user for AuthorizedKeysCommand specified, skipping");
600		return 0;
601	}
602
603	username = percent_expand(options.authorized_keys_command_user,
604	    "u", user_pw->pw_name, (char *)NULL);
605	pw = getpwnam(username);
606	if (pw == NULL) {
607		error("AuthorizedKeysCommandUser \"%s\" not found: %s",
608		    username, strerror(errno));
609		free(username);
610		return 0;
611	}
612	free(username);
613
614	temporarily_use_uid(pw);
615
616	if (stat(options.authorized_keys_command, &st) < 0) {
617		error("Could not stat AuthorizedKeysCommand \"%s\": %s",
618		    options.authorized_keys_command, strerror(errno));
619		goto out;
620	}
621	if (auth_secure_path(options.authorized_keys_command, &st, NULL, 0,
622	    errmsg, sizeof(errmsg)) != 0) {
623		error("Unsafe AuthorizedKeysCommand: %s", errmsg);
624		goto out;
625	}
626
627	if (pipe(p) != 0) {
628		error("%s: pipe: %s", __func__, strerror(errno));
629		goto out;
630	}
631
632	debug3("Running AuthorizedKeysCommand: \"%s %s\" as \"%s\"",
633	    options.authorized_keys_command, user_pw->pw_name, pw->pw_name);
634
635	/*
636	 * Don't want to call this in the child, where it can fatal() and
637	 * run cleanup_exit() code.
638	 */
639	restore_uid();
640
641	switch ((pid = fork())) {
642	case -1: /* error */
643		error("%s: fork: %s", __func__, strerror(errno));
644		close(p[0]);
645		close(p[1]);
646		return 0;
647	case 0: /* child */
648		for (i = 0; i < NSIG; i++)
649			signal(i, SIG_DFL);
650
651		if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
652			error("%s: open %s: %s", __func__, _PATH_DEVNULL,
653			    strerror(errno));
654			_exit(1);
655		}
656		/* Keep stderr around a while longer to catch errors */
657		if (dup2(devnull, STDIN_FILENO) == -1 ||
658		    dup2(p[1], STDOUT_FILENO) == -1) {
659			error("%s: dup2: %s", __func__, strerror(errno));
660			_exit(1);
661		}
662		closefrom(STDERR_FILENO + 1);
663
664		/* Don't use permanently_set_uid() here to avoid fatal() */
665		if (setgid(pw->pw_gid) != 0) {
666			error("setgid %u: %s", (u_int)pw->pw_gid,
667			    strerror(errno));
668			_exit(1);
669		}
670		if (setuid(pw->pw_uid) != 0) {
671			error("setuid %u: %s", (u_int)pw->pw_uid,
672			    strerror(errno));
673			_exit(1);
674		}
675		/* stdin is pointed to /dev/null at this point */
676		if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) {
677			error("%s: dup2: %s", __func__, strerror(errno));
678			_exit(1);
679		}
680
681		execl(options.authorized_keys_command,
682		    options.authorized_keys_command, user_pw->pw_name, NULL);
683
684		error("AuthorizedKeysCommand %s exec failed: %s",
685		    options.authorized_keys_command, strerror(errno));
686		_exit(127);
687	default: /* parent */
688		break;
689	}
690
691	temporarily_use_uid(pw);
692
693	close(p[1]);
694	if ((f = fdopen(p[0], "r")) == NULL) {
695		error("%s: fdopen: %s", __func__, strerror(errno));
696		close(p[0]);
697		/* Don't leave zombie child */
698		kill(pid, SIGTERM);
699		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
700			;
701		goto out;
702	}
703	ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
704	fclose(f);
705
706	while (waitpid(pid, &status, 0) == -1) {
707		if (errno != EINTR) {
708			error("%s: waitpid: %s", __func__, strerror(errno));
709			goto out;
710		}
711	}
712	if (WIFSIGNALED(status)) {
713		error("AuthorizedKeysCommand %s exited on signal %d",
714		    options.authorized_keys_command, WTERMSIG(status));
715		goto out;
716	} else if (WEXITSTATUS(status) != 0) {
717		error("AuthorizedKeysCommand %s returned status %d",
718		    options.authorized_keys_command, WEXITSTATUS(status));
719		goto out;
720	}
721	found_key = ok;
722 out:
723	restore_uid();
724	return found_key;
725}
726
727/*
728 * Check whether key authenticates and authorises the user.
729 */
730int
731user_key_allowed(struct passwd *pw, Key *key)
732{
733	u_int success, i;
734	char *file;
735
736	if (auth_key_is_revoked(key))
737		return 0;
738	if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
739		return 0;
740
741	success = user_cert_trusted_ca(pw, key);
742	if (success)
743		return success;
744
745	success = user_key_command_allowed2(pw, key);
746	if (success > 0)
747		return success;
748
749	for (i = 0; !success && i < options.num_authkeys_files; i++) {
750
751		if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
752			continue;
753		file = expand_authorized_keys(
754		    options.authorized_keys_files[i], pw);
755
756		success = user_key_allowed2(pw, key, file);
757		free(file);
758	}
759
760	return success;
761}
762
763Authmethod method_pubkey = {
764	"publickey",
765	userauth_pubkey,
766	&options.pubkey_authentication
767};
768