diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/auth/ntlm/auth_sam.c | 2 | ||||
-rw-r--r-- | source4/auth/sam.c | 6 | ||||
-rw-r--r-- | source4/heimdal/kdc/kerberos5.c | 1 | ||||
-rw-r--r-- | source4/heimdal/kdc/pkinit.c | 38 | ||||
-rw-r--r-- | source4/heimdal/lib/hdb/hdb.h | 7 | ||||
-rw-r--r-- | source4/kdc/hdb-samba4.c | 103 |
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; } |