diff options
-rw-r--r-- | source4/kdc/hdb-ldb.c | 194 |
1 files changed, 78 insertions, 116 deletions
diff --git a/source4/kdc/hdb-ldb.c b/source4/kdc/hdb-ldb.c index 8a43a19251..57218d72d9 100644 --- a/source4/kdc/hdb-ldb.c +++ b/source4/kdc/hdb-ldb.c @@ -52,13 +52,8 @@ static const char * const krb5_attrs[] = { "servicePrincipalName", "userAccountControl", - "sAMAccountType", - "objectSid", - "primaryGroupID", - "memberOf", - - "unicodePWD", + "unicodePwd", "lmPwdHash", "ntPwdHash", @@ -79,14 +74,9 @@ static const char * const krb5_attrs[] = { NULL }; -const char *cross_ref_attrs[] = { +static const char *realm_ref_attrs[] = { "nCName", - NULL -}; - -const char *realm_attrs[] = { - "dnsDomain", - "maxPwdAge", + "dnsRoot", NULL }; @@ -122,14 +112,14 @@ static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum h flags.renewable = 1; + /* All accounts are servers, but this may be disabled again in the caller */ + flags.server = 1; + /* Account types - clear the invalid bit if it turns out to be valid */ if (userAccountControl & UF_NORMAL_ACCOUNT) { if (ent_type == HDB_LDB_ENT_TYPE_CLIENT || ent_type == HDB_LDB_ENT_TYPE_ANY) { flags.client = 1; } - if (ent_type == HDB_LDB_ENT_TYPE_SERVER || ent_type == HDB_LDB_ENT_TYPE_ANY) { - flags.server = 1; - } flags.invalid = 0; } @@ -143,18 +133,12 @@ static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum h if (ent_type == HDB_LDB_ENT_TYPE_CLIENT || ent_type == HDB_LDB_ENT_TYPE_ANY) { flags.client = 1; } - if (ent_type == HDB_LDB_ENT_TYPE_SERVER || ent_type == HDB_LDB_ENT_TYPE_ANY) { - flags.server = 1; - } flags.invalid = 0; } if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) { if (ent_type == HDB_LDB_ENT_TYPE_CLIENT || ent_type == HDB_LDB_ENT_TYPE_ANY) { flags.client = 1; } - if (ent_type == HDB_LDB_ENT_TYPE_SERVER || ent_type == HDB_LDB_ENT_TYPE_ANY) { - flags.server = 1; - } flags.invalid = 0; } @@ -227,7 +211,7 @@ static HDBFlags uf2HDBFlags(krb5_context context, int userAccountControl, enum h */ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db, TALLOC_CTX *mem_ctx, krb5_const_principal principal, - enum hdb_ldb_ent_type ent_type, struct ldb_message *realm_msg, + enum hdb_ldb_ent_type ent_type, struct ldb_message *realm_ref_msg, struct ldb_message *msg, hdb_entry *ent) { @@ -235,7 +219,7 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db, int userAccountControl; int i; krb5_error_code ret = 0; - const char *dnsdomain = ldb_msg_find_string(realm_msg, "dnsDomain", NULL); + const char *dnsdomain = ldb_msg_find_string(realm_ref_msg, "dnsRoot", NULL); char *realm = strupper_talloc(mem_ctx, dnsdomain); if (!realm) { @@ -296,6 +280,12 @@ static krb5_error_code LDB_message2entry(krb5_context context, HDB *db, ent->flags.server = 1; } + if (lp_parm_bool(-1, "kdc", "require spn for service", True)) { + if (!ldb_msg_find_string(msg, "servicePrincipalName", NULL)) { + ent->flags.server = 0; + } + } + /* use 'whenCreated' */ ent->created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0); /* use '???' */ @@ -479,16 +469,7 @@ static krb5_error_code LDB_lookup_principal(krb5_context context, struct ldb_con struct ldb_message **msg = NULL; - /* Structure assignment, so we don't mess with the source parameter */ - struct Principal princ = *principal; - - /* Allow host/dns.name/realm@REALM, just convert into host/dns.name@REALM */ - if (princ.name.name_string.len == 3 - && strcasecmp_m(princ.name.name_string.val[2], princ.realm) == 0) { - princ.name.name_string.len = 2; - } - - ret = krb5_unparse_name(context, &princ, &princ_str); + ret = krb5_unparse_name(context, principal, &princ_str); if (ret != 0) { krb5_set_error_string(context, "LDB_lookup_principal: could not parse principal"); @@ -496,7 +477,7 @@ static krb5_error_code LDB_lookup_principal(krb5_context context, struct ldb_con return ret; } - ret = krb5_unparse_name_norealm(context, &princ, &short_princ); + ret = krb5_unparse_name_norealm(context, principal, &short_princ); if (ret != 0) { free(princ_str); @@ -515,17 +496,17 @@ static krb5_error_code LDB_lookup_principal(krb5_context context, struct ldb_con } switch (ent_type) { + case HDB_LDB_ENT_TYPE_CLIENT: + /* Can't happen */ + return EINVAL; + break; case HDB_LDB_ENT_TYPE_KRBTGT: filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))", KRB5_TGS_NAME); break; - case HDB_LDB_ENT_TYPE_CLIENT: - filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(|(samAccountName=%s)(userPrincipalName=%s)))", - short_princ_talloc, princ_str_talloc); - break; case HDB_LDB_ENT_TYPE_SERVER: - filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(|(samAccountName=%s)(servicePrincipalName=%s)))", - short_princ_talloc, short_princ_talloc); + filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))", + short_princ_talloc); break; case HDB_LDB_ENT_TYPE_ANY: filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(|(|(samAccountName=%s)(servicePrincipalName=%s))(userPrincipalName=%s)))", @@ -566,12 +547,9 @@ static krb5_error_code LDB_lookup_realm(krb5_context context, struct ldb_context const char *realm, struct ldb_message ***pmsg) { - int count; - struct ldb_dn *realm_dn; - const char *realm_dn_str; + int count; char *cross_ref_filter; struct ldb_message **cross_ref_msg; - struct ldb_message **msg; cross_ref_filter = talloc_asprintf(mem_ctx, "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))", @@ -582,7 +560,7 @@ static krb5_error_code LDB_lookup_realm(krb5_context context, struct ldb_context } count = ldb_search(ldb_ctx, NULL, LDB_SCOPE_SUBTREE, cross_ref_filter, - cross_ref_attrs, &cross_ref_msg); + realm_ref_attrs, &cross_ref_msg); if (count < 1) { krb5_warnx(context, "ldb_search: filter: '%s' failed: %d", cross_ref_filter, count); @@ -598,25 +576,10 @@ static krb5_error_code LDB_lookup_realm(krb5_context context, struct ldb_context return HDB_ERR_NOENTRY; } - realm_dn_str = ldb_msg_find_string(cross_ref_msg[0], "nCName", NULL); - realm_dn = ldb_dn_explode(mem_ctx, realm_dn_str); - - count = ldb_search(ldb_ctx, realm_dn, LDB_SCOPE_BASE, "(objectClass=domain)", - realm_attrs, &msg); if (pmsg) { - *pmsg = talloc_steal(mem_ctx, msg); + *pmsg = talloc_steal(mem_ctx, cross_ref_msg); } else { - talloc_free(msg); - } - - if (count < 1) { - krb5_warnx(context, "ldb_search: dn: %s not found: %d", realm_dn_str, count); - krb5_set_error_string(context, "ldb_search: dn: %s not found: %d", realm_dn_str, count); - return HDB_ERR_NOENTRY; - } else if (count > 1) { - krb5_warnx(context, "ldb_search: dn: '%s' more than 1 entry: %d", realm_dn_str, count); - krb5_set_error_string(context, "ldb_search: dn: %s more than 1 entry: %d", realm_dn_str, count); - return HDB_ERR_NOENTRY; + talloc_free(cross_ref_msg); } return 0; @@ -660,7 +623,7 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { struct ldb_message **msg = NULL; - struct ldb_message **realm_msg = NULL; + struct ldb_message **realm_ref_msg = NULL; struct ldb_message **realm_fixed_msg = NULL; enum hdb_ldb_ent_type ldb_ent_type; krb5_error_code ret; @@ -674,7 +637,7 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, return ENOMEM; } - /* Cludge, cludge cludge. If the realm part of krbtgt/realm, + /* Cludge, cludge cludge. If the realm part of krbtgt/realm, * is in our db, then direct the caller at our primary * krgtgt */ @@ -711,8 +674,9 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, return HDB_ERR_NOENTRY; } - ldb_ret = gendb_search_dn((struct ldb_context *)db->hdb_db, - mem_ctx, domain_dn, &realm_msg, realm_attrs); + ldb_ret = gendb_search((struct ldb_context *)db->hdb_db, + mem_ctx, NULL, &realm_ref_msg, realm_ref_attrs, + "ncName=%s", ldb_dn_linearize(mem_ctx, domain_dn)); if (ldb_ret != 1) { return HDB_ERR_NOENTRY; @@ -720,15 +684,40 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, ret = LDB_message2entry(context, db, mem_ctx, principal, ldb_ent_type, - realm_msg[0], msg[0], entry); + realm_ref_msg[0], msg[0], entry); talloc_free(mem_ctx); return ret; } case HDB_ENT_TYPE_SERVER: - if ((principal->name.name_string.len == 2) - && (strcmp(principal->name.name_string.val[0], KRB5_TGS_NAME) == 0)) { + if (principal->name.name_string.len == 2 + && (strcmp(principal->name.name_string.val[0], KRB5_TGS_NAME) == 0)) { /* krbtgt case. Either us or a trusted realm */ - + if ((LDB_lookup_realm(context, (struct ldb_context *)db->hdb_db, + mem_ctx, principal->name.name_string.val[1], &realm_fixed_msg) == 0)) { + /* us */ + const char *dnsdomain = ldb_msg_find_string(realm_fixed_msg[0], "dnsRoot", NULL); + char *realm_fixed = strupper_talloc(mem_ctx, dnsdomain); + if (!realm_fixed) { + krb5_set_error_string(context, "strupper_talloc: out of memory"); + talloc_free(mem_ctx); + return ENOMEM; + } + + free(principal->name.name_string.val[1]); + principal->name.name_string.val[1] = strdup(realm_fixed); + talloc_free(realm_fixed); + if (!principal->name.name_string.val[1]) { + krb5_set_error_string(context, "LDB_fetch: strdup() failed!"); + talloc_free(mem_ctx); + return ENOMEM; + } + ldb_ent_type = HDB_LDB_ENT_TYPE_KRBTGT; + break; + } else { + /* we should lookup trusted domains */ + return HDB_ERR_NOENTRY; + } + } else if (principal->name.name_string.len >= 2) { /* 'normal server' case */ int ldb_ret; @@ -761,53 +750,26 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, mem_ctx, user_dn, &msg, krb5_attrs); if (ldb_ret != 1) { - return HDB_ERR_NOENTRY; + return HDB_ERR_NOENTRY; } - ldb_ret = gendb_search_dn((struct ldb_context *)db->hdb_db, - mem_ctx, domain_dn, &realm_msg, realm_attrs); + ldb_ret = gendb_search((struct ldb_context *)db->hdb_db, + mem_ctx, NULL, &realm_ref_msg, realm_ref_attrs, + "ncName=%s", ldb_dn_linearize(mem_ctx, domain_dn)); if (ldb_ret != 1) { return HDB_ERR_NOENTRY; } - + ret = LDB_message2entry(context, db, mem_ctx, principal, ldb_ent_type, - realm_msg[0], msg[0], entry); + realm_ref_msg[0], msg[0], entry); talloc_free(mem_ctx); return ret; } else { - /* server as client principal case, but we must not lookup userPrincipalNames */ - } - } - - switch (ent_type) { - case HDB_ENT_TYPE_SERVER: - if (principal->name.name_string.len == 2 - && (strcmp(principal->name.name_string.val[0], KRB5_TGS_NAME) == 0) - && (LDB_lookup_realm(context, (struct ldb_context *)db->hdb_db, - mem_ctx, principal->name.name_string.val[1], &realm_fixed_msg) == 0)) { - const char *dnsdomain = ldb_msg_find_string(realm_fixed_msg[0], "dnsDomain", NULL); - char *realm_fixed = strupper_talloc(mem_ctx, dnsdomain); - if (!realm_fixed) { - krb5_set_error_string(context, "strupper_talloc: out of memory"); - talloc_free(mem_ctx); - return ENOMEM; - } - - free(principal->name.name_string.val[1]); - principal->name.name_string.val[1] = strdup(realm_fixed); - talloc_free(realm_fixed); - if (!principal->name.name_string.val[1]) { - krb5_set_error_string(context, "LDB_fetch: strdup() failed!"); - talloc_free(mem_ctx); - return ENOMEM; - } - ldb_ent_type = HDB_LDB_ENT_TYPE_KRBTGT; - break; - } else { ldb_ent_type = HDB_LDB_ENT_TYPE_SERVER; + /* server as client principal case, but we must not lookup userPrincipalNames */ break; } case HDB_ENT_TYPE_ANY: @@ -823,14 +785,14 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, realm = krb5_principal_get_realm(context, principal); ret = LDB_lookup_realm(context, (struct ldb_context *)db->hdb_db, - mem_ctx, realm, &realm_msg); + mem_ctx, realm, &realm_ref_msg); if (ret != 0) { krb5_warnx(context, "LDB_fetch: could not find realm"); talloc_free(mem_ctx); return HDB_ERR_NOENTRY; } - realm_dn = realm_msg[0]->dn; + realm_dn = samdb_result_dn(mem_ctx, realm_ref_msg[0], "nCName", NULL); ret = LDB_lookup_principal(context, (struct ldb_context *)db->hdb_db, mem_ctx, @@ -844,7 +806,7 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, } else { ret = LDB_message2entry(context, db, mem_ctx, principal, ldb_ent_type, - realm_msg[0], msg[0], entry); + realm_ref_msg[0], msg[0], entry); if (ret != 0) { krb5_warnx(context, "LDB_fetch: message2entry failed\n"); } @@ -869,7 +831,7 @@ struct hdb_ldb_seq { int index; int count; struct ldb_message **msgs; - struct ldb_message **realm_msgs; + struct ldb_message **realm_ref_msgs; }; static krb5_error_code LDB_seq(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) @@ -891,7 +853,7 @@ static krb5_error_code LDB_seq(krb5_context context, HDB *db, unsigned flags, hd if (priv->index < priv->count) { ret = LDB_message2entry(context, db, mem_ctx, NULL, HDB_LDB_ENT_TYPE_ANY, - priv->realm_msgs[0], priv->msgs[priv->index++], entry); + priv->realm_ref_msgs[0], priv->msgs[priv->index++], entry); } else { ret = HDB_ERR_NOENTRY; } @@ -914,7 +876,7 @@ static krb5_error_code LDB_firstkey(krb5_context context, HDB *db, unsigned flag char *realm; struct ldb_dn *realm_dn = NULL; struct ldb_message **msgs = NULL; - struct ldb_message **realm_msgs = NULL; + struct ldb_message **realm_ref_msgs = NULL; krb5_error_code ret; TALLOC_CTX *mem_ctx; @@ -932,7 +894,7 @@ static krb5_error_code LDB_firstkey(krb5_context context, HDB *db, unsigned flag priv->ctx = ldb_ctx; priv->index = 0; priv->msgs = NULL; - priv->realm_msgs = NULL; + priv->realm_ref_msgs = NULL; priv->count = 0; mem_ctx = talloc_named(priv, 0, "LDB_firstkey context"); @@ -949,7 +911,7 @@ static krb5_error_code LDB_firstkey(krb5_context context, HDB *db, unsigned flag } ret = LDB_lookup_realm(context, (struct ldb_context *)db->hdb_db, - mem_ctx, realm, &realm_msgs); + mem_ctx, realm, &realm_ref_msgs); free(realm); @@ -959,9 +921,9 @@ static krb5_error_code LDB_firstkey(krb5_context context, HDB *db, unsigned flag return HDB_ERR_NOENTRY; } - realm_dn = realm_msgs[0]->dn; + realm_dn = samdb_result_dn(mem_ctx, realm_ref_msgs[0], "nCName", NULL); - priv->realm_msgs = talloc_steal(priv, realm_msgs); + priv->realm_ref_msgs = talloc_steal(priv, realm_ref_msgs); krb5_warnx(context, "LDB_firstkey: realm ok\n"); @@ -1014,7 +976,7 @@ krb5_error_code hdb_ldb_create(TALLOC_CTX *mem_ctx, (*db)->hdb_db = NULL; /* Setup the link to LDB */ - (*db)->hdb_db = samdb_connect(db, system_session(db)); + (*db)->hdb_db = samdb_connect(*db, system_session(db)); if ((*db)->hdb_db == NULL) { krb5_warnx(context, "hdb_ldb_create: samdb_connect failed!"); krb5_set_error_string(context, "samdb_connect failed!"); |