summaryrefslogtreecommitdiffstats
path: root/crypto/openssh/auth2-pubkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/auth2-pubkey.c')
-rw-r--r--crypto/openssh/auth2-pubkey.c145
1 files changed, 128 insertions, 17 deletions
diff --git a/crypto/openssh/auth2-pubkey.c b/crypto/openssh/auth2-pubkey.c
index c4cadf4..35cf79c 100644
--- a/crypto/openssh/auth2-pubkey.c
+++ b/crypto/openssh/auth2-pubkey.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.22 2010/03/10 23:27:17 djm Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.26 2010/06/29 23:16:46 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@@ -57,6 +57,7 @@
#include "monitor_wrap.h"
#include "misc.h"
#include "authfile.h"
+#include "match.h"
/* import */
extern ServerOptions options;
@@ -176,6 +177,83 @@ done:
return authenticated;
}
+static int
+match_principals_option(const char *principal_list, struct KeyCert *cert)
+{
+ char *result;
+ u_int i;
+
+ /* XXX percent_expand() sequences for authorized_principals? */
+
+ for (i = 0; i < cert->nprincipals; i++) {
+ if ((result = match_list(cert->principals[i],
+ principal_list, NULL)) != NULL) {
+ debug3("matched principal from key options \"%.100s\"",
+ result);
+ xfree(result);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+match_principals_file(char *file, struct passwd *pw, struct KeyCert *cert)
+{
+ FILE *f;
+ char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts;
+ u_long linenum = 0;
+ u_int i;
+
+ temporarily_use_uid(pw);
+ debug("trying authorized principals file %s", file);
+ if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) {
+ restore_uid();
+ return 0;
+ }
+ while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
+ /* Skip leading whitespace. */
+ for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ /* Skip blank and comment lines. */
+ if ((ep = strchr(cp, '#')) != NULL)
+ *ep = '\0';
+ if (!*cp || *cp == '\n')
+ continue;
+ /* Trim trailing whitespace. */
+ ep = cp + strlen(cp) - 1;
+ while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t'))
+ *ep-- = '\0';
+ /*
+ * If the line has internal whitespace then assume it has
+ * key options.
+ */
+ line_opts = NULL;
+ if ((ep = strrchr(cp, ' ')) != NULL ||
+ (ep = strrchr(cp, '\t')) != NULL) {
+ for (; *ep == ' ' || *ep == '\t'; ep++)
+ ;;
+ line_opts = cp;
+ cp = ep;
+ }
+ for (i = 0; i < cert->nprincipals; i++) {
+ if (strcmp(cp, cert->principals[i]) == 0) {
+ debug3("matched principal from file \"%.100s\"",
+ cert->principals[i]);
+ if (auth_parse_options(pw, line_opts,
+ file, linenum) != 1)
+ continue;
+ fclose(f);
+ restore_uid();
+ return 1;
+ }
+ }
+ }
+ fclose(f);
+ restore_uid();
+ return 0;
+}
+
/* return 1 if user allows given key */
static int
user_key_allowed2(struct passwd *pw, Key *key, char *file)
@@ -233,26 +311,39 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
continue;
}
}
- if (auth_parse_options(pw, key_options, file, linenum) != 1)
- continue;
- if (key->type == KEY_RSA_CERT || key->type == KEY_DSA_CERT) {
- if (!key_is_cert_authority)
- continue;
+ if (key_is_cert(key)) {
if (!key_equal(found, key->cert->signature_key))
continue;
+ if (auth_parse_options(pw, key_options, file,
+ linenum) != 1)
+ continue;
+ if (!key_is_cert_authority)
+ continue;
fp = key_fingerprint(found, SSH_FP_MD5,
SSH_FP_HEX);
debug("matching CA found: file %s, line %lu, %s %s",
file, linenum, key_type(found), fp);
- if (key_cert_check_authority(key, 0, 0, pw->pw_name,
- &reason) != 0) {
+ /*
+ * If the user has specified a list of principals as
+ * a key option, then prefer that list to matching
+ * their username in the certificate principals list.
+ */
+ if (authorized_principals != NULL &&
+ !match_principals_option(authorized_principals,
+ key->cert)) {
+ reason = "Certificate does not contain an "
+ "authorized principal";
+ fail_reason:
xfree(fp);
error("%s", reason);
auth_debug_add("%s", reason);
continue;
}
- if (auth_cert_constraints(&key->cert->constraints,
- pw) != 0) {
+ if (key_cert_check_authority(key, 0, 0,
+ authorized_principals == NULL ? pw->pw_name : NULL,
+ &reason) != 0)
+ goto fail_reason;
+ if (auth_cert_options(key, pw) != 0) {
xfree(fp);
continue;
}
@@ -262,7 +353,12 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
xfree(fp);
found_key = 1;
break;
- } else if (!key_is_cert_authority && key_equal(found, key)) {
+ } else if (key_equal(found, key)) {
+ if (auth_parse_options(pw, key_options, file,
+ linenum) != 1)
+ continue;
+ if (key_is_cert_authority)
+ continue;
found_key = 1;
debug("matching key found: file %s, line %lu",
file, linenum);
@@ -285,7 +381,7 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
static int
user_cert_trusted_ca(struct passwd *pw, Key *key)
{
- char *ca_fp;
+ char *ca_fp, *principals_file = NULL;
const char *reason;
int ret = 0;
@@ -302,12 +398,25 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
options.trusted_user_ca_keys);
goto out;
}
- if (key_cert_check_authority(key, 0, 1, pw->pw_name, &reason) != 0) {
- error("%s", reason);
- auth_debug_add("%s", reason);
- goto out;
+ /*
+ * If AuthorizedPrincipals is in use, then compare the certificate
+ * principals against the names in that file rather than matching
+ * against the username.
+ */
+ if ((principals_file = authorized_principals_file(pw)) != NULL) {
+ if (!match_principals_file(principals_file, pw, key->cert)) {
+ reason = "Certificate does not contain an "
+ "authorized principal";
+ fail_reason:
+ error("%s", reason);
+ auth_debug_add("%s", reason);
+ goto out;
+ }
}
- if (auth_cert_constraints(&key->cert->constraints, pw) != 0)
+ if (key_cert_check_authority(key, 0, 1,
+ principals_file == NULL ? pw->pw_name : NULL, &reason) != 0)
+ goto fail_reason;
+ if (auth_cert_options(key, pw) != 0)
goto out;
verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s",
@@ -316,6 +425,8 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
ret = 1;
out:
+ if (principals_file != NULL)
+ xfree(principals_file);
if (ca_fp != NULL)
xfree(ca_fp);
return ret;
OpenPOWER on IntegriCloud