summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/auth/auth_sam.c5
-rw-r--r--source4/dsdb/samdb/cracknames.c61
-rw-r--r--source4/lib/ldb/common/ldb_parse.c13
-rw-r--r--source4/lib/ldb/include/ldb.h2
-rw-r--r--source4/rpc_server/lsa/dcesrv_lsa.c16
-rw-r--r--source4/rpc_server/samr/dcesrv_samr.c12
6 files changed, 82 insertions, 27 deletions
diff --git a/source4/auth/auth_sam.c b/source4/auth/auth_sam.c
index e65a5c70f6..95a7702822 100644
--- a/source4/auth/auth_sam.c
+++ b/source4/auth/auth_sam.c
@@ -280,10 +280,11 @@ static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *
const struct ldb_dn *domain_dn = NULL;
if (domain_name) {
+ char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
/* find the domain's DN */
ret_domain = gendb_search(sam_ctx, mem_ctx, NULL, &msgs_domain_ref, domain_ref_attrs,
"(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
- domain_name, domain_name);
+ escaped_domain, escaped_domain);
if (ret_domain == -1) {
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
@@ -306,7 +307,7 @@ static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *
/* pull the user attributes */
ret = gendb_search(sam_ctx, mem_ctx, domain_dn, &msgs, user_attrs,
"(&(sAMAccountName=%s)(objectclass=user))",
- account_name);
+ ldb_binary_encode_string(mem_ctx, account_name));
if (ret == -1) {
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
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,
diff --git a/source4/lib/ldb/common/ldb_parse.c b/source4/lib/ldb/common/ldb_parse.c
index 5824a8d003..25e4b727df 100644
--- a/source4/lib/ldb/common/ldb_parse.c
+++ b/source4/lib/ldb/common/ldb_parse.c
@@ -127,6 +127,19 @@ char *ldb_binary_encode(void *mem_ctx, struct ldb_val val)
return ret;
}
+/*
+ encode a string as a RFC2254 binary string, escaping any
+ non-printable or '\' characters. This routine is suitable for use
+ in escaping user data in ldap filters.
+*/
+char *ldb_binary_encode_string(void *mem_ctx, const char *string)
+{
+ struct ldb_val val;
+ val.data = string;
+ val.length = strlen(string);
+ return ldb_binary_encode(mem_ctx, val);
+}
+
/* find the first matching wildcard */
static char *ldb_parse_find_wildcard(char *value)
{
diff --git a/source4/lib/ldb/include/ldb.h b/source4/lib/ldb/include/ldb.h
index 2fdf40b3bc..9c3b033091 100644
--- a/source4/lib/ldb/include/ldb.h
+++ b/source4/lib/ldb/include/ldb.h
@@ -214,7 +214,7 @@ struct ldb_parse_tree {
struct ldb_parse_tree *ldb_parse_tree(void *mem_ctx, const char *s);
char *ldb_filter_from_tree(void *mem_ctx, struct ldb_parse_tree *tree);
char *ldb_binary_encode(void *ctx, struct ldb_val val);
-
+char *ldb_binary_encode_string(void *mem_ctx, const char *string);
/*
functions for controlling attribute handling
diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c
index a0770764f5..64da9f488f 100644
--- a/source4/rpc_server/lsa/dcesrv_lsa.c
+++ b/source4/rpc_server/lsa/dcesrv_lsa.c
@@ -579,7 +579,7 @@ static NTSTATUS lsa_CreateTrustedDomain(struct dcesrv_call_state *dce_call, TALL
ret = gendb_search(trusted_domain_state->policy->sam_ldb,
mem_ctx, policy_state->system_dn, &msgs, attrs,
"(&(cn=%s)(objectclass=trustedDomain))",
- r->in.info->name.string);
+ ldb_binary_encode_string(mem_ctx, r->in.info->name.string));
if (ret > 0) {
return NT_STATUS_OBJECT_NAME_COLLISION;
}
@@ -740,7 +740,7 @@ static NTSTATUS lsa_OpenTrustedDomainByName(struct dcesrv_call_state *dce_call,
ret = gendb_search(trusted_domain_state->policy->sam_ldb,
mem_ctx, policy_state->system_dn, &msgs, attrs,
"(&(flatname=%s)(objectclass=trustedDomain))",
- r->in.name.string);
+ ldb_binary_encode_string(mem_ctx, r->in.name.string));
if (ret == 0) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
@@ -1709,7 +1709,7 @@ static NTSTATUS lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX
return NT_STATUS_INVALID_PARAMETER;
}
- name2 = talloc_asprintf(mem_ctx, "%s Secret", name);
+ name2 = talloc_asprintf(mem_ctx, "%s Secret", ldb_binary_encode_string(mem_ctx, name));
/* search for the secret record */
ret = gendb_search(secret_state->sam_ldb,
mem_ctx, policy_state->system_dn, &msgs, attrs,
@@ -1745,7 +1745,8 @@ static NTSTATUS lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX
ret = gendb_search(secret_state->sam_ldb, mem_ctx,
ldb_dn_explode(mem_ctx, "cn=LSA Secrets"),
&msgs, attrs,
- "(&(cn=%s)(objectclass=secret))", name);
+ "(&(cn=%s)(objectclass=secret))",
+ ldb_binary_encode_string(mem_ctx, name));
if (ret > 0) {
return NT_STATUS_OBJECT_NAME_COLLISION;
}
@@ -1843,7 +1844,7 @@ static NTSTATUS lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *m
ret = gendb_search(secret_state->sam_ldb,
mem_ctx, policy_state->system_dn, &msgs, attrs,
"(&(cn=%s Secret)(objectclass=secret))",
- name);
+ ldb_binary_encode_string(mem_ctx, name));
if (ret == 0) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
@@ -1867,7 +1868,8 @@ static NTSTATUS lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *m
ret = gendb_search(secret_state->sam_ldb, mem_ctx,
ldb_dn_explode(mem_ctx, "cn=LSA Secrets"),
&msgs, attrs,
- "(&(cn=%s)(objectclass=secret))", name);
+ "(&(cn=%s)(objectclass=secret))",
+ ldb_binary_encode_string(mem_ctx, name));
if (ret == 0) {
return NT_STATUS_OBJECT_NAME_NOT_FOUND;
}
@@ -2496,7 +2498,7 @@ static NTSTATUS lsa_lookup_name(struct lsa_policy_state *state, TALLOC_CTX *mem_
name = p + 1;
}
- ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs, "sAMAccountName=%s", name);
+ ret = gendb_search(state->sam_ldb, mem_ctx, NULL, &res, attrs, "sAMAccountName=%s", ldb_binary_encode_string(mem_ctx, name));
if (ret == 1) {
*sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
if (*sid == NULL) {
diff --git a/source4/rpc_server/samr/dcesrv_samr.c b/source4/rpc_server/samr/dcesrv_samr.c
index e2b1a3bddc..3de85388dd 100644
--- a/source4/rpc_server/samr/dcesrv_samr.c
+++ b/source4/rpc_server/samr/dcesrv_samr.c
@@ -186,7 +186,7 @@ static NTSTATUS samr_LookupDomain(struct dcesrv_call_state *dce_call, TALLOC_CTX
ret = gendb_search(c_state->sam_ctx,
mem_ctx, NULL, &ref_msgs, ref_attrs,
"(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
- r->in.domain_name->string);
+ ldb_binary_encode_string(mem_ctx, r->in.domain_name->string));
if (ret != 1) {
return NT_STATUS_NO_SUCH_DOMAIN;
}
@@ -537,7 +537,7 @@ static NTSTATUS samr_CreateDomainGroup(struct dcesrv_call_state *dce_call, TALLO
name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
"sAMAccountName",
"(&(sAMAccountName=%s)(objectclass=group))",
- groupname);
+ ldb_binary_encode_string(mem_ctx, groupname));
if (name != NULL) {
return NT_STATUS_GROUP_EXISTS;
}
@@ -741,7 +741,8 @@ static NTSTATUS samr_CreateUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX
/* check if the user already exists */
name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
"sAMAccountName",
- "(&(sAMAccountName=%s)(objectclass=user))", account_name);
+ "(&(sAMAccountName=%s)(objectclass=user))",
+ ldb_binary_encode_string(mem_ctx, account_name));
if (name != NULL) {
return NT_STATUS_USER_EXISTS;
}
@@ -969,7 +970,7 @@ static NTSTATUS samr_CreateDomAlias(struct dcesrv_call_state *dce_call, TALLOC_C
name = samdb_search_string(d_state->sam_ctx, mem_ctx, NULL,
"sAMAccountName",
"(sAMAccountName=%s)(objectclass=group))",
- alias_name);
+ ldb_binary_encode_string(mem_ctx, alias_name));
if (name != NULL) {
return NT_STATUS_ALIAS_EXISTS;
@@ -1251,7 +1252,8 @@ static NTSTATUS samr_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX
r->out.types.ids[i] = SID_NAME_UNKNOWN;
count = gendb_search(d_state->sam_ctx, mem_ctx, d_state->domain_dn, &res, attrs,
- "sAMAccountName=%s", r->in.names[i].string);
+ "sAMAccountName=%s",
+ ldb_binary_encode_string(mem_ctx, r->in.names[i].string));
if (count != 1) {
status = STATUS_SOME_UNMAPPED;
continue;