diff options
Diffstat (limited to 'source4/kdc')
-rw-r--r-- | source4/kdc/hdb-samba4.c | 103 |
1 files changed, 91 insertions, 12 deletions
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; } |