diff options
author | djm@openbsd.org <djm@openbsd.org> | 2015-05-21 06:43:30 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2015-05-21 16:45:46 +1000 |
commit | bcc50d816187fa9a03907ac1f3a52f04a52e10d1 (patch) | |
tree | 7fee32fe8c063a24674a37aad34e4b381d995ae5 | |
parent | 24232a3e5ab467678a86aa67968bbb915caffed4 (diff) |
upstream commit
add AuthorizedPrincipalsCommand that allows getting
authorized_principals from a subprocess rather than a file, which is quite
useful in deployments with large userbases
feedback and ok markus@
Upstream-ID: aa1bdac7b16fc6d2fa3524ef08f04c7258d247f6
-rw-r--r-- | auth2-pubkey.c | 150 | ||||
-rw-r--r-- | servconf.c | 37 | ||||
-rw-r--r-- | servconf.h | 10 | ||||
-rw-r--r-- | sshd.c | 7 | ||||
-rw-r--r-- | sshd_config.5 | 38 |
5 files changed, 213 insertions, 29 deletions
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 553144c7b..c4e80b01b 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.50 2015/05/21 06:38:35 djm Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.51 2015/05/21 06:43:30 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -554,19 +554,13 @@ match_principals_option(const char *principal_list, struct sshkey_cert *cert) | |||
554 | } | 554 | } |
555 | 555 | ||
556 | static int | 556 | static int |
557 | match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) | 557 | process_principals(FILE *f, char *file, struct passwd *pw, |
558 | struct sshkey_cert *cert) | ||
558 | { | 559 | { |
559 | FILE *f; | ||
560 | char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; | 560 | char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; |
561 | u_long linenum = 0; | 561 | u_long linenum = 0; |
562 | u_int i; | 562 | u_int i; |
563 | 563 | ||
564 | temporarily_use_uid(pw); | ||
565 | debug("trying authorized principals file %s", file); | ||
566 | if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { | ||
567 | restore_uid(); | ||
568 | return 0; | ||
569 | } | ||
570 | while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { | 564 | while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { |
571 | /* Skip leading whitespace. */ | 565 | /* Skip leading whitespace. */ |
572 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) | 566 | for (cp = line; *cp == ' ' || *cp == '\t'; cp++) |
@@ -594,24 +588,128 @@ match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) | |||
594 | } | 588 | } |
595 | for (i = 0; i < cert->nprincipals; i++) { | 589 | for (i = 0; i < cert->nprincipals; i++) { |
596 | if (strcmp(cp, cert->principals[i]) == 0) { | 590 | if (strcmp(cp, cert->principals[i]) == 0) { |
597 | debug3("matched principal \"%.100s\" " | 591 | debug3("%s:%lu: matched principal \"%.100s\"", |
598 | "from file \"%s\" on line %lu", | 592 | file == NULL ? "(command)" : file, |
599 | cert->principals[i], file, linenum); | 593 | linenum, cert->principals[i]); |
600 | if (auth_parse_options(pw, line_opts, | 594 | if (auth_parse_options(pw, line_opts, |
601 | file, linenum) != 1) | 595 | file, linenum) != 1) |
602 | continue; | 596 | continue; |
603 | fclose(f); | ||
604 | restore_uid(); | ||
605 | return 1; | 597 | return 1; |
606 | } | 598 | } |
607 | } | 599 | } |
608 | } | 600 | } |
601 | return 0; | ||
602 | } | ||
603 | |||
604 | static int | ||
605 | match_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); | ||
609 | fclose(f); | 617 | fclose(f); |
610 | restore_uid(); | 618 | restore_uid(); |
611 | return 0; | 619 | return success; |
612 | } | 620 | } |
613 | 621 | ||
614 | /* | 622 | /* |
623 | * Checks whether principal is allowed in output of command. | ||
624 | * returns 1 if the principal is allowed or 0 otherwise. | ||
625 | */ | ||
626 | static int | ||
627 | match_principals_command(struct passwd *user_pw, struct sshkey *key) | ||
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, key->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 | /* | ||
615 | * Checks whether key is allowed in authorized_keys-format file, | 713 | * Checks whether key is allowed in authorized_keys-format file, |
616 | * returns 1 if the key is allowed or 0 otherwise. | 714 | * returns 1 if the key is allowed or 0 otherwise. |
617 | */ | 715 | */ |
@@ -733,7 +831,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
733 | { | 831 | { |
734 | char *ca_fp, *principals_file = NULL; | 832 | char *ca_fp, *principals_file = NULL; |
735 | const char *reason; | 833 | const char *reason; |
736 | int ret = 0; | 834 | int ret = 0, found_principal = 0; |
737 | 835 | ||
738 | if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) | 836 | if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) |
739 | return 0; | 837 | return 0; |
@@ -755,14 +853,20 @@ user_cert_trusted_ca(struct passwd *pw, Key *key) | |||
755 | * against the username. | 853 | * against the username. |
756 | */ | 854 | */ |
757 | if ((principals_file = authorized_principals_file(pw)) != NULL) { | 855 | if ((principals_file = authorized_principals_file(pw)) != NULL) { |
758 | if (!match_principals_file(principals_file, pw, key->cert)) { | 856 | if (match_principals_file(principals_file, pw, key->cert)) |
759 | reason = "Certificate does not contain an " | 857 | found_principal = 1; |
760 | "authorized principal"; | 858 | } |
859 | /* Try querying command if specified */ | ||
860 | if (!found_principal && match_principals_command(pw, key)) | ||
861 | found_principal = 1; | ||
862 | /* If principals file or command specify, then require a match here */ | ||
863 | if (!found_principal && (principals_file != NULL || | ||
864 | options.authorized_principals_command != NULL)) { | ||
865 | reason = "Certificate does not contain an authorized principal"; | ||
761 | fail_reason: | 866 | fail_reason: |
762 | error("%s", reason); | 867 | error("%s", reason); |
763 | auth_debug_add("%s", reason); | 868 | auth_debug_add("%s", reason); |
764 | goto out; | 869 | goto out; |
765 | } | ||
766 | } | 870 | } |
767 | if (key_cert_check_authority(key, 0, 1, | 871 | if (key_cert_check_authority(key, 0, 1, |
768 | principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) | 872 | principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) |
diff --git a/servconf.c b/servconf.c index 9257a174b..5acaf61b1 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.c,v 1.269 2015/05/04 06:10:48 djm Exp $ */ | 1 | /* $OpenBSD: servconf.c,v 1.270 2015/05/21 06:43:30 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
@@ -160,6 +160,8 @@ initialize_server_options(ServerOptions *options) | |||
160 | options->revoked_keys_file = NULL; | 160 | options->revoked_keys_file = NULL; |
161 | options->trusted_user_ca_keys = NULL; | 161 | options->trusted_user_ca_keys = NULL; |
162 | options->authorized_principals_file = NULL; | 162 | options->authorized_principals_file = NULL; |
163 | options->authorized_principals_command = NULL; | ||
164 | options->authorized_principals_command_user = NULL; | ||
163 | options->ip_qos_interactive = -1; | 165 | options->ip_qos_interactive = -1; |
164 | options->ip_qos_bulk = -1; | 166 | options->ip_qos_bulk = -1; |
165 | options->version_addendum = NULL; | 167 | options->version_addendum = NULL; |
@@ -400,6 +402,7 @@ typedef enum { | |||
400 | sUsePrivilegeSeparation, sAllowAgentForwarding, | 402 | sUsePrivilegeSeparation, sAllowAgentForwarding, |
401 | sHostCertificate, | 403 | sHostCertificate, |
402 | sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, | 404 | sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile, |
405 | sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser, | ||
403 | sKexAlgorithms, sIPQoS, sVersionAddendum, | 406 | sKexAlgorithms, sIPQoS, sVersionAddendum, |
404 | sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, | 407 | sAuthorizedKeysCommand, sAuthorizedKeysCommandUser, |
405 | sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, | 408 | sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, |
@@ -532,6 +535,8 @@ static struct { | |||
532 | { "ipqos", sIPQoS, SSHCFG_ALL }, | 535 | { "ipqos", sIPQoS, SSHCFG_ALL }, |
533 | { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, | 536 | { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL }, |
534 | { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, | 537 | { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL }, |
538 | { "authorizedprincipalscommand", sAuthorizedPrincipalsCommand, SSHCFG_ALL }, | ||
539 | { "authorizedprincipalscommanduser", sAuthorizedPrincipalsCommandUser, SSHCFG_ALL }, | ||
535 | { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, | 540 | { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL }, |
536 | { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, | 541 | { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL }, |
537 | { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL }, | 542 | { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL }, |
@@ -1734,6 +1739,34 @@ process_server_config_line(ServerOptions *options, char *line, | |||
1734 | *charptr = xstrdup(arg); | 1739 | *charptr = xstrdup(arg); |
1735 | break; | 1740 | break; |
1736 | 1741 | ||
1742 | case sAuthorizedPrincipalsCommand: | ||
1743 | if (cp == NULL) | ||
1744 | fatal("%.200s line %d: Missing argument.", filename, | ||
1745 | linenum); | ||
1746 | len = strspn(cp, WHITESPACE); | ||
1747 | if (*activep && | ||
1748 | options->authorized_principals_command == NULL) { | ||
1749 | if (cp[len] != '/' && strcasecmp(cp + len, "none") != 0) | ||
1750 | fatal("%.200s line %d: " | ||
1751 | "AuthorizedPrincipalsCommand must be " | ||
1752 | "an absolute path", filename, linenum); | ||
1753 | options->authorized_principals_command = | ||
1754 | xstrdup(cp + len); | ||
1755 | } | ||
1756 | return 0; | ||
1757 | |||
1758 | case sAuthorizedPrincipalsCommandUser: | ||
1759 | charptr = &options->authorized_principals_command_user; | ||
1760 | |||
1761 | arg = strdelim(&cp); | ||
1762 | if (!arg || *arg == '\0') | ||
1763 | fatal("%s line %d: missing " | ||
1764 | "AuthorizedPrincipalsCommandUser argument.", | ||
1765 | filename, linenum); | ||
1766 | if (*activep && *charptr == NULL) | ||
1767 | *charptr = xstrdup(arg); | ||
1768 | break; | ||
1769 | |||
1737 | case sAuthenticationMethods: | 1770 | case sAuthenticationMethods: |
1738 | if (options->num_auth_methods == 0) { | 1771 | if (options->num_auth_methods == 0) { |
1739 | while ((arg = strdelim(&cp)) && *arg != '\0') { | 1772 | while ((arg = strdelim(&cp)) && *arg != '\0') { |
@@ -2229,6 +2262,8 @@ dump_config(ServerOptions *o) | |||
2229 | ? "none" : o->version_addendum); | 2262 | ? "none" : o->version_addendum); |
2230 | dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command); | 2263 | dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command); |
2231 | dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user); | 2264 | dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user); |
2265 | dump_cfg_string(sAuthorizedPrincipalsCommand, o->authorized_principals_command); | ||
2266 | dump_cfg_string(sAuthorizedPrincipalsCommandUser, o->authorized_principals_command_user); | ||
2232 | dump_cfg_string(sHostKeyAgent, o->host_key_agent); | 2267 | dump_cfg_string(sHostKeyAgent, o->host_key_agent); |
2233 | dump_cfg_string(sKexAlgorithms, | 2268 | dump_cfg_string(sKexAlgorithms, |
2234 | o->kex_algorithms ? o->kex_algorithms : KEX_SERVER_KEX); | 2269 | o->kex_algorithms ? o->kex_algorithms : KEX_SERVER_KEX); |
diff --git a/servconf.h b/servconf.h index 38520f476..dc2a5f6a6 100644 --- a/servconf.h +++ b/servconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.h,v 1.117 2015/04/29 03:48:56 dtucker Exp $ */ | 1 | /* $OpenBSD: servconf.h,v 1.118 2015/05/21 06:43:31 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -178,9 +178,11 @@ typedef struct { | |||
178 | char *chroot_directory; | 178 | char *chroot_directory; |
179 | char *revoked_keys_file; | 179 | char *revoked_keys_file; |
180 | char *trusted_user_ca_keys; | 180 | char *trusted_user_ca_keys; |
181 | char *authorized_principals_file; | ||
182 | char *authorized_keys_command; | 181 | char *authorized_keys_command; |
183 | char *authorized_keys_command_user; | 182 | char *authorized_keys_command_user; |
183 | char *authorized_principals_file; | ||
184 | char *authorized_principals_command; | ||
185 | char *authorized_principals_command_user; | ||
184 | 186 | ||
185 | int64_t rekey_limit; | 187 | int64_t rekey_limit; |
186 | int rekey_interval; | 188 | int rekey_interval; |
@@ -216,9 +218,11 @@ struct connection_info { | |||
216 | M_CP_STROPT(banner); \ | 218 | M_CP_STROPT(banner); \ |
217 | M_CP_STROPT(trusted_user_ca_keys); \ | 219 | M_CP_STROPT(trusted_user_ca_keys); \ |
218 | M_CP_STROPT(revoked_keys_file); \ | 220 | M_CP_STROPT(revoked_keys_file); \ |
219 | M_CP_STROPT(authorized_principals_file); \ | ||
220 | M_CP_STROPT(authorized_keys_command); \ | 221 | M_CP_STROPT(authorized_keys_command); \ |
221 | M_CP_STROPT(authorized_keys_command_user); \ | 222 | M_CP_STROPT(authorized_keys_command_user); \ |
223 | M_CP_STROPT(authorized_principals_file); \ | ||
224 | M_CP_STROPT(authorized_principals_command); \ | ||
225 | M_CP_STROPT(authorized_principals_command_user); \ | ||
222 | M_CP_STROPT(hostbased_key_types); \ | 226 | M_CP_STROPT(hostbased_key_types); \ |
223 | M_CP_STROPT(pubkey_key_types); \ | 227 | M_CP_STROPT(pubkey_key_types); \ |
224 | M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \ | 228 | M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.448 2015/04/27 00:21:21 djm Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.449 2015/05/21 06:43:31 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -1698,6 +1698,11 @@ main(int ac, char **av) | |||
1698 | strcasecmp(options.authorized_keys_command, "none") != 0)) | 1698 | strcasecmp(options.authorized_keys_command, "none") != 0)) |
1699 | fatal("AuthorizedKeysCommand set without " | 1699 | fatal("AuthorizedKeysCommand set without " |
1700 | "AuthorizedKeysCommandUser"); | 1700 | "AuthorizedKeysCommandUser"); |
1701 | if (options.authorized_principals_command_user == NULL && | ||
1702 | (options.authorized_principals_command != NULL && | ||
1703 | strcasecmp(options.authorized_principals_command, "none") != 0)) | ||
1704 | fatal("AuthorizedPrincipalsCommand set without " | ||
1705 | "AuthorizedPrincipalsCommandUser"); | ||
1701 | 1706 | ||
1702 | /* | 1707 | /* |
1703 | * Check whether there is any path through configured auth methods. | 1708 | * Check whether there is any path through configured auth methods. |
diff --git a/sshd_config.5 b/sshd_config.5 index e40ecedef..884e767b8 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -33,7 +33,7 @@ | |||
33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 33 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 34 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35 | .\" | 35 | .\" |
36 | .\" $OpenBSD: sshd_config.5,v 1.201 2015/05/21 06:38:35 djm Exp $ | 36 | .\" $OpenBSD: sshd_config.5,v 1.202 2015/05/21 06:43:31 djm Exp $ |
37 | .Dd $Mdocdate: May 21 2015 $ | 37 | .Dd $Mdocdate: May 21 2015 $ |
38 | .Dt SSHD_CONFIG 5 | 38 | .Dt SSHD_CONFIG 5 |
39 | .Os | 39 | .Os |
@@ -287,6 +287,42 @@ directory. | |||
287 | Multiple files may be listed, separated by whitespace. | 287 | Multiple files may be listed, separated by whitespace. |
288 | The default is | 288 | The default is |
289 | .Dq .ssh/authorized_keys .ssh/authorized_keys2 . | 289 | .Dq .ssh/authorized_keys .ssh/authorized_keys2 . |
290 | .It Cm AuthorizedPrincipalsCommand | ||
291 | Specifies a program to be used to generate the list of allowed | ||
292 | certificate principals as per | ||
293 | .Cm AuthorizedPrincipalsFile . | ||
294 | The program must be owned by root, not writable by group or others and | ||
295 | specified by an absolute path. | ||
296 | .Pp | ||
297 | Arguments to | ||
298 | .Cm AuthorizedPrincipalsCommand | ||
299 | may be provided using the following tokens, which will be expanded | ||
300 | at runtime: %% is replaced by a literal '%', %u is replaced by the | ||
301 | username being authenticated and %h is replaced by the home directory | ||
302 | of the user being authenticated. | ||
303 | .Pp | ||
304 | The program should produce on standard output zero or | ||
305 | more lines of | ||
306 | .Cm AuthorizedPrincipalsFile | ||
307 | output. | ||
308 | If either | ||
309 | .Cm AuthorizedPrincipalsCommand | ||
310 | or | ||
311 | .Cm AuthorizedPrincipalsFile | ||
312 | is specified, then certificates offered by the client for authentication | ||
313 | must contain a principal that is listed. | ||
314 | By default, no AuthorizedPrincipalsCommand is run. | ||
315 | .It Cm AuthorizedPrincipalsCommandUser | ||
316 | Specifies the user under whose account the AuthorizedPrincipalsCommand is run. | ||
317 | It is recommended to use a dedicated user that has no other role on the host | ||
318 | than running authorized principals commands. | ||
319 | If | ||
320 | .Cm AuthorizedPrincipalsCommand | ||
321 | is specified but | ||
322 | .Cm AuthorizedPrincipalsCommandUser | ||
323 | is not, then | ||
324 | .Xr sshd 8 | ||
325 | will refuse to start. | ||
290 | .It Cm AuthorizedPrincipalsFile | 326 | .It Cm AuthorizedPrincipalsFile |
291 | Specifies a file that lists principal names that are accepted for | 327 | Specifies a file that lists principal names that are accepted for |
292 | certificate authentication. | 328 | certificate authentication. |