summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/auth/ntlm/auth_sam.c2
-rw-r--r--source4/auth/sam.c6
-rw-r--r--source4/heimdal/kdc/kerberos5.c1
-rw-r--r--source4/heimdal/kdc/pkinit.c38
-rw-r--r--source4/heimdal/lib/hdb/hdb.h7
-rw-r--r--source4/kdc/hdb-samba4.c103
6 files changed, 123 insertions, 34 deletions
diff --git a/source4/auth/ntlm/auth_sam.c b/source4/auth/ntlm/auth_sam.c
index 253ddf2286..a64c56d920 100644
--- a/source4/auth/ntlm/auth_sam.c
+++ b/source4/auth/ntlm/auth_sam.c
@@ -330,7 +330,7 @@ NTSTATUS authsam_get_server_info_principal(TALLOC_CTX *mem_ctx,
}
nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal,
- &domain_dn, &msg);
+ user_attrs, &domain_dn, &msg);
if (!NT_STATUS_IS_OK(nt_status)) {
return nt_status;
}
diff --git a/source4/auth/sam.c b/source4/auth/sam.c
index 635d94242f..8865170b14 100644
--- a/source4/auth/sam.c
+++ b/source4/auth/sam.c
@@ -399,6 +399,7 @@ _PUBLIC_ NTSTATUS authsam_make_server_info(TALLOC_CTX *mem_ctx, struct ldb_conte
NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
TALLOC_CTX *mem_ctx, const char *principal,
+ const char **attrs,
struct ldb_dn **domain_dn,
struct ldb_message **msg)
{
@@ -411,7 +412,8 @@ NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
return NT_STATUS_NO_MEMORY;
}
- nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal, &user_dn, domain_dn);
+ nt_status = crack_user_principal_name(sam_ctx, tmp_ctx, principal,
+ &user_dn, domain_dn);
if (!NT_STATUS_IS_OK(nt_status)) {
talloc_free(tmp_ctx);
return nt_status;
@@ -419,7 +421,7 @@ NTSTATUS sam_get_results_principal(struct ldb_context *sam_ctx,
/* pull the user attributes */
ret = gendb_search_single_extended_dn(sam_ctx, tmp_ctx, user_dn, LDB_SCOPE_BASE,
- msg, user_attrs, "(objectClass=*)");
+ msg, attrs, "(objectClass=*)");
if (ret != LDB_SUCCESS) {
talloc_free(tmp_ctx);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c
index 43d54bf702..53e9f54537 100644
--- a/source4/heimdal/kdc/kerberos5.c
+++ b/source4/heimdal/kdc/kerberos5.c
@@ -1053,6 +1053,7 @@ _kdc_as_rep(krb5_context context,
ret = _kdc_pk_check_client(context,
config,
+ clientdb,
client,
pkp,
&client_cert);
diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c
index 22734be811..644eae0fe4 100644
--- a/source4/heimdal/kdc/pkinit.c
+++ b/source4/heimdal/kdc/pkinit.c
@@ -1613,11 +1613,12 @@ match_ms_upn_san(krb5_context context,
krb5_kdc_configuration *config,
hx509_context hx509ctx,
hx509_cert client_cert,
- krb5_const_principal match)
+ HDB *clientdb,
+ hdb_entry_ex *client)
{
hx509_octet_string_list list;
krb5_principal principal = NULL;
- int ret, found = 0;
+ int ret;
MS_UPN_SAN upn;
size_t size;
@@ -1651,32 +1652,32 @@ match_ms_upn_san(krb5_context context,
goto out;
}
- /*
- * This is very wrong, but will do for now, should really and a
- * plugin to the windc layer to very this ACL.
- */
- strupr(principal->realm);
-
- if (krb5_principal_compare(context, principal, match) == TRUE)
- found = 1;
+ if (clientdb->hdb_check_pkinit_ms_upn_match) {
+ ret = clientdb->hdb_check_pkinit_ms_upn_match(context, clientdb, client, principal);
+ } else {
+
+ /*
+ * This is very wrong, but will do for a fallback
+ */
+ strupr(principal->realm);
+
+ if (krb5_principal_compare(context, principal, client->entry.principal) == FALSE)
+ ret = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
+ }
out:
if (principal)
krb5_free_principal(context, principal);
hx509_free_octet_string_list(&list);
- if (ret)
- return ret;
-
- if (!found)
- return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
- return 0;
+ return ret;
}
krb5_error_code
_kdc_pk_check_client(krb5_context context,
krb5_kdc_configuration *config,
- const hdb_entry_ex *client,
+ HDB *clientdb,
+ hdb_entry_ex *client,
pk_client_params *cp,
char **subject_name)
{
@@ -1745,7 +1746,8 @@ _kdc_pk_check_client(krb5_context context,
ret = match_ms_upn_san(context, config,
kdc_identity->hx509ctx,
cp->cert,
- client->entry.principal);
+ clientdb,
+ client);
if (ret == 0) {
kdc_log(context, config, 5,
"Found matching MS UPN SAN in certificate");
diff --git a/source4/heimdal/lib/hdb/hdb.h b/source4/heimdal/lib/hdb/hdb.h
index f490dbf2f0..8eba864fd3 100644
--- a/source4/heimdal/lib/hdb/hdb.h
+++ b/source4/heimdal/lib/hdb/hdb.h
@@ -220,9 +220,14 @@ typedef struct HDB{
* Check is delegation is allowed.
*/
krb5_error_code (*hdb_check_constrained_delegation)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal);
+
+ /**
+ * Check if this name is an alias for the supplied client for PKINIT userPrinicpalName logins
+ */
+ krb5_error_code (*hdb_check_pkinit_ms_upn_match)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal);
}HDB;
-#define HDB_INTERFACE_VERSION 5
+#define HDB_INTERFACE_VERSION 6
struct hdb_so_method {
int version;
diff --git a/source4/kdc/hdb-samba4.c b/source4/kdc/hdb-samba4.c
index 1a0e93f7ce..e39366c407 100644
--- a/source4/kdc/hdb-samba4.c
+++ b/source4/kdc/hdb-samba4.c
@@ -978,17 +978,16 @@ static krb5_error_code hdb_samba4_rename(krb5_context context, HDB *db, const ch
return HDB_ERR_DB_INUSE;
}
-static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db,
- struct loadparm_context *lp_ctx,
- TALLOC_CTX *mem_ctx,
- krb5_const_principal principal,
- unsigned flags,
- hdb_entry_ex *entry_ex) {
+static krb5_error_code hdb_samba4_lookup_client(krb5_context context, HDB *db,
+ struct loadparm_context *lp_ctx,
+ TALLOC_CTX *mem_ctx,
+ krb5_const_principal principal,
+ const char **attrs,
+ struct ldb_dn **realm_dn,
+ struct ldb_message **msg) {
NTSTATUS nt_status;
char *principal_string;
- struct ldb_dn *realm_dn;
krb5_error_code ret;
- struct ldb_message *msg = NULL;
ret = krb5_unparse_name(context, principal, &principal_string);
@@ -997,8 +996,8 @@ static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db,
}
nt_status = sam_get_results_principal((struct ldb_context *)db->hdb_db,
- mem_ctx, principal_string,
- &realm_dn, &msg);
+ mem_ctx, principal_string, attrs,
+ realm_dn, msg);
free(principal_string);
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
return HDB_ERR_NOENTRY;
@@ -1008,9 +1007,29 @@ static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db,
return EINVAL;
}
+ return ret;
+}
+
+static krb5_error_code hdb_samba4_fetch_client(krb5_context context, HDB *db,
+ struct loadparm_context *lp_ctx,
+ TALLOC_CTX *mem_ctx,
+ krb5_const_principal principal,
+ unsigned flags,
+ hdb_entry_ex *entry_ex) {
+ struct ldb_dn *realm_dn;
+ krb5_error_code ret;
+ struct ldb_message *msg = NULL;
+
+ ret = hdb_samba4_lookup_client(context, db, lp_ctx,
+ mem_ctx, principal, user_attrs,
+ &realm_dn, &msg);
+ if (ret != 0) {
+ return ret;
+ }
+
ret = hdb_samba4_message2entry(context, db, lp_ctx, mem_ctx,
- principal, HDB_SAMBA4_ENT_TYPE_CLIENT,
- realm_dn, msg, entry_ex);
+ principal, HDB_SAMBA4_ENT_TYPE_CLIENT,
+ realm_dn, msg, entry_ex);
return ret;
}
@@ -1422,6 +1441,11 @@ static krb5_error_code hdb_samba4_destroy(krb5_context context, HDB *db)
return 0;
}
+
+/* Check if a given entry may delegate to this target principal
+ *
+ * This is currently a very nasty hack - allowing only delegation to itself.
+ */
krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HDB *db,
hdb_entry_ex *entry,
krb5_const_principal target_principal)
@@ -1491,6 +1515,60 @@ krb5_error_code hdb_samba4_check_constrained_delegation(krb5_context context, HD
return ret;
}
+/* Certificates printed by a the Certificate Authority might have a
+ * slightly different form of the user principal name to that in the
+ * database. Allow a mismatch where they both refer to the same
+ * SID */
+
+krb5_error_code hdb_samba4_check_pkinit_ms_upn_match(krb5_context context, HDB *db,
+ hdb_entry_ex *entry,
+ krb5_const_principal certificate_principal)
+{
+ struct ldb_context *ldb_ctx = (struct ldb_context *)db->hdb_db;
+ struct loadparm_context *lp_ctx = talloc_get_type(ldb_get_opaque(ldb_ctx, "loadparm"),
+ struct loadparm_context);
+ krb5_error_code ret;
+ struct ldb_dn *realm_dn;
+ struct ldb_message *msg;
+ struct dom_sid *orig_sid;
+ struct dom_sid *target_sid;
+ struct hdb_samba4_private *p = talloc_get_type(entry->ctx, struct hdb_samba4_private);
+ const char *ms_upn_check_attrs[] = {
+ "objectSid", NULL
+ };
+
+ TALLOC_CTX *mem_ctx = talloc_named(db, 0, "hdb_samba4_check_constrained_delegation");
+
+ if (!mem_ctx) {
+ ret = ENOMEM;
+ krb5_set_error_message(context, ret, "hdb_samba4_fetch: talloc_named() failed!");
+ return ret;
+ }
+
+ ret = hdb_samba4_lookup_client(context, db, lp_ctx,
+ mem_ctx, certificate_principal,
+ ms_upn_check_attrs, &realm_dn, &msg);
+
+ if (ret != 0) {
+ talloc_free(mem_ctx);
+ return ret;
+ }
+
+ orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
+ target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
+
+ /* Consider these to be the same principal, even if by a different
+ * name. The easy and safe way to prove this is by SID
+ * comparison */
+ if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
+ talloc_free(mem_ctx);
+ return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
+ }
+
+ talloc_free(mem_ctx);
+ return ret;
+}
+
/* This interface is to be called by the KDC and libnet_keytab_dump, which is expecting Samba
* calling conventions. It is also called by a wrapper
* (hdb_samba4_create) from the kpasswdd -> krb5 -> keytab_hdb -> hdb
@@ -1556,6 +1634,7 @@ NTSTATUS hdb_samba4_create_kdc(TALLOC_CTX *mem_ctx,
(*db)->hdb_auth_status = NULL;
(*db)->hdb_check_constrained_delegation = hdb_samba4_check_constrained_delegation;
+ (*db)->hdb_check_pkinit_ms_upn_match = hdb_samba4_check_pkinit_ms_upn_match;
return NT_STATUS_OK;
}