Example #1
0
/**
   \details Check if the user record which legacyExchangeDN points to
   belongs to the Exchange organization and is enabled

   \param dce_call pointer to the session context
   \param emsmdbp_ctx pointer to the EMSMDBP context
   \param legacyExchangeDN pointer to the userDN to lookup
   \param msg pointer on pointer to the LDB message matching the record

   \note Users can set msg to NULL if they do not intend to retrieve
   the message

   \return true on success, otherwise false
 */
_PUBLIC_ bool emsmdbp_verify_userdn(struct dcesrv_call_state *dce_call,
				    struct emsmdbp_context *emsmdbp_ctx,
				    const char *legacyExchangeDN,
				    struct ldb_message **msg)
{
	int			ret;
	int			msExchUserAccountControl;
	struct ldb_result	*res = NULL;
	const char * const	recipient_attrs[] = { "*", NULL };

	/* Sanity Checks */
	if (!legacyExchangeDN) return false;

	ret = ldb_search(emsmdbp_ctx->samdb_ctx, emsmdbp_ctx, &res,
			 ldb_get_default_basedn(emsmdbp_ctx->samdb_ctx),
			 LDB_SCOPE_SUBTREE, recipient_attrs, "(legacyExchangeDN=%s)",
			 ldb_binary_encode_string(emsmdbp_ctx, legacyExchangeDN));

	/* If the search failed */
	if (ret != LDB_SUCCESS || !res->count) {
		return false;
	}

	/* Checks msExchUserAccountControl value */
	msExchUserAccountControl = ldb_msg_find_attr_as_int(res->msgs[0], "msExchUserAccountControl", 2);
	if (msExchUserAccountControl == 2) {
		return false;
	}

	if (msg) {
		*msg = res->msgs[0];
	}

	return true;
}
Example #2
0
static char *samldb_generate_samAccountName(struct ldb_module *module, TALLOC_CTX *mem_ctx) 
{
	char *name;
	const char *attrs[] = { NULL };
	struct ldb_message **msgs;
	int ret;
	
	/* Format: $000000-000000000000 */
	
	do {
		name = talloc_asprintf(mem_ctx, "$%.6X-%.6X%.6X", (unsigned int)random(), (unsigned int)random(), (unsigned int)random());
		/* TODO: Figure out exactly what this is meant to conflict with */
		ret = gendb_search(module->ldb,
				   mem_ctx, NULL, &msgs, attrs,
				   "samAccountName=%s",
				   ldb_binary_encode_string(mem_ctx, name));
		if (ret == 0) {
			/* Great. There are no conflicting users/groups/etc */
			return name;
		} else if (ret == -1) {
			/* Bugger, there is a problem, and we don't know what it is until gendb_search improves */
			return NULL;
		} else {
			talloc_free(name);
                        /* gah, there are conflicting sids, lets move around the loop again... */
		}
	} while (1);
}
Example #3
0
/**
   \details Get the organization name (like "First Organization") as a DN.

   \param emsmdbp_ctx pointer to the EMSMDBP context
   \param basedn pointer to the returned struct ldb_dn

   \return MAPI_E_SUCCESS or an error if something happens
 */
_PUBLIC_ enum MAPISTATUS emsmdbp_get_org_dn(struct emsmdbp_context *emsmdbp_ctx, struct ldb_dn **basedn)
{
	enum MAPISTATUS		retval;
	int			ret;
	struct ldb_result	*res = NULL;
	char			*org_name;

	OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
	OPENCHANGE_RETVAL_IF(!emsmdbp_ctx->samdb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
	OPENCHANGE_RETVAL_IF(!basedn, MAPI_E_INVALID_PARAMETER, NULL);

	retval = emsmdbp_fetch_organizational_units(emsmdbp_ctx, emsmdbp_ctx, &org_name, NULL);
	OPENCHANGE_RETVAL_IF(retval != MAPI_E_SUCCESS, retval, NULL);

	ret = ldb_search(emsmdbp_ctx->samdb_ctx, emsmdbp_ctx, &res,
			 ldb_get_config_basedn(emsmdbp_ctx->samdb_ctx),
                         LDB_SCOPE_SUBTREE, NULL,
                         "(&(objectClass=msExchOrganizationContainer)(cn=%s))",
                         ldb_binary_encode_string(emsmdbp_ctx, org_name));
	talloc_free(org_name);

	/* If the search failed */
        if (ret != LDB_SUCCESS) {
	  	DEBUG(1, ("emsmdbp_get_org_dn ldb_search failure.\n"));
		return MAPI_E_NOT_FOUND;
        }

	*basedn = ldb_dn_new(emsmdbp_ctx, emsmdbp_ctx->samdb_ctx,
			     ldb_msg_find_attr_as_string(res->msgs[0], "distinguishedName", NULL));
	return MAPI_E_SUCCESS;
}
Example #4
0
/**
   \details Get the email of current user.

   \param emsmdbp_ctx pointer to the EMSMDBP context
   \param email pointer to return the email

   \note The email is obtained from proxyAddresses attribute, the one that
   starts with "SMTP:" which is the one used to authenticate on external
   smtp service.

   \return MAPI_E_SUCCESS or an error if something happens
 */
_PUBLIC_ enum MAPISTATUS emsmdbp_get_external_email(struct emsmdbp_context *emsmdbp_ctx, const char **email)
{
	const char * const		attrs[] = { "proxyAddresses", NULL };
	const char			*prefix = "SMTP:";
	size_t				prefix_len;
	int				ret, i;
	struct ldb_result		*res = NULL;
	struct ldb_message_element	*el = NULL;
	const struct ldb_val		*value = NULL;
	bool				found = false;

	OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
	OPENCHANGE_RETVAL_IF(!emsmdbp_ctx->samdb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
	OPENCHANGE_RETVAL_IF(!email, MAPI_E_INVALID_PARAMETER, NULL);

	ret = ldb_search(emsmdbp_ctx->samdb_ctx, emsmdbp_ctx, &res,
			 ldb_get_default_basedn(emsmdbp_ctx->samdb_ctx),
			 LDB_SCOPE_SUBTREE, attrs,
			 "(&(objectClass=user)(sAMAccountName=%s))",
			 ldb_binary_encode_string(emsmdbp_ctx, emsmdbp_ctx->username));

	if (ret != LDB_SUCCESS || res->count == 0) {
		OC_DEBUG(5, "Couldn't find %s using ldb_search", emsmdbp_ctx->username);
		return MAPI_E_NOT_FOUND;
	}

	el = ldb_msg_find_element(res->msgs[0], attrs[0]);
	if (!el) return MAPI_E_NOT_FOUND;

	prefix_len = strlen(prefix);
	for (i = 0; !found && i < el->num_values; i++) {
		value = (struct ldb_val *) &el->values[i];
		if (!value || value->length <= prefix_len || value->data[value->length] != '\0')
			continue;

		/* Searching for SMTP:[email protected] entry */
		if (strncmp((const char *)value->data, prefix, prefix_len) == 0) {
			*email = (char *)(value->data + prefix_len);
			found = true;
		}
	}

	return found ? MAPI_E_SUCCESS : MAPI_E_NOT_FOUND;
}
Example #5
0
/**
   \details Check if the authenticated user belongs to the Exchange
   organization and is enabled

   \param dce_call pointer to the session context
   \param emsmdbp_ctx pointer to the EMSMDBP context

   \return true on success, otherwise false
 */
_PUBLIC_ bool emsmdbp_verify_user(struct dcesrv_call_state *dce_call,
				  struct emsmdbp_context *emsmdbp_ctx)
{
	int			ret;
	const char		*username = NULL;
	int			msExchUserAccountControl;
	struct ldb_result	*res = NULL;
	const char * const	recipient_attrs[] = { "msExchUserAccountControl", NULL };

	username = dcesrv_call_account_name(dce_call);

	ret = ldb_search(emsmdbp_ctx->samdb_ctx, emsmdbp_ctx, &res,
			 ldb_get_default_basedn(emsmdbp_ctx->samdb_ctx),
			 LDB_SCOPE_SUBTREE, recipient_attrs, "sAMAccountName=%s",
			 ldb_binary_encode_string(emsmdbp_ctx, username));

	/* If the search failed */
	if (ret != LDB_SUCCESS || !res->count) {
		return false;
	}

	/* If msExchUserAccountControl attribute is not found */
	if (!res->msgs[0]->num_elements) {
		return false;
	}

	/* If the attribute exists check its value */
	msExchUserAccountControl = ldb_msg_find_attr_as_int(res->msgs[0], "msExchUserAccountControl", 2);
	if (msExchUserAccountControl == 2) {
		return false;
	}

	/* Get a copy of the username for later use and setup missing conn_info components */
	emsmdbp_ctx->username = talloc_strdup(emsmdbp_ctx, username);
	openchangedb_get_MailboxReplica(emsmdbp_ctx->oc_ctx, emsmdbp_ctx->username, &emsmdbp_ctx->mstore_ctx->conn_info->repl_id, &emsmdbp_ctx->mstore_ctx->conn_info->replica_guid);

	return true;
}
Example #6
0
static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
				       const char *account_name,
				       struct ldb_dn *domain_dn,
				       struct ldb_message **ret_msg)
{
	int ret;

	/* pull the user attributes */
	ret = gendb_search_single_extended_dn(sam_ctx, mem_ctx, domain_dn, LDB_SCOPE_SUBTREE,
					      ret_msg, user_attrs,
					      "(&(sAMAccountName=%s)(objectclass=user))", 
					      ldb_binary_encode_string(mem_ctx, account_name));
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n", 
			 account_name, ldb_dn_get_linearized(domain_dn)));
		return NT_STATUS_NO_SUCH_USER;		
	}
	if (ret != LDB_SUCCESS) {
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	
	return NT_STATUS_OK;
}
Example #7
0
/*
  Check if particular SPN exists for an account
 */
static bool dreplsrv_spn_exists(struct ldb_context *samdb, struct ldb_dn *ntds_dn,
				const char *principal_name)
{
	TALLOC_CTX *tmp_ctx;
	const char *attrs[] = { "serverReference", NULL };
	const char *attrs_empty[] = { NULL };
	int ret;
	struct ldb_result *res;
	struct ldb_dn *account_dn;

	tmp_ctx = talloc_new(samdb);

	ret = dsdb_search_dn(samdb, tmp_ctx, &res, ntds_dn, attrs, 0);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return false;
	}

	account_dn = ldb_msg_find_attr_as_dn(samdb, tmp_ctx, res->msgs[0], "serverReference");
	if (account_dn == NULL) {
		talloc_free(tmp_ctx);
		return false;
	}

	talloc_free(res);

	ret = dsdb_search(samdb, tmp_ctx, &res, account_dn, LDB_SCOPE_BASE, attrs_empty,
			0, "servicePrincipalName=%s",
			ldb_binary_encode_string(tmp_ctx, principal_name));
	if (ret != LDB_SUCCESS || res->count != 1) {
		talloc_free(tmp_ctx);
		return false;
	}

	talloc_free(tmp_ctx);
	return true;
}
Example #8
0
/*
  lookup a SID for 1 name
*/
static NTSTATUS dcesrv_lsa_lookup_name(struct tevent_context *ev_ctx,
                                       struct loadparm_context *lp_ctx,
                                       struct lsa_policy_state *state, TALLOC_CTX *mem_ctx,
                                       const char *name, const char **authority_name,
                                       struct dom_sid **sid, enum lsa_SidType *rtype,
                                       uint32_t *rid)
{
    int ret, i;
    uint32_t atype;
    struct ldb_message **res;
    const char * const attrs[] = { "objectSid", "sAMAccountType", NULL};
    const char *p;
    const char *domain;
    const char *username;
    struct ldb_dn *domain_dn;
    struct dom_sid *domain_sid;
    NTSTATUS status;

    p = strchr_m(name, '\\');
    if (p != NULL) {
        domain = talloc_strndup(mem_ctx, name, p-name);
        if (!domain) {
            return NT_STATUS_NO_MEMORY;
        }
        username = p + 1;
    } else if (strchr_m(name, '@')) {
        status = crack_name_to_nt4_name(mem_ctx, ev_ctx, lp_ctx, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, name, &domain, &username);
        if (!NT_STATUS_IS_OK(status)) {
            DEBUG(3, ("Failed to crack name %s into an NT4 name: %s\n", name, nt_errstr(status)));
            return status;
        }
    } else {
        domain = NULL;
        username = name;
    }

    if (!domain) {
        /* Look up table of well known names */
        status = lookup_well_known_names(mem_ctx, NULL, username, authority_name, sid, rtype);
        if (NT_STATUS_IS_OK(status)) {
            dom_sid_split_rid(NULL, *sid, NULL, rid);
            return NT_STATUS_OK;
        }

        if (username == NULL) {
            *authority_name = NAME_BUILTIN;
            *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN);
            *rtype = SID_NAME_DOMAIN;
            *rid = 0xFFFFFFFF;
            return NT_STATUS_OK;
        }

        if (strcasecmp_m(username, NAME_NT_AUTHORITY) == 0) {
            *authority_name = NAME_NT_AUTHORITY;
            *sid =  dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
            *rtype = SID_NAME_DOMAIN;
            dom_sid_split_rid(NULL, *sid, NULL, rid);
            return NT_STATUS_OK;
        }
        if (strcasecmp_m(username, NAME_BUILTIN) == 0) {
            *authority_name = NAME_BUILTIN;
            *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN);
            *rtype = SID_NAME_DOMAIN;
            *rid = 0xFFFFFFFF;
            return NT_STATUS_OK;
        }
        if (strcasecmp_m(username, state->domain_dns) == 0) {
            *authority_name = state->domain_name;
            *sid =  state->domain_sid;
            *rtype = SID_NAME_DOMAIN;
            *rid = 0xFFFFFFFF;
            return NT_STATUS_OK;
        }
        if (strcasecmp_m(username, state->domain_name) == 0) {
            *authority_name = state->domain_name;
            *sid =  state->domain_sid;
            *rtype = SID_NAME_DOMAIN;
            *rid = 0xFFFFFFFF;
            return NT_STATUS_OK;
        }

        /* Perhaps this is a well known user? */
        name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_NT_AUTHORITY, username);
        if (!name) {
            return NT_STATUS_NO_MEMORY;
        }
        status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid);
        if (NT_STATUS_IS_OK(status)) {
            return status;
        }

        /* Perhaps this is a BUILTIN user? */
        name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_BUILTIN, username);
        if (!name) {
            return NT_STATUS_NO_MEMORY;
        }
        status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid);
        if (NT_STATUS_IS_OK(status)) {
            return status;
        }

        /* OK, I give up - perhaps we need to assume the user is in our domain? */
        name = talloc_asprintf(mem_ctx, "%s\\%s", state->domain_name, username);
        if (!name) {
            return NT_STATUS_NO_MEMORY;
        }
        status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid);
        if (NT_STATUS_IS_OK(status)) {
            return status;
        }

        return STATUS_SOME_UNMAPPED;
    } else if (strcasecmp_m(domain, NAME_NT_AUTHORITY) == 0) {
        if (!*username) {
            *authority_name = NAME_NT_AUTHORITY;
            *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY);
            *rtype = SID_NAME_DOMAIN;
            dom_sid_split_rid(NULL, *sid, NULL, rid);
            return NT_STATUS_OK;
        }

        /* Look up table of well known names */
        status = lookup_well_known_names(mem_ctx, domain, username, authority_name,
                                         sid, rtype);
        if (NT_STATUS_IS_OK(status)) {
            dom_sid_split_rid(NULL, *sid, NULL, rid);
        }
        return status;
    } else if (strcasecmp_m(domain, NAME_BUILTIN) == 0) {
        *authority_name = NAME_BUILTIN;
        domain_dn = state->builtin_dn;
    } else if (strcasecmp_m(domain, state->domain_dns) == 0) {
        *authority_name = state->domain_name;
        domain_dn = state->domain_dn;
    } else if (strcasecmp_m(domain, state->domain_name) == 0) {
        *authority_name = state->domain_name;
        domain_dn = state->domain_dn;
    } else {
        /* Not local, need to ask winbind in future */
        return STATUS_SOME_UNMAPPED;
    }

    ret = gendb_search_dn(state->sam_ldb, mem_ctx, domain_dn, &res, attrs);
    if (ret == 1) {
        domain_sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid");
        if (domain_sid == NULL) {
            return NT_STATUS_INVALID_SID;
        }
    } else {
        return NT_STATUS_INVALID_SID;
    }

    if (!*username) {
        *sid = domain_sid;
        *rtype = SID_NAME_DOMAIN;
        *rid = 0xFFFFFFFF;
        return NT_STATUS_OK;
    }

    ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs,
                       "(&(sAMAccountName=%s)(objectSid=*))",
                       ldb_binary_encode_string(mem_ctx, username));
    if (ret == -1) {
        return NT_STATUS_INVALID_SID;
    }

    for (i=0; i < ret; i++) {
        *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid");
        if (*sid == NULL) {
            return NT_STATUS_INVALID_SID;
        }

        /* Check that this is in the domain */
        if (!dom_sid_in_domain(domain_sid, *sid)) {
            continue;
        }

        atype = samdb_result_uint(res[i], "sAMAccountType", 0);

        *rtype = ds_atype_map(atype);
        if (*rtype == SID_NAME_UNKNOWN) {
            return STATUS_SOME_UNMAPPED;
        }

        dom_sid_split_rid(NULL, *sid, NULL, rid);
        return NT_STATUS_OK;
    }

    /* need to check for an allocated sid */

    return NT_STATUS_INVALID_SID;
}
Example #9
0
/*
  fill in the cldap netlogon union for a given version
*/
NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx,
					 TALLOC_CTX *mem_ctx,
					 const char *domain,
					 const char *netbios_domain,
					 struct dom_sid *domain_sid,
					 const char *domain_guid,
					 const char *user,
					 uint32_t acct_control,
					 const char *src_address,
					 uint32_t version,
					 struct loadparm_context *lp_ctx,
					 struct netlogon_samlogon_response *netlogon,
					 bool fill_on_blank_request)
{
	const char *dom_attrs[] = {"objectGUID", NULL};
	const char *none_attrs[] = {NULL};
	struct ldb_result *dom_res = NULL, *user_res = NULL;
	int ret;
	const char **services = lpcfg_server_services(lp_ctx);
	uint32_t server_type;
	const char *pdc_name;
	struct GUID domain_uuid;
	const char *dns_domain;
	const char *forest_domain;
	const char *pdc_dns_name;
	const char *flatname;
	const char *server_site;
	const char *client_site;
	const char *pdc_ip;
	struct ldb_dn *domain_dn = NULL;
	struct interface *ifaces;
	bool user_known, am_rodc;
	NTSTATUS status;

	/* the domain parameter could have an optional trailing "." */
	if (domain && domain[strlen(domain)-1] == '.') {
		domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1);
		NT_STATUS_HAVE_NO_MEMORY(domain);
	}

	/* Lookup using long or short domainname */
	if (domain && (strcasecmp_m(domain, lpcfg_dnsdomain(lp_ctx)) == 0)) {
		domain_dn = ldb_get_default_basedn(sam_ctx);
	}
	if (netbios_domain && (strcasecmp_m(netbios_domain, lpcfg_sam_name(lp_ctx)) == 0)) {
		domain_dn = ldb_get_default_basedn(sam_ctx);
	}
	if (domain_dn) {
		const char *domain_identifier = domain != NULL ? domain
							: netbios_domain;
		ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
				 domain_dn, LDB_SCOPE_BASE, dom_attrs,
				 "objectClass=domain");
		if (ret != LDB_SUCCESS) {
			DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n",
				 domain_identifier,
				 ldb_dn_get_linearized(domain_dn),
				 ldb_errstring(sam_ctx)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		}
		if (dom_res->count != 1) {
			DEBUG(2,("Error finding domain '%s'/'%s' in sam\n",
				 domain_identifier,
				 ldb_dn_get_linearized(domain_dn)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		}
	}

	/* Lookup using GUID or SID */
	if ((dom_res == NULL) && (domain_guid || domain_sid)) {
		if (domain_guid) {
			struct GUID binary_guid;
			struct ldb_val guid_val;

			/* By this means, we ensure we don't have funny stuff in the GUID */

			status = GUID_from_string(domain_guid, &binary_guid);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}

			/* And this gets the result into the binary format we want anyway */
			status = GUID_to_ndr_blob(&binary_guid, mem_ctx, &guid_val);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
						 NULL, LDB_SCOPE_SUBTREE, 
						 dom_attrs, 
						 "(&(objectCategory=DomainDNS)(objectGUID=%s))", 
						 ldb_binary_encode(mem_ctx, guid_val));
		} else { /* domain_sid case */
			ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
					 NULL, LDB_SCOPE_SUBTREE,
					 dom_attrs,
					 "(&(objectCategory=DomainDNS)(objectSid=%s))",
					 dom_sid_string(mem_ctx, domain_sid));
		}
		
		if (ret != LDB_SUCCESS) {
			DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam: %s\n",
				 domain_guid, dom_sid_string(mem_ctx, domain_sid),
				 ldb_errstring(sam_ctx)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		} else if (dom_res->count == 1) {
			/* Ok, now just check it is our domain */
			if (ldb_dn_compare(ldb_get_default_basedn(sam_ctx),
					   dom_res->msgs[0]->dn) != 0) {
				DEBUG(2,("The GUID '%s' or SID '%s' doesn't identify our domain\n",
					 domain_guid,
					 dom_sid_string(mem_ctx, domain_sid)));
				return NT_STATUS_NO_SUCH_DOMAIN;
			}
		} else {
			DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam\n",
				 domain_guid, dom_sid_string(mem_ctx, domain_sid)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		}
	}

	if (dom_res == NULL && fill_on_blank_request) {
		/* blank inputs gives our domain - tested against
		   w2k8r2. Without this ADUC on Win7 won't start */
		domain_dn = ldb_get_default_basedn(sam_ctx);
		ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
				 domain_dn, LDB_SCOPE_BASE, dom_attrs,
				 "objectClass=domain");
		if (ret != LDB_SUCCESS) {
			DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n",
				 lpcfg_dnsdomain(lp_ctx),
				 ldb_dn_get_linearized(domain_dn),
				 ldb_errstring(sam_ctx)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		}
	}

        if (dom_res == NULL) {
		DEBUG(2,(__location__ ": Unable to get domain information with no inputs\n"));
		return NT_STATUS_NO_SUCH_DOMAIN;
	}

	/* work around different inputs for not-specified users */
	if (!user) {
		user = "";
	}

	/* Enquire about any valid username with just a CLDAP packet -
	 * if kerberos didn't also do this, the security folks would
	 * scream... */
	if (user[0]) {							\
		/* Only allow some bits to be enquired:  [MS-ATDS] 7.3.3.2 */
		if (acct_control == (uint32_t)-1) {
			acct_control = 0;
		}
		acct_control = acct_control & (ACB_TEMPDUP | ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST);

		/* We must exclude disabled accounts, but otherwise do the bitwise match the client asked for */
		ret = ldb_search(sam_ctx, mem_ctx, &user_res,
					 dom_res->msgs[0]->dn, LDB_SCOPE_SUBTREE, 
					 none_attrs, 
					 "(&(objectClass=user)(samAccountName=%s)"
					 "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))"
					 "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))", 
					 ldb_binary_encode_string(mem_ctx, user),
					 UF_ACCOUNTDISABLE, ds_acb2uf(acct_control));
		if (ret != LDB_SUCCESS) {
			DEBUG(2,("Unable to find reference to user '%s' with ACB 0x%8x under %s: %s\n",
				 user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn),
				 ldb_errstring(sam_ctx)));
			return NT_STATUS_NO_SUCH_USER;
		} else if (user_res->count == 1) {
			user_known = true;
		} else {
			user_known = false;
		}

	} else {
		user_known = true;
	}
		
	server_type      = 
		DS_SERVER_DS | DS_SERVER_TIMESERV |
		DS_SERVER_GOOD_TIMESERV;

	if (samdb_is_pdc(sam_ctx)) {
		server_type |= DS_SERVER_PDC;
	}

	if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008) {
		server_type |= DS_SERVER_FULL_SECRET_DOMAIN_6;
	}

	if (samdb_is_gc(sam_ctx)) {
		server_type |= DS_SERVER_GC;
	}

	if (str_list_check(services, "ldap")) {
		server_type |= DS_SERVER_LDAP;
	}

	if (str_list_check(services, "kdc")) {
		server_type |= DS_SERVER_KDC;
	}

	if (samdb_rodc(sam_ctx, &am_rodc) == LDB_SUCCESS && !am_rodc) {
		server_type |= DS_SERVER_WRITABLE;
	}

	pdc_name         = talloc_asprintf(mem_ctx, "\\\\%s",
					   lpcfg_netbios_name(lp_ctx));
	NT_STATUS_HAVE_NO_MEMORY(pdc_name);
	domain_uuid      = samdb_result_guid(dom_res->msgs[0], "objectGUID");
	dns_domain       = lpcfg_dnsdomain(lp_ctx);
	forest_domain    = samdb_forest_name(sam_ctx, mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(forest_domain);
	pdc_dns_name     = talloc_asprintf(mem_ctx, "%s.%s", 
					   strlower_talloc(mem_ctx, 
							   lpcfg_netbios_name(lp_ctx)),
					   dns_domain);
	NT_STATUS_HAVE_NO_MEMORY(pdc_dns_name);
	flatname         = lpcfg_workgroup(lp_ctx);

	server_site      = samdb_server_site_name(sam_ctx, mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(server_site);
	client_site      = samdb_client_site_name(sam_ctx, mem_ctx,
						  src_address, NULL);
	NT_STATUS_HAVE_NO_MEMORY(client_site);
	if (strcasecmp(server_site, client_site) == 0) {
		server_type |= DS_SERVER_CLOSEST;
	}

	load_interface_list(mem_ctx, lp_ctx, &ifaces);
	if (src_address) {
		pdc_ip = iface_list_best_ip(ifaces, src_address);
	} else {
		pdc_ip = iface_list_first_v4(ifaces);
	}
	if (pdc_ip == NULL || !is_ipaddress_v4(pdc_ip)) {
		/* this matches windows behaviour */
		pdc_ip = "127.0.0.1";
	}

	ZERO_STRUCTP(netlogon);

	/* check if either of these bits is present */
	if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) {
		uint32_t extra_flags = 0;
		netlogon->ntver = NETLOGON_NT_VERSION_5EX;

		/* could check if the user exists */
		if (user_known) {
			netlogon->data.nt5_ex.command      = LOGON_SAM_LOGON_RESPONSE_EX;
		} else {
			netlogon->data.nt5_ex.command      = LOGON_SAM_LOGON_USER_UNKNOWN_EX;
		}
		netlogon->data.nt5_ex.pdc_name     = pdc_name;
		netlogon->data.nt5_ex.user_name    = user;
		netlogon->data.nt5_ex.domain_name  = flatname;
		netlogon->data.nt5_ex.domain_uuid  = domain_uuid;
		netlogon->data.nt5_ex.forest       = forest_domain;
		netlogon->data.nt5_ex.dns_domain   = dns_domain;
		netlogon->data.nt5_ex.pdc_dns_name = pdc_dns_name;
		netlogon->data.nt5_ex.server_site  = server_site;
		netlogon->data.nt5_ex.client_site  = client_site;
		if (version & NETLOGON_NT_VERSION_5EX_WITH_IP) {
			/* note that this is always a IPV4 address */
			extra_flags = NETLOGON_NT_VERSION_5EX_WITH_IP;
			netlogon->data.nt5_ex.sockaddr.sockaddr_family    = 2;
			netlogon->data.nt5_ex.sockaddr.pdc_ip       = pdc_ip;
			netlogon->data.nt5_ex.sockaddr.remaining = data_blob_talloc_zero(mem_ctx, 8);
		}
		netlogon->data.nt5_ex.server_type  = server_type;
		netlogon->data.nt5_ex.nt_version   = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5EX|extra_flags;
		netlogon->data.nt5_ex.lmnt_token   = 0xFFFF;
		netlogon->data.nt5_ex.lm20_token   = 0xFFFF;

	} else if (version & NETLOGON_NT_VERSION_5) {
		netlogon->ntver = NETLOGON_NT_VERSION_5;

		/* could check if the user exists */
		if (user_known) {
			netlogon->data.nt5.command      = LOGON_SAM_LOGON_RESPONSE;
		} else {
			netlogon->data.nt5.command      = LOGON_SAM_LOGON_USER_UNKNOWN;
		}
		netlogon->data.nt5.pdc_name     = pdc_name;
		netlogon->data.nt5.user_name    = user;
		netlogon->data.nt5.domain_name  = flatname;
		netlogon->data.nt5.domain_uuid  = domain_uuid;
		netlogon->data.nt5.forest       = forest_domain;
		netlogon->data.nt5.dns_domain   = dns_domain;
		netlogon->data.nt5.pdc_dns_name = pdc_dns_name;
		netlogon->data.nt5.pdc_ip       = pdc_ip;
		netlogon->data.nt5.server_type  = server_type;
		netlogon->data.nt5.nt_version   = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5;
		netlogon->data.nt5.lmnt_token   = 0xFFFF;
		netlogon->data.nt5.lm20_token   = 0xFFFF;

	} else /* (version & NETLOGON_NT_VERSION_1) and all other cases */ {
		netlogon->ntver = NETLOGON_NT_VERSION_1;
		/* could check if the user exists */
		if (user_known) {
			netlogon->data.nt4.command      = LOGON_SAM_LOGON_RESPONSE;
		} else {
			netlogon->data.nt4.command      = LOGON_SAM_LOGON_USER_UNKNOWN;
		}
		netlogon->data.nt4.pdc_name    = pdc_name;
		netlogon->data.nt4.user_name   = user;
		netlogon->data.nt4.domain_name = flatname;
		netlogon->data.nt4.nt_version  = NETLOGON_NT_VERSION_1;
		netlogon->data.nt4.lmnt_token  = 0xFFFF;
		netlogon->data.nt4.lm20_token  = 0xFFFF;
	}

	return NT_STATUS_OK;
}
Example #10
0
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)
{
    krb5_error_code ret;
    const char *domain_filter = NULL;
    const char *result_filter = NULL;
    struct ldb_dn *name_dn = NULL;

    struct smb_krb5_context *smb_krb5_context = NULL;

    info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    info1->dns_domain_name = NULL;
    info1->result_name = NULL;

    if (!name) {
        return WERR_INVALID_PARAM;
    }

    /* TODO: - fill the correct names in all cases!
     *       - handle format_flags
     */

    /* here we need to set the domain_filter and/or the result_filter */
    switch (format_offered) {
    case DRSUAPI_DS_NAME_FORMAT_UNKNOWN:
    {
        int i;
        enum drsuapi_DsNameFormat formats[] = {
            DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
            DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_CANONICAL,
            DRSUAPI_DS_NAME_FORMAT_GUID, DRSUAPI_DS_NAME_FORMAT_DISPLAY,
            DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
            DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
            DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
        };
        WERROR werr;
        for (i=0; i < ARRAY_SIZE(formats); i++) {
            werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1);
            if (!W_ERROR_IS_OK(werr)) {
                return werr;
            }
            if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
                return werr;
            }
        }
        return werr;
    }

    case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
    case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
    {
        char *str, *s, *account;

        if (strlen(name) == 0) {
            info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
            return WERR_OK;
        }

        str = talloc_strdup(mem_ctx, name);
        W_ERROR_HAVE_NO_MEMORY(str);

        if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) {
            /* Look backwards for the \n, and replace it with / */
            s = strrchr(str, '\n');
            if (!s) {
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }
            s[0] = '/';
        }

        s = strchr(str, '/');
        if (!s) {
            /* there must be at least one / */
            info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
            return WERR_OK;
        }

        s[0] = '\0';
        s++;

        domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(ncName=%s))",
                                        ldb_dn_get_linearized(samdb_dns_domain_to_dn(sam_ctx, mem_ctx, str)));
        W_ERROR_HAVE_NO_MEMORY(domain_filter);

        /* There may not be anything after the domain component (search for the domain itself) */
        if (s[0]) {

            account = strrchr(s, '/');
            if (!account) {
                account = s;
            } else {
                account++;
            }
            account = ldb_binary_encode_string(mem_ctx, account);
            W_ERROR_HAVE_NO_MEMORY(account);
            result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
                                            account);
            W_ERROR_HAVE_NO_MEMORY(result_filter);
        }
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
        char *p;
        char *domain;
        const char *account = NULL;

        domain = talloc_strdup(mem_ctx, name);
        W_ERROR_HAVE_NO_MEMORY(domain);

        p = strchr(domain, '\\');
        if (!p) {
            /* invalid input format */
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        p[0] = '\0';

        if (p[1]) {
            account = &p[1];
        }

        domain_filter = talloc_asprintf(mem_ctx,
                                        "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
                                        ldb_binary_encode_string(mem_ctx, domain));
        W_ERROR_HAVE_NO_MEMORY(domain_filter);
        if (account) {
            result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
                                            ldb_binary_encode_string(mem_ctx, account));
            W_ERROR_HAVE_NO_MEMORY(result_filter);
        }

        talloc_free(domain);
        break;
    }

    /* A LDAP DN as a string */
    case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
        domain_filter = NULL;
        name_dn = ldb_dn_new(mem_ctx, sam_ctx, name);
        if (! ldb_dn_validate(name_dn)) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        break;
    }

    /* A GUID as a string */
    case DRSUAPI_DS_NAME_FORMAT_GUID: {
        struct GUID guid;
        char *ldap_guid;
        NTSTATUS nt_status;
        domain_filter = NULL;

        nt_status = GUID_from_string(name, &guid);
        if (!NT_STATUS_IS_OK(nt_status)) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }

        ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
        if (!ldap_guid) {
            return WERR_NOMEM;
        }
        result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
                                        ldap_guid);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
        domain_filter = NULL;

        result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
                                        ldb_binary_encode_string(mem_ctx, name),
                                        ldb_binary_encode_string(mem_ctx, name));
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }

    /* A S-1234-5678 style string */
    case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
        struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
        char *ldap_sid;

        domain_filter = NULL;
        if (!sid) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx,
                                           sid);
        if (!ldap_sid) {
            return WERR_NOMEM;
        }
        result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
                                        ldap_sid);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
        krb5_principal principal;
        char *unparsed_name;

        ret = smb_krb5_init_context(mem_ctx,
                                    ldb_get_event_context(sam_ctx),
                                    (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
                                    &smb_krb5_context);

        if (ret) {
            return WERR_NOMEM;
        }

        /* Ensure we reject compleate junk first */
        ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
        if (ret) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }

        domain_filter = NULL;

        /* By getting the unparsed name here, we ensure the escaping is correct (and trust the client less) */
        ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_NOMEM;
        }

        krb5_free_principal(smb_krb5_context->krb5_context, principal);

        /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */
        result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))",
                                        ldb_binary_encode_string(mem_ctx, unparsed_name));

        free(unparsed_name);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
        krb5_principal principal;
        char *unparsed_name_short;
        char *service;

        ret = smb_krb5_init_context(mem_ctx,
                                    ldb_get_event_context(sam_ctx),
                                    (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
                                    &smb_krb5_context);

        if (ret) {
            return WERR_NOMEM;
        }

        ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
        if (ret == 0 && principal->name.name_string.len < 2) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_OK;
        }
        ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
                                    KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);

            return dns_domain_from_principal(mem_ctx, smb_krb5_context,
                                             name, info1);
        }

        domain_filter = NULL;

        ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
                                      KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_NOMEM;
        }

        service = principal->name.name_string.val[0];
        if ((principal->name.name_string.len == 2) && (strcasecmp(service, "host") == 0)) {
            /* the 'cn' attribute is just the leading part of the name */
            char *computer_name;
            computer_name = talloc_strndup(mem_ctx, principal->name.name_string.val[1],
                                           strcspn(principal->name.name_string.val[1], "."));
            if (computer_name == NULL) {
                return WERR_NOMEM;
            }

            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, computer_name));
        } 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);
        W_ERROR_HAVE_NO_MEMORY(result_filter);

        break;
    }
    default: {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    }

    if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
        return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
                                         name_dn, name, info1);
    }

    return DsCrackNameOneFilter(sam_ctx, mem_ctx,
                                smb_krb5_context,
                                format_flags, format_offered, format_desired,
                                name_dn, name,
                                domain_filter, result_filter,
                                info1);
}
Example #11
0
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,
                             const char *name, struct drsuapi_DsNameInfo1 *info1)
{
    int ldb_ret;
    WERROR status;
    const char *domain_filter = NULL;
    const char *result_filter = NULL;
    krb5_error_code ret;
    krb5_principal principal;
    const char *realm;
    char *unparsed_name_short;
    const char *domain_attrs[] = { NULL };
    struct ldb_result *domain_res = NULL;

    /* Prevent recursion */
    if (!name) {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
                                KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
    if (ret) {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);

    ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
                         samdb_partitions_dn(sam_ctx, mem_ctx),
                         LDB_SCOPE_ONELEVEL,
                         domain_attrs,
                         "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
                         ldb_binary_encode_string(mem_ctx, realm),
                         ldb_binary_encode_string(mem_ctx, realm));

    if (ldb_ret != LDB_SUCCESS) {
        DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s", ldb_errstring(sam_ctx)));
        info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
        return WERR_OK;
    }

    switch (domain_res->count) {
    case 1:
        break;
    case 0:
        return dns_domain_from_principal(mem_ctx, smb_krb5_context,
                                         name, info1);
    default:
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
        return WERR_OK;
    }

    ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
                                  KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
    krb5_free_principal(smb_krb5_context->krb5_context, principal);

    if (ret) {
        free(unparsed_name_short);
        return WERR_NOMEM;
    }

    /* This may need to be extended for more userPrincipalName variations */
    result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))",
                                    ldb_binary_encode_string(mem_ctx, unparsed_name_short));

    domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));

    if (!result_filter || !domain_filter) {
        free(unparsed_name_short);
        return WERR_NOMEM;
    }
    status = DsCrackNameOneFilter(sam_ctx, mem_ctx,
                                  smb_krb5_context,
                                  format_flags, format_offered, format_desired,
                                  NULL, unparsed_name_short, domain_filter, result_filter,
                                  info1);
    free(unparsed_name_short);

    return status;
}
/*
 * This function will workout the filtering parameter in order to be able to do
 * the adapted search when the incomming format is format_functional.
 * This boils down to defining the search_dn (passed as pointer to ldb_dn *) and the
 * ldap filter request.
 * Main input parameters are:
 * * name, which is the portion of the functional name after the
 * first '/'.
 * * domain_filter, which is a ldap search filter used to find the NC DN given the
 * function name to crack.
 */
static WERROR get_format_functional_filtering_param(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
			char *name, struct drsuapi_DsNameInfo1 *info1,
			struct ldb_dn **psearch_dn, const char *domain_filter, const char **presult_filter)
{
	struct ldb_result *domain_res = NULL;
	const char * const domain_attrs[] = {"ncName", NULL};
	struct ldb_dn *partitions_basedn = samdb_partitions_dn(sam_ctx, mem_ctx);
	int ldb_ret;
	char *account,  *s, *result_filter = NULL;
	struct ldb_dn *search_dn = NULL;

	*psearch_dn = NULL;
	*presult_filter = NULL;

	ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
				partitions_basedn,
				LDB_SCOPE_ONELEVEL,
				domain_attrs,
				"%s", domain_filter);

	if (ldb_ret != LDB_SUCCESS) {
		DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
		info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
		return WERR_FOOBAR;
	}

	if (domain_res->count == 1) {
		struct ldb_dn *tmp_dn = samdb_result_dn(sam_ctx, mem_ctx, domain_res->msgs[0], "ncName", NULL);
		const char * const name_attrs[] = {"name", NULL};

		account = name;
		s = strchr(account, '/');
		talloc_free(domain_res);
		while(s) {
			s[0] = '\0';
			s++;

			ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
						tmp_dn,
						LDB_SCOPE_ONELEVEL,
						name_attrs,
						"name=%s", account);

			if (ldb_ret != LDB_SUCCESS) {
				DEBUG(2, ("DsCrackNameOne domain ref search failed: %s\n", ldb_errstring(sam_ctx)));
				info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
				return WERR_OK;
			}
			talloc_free(tmp_dn);
			switch (domain_res->count) {
			case 1:
				break;
			case 0:
				talloc_free(domain_res);
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
				return WERR_OK;
			default:
				talloc_free(domain_res);
				info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
				return WERR_OK;
			}

			tmp_dn = talloc_steal(mem_ctx, domain_res->msgs[0]->dn);
			talloc_free(domain_res);
			search_dn = tmp_dn;
			account = s;
			s = strchr(account, '/');
		}
		account = ldb_binary_encode_string(mem_ctx, account);
		W_ERROR_HAVE_NO_MEMORY(account);
		result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
						account);
		W_ERROR_HAVE_NO_MEMORY(result_filter);
	}
	*psearch_dn = search_dn;
	*presult_filter = result_filter;
	return WERR_OK;
}
Example #13
0
/**
   \details Resolve a recipient and build the associated RecipientRow
   structure

   \param mem_ctx pointer to the memory context
   \param emsmdbp_ctx pointer to the EMSMDBP context
   \param recipient pointer to the recipient string
   \param properties array of properties to lookup for a recipient
   \param row the RecipientRow to fill in

   \note This is a very preliminary implementation with a lot of
   pseudo-hardcoded things. Lot of work is required to make this
   function generic and to cover all different cases

   \return Allocated RecipientRow on success, otherwise NULL
 */
_PUBLIC_ enum MAPISTATUS emsmdbp_resolve_recipient(TALLOC_CTX *mem_ctx,
						   struct emsmdbp_context *emsmdbp_ctx,
						   char *recipient,
						   struct mapi_SPropTagArray *properties,
						   struct RecipientRow *row)
{
	enum MAPISTATUS		retval;
	struct ldb_result	*res = NULL;
	const char * const	recipient_attrs[] = { "*", NULL };
	int			ret;
	uint32_t		i;
	uint32_t		property = 0;
	void			*data;
	char			*str;
	char			*username;
	char			*legacyExchangeDN;
	uint32_t		org_length;
	uint32_t		l;

	/* Sanity checks */
	OPENCHANGE_RETVAL_IF(!mem_ctx, MAPI_E_NOT_INITIALIZED, NULL);
	OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
	OPENCHANGE_RETVAL_IF(!emsmdbp_ctx->samdb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
	OPENCHANGE_RETVAL_IF(!properties, MAPI_E_INVALID_PARAMETER, NULL);
	OPENCHANGE_RETVAL_IF(!recipient, MAPI_E_INVALID_PARAMETER, NULL);
	OPENCHANGE_RETVAL_IF(!row, MAPI_E_INVALID_PARAMETER, NULL);

	ret = ldb_search(emsmdbp_ctx->samdb_ctx, emsmdbp_ctx, &res,
			 ldb_get_default_basedn(emsmdbp_ctx->samdb_ctx),
			 LDB_SCOPE_SUBTREE, recipient_attrs,
			 "(&(objectClass=user)(sAMAccountName=*%s*)(!(objectClass=computer)))",
			 ldb_binary_encode_string(mem_ctx, recipient));

	/* If the search failed, build an external recipient: very basic for the moment */
	if (ret != LDB_SUCCESS || !res->count) {
	failure:
		row->RecipientFlags = 0x07db;
		row->EmailAddress.lpszW = talloc_strdup(mem_ctx, recipient);
		row->DisplayName.lpszW = talloc_strdup(mem_ctx, recipient);
		row->SimpleDisplayName.lpszW = talloc_strdup(mem_ctx, recipient);
		row->prop_count = properties->cValues;
		row->layout = 0x1;
		row->prop_values.length = 0;
		for (i = 0; i < properties->cValues; i++) {
			switch (properties->aulPropTag[i]) {
			case PidTagSmtpAddress:
				property = properties->aulPropTag[i];
				data = (void *) recipient;
				break;
			default:
				retval = MAPI_E_NOT_FOUND;
				property = (properties->aulPropTag[i] & 0xFFFF0000) + PT_ERROR;
				data = (void *)&retval;
				break;
			}

			libmapiserver_push_property(mem_ctx,
						    property, (const void *)data, &row->prop_values, 
						    row->layout, 0, 0);
		}

		return MAPI_E_SUCCESS;
	}

	/* Otherwise build a RecipientRow for resolved username */

	username = (char *) ldb_msg_find_attr_as_string(res->msgs[0], "mailNickname", NULL);
	legacyExchangeDN = (char *) ldb_msg_find_attr_as_string(res->msgs[0], "legacyExchangeDN", NULL);
	if (!username || !legacyExchangeDN) {
		DEBUG(0, ("record found but mailNickname or legacyExchangeDN is missing for %s\n", recipient));
		goto failure;
	}
	org_length = strlen(legacyExchangeDN) - strlen(username);

	/* Check if we need a flagged blob */
	row->layout = 0;
	for (i = 0; i < properties->cValues; i++) {
		switch (properties->aulPropTag[i]) {
		case PR_DISPLAY_TYPE:
		case PR_OBJECT_TYPE:
		case PidTagAddressBookDisplayNamePrintable:
		case PidTagSmtpAddress:
			break;
		default:
			row->layout = 1;
			break;
		}
	}

	row->RecipientFlags = 0x06d1;
	row->AddressPrefixUsed.prefix_size = org_length;
	row->DisplayType.display_type = SINGLE_RECIPIENT;
	row->X500DN.recipient_x500name = talloc_strdup(mem_ctx, username);

	row->DisplayName.lpszW = talloc_strdup(mem_ctx, username);
	row->SimpleDisplayName.lpszW = talloc_strdup(mem_ctx, username);
	row->prop_count = properties->cValues;
	row->prop_values.length = 0;

	/* Add this very small set of properties */
	for (i = 0; i < properties->cValues; i++) {
		switch (properties->aulPropTag[i]) {
		case PR_DISPLAY_TYPE:
			property = properties->aulPropTag[i];
			l = 0x0;
			data = (void *)&l;
			break;
		case PR_OBJECT_TYPE:
			property = properties->aulPropTag[i];
			l = MAPI_MAILUSER;
			data = (void *)&l;
			break;
		case PidTagAddressBookDisplayNamePrintable:
			property = properties->aulPropTag[i];
			str = (char *) ldb_msg_find_attr_as_string(res->msgs[0], "mailNickname", NULL);
			data = (void *) str;
			break;
		case PidTagSmtpAddress:
			property = properties->aulPropTag[i];
			str = (char *) ldb_msg_find_attr_as_string(res->msgs[0], "legacyExchangeDN", NULL);
			data = (void *) str;
			break;
		default:
			retval = MAPI_E_NOT_FOUND;
			property = (properties->aulPropTag[i] & 0xFFFF0000) + PT_ERROR;
			data = (void *)&retval;
			break;
		}
		libmapiserver_push_property(mem_ctx,
					    property, (const void *)data, &row->prop_values, 
					    row->layout, 0, 0);
	}

	return MAPI_E_SUCCESS;
}
Example #14
0
/* Add a user, SAMR style, including the correct transaction
 * semantics.  Used by the SAMR server and by pdb_samba4 */
NTSTATUS dsdb_add_user(struct ldb_context *ldb,
		       TALLOC_CTX *mem_ctx,
		       const char *account_name,
		       uint32_t acct_flags,
		       struct dom_sid **sid,
		       struct ldb_dn **dn)
{
	const char *name;
	struct ldb_message *msg;
	int ret;
	const char *container, *obj_class=NULL;
	char *cn_name;
	size_t cn_name_len;

	const char *attrs[] = {
		"objectSid",
		"userAccountControl",
		NULL
	};

	uint32_t user_account_control;
	struct ldb_dn *account_dn;
	struct dom_sid *account_sid;

	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	/*
	 * Start a transaction, so we can query and do a subsequent atomic
	 * modify
	 */

	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to start a transaction for user creation: %s\n",
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* check if the user already exists */
	name = samdb_search_string(ldb, tmp_ctx, NULL,
				   "sAMAccountName",
				   "(&(sAMAccountName=%s)(objectclass=user))",
				   ldb_binary_encode_string(tmp_ctx, account_name));
	if (name != NULL) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_USER_EXISTS;
	}

	cn_name = talloc_strdup(tmp_ctx, account_name);
	if (!cn_name) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	cn_name_len = strlen(cn_name);
	if (cn_name_len < 1) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	msg = ldb_msg_new(tmp_ctx);
	if (msg == NULL) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	/* This must be one of these values *only* */
	if (acct_flags == ACB_NORMAL) {
		container = "CN=Users";
		obj_class = "user";

	} else if (acct_flags == ACB_WSTRUST) {
		if (cn_name[cn_name_len - 1] != '$') {
			ldb_transaction_cancel(ldb);
			return NT_STATUS_FOOBAR;
		}
		cn_name[cn_name_len - 1] = '\0';
		container = "CN=Computers";
		obj_class = "computer";

	} else if (acct_flags == ACB_SVRTRUST) {
		if (cn_name[cn_name_len - 1] != '$') {
			ldb_transaction_cancel(ldb);
			return NT_STATUS_FOOBAR;
		}
		cn_name[cn_name_len - 1] = '\0';
		container = "OU=Domain Controllers";
		obj_class = "computer";
	} else {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* add core elements to the ldb_message for the user */
	msg->dn = ldb_dn_copy(msg, ldb_get_default_basedn(ldb));
	if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_FOOBAR;
	}

	ldb_msg_add_string(msg, "sAMAccountName", account_name);
	ldb_msg_add_string(msg, "objectClass", obj_class);

	/* create the user */
	ret = ldb_add(ldb, msg);
	switch (ret) {
	case LDB_SUCCESS:
		break;
	case LDB_ERR_ENTRY_ALREADY_EXISTS:
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Failed to create user record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_USER_EXISTS;
	case LDB_ERR_UNWILLING_TO_PERFORM:
	case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Failed to create user record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_ACCESS_DENIED;
	default:
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Failed to create user record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	account_dn = msg->dn;

	/* retrieve the sid and account control bits for the user just created */
	ret = dsdb_search_one(ldb, tmp_ctx, &msg,
			      account_dn, LDB_SCOPE_BASE, attrs, 0, NULL);

	if (ret != LDB_SUCCESS) {
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Can't locate the account we just created %s: %s\n",
			 ldb_dn_get_linearized(account_dn), ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
	if (account_sid == NULL) {
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
			 ldb_dn_get_linearized(msg->dn)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* Change the account control to be the correct account type.
	 * The default is for a workstation account */
	user_account_control = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
	user_account_control = (user_account_control &
				~(UF_NORMAL_ACCOUNT |
				  UF_INTERDOMAIN_TRUST_ACCOUNT |
				  UF_WORKSTATION_TRUST_ACCOUNT |
				  UF_SERVER_TRUST_ACCOUNT));
	user_account_control |= ds_acb2uf(acct_flags);

	talloc_free(msg);
	msg = ldb_msg_new(tmp_ctx);
	if (msg == NULL) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	msg->dn = account_dn;

	if (samdb_msg_add_uint(ldb, tmp_ctx, msg,
			       "userAccountControl",
			       user_account_control) != LDB_SUCCESS) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	/* modify the samdb record */
	ret = dsdb_replace(ldb, msg, 0);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);

		/* we really need samdb.c to return NTSTATUS */
		return NT_STATUS_UNSUCCESSFUL;
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	*dn = talloc_steal(mem_ctx, account_dn);
	*sid = talloc_steal(mem_ctx, account_sid);
	talloc_free(tmp_ctx);
	return NT_STATUS_OK;
}
Example #15
0
NTSTATUS dsdb_add_domain_alias(struct ldb_context *ldb,
			       TALLOC_CTX *mem_ctx,
			       const char *alias_name,
			       struct dom_sid **sid,
			       struct ldb_dn **dn)
{
	const char *name;
	struct ldb_message *msg;
	struct dom_sid *alias_sid;
	int ret;

	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	if (ldb_transaction_start(ldb) != LDB_SUCCESS) {
		DEBUG(0, ("Failed to start transaction in dsdb_add_domain_alias(): %s\n", ldb_errstring(ldb)));
		return NT_STATUS_INTERNAL_ERROR;
	}

	/* Check if alias already exists */
	name = samdb_search_string(ldb, tmp_ctx, NULL,
				   "sAMAccountName",
				   "(sAMAccountName=%s)(objectclass=group))",
				   ldb_binary_encode_string(mem_ctx, alias_name));

	if (name != NULL) {
		talloc_free(tmp_ctx);
		ldb_transaction_cancel(ldb);
		return NT_STATUS_ALIAS_EXISTS;
	}

	msg = ldb_msg_new(tmp_ctx);
	if (msg == NULL) {
		talloc_free(tmp_ctx);
		ldb_transaction_cancel(ldb);
		return NT_STATUS_NO_MEMORY;
	}

	/* add core elements to the ldb_message for the alias */
	msg->dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(ldb));
	ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", alias_name);
	if (!msg->dn) {
		talloc_free(tmp_ctx);
		ldb_transaction_cancel(ldb);
		return NT_STATUS_NO_MEMORY;
	}

	ldb_msg_add_string(msg, "sAMAccountName", alias_name);
	ldb_msg_add_string(msg, "objectClass", "group");
	samdb_msg_add_int(ldb, mem_ctx, msg, "groupType", GTYPE_SECURITY_DOMAIN_LOCAL_GROUP);

	/* create the alias */
	ret = ldb_add(ldb, msg);
	switch (ret) {
	case LDB_SUCCESS:
		break;
	case LDB_ERR_ENTRY_ALREADY_EXISTS:
		talloc_free(tmp_ctx);
		ldb_transaction_cancel(ldb);
		return NT_STATUS_ALIAS_EXISTS;
	case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
		talloc_free(tmp_ctx);
		ldb_transaction_cancel(ldb);
		return NT_STATUS_ACCESS_DENIED;
	default:
		DEBUG(0,("Failed to create alias record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		ldb_transaction_cancel(ldb);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* retrieve the sid for the alias just created */
	alias_sid = samdb_search_dom_sid(ldb, tmp_ctx,
					 msg->dn, "objectSid", NULL);

	if (ldb_transaction_commit(ldb) != LDB_SUCCESS) {
		DEBUG(0, ("Failed to commit transaction in dsdb_add_domain_alias(): %s\n",
			  ldb_errstring(ldb)));
		return NT_STATUS_INTERNAL_ERROR;
	}

	*dn = talloc_steal(mem_ctx, msg->dn);
	*sid = talloc_steal(mem_ctx, alias_sid);
	talloc_free(tmp_ctx);


	return NT_STATUS_OK;
}
Example #16
0
/*
  called by samr_CreateDomainGroup and pdb_samba4
*/
NTSTATUS dsdb_add_domain_group(struct ldb_context *ldb,
			       TALLOC_CTX *mem_ctx,
			       const char *groupname,
			       struct dom_sid **sid,
			       struct ldb_dn **dn)
{
	const char *name;
	struct ldb_message *msg;
	struct dom_sid *group_sid;
	int ret;

	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	/* check if the group already exists */
	name = samdb_search_string(ldb, tmp_ctx, NULL,
				   "sAMAccountName",
				   "(&(sAMAccountName=%s)(objectclass=group))",
				   ldb_binary_encode_string(tmp_ctx, groupname));
	if (name != NULL) {
		return NT_STATUS_GROUP_EXISTS;
	}

	msg = ldb_msg_new(tmp_ctx);
	if (msg == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	/* add core elements to the ldb_message for the user */
	msg->dn = ldb_dn_copy(tmp_ctx, ldb_get_default_basedn(ldb));
	ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Users", groupname);
	if (!msg->dn) {
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	ldb_msg_add_string(msg, "sAMAccountName", groupname);
	ldb_msg_add_string(msg, "objectClass", "group");

	/* create the group */
	ret = ldb_add(ldb, msg);
	switch (ret) {
	case  LDB_SUCCESS:
		break;
	case  LDB_ERR_ENTRY_ALREADY_EXISTS:
		DEBUG(0,("Failed to create group record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_GROUP_EXISTS;
	case  LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
		DEBUG(0,("Failed to create group record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_ACCESS_DENIED;
	default:
		DEBUG(0,("Failed to create group record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* retrieve the sid for the group just created */
	group_sid = samdb_search_dom_sid(ldb, tmp_ctx,
					 msg->dn, "objectSid", NULL);
	if (group_sid == NULL) {
		return NT_STATUS_UNSUCCESSFUL;
	}

	*dn = talloc_steal(mem_ctx, msg->dn);
	*sid = talloc_steal(mem_ctx, group_sid);
	talloc_free(tmp_ctx);
	return NT_STATUS_OK;
}