summaryrefslogtreecommitdiff
path: root/auth2-pubkey.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2018-03-03 03:15:51 +0000
committerDamien Miller <djm@mindrot.org>2018-03-03 14:37:16 +1100
commit7c856857607112a3dfe6414696bf4c7ab7fb0cb3 (patch)
tree48c837fc9c9e11d64862d4f54c1a886b54d8721c /auth2-pubkey.c
parent90c4bec8b5f9ec4c003ae4abdf13fc7766f00c8b (diff)
upstream: switch over to the new authorized_keys options API and
remove the legacy one. Includes a fairly big refactor of auth2-pubkey.c to retain less state between key file lines. feedback and ok markus@ OpenBSD-Commit-ID: dece6cae0f47751b9892080eb13d6625599573df
Diffstat (limited to 'auth2-pubkey.c')
-rw-r--r--auth2-pubkey.c532
1 files changed, 365 insertions, 167 deletions
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index 8fb7ffe71..8024b1d6a 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: auth2-pubkey.c,v 1.76 2018/02/07 22:52:45 dtucker Exp $ */ 1/* $OpenBSD: auth2-pubkey.c,v 1.77 2018/03/03 03:15:51 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * 4 *
@@ -88,6 +88,7 @@ static int
88userauth_pubkey(struct ssh *ssh) 88userauth_pubkey(struct ssh *ssh)
89{ 89{
90 Authctxt *authctxt = ssh->authctxt; 90 Authctxt *authctxt = ssh->authctxt;
91 struct passwd *pw = authctxt->pw;
91 struct sshbuf *b; 92 struct sshbuf *b;
92 struct sshkey *key = NULL; 93 struct sshkey *key = NULL;
93 char *pkalg, *userstyle = NULL, *key_s = NULL, *ca_s = NULL; 94 char *pkalg, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
@@ -95,6 +96,7 @@ userauth_pubkey(struct ssh *ssh)
95 size_t blen, slen; 96 size_t blen, slen;
96 int r, pktype; 97 int r, pktype;
97 int authenticated = 0; 98 int authenticated = 0;
99 struct sshauthopt *authopts = NULL;
98 100
99 if (!authctxt->valid) { 101 if (!authctxt->valid) {
100 debug2("%s: disabled because of invalid user", __func__); 102 debug2("%s: disabled because of invalid user", __func__);
@@ -185,7 +187,7 @@ userauth_pubkey(struct ssh *ssh)
185 187
186 /* test for correct signature */ 188 /* test for correct signature */
187 authenticated = 0; 189 authenticated = 0;
188 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && 190 if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) &&
189 PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), 191 PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
190 sshbuf_len(b), NULL, ssh->compat)) == 0) { 192 sshbuf_len(b), NULL, ssh->compat)) == 0) {
191 authenticated = 1; 193 authenticated = 1;
@@ -210,7 +212,7 @@ userauth_pubkey(struct ssh *ssh)
210 * if a user is not allowed to login. is this an 212 * if a user is not allowed to login. is this an
211 * issue? -markus 213 * issue? -markus
212 */ 214 */
213 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { 215 if (PRIVSEP(user_key_allowed(ssh, pw, key, 0, NULL))) {
214 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK)) 216 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK))
215 != 0 || 217 != 0 ||
216 (r = sshpkt_put_cstring(ssh, pkalg)) != 0 || 218 (r = sshpkt_put_cstring(ssh, pkalg)) != 0 ||
@@ -221,10 +223,14 @@ userauth_pubkey(struct ssh *ssh)
221 authctxt->postponed = 1; 223 authctxt->postponed = 1;
222 } 224 }
223 } 225 }
224 if (authenticated != 1)
225 auth_clear_options();
226done: 226done:
227 if (authenticated == 1 && auth_activate_options(ssh, authopts) != 0) {
228 debug("%s: key options inconsistent with existing", __func__);
229 authenticated = 0;
230 }
227 debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); 231 debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg);
232
233 sshauthopt_free(authopts);
228 sshkey_free(key); 234 sshkey_free(key);
229 free(userstyle); 235 free(userstyle);
230 free(pkalg); 236 free(pkalg);
@@ -254,18 +260,77 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert)
254 return 0; 260 return 0;
255} 261}
256 262
263/*
264 * Process a single authorized_principals format line. Returns 0 and sets
265 * authoptsp is principal is authorised, -1 otherwise. "loc" is used as a
266 * log preamble for file/line information.
267 */
268static int
269check_principals_line(struct ssh *ssh, char *cp, const struct sshkey_cert *cert,
270 const char *loc, struct sshauthopt **authoptsp)
271{
272 u_int i, found = 0;
273 char *ep, *line_opts;
274 const char *reason = NULL;
275 struct sshauthopt *opts = NULL;
276
277 if (authoptsp != NULL)
278 *authoptsp = NULL;
279
280 /* Trim trailing whitespace. */
281 ep = cp + strlen(cp) - 1;
282 while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
283 *ep-- = '\0';
284
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 if ((opts = sshauthopt_parse(line_opts, &reason)) == NULL) {
298 debug("%s: bad principals options: %s", loc, reason);
299 auth_debug_add("%s: bad principals options: %s", loc, reason);
300 return -1;
301 }
302 /* Check principals in cert against those on line */
303 for (i = 0; i < cert->nprincipals; i++) {
304 if (strcmp(cp, cert->principals[i]) != 0)
305 continue;
306 debug3("%s: matched principal \"%.100s\"",
307 loc, cert->principals[i]);
308 found = 1;
309 }
310 if (found && authoptsp != NULL) {
311 *authoptsp = opts;
312 opts = NULL;
313 }
314 sshauthopt_free(opts);
315 return found ? 0 : -1;
316}
317
257static int 318static int
258process_principals(FILE *f, const char *file, struct passwd *pw, 319process_principals(struct ssh *ssh, FILE *f, const char *file,
259 const struct sshkey_cert *cert) 320 const struct sshkey_cert *cert, struct sshauthopt **authoptsp)
260{ 321{
261 char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; 322 char loc[256], line[SSH_MAX_PUBKEY_BYTES], *cp, *ep;
262 u_long linenum = 0; 323 u_long linenum = 0;
263 u_int i, found_principal = 0; 324 u_int found_principal = 0;
325
326 if (authoptsp != NULL)
327 *authoptsp = NULL;
264 328
265 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 329 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
266 /* Always consume entire input */ 330 /* Always consume entire input */
267 if (found_principal) 331 if (found_principal)
268 continue; 332 continue;
333
269 /* Skip leading whitespace. */ 334 /* Skip leading whitespace. */
270 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 335 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
271 ; 336 ;
@@ -274,50 +339,33 @@ process_principals(FILE *f, const char *file, struct passwd *pw,
274 *ep = '\0'; 339 *ep = '\0';
275 if (!*cp || *cp == '\n') 340 if (!*cp || *cp == '\n')
276 continue; 341 continue;
277 /* Trim trailing whitespace. */ 342
278 ep = cp + strlen(cp) - 1; 343 snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
279 while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) 344 if (check_principals_line(ssh, cp, cert, loc, authoptsp) == 0)
280 *ep-- = '\0'; 345 found_principal = 1;
281 /*
282 * If the line has internal whitespace then assume it has
283 * key options.
284 */
285 line_opts = NULL;
286 if ((ep = strrchr(cp, ' ')) != NULL ||
287 (ep = strrchr(cp, '\t')) != NULL) {
288 for (; *ep == ' ' || *ep == '\t'; ep++)
289 ;
290 line_opts = cp;
291 cp = ep;
292 }
293 for (i = 0; i < cert->nprincipals; i++) {
294 if (strcmp(cp, cert->principals[i]) == 0) {
295 debug3("%s:%lu: matched principal \"%.100s\"",
296 file, linenum, cert->principals[i]);
297 if (auth_parse_options(pw, line_opts,
298 file, linenum) != 1)
299 continue;
300 found_principal = 1;
301 continue;
302 }
303 }
304 } 346 }
305 return found_principal; 347 return found_principal;
306} 348}
307 349
350/* XXX remove pw args here and elsewhere once ssh->authctxt is guaranteed */
351
308static int 352static int
309match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) 353match_principals_file(struct ssh *ssh, struct passwd *pw, char *file,
354 struct sshkey_cert *cert, struct sshauthopt **authoptsp)
310{ 355{
311 FILE *f; 356 FILE *f;
312 int success; 357 int success;
313 358
359 if (authoptsp != NULL)
360 *authoptsp = NULL;
361
314 temporarily_use_uid(pw); 362 temporarily_use_uid(pw);
315 debug("trying authorized principals file %s", file); 363 debug("trying authorized principals file %s", file);
316 if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { 364 if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
317 restore_uid(); 365 restore_uid();
318 return 0; 366 return 0;
319 } 367 }
320 success = process_principals(f, file, pw, cert); 368 success = process_principals(ssh, f, file, cert, authoptsp);
321 fclose(f); 369 fclose(f);
322 restore_uid(); 370 restore_uid();
323 return success; 371 return success;
@@ -328,12 +376,13 @@ match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert)
328 * returns 1 if the principal is allowed or 0 otherwise. 376 * returns 1 if the principal is allowed or 0 otherwise.
329 */ 377 */
330static int 378static int
331match_principals_command(struct passwd *user_pw, const struct sshkey *key) 379match_principals_command(struct ssh *ssh, struct passwd *user_pw,
380 const struct sshkey *key, struct sshauthopt **authoptsp)
332{ 381{
382 struct passwd *runas_pw = NULL;
333 const struct sshkey_cert *cert = key->cert; 383 const struct sshkey_cert *cert = key->cert;
334 FILE *f = NULL; 384 FILE *f = NULL;
335 int r, ok, found_principal = 0; 385 int r, ok, found_principal = 0;
336 struct passwd *pw;
337 int i, ac = 0, uid_swapped = 0; 386 int i, ac = 0, uid_swapped = 0;
338 pid_t pid; 387 pid_t pid;
339 char *tmp, *username = NULL, *command = NULL, **av = NULL; 388 char *tmp, *username = NULL, *command = NULL, **av = NULL;
@@ -341,6 +390,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
341 char serial_s[16]; 390 char serial_s[16];
342 void (*osigchld)(int); 391 void (*osigchld)(int);
343 392
393 if (authoptsp != NULL)
394 *authoptsp = NULL;
344 if (options.authorized_principals_command == NULL) 395 if (options.authorized_principals_command == NULL)
345 return 0; 396 return 0;
346 if (options.authorized_principals_command_user == NULL) { 397 if (options.authorized_principals_command_user == NULL) {
@@ -358,8 +409,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
358 /* Prepare and verify the user for the command */ 409 /* Prepare and verify the user for the command */
359 username = percent_expand(options.authorized_principals_command_user, 410 username = percent_expand(options.authorized_principals_command_user,
360 "u", user_pw->pw_name, (char *)NULL); 411 "u", user_pw->pw_name, (char *)NULL);
361 pw = getpwnam(username); 412 runas_pw = getpwnam(username);
362 if (pw == NULL) { 413 if (runas_pw == NULL) {
363 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", 414 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s",
364 username, strerror(errno)); 415 username, strerror(errno));
365 goto out; 416 goto out;
@@ -417,15 +468,15 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
417 /* Prepare a printable command for logs, etc. */ 468 /* Prepare a printable command for logs, etc. */
418 command = argv_assemble(ac, av); 469 command = argv_assemble(ac, av);
419 470
420 if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, 471 if ((pid = subprocess("AuthorizedPrincipalsCommand", runas_pw, command,
421 ac, av, &f, 472 ac, av, &f,
422 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) 473 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
423 goto out; 474 goto out;
424 475
425 uid_swapped = 1; 476 uid_swapped = 1;
426 temporarily_use_uid(pw); 477 temporarily_use_uid(runas_pw);
427 478
428 ok = process_principals(f, "(command)", pw, cert); 479 ok = process_principals(ssh, f, "(command)", cert, authoptsp);
429 480
430 fclose(f); 481 fclose(f);
431 f = NULL; 482 f = NULL;
@@ -452,130 +503,225 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key)
452 free(keytext); 503 free(keytext);
453 return found_principal; 504 return found_principal;
454} 505}
506
507static void
508skip_space(char **cpp)
509{
510 char *cp;
511
512 for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
513 ;
514 *cpp = cp;
515}
516
517/*
518 * Advanced *cpp past the end of key options, defined as the first unquoted
519 * whitespace character. Returns 0 on success or -1 on failure (e.g.
520 * unterminated quotes).
521 */
522static int
523advance_past_options(char **cpp)
524{
525 char *cp = *cpp;
526 int quoted = 0;
527
528 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
529 if (*cp == '\\' && cp[1] == '"')
530 cp++; /* Skip both */
531 else if (*cp == '"')
532 quoted = !quoted;
533 }
534 *cpp = cp;
535 /* return failure for unterminated quotes */
536 return (*cp == '\0' && quoted) ? -1 : 0;
537}
538
539/*
540 * Check a single line of an authorized_keys-format file. Returns 0 if key
541 * matches, -1 otherwise. Will return key/cert options via *authoptsp
542 * on success. "loc" is used as file/line location in log messages.
543 */
544static int
545check_authkey_line(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
546 char *cp, const char *loc, struct sshauthopt **authoptsp)
547{
548 int want_keytype = sshkey_is_cert(key) ? KEY_UNSPEC : key->type;
549 struct sshkey *found = NULL;
550 struct sshauthopt *keyopts = NULL, *certopts = NULL, *finalopts = NULL;
551 char *key_options = NULL, *fp = NULL;
552 const char *reason = NULL;
553 int ret = -1;
554
555 if (authoptsp != NULL)
556 *authoptsp = NULL;
557
558 if ((found = sshkey_new(want_keytype)) == NULL) {
559 debug3("%s: keytype %d failed", __func__, want_keytype);
560 goto out;
561 }
562
563 /* XXX djm: peek at key type in line and skip if unwanted */
564
565 if (sshkey_read(found, &cp) != 0) {
566 /* no key? check for options */
567 debug2("%s: check options: '%s'", loc, cp);
568 key_options = cp;
569 if (advance_past_options(&cp) != 0) {
570 reason = "invalid key option string";
571 goto fail_reason;
572 }
573 skip_space(&cp);
574 if (sshkey_read(found, &cp) != 0) {
575 /* still no key? advance to next line*/
576 debug2("%s: advance: '%s'", loc, cp);
577 goto out;
578 }
579 }
580 /* Parse key options now; we need to know if this is a CA key */
581 if ((keyopts = sshauthopt_parse(key_options, &reason)) == NULL) {
582 debug("%s: bad key options: %s", loc, reason);
583 auth_debug_add("%s: bad key options: %s", loc, reason);
584 goto out;
585 }
586 /* Ignore keys that don't match or incorrectly marked as CAs */
587 if (sshkey_is_cert(key)) {
588 /* Certificate; check signature key against CA */
589 if (!sshkey_equal(found, key->cert->signature_key) ||
590 !keyopts->cert_authority)
591 goto out;
592 } else {
593 /* Plain key: check it against key found in file */
594 if (!sshkey_equal(found, key) || keyopts->cert_authority)
595 goto out;
596 }
597
598 /* We have a candidate key, perform authorisation checks */
599 if ((fp = sshkey_fingerprint(found,
600 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
601 fatal("%s: fingerprint failed", __func__);
602
603 debug("%s: matching %s found: %s %s", loc,
604 sshkey_is_cert(key) ? "CA" : "key", sshkey_type(found), fp);
605
606 if (auth_authorise_keyopts(ssh, pw, keyopts,
607 sshkey_is_cert(key), loc) != 0) {
608 reason = "Refused by key options";
609 goto fail_reason;
610 }
611 /* That's all we need for plain keys. */
612 if (!sshkey_is_cert(key)) {
613 verbose("Accepted key %s %s found at %s",
614 sshkey_type(found), fp, loc);
615 finalopts = keyopts;
616 keyopts = NULL;
617 goto success;
618 }
619
620 /*
621 * Additional authorisation for certificates.
622 */
623
624 /* Parse and check options present in certificate */
625 if ((certopts = sshauthopt_from_cert(key)) == NULL) {
626 reason = "Invalid certificate options";
627 goto fail_reason;
628 }
629 if (auth_authorise_keyopts(ssh, pw, certopts, 0, loc) != 0) {
630 reason = "Refused by certificate options";
631 goto fail_reason;
632 }
633 if ((finalopts = sshauthopt_merge(keyopts, certopts, &reason)) == NULL)
634 goto fail_reason;
635
636 /*
637 * If the user has specified a list of principals as
638 * a key option, then prefer that list to matching
639 * their username in the certificate principals list.
640 */
641 if (keyopts->cert_principals != NULL &&
642 !match_principals_option(keyopts->cert_principals, key->cert)) {
643 reason = "Certificate does not contain an authorized principal";
644 goto fail_reason;
645 }
646 if (sshkey_cert_check_authority(key, 0, 0,
647 keyopts->cert_principals == NULL ? pw->pw_name : NULL, &reason) != 0)
648 goto fail_reason;
649
650 verbose("Accepted certificate ID \"%s\" (serial %llu) "
651 "signed by CA %s %s found at %s",
652 key->cert->key_id,
653 (unsigned long long)key->cert->serial,
654 sshkey_type(found), fp, loc);
655
656 success:
657 if (finalopts == NULL)
658 fatal("%s: internal error: missing options", __func__);
659 if (authoptsp != NULL) {
660 *authoptsp = finalopts;
661 finalopts = NULL;
662 }
663 /* success */
664 ret = 0;
665 goto out;
666
667 fail_reason:
668 error("%s", reason);
669 auth_debug_add("%s", reason);
670 out:
671 free(fp);
672 sshauthopt_free(keyopts);
673 sshauthopt_free(certopts);
674 sshauthopt_free(finalopts);
675 sshkey_free(found);
676 return ret;
677}
678
455/* 679/*
456 * Checks whether key is allowed in authorized_keys-format file, 680 * Checks whether key is allowed in authorized_keys-format file,
457 * returns 1 if the key is allowed or 0 otherwise. 681 * returns 1 if the key is allowed or 0 otherwise.
458 */ 682 */
459static int 683static int
460check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw) 684check_authkeys_file(struct ssh *ssh, struct passwd *pw, FILE *f,
685 char *file, struct sshkey *key, struct sshauthopt **authoptsp)
461{ 686{
462 char line[SSH_MAX_PUBKEY_BYTES]; 687 char *cp, line[SSH_MAX_PUBKEY_BYTES], loc[256];
463 int found_key = 0; 688 int found_key = 0;
464 u_long linenum = 0; 689 u_long linenum = 0;
465 struct sshkey *found = NULL;
466 690
467 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 691 if (authoptsp != NULL)
468 char *cp, *key_options = NULL, *fp = NULL; 692 *authoptsp = NULL;
469 const char *reason = NULL;
470 693
694 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
471 /* Always consume entire file */ 695 /* Always consume entire file */
472 if (found_key) 696 if (found_key)
473 continue; 697 continue;
474 sshkey_free(found);
475 found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type);
476 if (found == NULL)
477 goto done;
478 auth_clear_options();
479 698
480 /* Skip leading whitespace, empty and comment lines. */ 699 /* Skip leading whitespace, empty and comment lines. */
481 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 700 cp = line;
482 ; 701 skip_space(&cp);
483 if (!*cp || *cp == '\n' || *cp == '#') 702 if (!*cp || *cp == '\n' || *cp == '#')
484 continue; 703 continue;
485 704 snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum);
486 if (sshkey_read(found, &cp) != 0) { 705 if (check_authkey_line(ssh, pw, key, cp, loc, authoptsp) == 0)
487 /* no key? check if there are options for this key */
488 int quoted = 0;
489 debug2("user_key_allowed: check options: '%s'", cp);
490 key_options = cp;
491 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
492 if (*cp == '\\' && cp[1] == '"')
493 cp++; /* Skip both */
494 else if (*cp == '"')
495 quoted = !quoted;
496 }
497 /* Skip remaining whitespace. */
498 for (; *cp == ' ' || *cp == '\t'; cp++)
499 ;
500 if (sshkey_read(found, &cp) != 0) {
501 debug2("user_key_allowed: advance: '%s'", cp);
502 /* still no key? advance to next line*/
503 continue;
504 }
505 }
506 if (sshkey_is_cert(key)) {
507 if (!sshkey_equal(found, key->cert->signature_key))
508 continue;
509 if (auth_parse_options(pw, key_options, file,
510 linenum) != 1)
511 continue;
512 if (!key_is_cert_authority)
513 continue;
514 if ((fp = sshkey_fingerprint(found,
515 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
516 continue;
517 debug("matching CA found: file %s, line %lu, %s %s",
518 file, linenum, sshkey_type(found), fp);
519 /*
520 * If the user has specified a list of principals as
521 * a key option, then prefer that list to matching
522 * their username in the certificate principals list.
523 */
524 if (authorized_principals != NULL &&
525 !match_principals_option(authorized_principals,
526 key->cert)) {
527 reason = "Certificate does not contain an "
528 "authorized principal";
529 fail_reason:
530 free(fp);
531 error("%s", reason);
532 auth_debug_add("%s", reason);
533 continue;
534 }
535 if (sshkey_cert_check_authority(key, 0, 0,
536 authorized_principals == NULL ? pw->pw_name : NULL,
537 &reason) != 0)
538 goto fail_reason;
539 if (auth_cert_options(key, pw, &reason) != 0)
540 goto fail_reason;
541 verbose("Accepted certificate ID \"%s\" (serial %llu) "
542 "signed by %s CA %s via %s", key->cert->key_id,
543 (unsigned long long)key->cert->serial,
544 sshkey_type(found), fp, file);
545 free(fp);
546 found_key = 1;
547 break;
548 } else if (sshkey_equal(found, key)) {
549 if (auth_parse_options(pw, key_options, file,
550 linenum) != 1)
551 continue;
552 if (key_is_cert_authority)
553 continue;
554 if ((fp = sshkey_fingerprint(found,
555 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
556 continue;
557 debug("matching key found: file %s, line %lu %s %s",
558 file, linenum, sshkey_type(found), fp);
559 free(fp);
560 found_key = 1; 706 found_key = 1;
561 continue;
562 }
563 } 707 }
564 done:
565 sshkey_free(found);
566 if (!found_key)
567 debug2("key not found");
568 return found_key; 708 return found_key;
569} 709}
570 710
571/* Authenticate a certificate key against TrustedUserCAKeys */ 711/* Authenticate a certificate key against TrustedUserCAKeys */
572static int 712static int
573user_cert_trusted_ca(struct passwd *pw, struct sshkey *key) 713user_cert_trusted_ca(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
714 struct sshauthopt **authoptsp)
574{ 715{
575 char *ca_fp, *principals_file = NULL; 716 char *ca_fp, *principals_file = NULL;
576 const char *reason; 717 const char *reason;
718 struct sshauthopt *principals_opts = NULL, *cert_opts = NULL;
719 struct sshauthopt *final_opts = NULL;
577 int r, ret = 0, found_principal = 0, use_authorized_principals; 720 int r, ret = 0, found_principal = 0, use_authorized_principals;
578 721
722 if (authoptsp != NULL)
723 *authoptsp = NULL;
724
579 if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL) 725 if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL)
580 return 0; 726 return 0;
581 727
@@ -596,36 +742,69 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
596 * against the username. 742 * against the username.
597 */ 743 */
598 if ((principals_file = authorized_principals_file(pw)) != NULL) { 744 if ((principals_file = authorized_principals_file(pw)) != NULL) {
599 if (match_principals_file(principals_file, pw, key->cert)) 745 if (match_principals_file(ssh, pw, principals_file,
746 key->cert, &principals_opts))
600 found_principal = 1; 747 found_principal = 1;
601 } 748 }
602 /* Try querying command if specified */ 749 /* Try querying command if specified */
603 if (!found_principal && match_principals_command(pw, key)) 750 if (!found_principal && match_principals_command(ssh, pw, key,
751 &principals_opts))
604 found_principal = 1; 752 found_principal = 1;
605 /* If principals file or command is specified, then require a match */ 753 /* If principals file or command is specified, then require a match */
606 use_authorized_principals = principals_file != NULL || 754 use_authorized_principals = principals_file != NULL ||
607 options.authorized_principals_command != NULL; 755 options.authorized_principals_command != NULL;
608 if (!found_principal && use_authorized_principals) { 756 if (!found_principal && use_authorized_principals) {
609 reason = "Certificate does not contain an authorized principal"; 757 reason = "Certificate does not contain an authorized principal";
610 fail_reason: 758 goto fail_reason;
611 error("%s", reason);
612 auth_debug_add("%s", reason);
613 goto out;
614 } 759 }
760 if (use_authorized_principals && principals_opts == NULL)
761 fatal("%s: internal error: missing principals_opts", __func__);
615 if (sshkey_cert_check_authority(key, 0, 1, 762 if (sshkey_cert_check_authority(key, 0, 1,
616 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) 763 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0)
617 goto fail_reason; 764 goto fail_reason;
618 if (auth_cert_options(key, pw, &reason) != 0) 765
766 /* Check authority from options in key and from principals file/cmd */
767 if ((cert_opts = sshauthopt_from_cert(key)) == NULL) {
768 reason = "Invalid certificate options";
769 goto fail_reason;
770 }
771 if (auth_authorise_keyopts(ssh, pw, cert_opts, 0, "cert") != 0) {
772 reason = "Refused by certificate options";
619 goto fail_reason; 773 goto fail_reason;
774 }
775 if (principals_opts == NULL) {
776 final_opts = cert_opts;
777 cert_opts = NULL;
778 } else {
779 if (auth_authorise_keyopts(ssh, pw, principals_opts, 0,
780 "principals") != 0) {
781 reason = "Refused by certificate principals options";
782 goto fail_reason;
783 }
784 if ((final_opts = sshauthopt_merge(principals_opts,
785 cert_opts, &reason)) == NULL) {
786 fail_reason:
787 error("%s", reason);
788 auth_debug_add("%s", reason);
789 goto out;
790 }
791 }
620 792
793 /* Success */
621 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " 794 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by "
622 "%s CA %s via %s", key->cert->key_id, 795 "%s CA %s via %s", key->cert->key_id,
623 (unsigned long long)key->cert->serial, 796 (unsigned long long)key->cert->serial,
624 sshkey_type(key->cert->signature_key), ca_fp, 797 sshkey_type(key->cert->signature_key), ca_fp,
625 options.trusted_user_ca_keys); 798 options.trusted_user_ca_keys);
799 if (authoptsp != NULL) {
800 *authoptsp = final_opts;
801 final_opts = NULL;
802 }
626 ret = 1; 803 ret = 1;
627
628 out: 804 out:
805 sshauthopt_free(principals_opts);
806 sshauthopt_free(cert_opts);
807 sshauthopt_free(final_opts);
629 free(principals_file); 808 free(principals_file);
630 free(ca_fp); 809 free(ca_fp);
631 return ret; 810 return ret;
@@ -636,17 +815,22 @@ user_cert_trusted_ca(struct passwd *pw, struct sshkey *key)
636 * returns 1 if the key is allowed or 0 otherwise. 815 * returns 1 if the key is allowed or 0 otherwise.
637 */ 816 */
638static int 817static int
639user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file) 818user_key_allowed2(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
819 char *file, struct sshauthopt **authoptsp)
640{ 820{
641 FILE *f; 821 FILE *f;
642 int found_key = 0; 822 int found_key = 0;
643 823
824 if (authoptsp != NULL)
825 *authoptsp = NULL;
826
644 /* Temporarily use the user's uid. */ 827 /* Temporarily use the user's uid. */
645 temporarily_use_uid(pw); 828 temporarily_use_uid(pw);
646 829
647 debug("trying public key file %s", file); 830 debug("trying public key file %s", file);
648 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { 831 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
649 found_key = check_authkeys_file(f, file, key, pw); 832 found_key = check_authkeys_file(ssh, pw, f, file,
833 key, authoptsp);
650 fclose(f); 834 fclose(f);
651 } 835 }
652 836
@@ -659,17 +843,20 @@ user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file)
659 * returns 1 if the key is allowed or 0 otherwise. 843 * returns 1 if the key is allowed or 0 otherwise.
660 */ 844 */
661static int 845static int
662user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key) 846user_key_command_allowed2(struct ssh *ssh, struct passwd *user_pw,
847 struct sshkey *key, struct sshauthopt **authoptsp)
663{ 848{
849 struct passwd *runas_pw = NULL;
664 FILE *f = NULL; 850 FILE *f = NULL;
665 int r, ok, found_key = 0; 851 int r, ok, found_key = 0;
666 struct passwd *pw;
667 int i, uid_swapped = 0, ac = 0; 852 int i, uid_swapped = 0, ac = 0;
668 pid_t pid; 853 pid_t pid;
669 char *username = NULL, *key_fp = NULL, *keytext = NULL; 854 char *username = NULL, *key_fp = NULL, *keytext = NULL;
670 char *tmp, *command = NULL, **av = NULL; 855 char *tmp, *command = NULL, **av = NULL;
671 void (*osigchld)(int); 856 void (*osigchld)(int);
672 857
858 if (authoptsp != NULL)
859 *authoptsp = NULL;
673 if (options.authorized_keys_command == NULL) 860 if (options.authorized_keys_command == NULL)
674 return 0; 861 return 0;
675 if (options.authorized_keys_command_user == NULL) { 862 if (options.authorized_keys_command_user == NULL) {
@@ -686,8 +873,8 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
686 /* Prepare and verify the user for the command */ 873 /* Prepare and verify the user for the command */
687 username = percent_expand(options.authorized_keys_command_user, 874 username = percent_expand(options.authorized_keys_command_user,
688 "u", user_pw->pw_name, (char *)NULL); 875 "u", user_pw->pw_name, (char *)NULL);
689 pw = getpwnam(username); 876 runas_pw = getpwnam(username);
690 if (pw == NULL) { 877 if (runas_pw == NULL) {
691 error("AuthorizedKeysCommandUser \"%s\" not found: %s", 878 error("AuthorizedKeysCommandUser \"%s\" not found: %s",
692 username, strerror(errno)); 879 username, strerror(errno));
693 goto out; 880 goto out;
@@ -745,15 +932,16 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
745 xasprintf(&command, "%s %s", av[0], av[1]); 932 xasprintf(&command, "%s %s", av[0], av[1]);
746 } 933 }
747 934
748 if ((pid = subprocess("AuthorizedKeysCommand", pw, command, 935 if ((pid = subprocess("AuthorizedKeysCommand", runas_pw, command,
749 ac, av, &f, 936 ac, av, &f,
750 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) 937 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0)
751 goto out; 938 goto out;
752 939
753 uid_swapped = 1; 940 uid_swapped = 1;
754 temporarily_use_uid(pw); 941 temporarily_use_uid(runas_pw);
755 942
756 ok = check_authkeys_file(f, options.authorized_keys_command, key, pw); 943 ok = check_authkeys_file(ssh, user_pw, f,
944 options.authorized_keys_command, key, authoptsp);
757 945
758 fclose(f); 946 fclose(f);
759 f = NULL; 947 f = NULL;
@@ -783,10 +971,14 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key)
783 * Check whether key authenticates and authorises the user. 971 * Check whether key authenticates and authorises the user.
784 */ 972 */
785int 973int
786user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt) 974user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
975 int auth_attempt, struct sshauthopt **authoptsp)
787{ 976{
788 u_int success, i; 977 u_int success, i;
789 char *file; 978 char *file;
979 struct sshauthopt *opts = NULL;
980 if (authoptsp != NULL)
981 *authoptsp = NULL;
790 982
791 if (auth_key_is_revoked(key)) 983 if (auth_key_is_revoked(key))
792 return 0; 984 return 0;
@@ -794,25 +986,31 @@ user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt)
794 auth_key_is_revoked(key->cert->signature_key)) 986 auth_key_is_revoked(key->cert->signature_key))
795 return 0; 987 return 0;
796 988
797 success = user_cert_trusted_ca(pw, key); 989 if ((success = user_cert_trusted_ca(ssh, pw, key, &opts)) != 0)
798 if (success) 990 goto out;
799 return success; 991 sshauthopt_free(opts);
992 opts = NULL;
800 993
801 success = user_key_command_allowed2(pw, key); 994 if ((success = user_key_command_allowed2(ssh, pw, key, &opts)) != 0)
802 if (success > 0) 995 goto out;
803 return success; 996 sshauthopt_free(opts);
997 opts = NULL;
804 998
805 for (i = 0; !success && i < options.num_authkeys_files; i++) { 999 for (i = 0; !success && i < options.num_authkeys_files; i++) {
806
807 if (strcasecmp(options.authorized_keys_files[i], "none") == 0) 1000 if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
808 continue; 1001 continue;
809 file = expand_authorized_keys( 1002 file = expand_authorized_keys(
810 options.authorized_keys_files[i], pw); 1003 options.authorized_keys_files[i], pw);
811 1004 success = user_key_allowed2(ssh, pw, key, file, &opts);
812 success = user_key_allowed2(pw, key, file);
813 free(file); 1005 free(file);
814 } 1006 }
815 1007
1008 out:
1009 if (success && authoptsp != NULL) {
1010 *authoptsp = opts;
1011 opts = NULL;
1012 }
1013 sshauthopt_free(opts);
816 return success; 1014 return success;
817} 1015}
818 1016