GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/ssh/sshd/../auth2-pubkey.c Lines: 0 443 0.0 %
Date: 2017-11-07 Branches: 0 323 0.0 %

Line Branch Exec Source
1
/* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 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
27
#include <sys/types.h>
28
#include <sys/stat.h>
29
30
#include <errno.h>
31
#include <fcntl.h>
32
#include <paths.h>
33
#include <pwd.h>
34
#include <signal.h>
35
#include <stdio.h>
36
#include <stdarg.h>
37
#include <string.h>
38
#include <time.h>
39
#include <unistd.h>
40
#include <limits.h>
41
42
#include "xmalloc.h"
43
#include "ssh.h"
44
#include "ssh2.h"
45
#include "packet.h"
46
#include "buffer.h"
47
#include "log.h"
48
#include "misc.h"
49
#include "servconf.h"
50
#include "compat.h"
51
#include "sshkey.h"
52
#include "hostfile.h"
53
#include "auth.h"
54
#include "pathnames.h"
55
#include "uidswap.h"
56
#include "auth-options.h"
57
#include "canohost.h"
58
#ifdef GSSAPI
59
#include "ssh-gss.h"
60
#endif
61
#include "monitor_wrap.h"
62
#include "authfile.h"
63
#include "match.h"
64
#include "ssherr.h"
65
#include "channels.h" /* XXX for session.h */
66
#include "session.h" /* XXX for child_set_env(); refactor? */
67
68
/* import */
69
extern ServerOptions options;
70
extern u_char *session_id2;
71
extern u_int session_id2_len;
72
73
static int
74
userauth_pubkey(struct ssh *ssh)
75
{
76
	Authctxt *authctxt = ssh->authctxt;
77
	struct sshbuf *b;
78
	struct sshkey *key = NULL;
79
	char *pkalg, *userstyle = NULL, *fp = NULL;
80
	u_char *pkblob, *sig, have_sig;
81
	size_t blen, slen;
82
	int r, pktype;
83
	int authenticated = 0;
84
85
	if (!authctxt->valid) {
86
		debug2("%s: disabled because of invalid user", __func__);
87
		return 0;
88
	}
89
	if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0)
90
		fatal("%s: sshpkt_get_u8 failed: %s", __func__, ssh_err(r));
91
	if (ssh->compat & SSH_BUG_PKAUTH) {
92
		debug2("%s: SSH_BUG_PKAUTH", __func__);
93
		if ((b = sshbuf_new()) == NULL)
94
			fatal("%s: sshbuf_new failed", __func__);
95
		/* no explicit pkalg given */
96
		/* so we have to extract the pkalg from the pkblob */
97
		/* XXX use sshbuf_from() */
98
		if ((r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
99
		    (r = sshbuf_put(b, pkblob, blen)) != 0 ||
100
		    (r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0)
101
			fatal("%s: failed: %s", __func__, ssh_err(r));
102
		sshbuf_free(b);
103
	} else {
104
		if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
105
		    (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
106
			fatal("%s: sshpkt_get_cstring failed: %s",
107
			    __func__, ssh_err(r));
108
	}
109
	pktype = sshkey_type_from_name(pkalg);
110
	if (pktype == KEY_UNSPEC) {
111
		/* this is perfectly legal */
112
		logit("%s: unsupported public key algorithm: %s",
113
		    __func__, pkalg);
114
		goto done;
115
	}
116
	if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) {
117
		error("%s: could not parse key: %s", __func__, ssh_err(r));
118
		goto done;
119
	}
120
	if (key == NULL) {
121
		error("%s: cannot decode key: %s", __func__, pkalg);
122
		goto done;
123
	}
124
	if (key->type != pktype) {
125
		error("%s: type mismatch for decoded key "
126
		    "(received %d, expected %d)", __func__, key->type, pktype);
127
		goto done;
128
	}
129
	if (sshkey_type_plain(key->type) == KEY_RSA &&
130
	    (ssh->compat & SSH_BUG_RSASIGMD5) != 0) {
131
		logit("Refusing RSA key because client uses unsafe "
132
		    "signature scheme");
133
		goto done;
134
	}
135
	fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
136
	if (auth2_key_already_used(authctxt, key)) {
137
		logit("refusing previously-used %s key", sshkey_type(key));
138
		goto done;
139
	}
140
	if (match_pattern_list(sshkey_ssh_name(key),
141
	    options.pubkey_key_types, 0) != 1) {
142
		logit("%s: key type %s not in PubkeyAcceptedKeyTypes",
143
		    __func__, sshkey_ssh_name(key));
144
		goto done;
145
	}
146
147
	if (have_sig) {
148
		debug3("%s: have signature for %s %s",
149
		    __func__, sshkey_type(key), fp);
150
		if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 ||
151
		    (r = sshpkt_get_end(ssh)) != 0)
152
			fatal("%s: %s", __func__, ssh_err(r));
153
		if ((b = sshbuf_new()) == NULL)
154
			fatal("%s: sshbuf_new failed", __func__);
155
		if (ssh->compat & SSH_OLD_SESSIONID) {
156
			if ((r = sshbuf_put(b, session_id2,
157
			    session_id2_len)) != 0)
158
				fatal("%s: sshbuf_put session id: %s",
159
				    __func__, ssh_err(r));
160
		} else {
161
			if ((r = sshbuf_put_string(b, session_id2,
162
			    session_id2_len)) != 0)
163
				fatal("%s: sshbuf_put_string session id: %s",
164
				    __func__, ssh_err(r));
165
		}
166
		/* reconstruct packet */
167
		xasprintf(&userstyle, "%s%s%s", authctxt->user,
168
		    authctxt->style ? ":" : "",
169
		    authctxt->style ? authctxt->style : "");
170
		if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
171
		    (r = sshbuf_put_cstring(b, userstyle)) != 0 ||
172
		    (r = sshbuf_put_cstring(b, ssh->compat & SSH_BUG_PKSERVICE ?
173
		    "ssh-userauth" : authctxt->service)) != 0)
174
			fatal("%s: build packet failed: %s",
175
			    __func__, ssh_err(r));
176
		if (ssh->compat & SSH_BUG_PKAUTH) {
177
			if ((r = sshbuf_put_u8(b, have_sig)) != 0)
178
				fatal("%s: build packet failed: %s",
179
				    __func__, ssh_err(r));
180
		} else {
181
			if ((r = sshbuf_put_cstring(b, "publickey")) != 0 ||
182
			    (r = sshbuf_put_u8(b, have_sig)) != 0 ||
183
			    (r = sshbuf_put_cstring(b, pkalg) != 0))
184
				fatal("%s: build packet failed: %s",
185
				    __func__, ssh_err(r));
186
		}
187
		if ((r = sshbuf_put_string(b, pkblob, blen)) != 0)
188
			fatal("%s: build packet failed: %s",
189
			    __func__, ssh_err(r));
190
#ifdef DEBUG_PK
191
		sshbuf_dump(b, stderr);
192
#endif
193
194
		/* test for correct signature */
195
		authenticated = 0;
196
		if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
197
		    PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
198
		    sshbuf_len(b), ssh->compat)) == 0) {
199
			authenticated = 1;
200
		}
201
		sshbuf_free(b);
202
		free(sig);
203
		auth2_record_key(authctxt, authenticated, key);
204
	} else {
205
		debug("%s: test whether pkalg/pkblob are acceptable for %s %s",
206
		    __func__, sshkey_type(key), fp);
207
		if ((r = sshpkt_get_end(ssh)) != 0)
208
			fatal("%s: %s", __func__, ssh_err(r));
209
210
		/* XXX fake reply and always send PK_OK ? */
211
		/*
212
		 * XXX this allows testing whether a user is allowed
213
		 * to login: if you happen to have a valid pubkey this
214
		 * message is sent. the message is NEVER sent at all
215
		 * if a user is not allowed to login. is this an
216
		 * issue? -markus
217
		 */
218
		if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) {
219
			if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
220
			    != 0 ||
221
			    (r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
222
			    (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 ||
223
			    (r = sshpkt_send(ssh)) != 0)
224
				fatal("%s: %s", __func__, ssh_err(r));
225
			ssh_packet_write_wait(ssh);
226
			authctxt->postponed = 1;
227
		}
228
	}
229
	if (authenticated != 1)
230
		auth_clear_options();
231
done:
232
	debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
233
	sshkey_free(key);
234
	free(userstyle);
235
	free(pkalg);
236
	free(pkblob);
237
	free(fp);
238
	return authenticated;
239
}
240
241
static int
242
match_principals_option(const char *principal_list, struct sshkey_cert *cert)
243
{
244
	char *result;
245
	u_int i;
246
247
	/* XXX percent_expand() sequences for authorized_principals? */
248
249
	for (i = 0; i < cert->nprincipals; i++) {
250
		if ((result = match_list(cert->principals[i],
251
		    principal_list, NULL)) != NULL) {
252
			debug3("matched principal from key options \"%.100s\"",
253
			    result);
254
			free(result);
255
			return 1;
256
		}
257
	}
258
	return 0;
259
}
260
261
static int
262
process_principals(FILE *f, const char *file, struct passwd *pw,
263
    const struct sshkey_cert *cert)
264
{
265
	char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
266
	u_long linenum = 0;
267
	u_int i, found_principal = 0;
268
269
	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
270
		/* Always consume entire input */
271
		if (found_principal)
272
			continue;
273
		/* Skip leading whitespace. */
274
		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
275
			;
276
		/* Skip blank and comment lines. */
277
		if ((ep = strchr(cp, '#')) != NULL)
278
			*ep = '\0';
279
		if (!*cp || *cp == '\n')
280
			continue;
281
		/* Trim trailing whitespace. */
282
		ep = cp + strlen(cp) - 1;
283
		while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
284
			*ep-- = '\0';
285
		/*
286
		 * If the line has internal whitespace then assume it has
287
		 * key options.
288
		 */
289
		line_opts = NULL;
290
		if ((ep = strrchr(cp, ' ')) != NULL ||
291
		    (ep = strrchr(cp, '\t')) != NULL) {
292
			for (; *ep == ' ' || *ep == '\t'; ep++)
293
				;
294
			line_opts = cp;
295
			cp = ep;
296
		}
297
		for (i = 0; i < cert->nprincipals; i++) {
298
			if (strcmp(cp, cert->principals[i]) == 0) {
299
				debug3("%s:%lu: matched principal \"%.100s\"",
300
				    file, linenum, cert->principals[i]);
301
				if (auth_parse_options(pw, line_opts,
302
				    file, linenum) != 1)
303
					continue;
304
				found_principal = 1;
305
				continue;
306
			}
307
		}
308
	}
309
	return found_principal;
310
}
311
312
static int
313
match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
314
{
315
	FILE *f;
316
	int success;
317
318
	temporarily_use_uid(pw);
319
	debug("trying authorized principals file %s", file);
320
	if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
321
		restore_uid();
322
		return 0;
323
	}
324
	success = process_principals(f, file, pw, cert);
325
	fclose(f);
326
	restore_uid();
327
	return success;
328
}
329
330
/*
331
 * Checks whether principal is allowed in output of command.
332
 * returns 1 if the principal is allowed or 0 otherwise.
333
 */
334
static int
335
match_principals_command(struct passwd *user_pw, const struct sshkey *key)
336
{
337
	const struct sshkey_cert *cert = key->cert;
338
	FILE *f = NULL;
339
	int r, ok, found_principal = 0;
340
	struct passwd *pw;
341
	int i, ac = 0, uid_swapped = 0;
342
	pid_t pid;
343
	char *tmp, *username = NULL, *command = NULL, **av = NULL;
344
	char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL;
345
	char serial_s[16];
346
	void (*osigchld)(int);
347
348
	if (options.authorized_principals_command == NULL)
349
		return 0;
350
	if (options.authorized_principals_command_user == NULL) {
351
		error("No user for AuthorizedPrincipalsCommand specified, "
352
		    "skipping");
353
		return 0;
354
	}
355
356
	/*
357
	 * NB. all returns later this function should go via "out" to
358
	 * ensure the original SIGCHLD handler is restored properly.
359
	 */
360
	osigchld = signal(SIGCHLD, SIG_DFL);
361
362
	/* Prepare and verify the user for the command */
363
	username = percent_expand(options.authorized_principals_command_user,
364
	    "u", user_pw->pw_name, (char *)NULL);
365
	pw = getpwnam(username);
366
	if (pw == NULL) {
367
		error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
368
		    username, strerror(errno));
369
		goto out;
370
	}
371
372
	/* Turn the command into an argument vector */
373
	if (argv_split(options.authorized_principals_command, &ac, &av) != 0) {
374
		error("AuthorizedPrincipalsCommand \"%s\" contains "
375
		    "invalid quotes", command);
376
		goto out;
377
	}
378
	if (ac == 0) {
379
		error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments",
380
		    command);
381
		goto out;
382
	}
383
	if ((ca_fp = sshkey_fingerprint(cert->signature_key,
384
	    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
385
		error("%s: sshkey_fingerprint failed", __func__);
386
		goto out;
387
	}
388
	if ((key_fp = sshkey_fingerprint(key,
389
	    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
390
		error("%s: sshkey_fingerprint failed", __func__);
391
		goto out;
392
	}
393
	if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) {
394
		error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
395
		goto out;
396
	}
397
	if ((r = sshkey_to_base64(key, &keytext)) != 0) {
398
		error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
399
		goto out;
400
	}
401
	snprintf(serial_s, sizeof(serial_s), "%llu",
402
	    (unsigned long long)cert->serial);
403
	for (i = 1; i < ac; i++) {
404
		tmp = percent_expand(av[i],
405
		    "u", user_pw->pw_name,
406
		    "h", user_pw->pw_dir,
407
		    "t", sshkey_ssh_name(key),
408
		    "T", sshkey_ssh_name(cert->signature_key),
409
		    "f", key_fp,
410
		    "F", ca_fp,
411
		    "k", keytext,
412
		    "K", catext,
413
		    "i", cert->key_id,
414
		    "s", serial_s,
415
		    (char *)NULL);
416
		if (tmp == NULL)
417
			fatal("%s: percent_expand failed", __func__);
418
		free(av[i]);
419
		av[i] = tmp;
420
	}
421
	/* Prepare a printable command for logs, etc. */
422
	command = argv_assemble(ac, av);
423
424
	if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command,
425
	    ac, av, &f,
426
	    SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
427
		goto out;
428
429
	uid_swapped = 1;
430
	temporarily_use_uid(pw);
431
432
	ok = process_principals(f, "(command)", pw, cert);
433
434
	fclose(f);
435
	f = NULL;
436
437
	if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0)
438
		goto out;
439
440
	/* Read completed successfully */
441
	found_principal = ok;
442
 out:
443
	if (f != NULL)
444
		fclose(f);
445
	signal(SIGCHLD, osigchld);
446
	for (i = 0; i < ac; i++)
447
		free(av[i]);
448
	free(av);
449
	if (uid_swapped)
450
		restore_uid();
451
	free(command);
452
	free(username);
453
	free(ca_fp);
454
	free(key_fp);
455
	free(catext);
456
	free(keytext);
457
	return found_principal;
458
}
459
/*
460
 * Checks whether key is allowed in authorized_keys-format file,
461
 * returns 1 if the key is allowed or 0 otherwise.
462
 */
463
static int
464
check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw)
465
{
466
	char line[SSH_MAX_PUBKEY_BYTES];
467
	int found_key = 0;
468
	u_long linenum = 0;
469
	struct sshkey *found = NULL;
470
471
	while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
472
		char *cp, *key_options = NULL, *fp = NULL;
473
		const char *reason = NULL;
474
475
		/* Always consume entire file */
476
		if (found_key)
477
			continue;
478
		if (found != NULL)
479
			sshkey_free(found);
480
		found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type);
481
		if (found == NULL)
482
			goto done;
483
		auth_clear_options();
484
485
		/* Skip leading whitespace, empty and comment lines. */
486
		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
487
			;
488
		if (!*cp || *cp == '\n' || *cp == '#')
489
			continue;
490
491
		if (sshkey_read(found, &cp) != 0) {
492
			/* no key?  check if there are options for this key */
493
			int quoted = 0;
494
			debug2("user_key_allowed: check options: '%s'", cp);
495
			key_options = cp;
496
			for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
497
				if (*cp == '\\' && cp[1] == '"')
498
					cp++;	/* Skip both */
499
				else if (*cp == '"')
500
					quoted = !quoted;
501
			}
502
			/* Skip remaining whitespace. */
503
			for (; *cp == ' ' || *cp == '\t'; cp++)
504
				;
505
			if (sshkey_read(found, &cp) != 0) {
506
				debug2("user_key_allowed: advance: '%s'", cp);
507
				/* still no key?  advance to next line*/
508
				continue;
509
			}
510
		}
511
		if (sshkey_is_cert(key)) {
512
			if (!sshkey_equal(found, key->cert->signature_key))
513
				continue;
514
			if (auth_parse_options(pw, key_options, file,
515
			    linenum) != 1)
516
				continue;
517
			if (!key_is_cert_authority)
518
				continue;
519
			if ((fp = sshkey_fingerprint(found,
520
			    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
521
				continue;
522
			debug("matching CA found: file %s, line %lu, %s %s",
523
			    file, linenum, sshkey_type(found), fp);
524
			/*
525
			 * If the user has specified a list of principals as
526
			 * a key option, then prefer that list to matching
527
			 * their username in the certificate principals list.
528
			 */
529
			if (authorized_principals != NULL &&
530
			    !match_principals_option(authorized_principals,
531
			    key->cert)) {
532
				reason = "Certificate does not contain an "
533
				    "authorized principal";
534
 fail_reason:
535
				free(fp);
536
				error("%s", reason);
537
				auth_debug_add("%s", reason);
538
				continue;
539
			}
540
			if (sshkey_cert_check_authority(key, 0, 0,
541
			    authorized_principals == NULL ? pw->pw_name : NULL,
542
			    &reason) != 0)
543
				goto fail_reason;
544
			if (auth_cert_options(key, pw, &reason) != 0)
545
				goto fail_reason;
546
			verbose("Accepted certificate ID \"%s\" (serial %llu) "
547
			    "signed by %s CA %s via %s", key->cert->key_id,
548
			    (unsigned long long)key->cert->serial,
549
			    sshkey_type(found), fp, file);
550
			free(fp);
551
			found_key = 1;
552
			break;
553
		} else if (sshkey_equal(found, key)) {
554
			if (auth_parse_options(pw, key_options, file,
555
			    linenum) != 1)
556
				continue;
557
			if (key_is_cert_authority)
558
				continue;
559
			if ((fp = sshkey_fingerprint(found,
560
			    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
561
				continue;
562
			debug("matching key found: file %s, line %lu %s %s",
563
			    file, linenum, sshkey_type(found), fp);
564
			free(fp);
565
			found_key = 1;
566
			continue;
567
		}
568
	}
569
 done:
570
	if (found != NULL)
571
		sshkey_free(found);
572
	if (!found_key)
573
		debug2("key not found");
574
	return found_key;
575
}
576
577
/* Authenticate a certificate key against TrustedUserCAKeys */
578
static int
579
user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
580
{
581
	char *ca_fp, *principals_file = NULL;
582
	const char *reason;
583
	int r, ret = 0, found_principal = 0, use_authorized_principals;
584
585
	if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL)
586
		return 0;
587
588
	if ((ca_fp = sshkey_fingerprint(key->cert->signature_key,
589
	    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
590
		return 0;
591
592
	if ((r = sshkey_in_file(key->cert->signature_key,
593
	    options.trusted_user_ca_keys, 1, 0)) != 0) {
594
		debug2("%s: CA %s %s is not listed in %s: %s", __func__,
595
		    sshkey_type(key->cert->signature_key), ca_fp,
596
		    options.trusted_user_ca_keys, ssh_err(r));
597
		goto out;
598
	}
599
	/*
600
	 * If AuthorizedPrincipals is in use, then compare the certificate
601
	 * principals against the names in that file rather than matching
602
	 * against the username.
603
	 */
604
	if ((principals_file = authorized_principals_file(pw)) != NULL) {
605
		if (match_principals_file(principals_file, pw, key->cert))
606
			found_principal = 1;
607
	}
608
	/* Try querying command if specified */
609
	if (!found_principal && match_principals_command(pw, key))
610
		found_principal = 1;
611
	/* If principals file or command is specified, then require a match */
612
	use_authorized_principals = principals_file != NULL ||
613
            options.authorized_principals_command != NULL;
614
	if (!found_principal && use_authorized_principals) {
615
		reason = "Certificate does not contain an authorized principal";
616
 fail_reason:
617
		error("%s", reason);
618
		auth_debug_add("%s", reason);
619
		goto out;
620
	}
621
	if (sshkey_cert_check_authority(key, 0, 1,
622
	    use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
623
		goto fail_reason;
624
	if (auth_cert_options(key, pw, &reason) != 0)
625
		goto fail_reason;
626
627
	verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
628
	    "%s CA %s via %s", key->cert->key_id,
629
	    (unsigned long long)key->cert->serial,
630
	    sshkey_type(key->cert->signature_key), ca_fp,
631
	    options.trusted_user_ca_keys);
632
	ret = 1;
633
634
 out:
635
	free(principals_file);
636
	free(ca_fp);
637
	return ret;
638
}
639
640
/*
641
 * Checks whether key is allowed in file.
642
 * returns 1 if the key is allowed or 0 otherwise.
643
 */
644
static int
645
user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file)
646
{
647
	FILE *f;
648
	int found_key = 0;
649
650
	/* Temporarily use the user's uid. */
651
	temporarily_use_uid(pw);
652
653
	debug("trying public key file %s", file);
654
	if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
655
		found_key = check_authkeys_file(f, file, key, pw);
656
		fclose(f);
657
	}
658
659
	restore_uid();
660
	return found_key;
661
}
662
663
/*
664
 * Checks whether key is allowed in output of command.
665
 * returns 1 if the key is allowed or 0 otherwise.
666
 */
667
static int
668
user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
669
{
670
	FILE *f = NULL;
671
	int r, ok, found_key = 0;
672
	struct passwd *pw;
673
	int i, uid_swapped = 0, ac = 0;
674
	pid_t pid;
675
	char *username = NULL, *key_fp = NULL, *keytext = NULL;
676
	char *tmp, *command = NULL, **av = NULL;
677
	void (*osigchld)(int);
678
679
	if (options.authorized_keys_command == NULL)
680
		return 0;
681
	if (options.authorized_keys_command_user == NULL) {
682
		error("No user for AuthorizedKeysCommand specified, skipping");
683
		return 0;
684
	}
685
686
	/*
687
	 * NB. all returns later this function should go via "out" to
688
	 * ensure the original SIGCHLD handler is restored properly.
689
	 */
690
	osigchld = signal(SIGCHLD, SIG_DFL);
691
692
	/* Prepare and verify the user for the command */
693
	username = percent_expand(options.authorized_keys_command_user,
694
	    "u", user_pw->pw_name, (char *)NULL);
695
	pw = getpwnam(username);
696
	if (pw == NULL) {
697
		error("AuthorizedKeysCommandUser \"%s\" not found: %s",
698
		    username, strerror(errno));
699
		goto out;
700
	}
701
702
	/* Prepare AuthorizedKeysCommand */
703
	if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash,
704
	    SSH_FP_DEFAULT)) == NULL) {
705
		error("%s: sshkey_fingerprint failed", __func__);
706
		goto out;
707
	}
708
	if ((r = sshkey_to_base64(key, &keytext)) != 0) {
709
		error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r));
710
		goto out;
711
	}
712
713
	/* Turn the command into an argument vector */
714
	if (argv_split(options.authorized_keys_command, &ac, &av) != 0) {
715
		error("AuthorizedKeysCommand \"%s\" contains invalid quotes",
716
		    command);
717
		goto out;
718
	}
719
	if (ac == 0) {
720
		error("AuthorizedKeysCommand \"%s\" yielded no arguments",
721
		    command);
722
		goto out;
723
	}
724
	for (i = 1; i < ac; i++) {
725
		tmp = percent_expand(av[i],
726
		    "u", user_pw->pw_name,
727
		    "h", user_pw->pw_dir,
728
		    "t", sshkey_ssh_name(key),
729
		    "f", key_fp,
730
		    "k", keytext,
731
		    (char *)NULL);
732
		if (tmp == NULL)
733
			fatal("%s: percent_expand failed", __func__);
734
		free(av[i]);
735
		av[i] = tmp;
736
	}
737
	/* Prepare a printable command for logs, etc. */
738
	command = argv_assemble(ac, av);
739
740
	/*
741
	 * If AuthorizedKeysCommand was run without arguments
742
	 * then fall back to the old behaviour of passing the
743
	 * target username as a single argument.
744
	 */
745
	if (ac == 1) {
746
		av = xreallocarray(av, ac + 2, sizeof(*av));
747
		av[1] = xstrdup(user_pw->pw_name);
748
		av[2] = NULL;
749
		/* Fix up command too, since it is used in log messages */
750
		free(command);
751
		xasprintf(&command, "%s %s", av[0], av[1]);
752
	}
753
754
	if ((pid = subprocess("AuthorizedKeysCommand", pw, command,
755
	    ac, av, &f,
756
	    SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
757
		goto out;
758
759
	uid_swapped = 1;
760
	temporarily_use_uid(pw);
761
762
	ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
763
764
	fclose(f);
765
	f = NULL;
766
767
	if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0)
768
		goto out;
769
770
	/* Read completed successfully */
771
	found_key = ok;
772
 out:
773
	if (f != NULL)
774
		fclose(f);
775
	signal(SIGCHLD, osigchld);
776
	for (i = 0; i < ac; i++)
777
		free(av[i]);
778
	free(av);
779
	if (uid_swapped)
780
		restore_uid();
781
	free(command);
782
	free(username);
783
	free(key_fp);
784
	free(keytext);
785
	return found_key;
786
}
787
788
/*
789
 * Check whether key authenticates and authorises the user.
790
 */
791
int
792
user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
793
{
794
	u_int success, i;
795
	char *file;
796
797
	if (auth_key_is_revoked(key))
798
		return 0;
799
	if (sshkey_is_cert(key) &&
800
	    auth_key_is_revoked(key->cert->signature_key))
801
		return 0;
802
803
	success = user_cert_trusted_ca(pw, key);
804
	if (success)
805
		return success;
806
807
	success = user_key_command_allowed2(pw, key);
808
	if (success > 0)
809
		return success;
810
811
	for (i = 0; !success && i < options.num_authkeys_files; i++) {
812
813
		if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
814
			continue;
815
		file = expand_authorized_keys(
816
		    options.authorized_keys_files[i], pw);
817
818
		success = user_key_allowed2(pw, key, file);
819
		free(file);
820
	}
821
822
	return success;
823
}
824
825
Authmethod method_pubkey = {
826
	"publickey",
827
	userauth_pubkey,
828
	&options.pubkey_authentication
829
};