diff options
Diffstat (limited to 'source4/dsdb')
-rw-r--r-- | source4/dsdb/samdb/cracknames.c | 61 |
1 files changed, 49 insertions, 12 deletions
diff --git a/source4/dsdb/samdb/cracknames.c b/source4/dsdb/samdb/cracknames.c index c95ab047e3..2010005a6b 100644 --- a/source4/dsdb/samdb/cracknames.c +++ b/source4/dsdb/samdb/cracknames.c @@ -115,6 +115,11 @@ static enum drsuapi_DsNameStatus LDB_lookup_spn_alias(krb5_context context, stru return DRSUAPI_DS_NAME_STATUS_NOT_FOUND; } +/* When cracking a ServicePrincipalName, many services may be served + * by the host/ servicePrincipalName. The incoming query is for cifs/ + * but we translate it here, and search on host/. This is done after + * the cifs/ entry has been searched for, making this a fallback */ + static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, uint32_t format_flags, uint32_t format_offered, uint32_t format_desired, @@ -185,6 +190,8 @@ static WERROR DsCrackNameSPNAlias(struct ldb_context *sam_ctx, TALLOC_CTX *mem_c return wret; } +/* Subcase of CrackNames, for the userPrincipalName */ + static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, uint32_t format_flags, uint32_t format_offered, uint32_t format_desired, @@ -214,7 +221,8 @@ static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, realm = krb5_princ_realm(smb_krb5_context->krb5_context, principal); domain_filter = talloc_asprintf(mem_ctx, "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))", - *realm, *realm); + ldb_binary_encode_string(mem_ctx, *realm), + ldb_binary_encode_string(mem_ctx, *realm)); ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short); krb5_free_principal(smb_krb5_context->krb5_context, principal); @@ -225,7 +233,7 @@ static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, /* This may need to be extended for more userPrincipalName variations */ result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))", - unparsed_name_short); + ldb_binary_encode_string(mem_ctx, unparsed_name_short)); if (!result_filter || !domain_filter) { free(unparsed_name_short); return WERR_NOMEM; @@ -239,6 +247,8 @@ static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, return status; } +/* Crack a single 'name', from format_offered into format_desired, returning the result in info1 */ + WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, uint32_t format_flags, uint32_t format_offered, uint32_t format_desired, const char *name, struct drsuapi_DsNameInfo1 *info1) @@ -284,7 +294,7 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, domain_filter = talloc_asprintf(mem_ctx, "(&(&(&(dnsRoot=%s)(objectclass=crossRef)))(nETBIOSName=*)(ncName=*))", - str); + ldb_binary_encode_string(mem_ctx, str)); WERR_TALLOC_CHECK(domain_filter); break; @@ -311,11 +321,11 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, domain_filter = talloc_asprintf(mem_ctx, "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", - domain); + ldb_binary_encode_string(mem_ctx, domain)); WERR_TALLOC_CHECK(domain_filter); if (account) { result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)", - account); + ldb_binary_encode_string(mem_ctx, account)); WERR_TALLOC_CHECK(result_filter); } @@ -356,7 +366,8 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, domain_filter = NULL; result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))", - name, name); + ldb_binary_encode_string(mem_ctx, name), + ldb_binary_encode_string(mem_ctx, name)); WERR_TALLOC_CHECK(result_filter); break; } @@ -399,7 +410,7 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, krb5_free_principal(smb_krb5_context->krb5_context, principal); result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))", - unparsed_name); + ldb_binary_encode_string(mem_ctx, unparsed_name)); free(unparsed_name); WERR_TALLOC_CHECK(result_filter); @@ -408,6 +419,7 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: { krb5_principal principal; char *unparsed_name_short; + char *service; ret = krb5_parse_name_norealm(smb_krb5_context->krb5_context, name, &principal); if (ret) { /* perhaps it's a principal with a realm, so return the right 'domain only' response */ @@ -437,13 +449,20 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, domain_filter = NULL; ret = krb5_unparse_name_norealm(smb_krb5_context->krb5_context, principal, &unparsed_name_short); - krb5_free_principal(smb_krb5_context->krb5_context, principal); if (ret) { + krb5_free_principal(smb_krb5_context->krb5_context, principal); return WERR_NOMEM; } - - result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(servicePrincipalName=%s))", - unparsed_name_short); + service = principal->name.name_string.val[0]; + if ((principal->name.name_string.len == 2) && (strcasecmp(service, "host") == 0)) { + result_filter = talloc_asprintf(mem_ctx, "(|(&(servicePrincipalName=%s)(objectClass=user))(&(cn=%s)(objectClass=computer)))", + ldb_binary_encode_string(mem_ctx, unparsed_name_short), + ldb_binary_encode_string(mem_ctx, principal->name.name_string.val[1])); + } else { + result_filter = talloc_asprintf(mem_ctx, "(&(servicePrincipalName=%s)(objectClass=user))", + ldb_binary_encode_string(mem_ctx, unparsed_name_short)); + } + krb5_free_principal(smb_krb5_context->krb5_context, principal); free(unparsed_name_short); WERR_TALLOC_CHECK(result_filter); @@ -469,6 +488,10 @@ WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, info1); } +/* Subcase of CrackNames. It is possible to translate a LDAP-style DN + * (FQDN_1779) into a canoical name without actually searching the + * database */ + static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx, uint32_t format_offered, uint32_t format_desired, const struct ldb_dn *name_dn, const char *name, @@ -498,9 +521,15 @@ static WERROR DsCrackNameOneSyntactical(TALLOC_CTX *mem_ctx, } return WERR_OK; - } +/* Given a filter for the domain, and one for the result, perform the + * ldb search. The format offered and desired flags change the + * behaviours, including what attributes to return. + * + * The smb_krb5_context is required because we use the krb5 libs for principal parsing + */ + static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct smb_krb5_context *smb_krb5_context, uint32_t format_flags, uint32_t format_offered, uint32_t format_desired, @@ -733,6 +762,10 @@ static WERROR DsCrackNameOneFilter(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ return WERR_INVALID_PARAM; } +/* Given a user Principal Name (such as foo@bar.com), + * return the user and domain DNs. This is used in the KDC to then + * return the Keys and evaluate policy */ + NTSTATUS crack_user_principal_name(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, const char *user_principal_name, @@ -792,6 +825,10 @@ NTSTATUS crack_user_principal_name(struct ldb_context *sam_ctx, } +/* Given a Service Principal Name (such as host/foo.bar.com@BAR.COM), + * return the user and domain DNs. This is used in the KDC to then + * return the Keys and evaluate policy */ + NTSTATUS crack_service_principal_name(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, const char *service_principal_name, |