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); }
int gendb_search_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct ldb_message ***res, const char * const *attrs) { return gendb_search(ldb, mem_ctx, dn, res, attrs, NULL); }
/* lookup a name for 1 SID */ static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, struct dom_sid *sid, const char *sid_str, const char **authority_name, const char **name, enum lsa_SidType *rtype) { NTSTATUS status; int ret; uint32_t atype; struct ldb_message **res; struct ldb_dn *domain_dn; const char * const attrs[] = { "sAMAccountName", "sAMAccountType", "cn", NULL}; status = lookup_well_known_sids(mem_ctx, sid_str, authority_name, name, rtype); if (NT_STATUS_IS_OK(status)) { return status; } if (dom_sid_in_domain(state->domain_sid, sid)) { *authority_name = state->domain_name; domain_dn = state->domain_dn; } else if (dom_sid_in_domain(state->builtin_sid, sid)) { *authority_name = NAME_BUILTIN; domain_dn = state->builtin_dn; } else { /* Not well known, our domain or built in */ /* In future, we must look at SID histories, and at trusted domains via winbind */ return NT_STATUS_NOT_FOUND; } ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, "objectSid=%s", ldap_encode_ndr_dom_sid(mem_ctx, sid)); if (ret == 1) { *name = ldb_msg_find_attr_as_string(res[0], "sAMAccountName", NULL); if (!*name) { *name = ldb_msg_find_attr_as_string(res[0], "cn", NULL); if (!*name) { *name = talloc_strdup(mem_ctx, sid_str); NT_STATUS_HAVE_NO_MEMORY(*name); } } atype = samdb_result_uint(res[0], "sAMAccountType", 0); *rtype = ds_atype_map(atype); return NT_STATUS_OK; } /* need to re-add a check for an allocated sid */ return NT_STATUS_NOT_FOUND; }
/* add privilege bits for one sid to a security_token */ static NTSTATUS samdb_privilege_setup_sid(struct ldb_context *pdb, TALLOC_CTX *mem_ctx, struct security_token *token, const struct dom_sid *sid) { const char * const attrs[] = { "privilege", NULL }; struct ldb_message **res = NULL; struct ldb_message_element *el; unsigned int i; int ret; char *sidstr; sidstr = ldap_encode_ndr_dom_sid(mem_ctx, sid); NT_STATUS_HAVE_NO_MEMORY(sidstr); ret = gendb_search(pdb, mem_ctx, NULL, &res, attrs, "objectSid=%s", sidstr); talloc_free(sidstr); if (ret != 1) { /* not an error to not match */ return NT_STATUS_OK; } el = ldb_msg_find_element(res[0], "privilege"); if (el == NULL) { return NT_STATUS_OK; } for (i=0;i<el->num_values;i++) { const char *priv_str = (const char *)el->values[i].data; enum sec_privilege privilege = sec_privilege_id(priv_str); if (privilege == SEC_PRIV_INVALID) { uint32_t right_bit = sec_right_bit(priv_str); security_token_set_right_bit(token, right_bit); if (right_bit == 0) { DEBUG(1,("Unknown privilege '%s' in samdb\n", priv_str)); } continue; } security_token_set_privilege(token, privilege); } return NT_STATUS_OK; }
NTSTATUS cli_credentials_update_all_keytabs(TALLOC_CTX *parent_ctx) { TALLOC_CTX *mem_ctx; int ldb_ret; struct ldb_context *ldb; struct ldb_message **msgs; const char *attrs[] = { NULL }; struct cli_credentials *creds; const char *filter; NTSTATUS status; int i, ret; mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return NT_STATUS_NO_MEMORY; } /* Local secrets are stored in secrets.ldb */ ldb = secrets_db_connect(mem_ctx); if (!ldb) { DEBUG(1, ("Could not open secrets.ldb\n")); talloc_free(mem_ctx); return NT_STATUS_ACCESS_DENIED; } /* search for the secret record, but only of things we can * actually update */ ldb_ret = gendb_search(ldb, mem_ctx, NULL, &msgs, attrs, "(&(objectClass=kerberosSecret)(|(secret=*)(ntPwdHash=*)))"); if (ldb_ret == -1) { DEBUG(1, ("Error looking for kerberos type secrets to push into a keytab:: %s", ldb_errstring(ldb))); talloc_free(mem_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } for (i=0; i < ldb_ret; i++) { /* Make a credentials structure from it */ creds = cli_credentials_init(mem_ctx); if (!creds) { DEBUG(1, ("cli_credentials_init failed!")); talloc_free(mem_ctx); return NT_STATUS_NO_MEMORY; } cli_credentials_set_conf(creds); filter = talloc_asprintf(mem_ctx, "dn=%s", ldb_dn_get_linearized(msgs[i]->dn)); status = cli_credentials_set_secrets(creds, NULL, filter); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to read secrets for keytab update for %s\n", filter)); continue; } ret = cli_credentials_update_keytab(creds); if (ret != 0) { DEBUG(1, ("Failed to update keytab for %s\n", filter)); continue; } } return NT_STATUS_OK; }
/** * Fill in credentials for the machine trust account, from the secrets database. * * @param cred Credentials structure to fill in * @retval NTSTATUS error detailing any failure */ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred, const char *base, const char *filter) { TALLOC_CTX *mem_ctx; struct ldb_context *ldb; int ldb_ret; struct ldb_message **msgs; const char *attrs[] = { "secret", "priorSecret", "samAccountName", "flatname", "realm", "secureChannelType", "ntPwdHash", "msDS-KeyVersionNumber", "saltPrincipal", "privateKeytab", "krb5Keytab", NULL }; const char *machine_account; const char *password; const char *old_password; const char *domain; const char *realm; enum netr_SchannelType sct; const char *salt_principal; const char *keytab; /* ok, we are going to get it now, don't recurse back here */ cred->machine_account_pending = False; /* some other parts of the system will key off this */ cred->machine_account = True; mem_ctx = talloc_named(cred, 0, "cli_credentials fetch machine password"); /* Local secrets are stored in secrets.ldb */ ldb = secrets_db_connect(mem_ctx); if (!ldb) { /* set anonymous as the fallback, if the machine account won't work */ cli_credentials_set_anonymous(cred); DEBUG(1, ("Could not open secrets.ldb\n")); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } /* search for the secret record */ ldb_ret = gendb_search(ldb, mem_ctx, ldb_dn_new(mem_ctx, ldb, base), &msgs, attrs, "%s", filter); if (ldb_ret == 0) { DEBUG(1, ("Could not find entry to match filter: %s\n", filter)); /* set anonymous as the fallback, if the machine account won't work */ cli_credentials_set_anonymous(cred); talloc_free(mem_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } else if (ldb_ret != 1) { DEBUG(1, ("Found more than one (%d) entry to match filter: %s\n", ldb_ret, filter)); /* set anonymous as the fallback, if the machine account won't work */ cli_credentials_set_anonymous(cred); talloc_free(mem_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } password = ldb_msg_find_attr_as_string(msgs[0], "secret", NULL); old_password = ldb_msg_find_attr_as_string(msgs[0], "priorSecret", NULL); machine_account = ldb_msg_find_attr_as_string(msgs[0], "samAccountName", NULL); if (!machine_account) { DEBUG(1, ("Could not find 'samAccountName' in join record to domain: %s\n", cli_credentials_get_domain(cred))); /* set anonymous as the fallback, if the machine account won't work */ cli_credentials_set_anonymous(cred); talloc_free(mem_ctx); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } salt_principal = ldb_msg_find_attr_as_string(msgs[0], "saltPrincipal", NULL); cli_credentials_set_salt_principal(cred, salt_principal); sct = ldb_msg_find_attr_as_int(msgs[0], "secureChannelType", 0); if (sct) { cli_credentials_set_secure_channel_type(cred, sct); } if (!password) { const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msgs[0], "ntPwdHash"); struct samr_Password hash; ZERO_STRUCT(hash); if (nt_password_hash) { memcpy(hash.hash, nt_password_hash->data, MIN(nt_password_hash->length, sizeof(hash.hash))); cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED); } else { cli_credentials_set_password(cred, NULL, CRED_SPECIFIED); } } else { cli_credentials_set_password(cred, password, CRED_SPECIFIED); } domain = ldb_msg_find_attr_as_string(msgs[0], "flatname", NULL); if (domain) { cli_credentials_set_domain(cred, domain, CRED_SPECIFIED); } realm = ldb_msg_find_attr_as_string(msgs[0], "realm", NULL); if (realm) { cli_credentials_set_realm(cred, realm, CRED_SPECIFIED); } cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED); cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msgs[0], "msDS-KeyVersionNumber", 0)); /* If there was an external keytab specified by reference in * the LDB, then use this. Otherwise we will make one up * (chewing CPU time) from the password */ keytab = ldb_msg_find_attr_as_string(msgs[0], "krb5Keytab", NULL); if (keytab) { cli_credentials_set_keytab_name(cred, keytab, CRED_SPECIFIED); } else { keytab = ldb_msg_find_attr_as_string(msgs[0], "privateKeytab", NULL); if (keytab) { keytab = talloc_asprintf(mem_ctx, "FILE:%s", private_path(mem_ctx, keytab)); if (keytab) { cli_credentials_set_keytab_name(cred, keytab, CRED_SPECIFIED); } } } talloc_free(mem_ctx); return NT_STATUS_OK; }
/* 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; }
static int samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg) { struct ldb_message *msg2; const char *rdn_name; struct dom_sid *dom_sid; struct dom_sid *sid; const char *dom_attrs[] = { "name", NULL }; struct ldb_message **dom_msgs; const char *errstr; int ret; TALLOC_CTX *mem_ctx = talloc_new(msg); if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* build the new msg */ msg2 = ldb_msg_copy(mem_ctx, msg); if (!msg2) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincpal_object: ldb_msg_copy failed!\n"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateForeignSecurityPrincipal)(objectclass=foreignSecurityPrincipalTemplate))", &errstr); if (ret != 0) { ldb_asprintf_errstring(module->ldb, "samldb_fill_foreignSecurityPrincipal_object: " "Error copying template: %s", errstr); talloc_free(mem_ctx); return ret; } rdn_name = ldb_dn_get_rdn_name(msg2->dn); if (strcasecmp(rdn_name, "cn") != 0) { ldb_asprintf_errstring(module->ldb, "Bad RDN (%s=) for ForeignSecurityPrincipal, should be CN=!", rdn_name); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } /* Slightly different for the foreign sids. We don't want * domain SIDs ending up there, it would cause all sorts of * pain */ sid = dom_sid_parse_talloc(msg2, (const char *)ldb_dn_get_rdn_val(msg2->dn)->data); if (!sid) { ldb_set_errstring(module->ldb, "No valid found SID in ForeignSecurityPrincipal CN!"); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) { talloc_free(sid); return LDB_ERR_OPERATIONS_ERROR; } dom_sid = dom_sid_dup(mem_ctx, sid); if (!dom_sid) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } /* get the domain component part of the provided SID */ dom_sid->num_auths--; /* find the domain DN */ ret = gendb_search(module->ldb, mem_ctx, NULL, &dom_msgs, dom_attrs, "(&(objectSid=%s)(objectclass=domain))", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid)); if (ret >= 1) { /* We don't really like the idea of foreign sids that are not foreign, but it happens */ const char *name = samdb_result_string(dom_msgs[0], "name", NULL); ldb_debug(module->ldb, LDB_DEBUG_TRACE, "NOTE (strange but valid): Adding foreign SID record with SID %s, but this domian (%s) is already in the database", dom_sid_string(mem_ctx, sid), name); } else if (ret == -1) { ldb_asprintf_errstring(module->ldb, "samldb_fill_foreignSecurityPrincipal_object: error searching for a domain with this sid: %s\n", dom_sid_string(mem_ctx, dom_sid)); talloc_free(dom_msgs); return LDB_ERR_OPERATIONS_ERROR; } /* This isn't an operation on a domain we know about, so just * check for the SID, looking for duplicates via the common * code */ ret = samldb_notice_sid(module, msg2, sid); if (ret == 0) { talloc_steal(msg, msg2); *ret_msg = msg2; } return ret; }
/* fill in the cldap netlogon union for a given version */ static NTSTATUS cldapd_netlogon_fill(struct cldapd_server *cldapd, TALLOC_CTX *mem_ctx, const char *domain, const char *domain_guid, const char *user, const char *src_address, uint32_t version, union nbt_cldap_netlogon *netlogon) { const char *ref_attrs[] = {"nETBIOSName", "dnsRoot", "ncName", NULL}; const char *dom_attrs[] = {"objectGUID", NULL}; struct ldb_message **ref_res, **dom_res; int ret, count = 0; const char **services = lp_server_services(); uint32_t server_type; const char *pdc_name; struct GUID domain_uuid; const char *realm; const char *dns_domain; const char *pdc_dns_name; const char *flatname; const char *server_site; const char *client_site; const char *pdc_ip; struct ldb_dn *partitions_basedn; partitions_basedn = samdb_partitions_dn(cldapd->samctx, mem_ctx); /* the domain has an optional trailing . */ if (domain && domain[strlen(domain)-1] == '.') { domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1); } if (domain) { struct ldb_result *dom_ldb_result; struct ldb_dn *dom_dn; /* try and find the domain */ count = gendb_search(cldapd->samctx, mem_ctx, partitions_basedn, &ref_res, ref_attrs, "(&(&(objectClass=crossRef)(dnsRoot=%s))(nETBIOSName=*))", domain); if (count == 1) { dom_dn = samdb_result_dn(cldapd->samctx, mem_ctx, ref_res[0], "ncName", NULL); if (!dom_dn) { return NT_STATUS_NO_SUCH_DOMAIN; } ret = ldb_search(cldapd->samctx, dom_dn, LDB_SCOPE_BASE, "objectClass=domain", dom_attrs, &dom_ldb_result); if (ret != LDB_SUCCESS) { DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", domain, ldb_dn_get_linearized(dom_dn), ldb_errstring(cldapd->samctx))); return NT_STATUS_NO_SUCH_DOMAIN; } talloc_steal(mem_ctx, dom_ldb_result); if (dom_ldb_result->count != 1) { DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", domain, ldb_dn_get_linearized(dom_dn))); return NT_STATUS_NO_SUCH_DOMAIN; } dom_res = dom_ldb_result->msgs; } } if (count == 0 && domain_guid) { /* OK, so no dice with the name, try and find the domain with the GUID */ count = gendb_search(cldapd->samctx, mem_ctx, NULL, &dom_res, dom_attrs, "(&(objectClass=domainDNS)(objectGUID=%s))", domain_guid); if (count == 1) { /* try and find the domain */ ret = gendb_search(cldapd->samctx, mem_ctx, partitions_basedn, &ref_res, ref_attrs, "(&(objectClass=crossRef)(ncName=%s))", ldb_dn_get_linearized(dom_res[0]->dn)); if (ret != 1) { DEBUG(2,("Unable to find referece to '%s' in sam\n", ldb_dn_get_linearized(dom_res[0]->dn))); return NT_STATUS_NO_SUCH_DOMAIN; } } } if (count == 0) { DEBUG(2,("Unable to find domain with name %s or GUID {%s}\n", domain, domain_guid)); return NT_STATUS_NO_SUCH_DOMAIN; } server_type = NBT_SERVER_PDC | NBT_SERVER_GC | NBT_SERVER_DS | NBT_SERVER_TIMESERV | NBT_SERVER_CLOSEST | NBT_SERVER_WRITABLE | NBT_SERVER_GOOD_TIMESERV; if (str_list_check(services, "ldap")) { server_type |= NBT_SERVER_LDAP; } if (str_list_check(services, "kdc")) { server_type |= NBT_SERVER_KDC; } pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name()); domain_uuid = samdb_result_guid(dom_res[0], "objectGUID"); realm = samdb_result_string(ref_res[0], "dnsRoot", lp_realm()); dns_domain = samdb_result_string(ref_res[0], "dnsRoot", lp_realm()); pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s", strlower_talloc(mem_ctx, lp_netbios_name()), dns_domain); flatname = samdb_result_string(ref_res[0], "nETBIOSName", lp_workgroup()); server_site = "Default-First-Site-Name"; client_site = "Default-First-Site-Name"; pdc_ip = iface_best_ip(src_address); ZERO_STRUCTP(netlogon); switch (version & 0xF) { case 0: case 1: netlogon->logon1.type = (user?19+2:19); netlogon->logon1.pdc_name = pdc_name; netlogon->logon1.user_name = user; netlogon->logon1.domain_name = flatname; netlogon->logon1.nt_version = 1; netlogon->logon1.lmnt_token = 0xFFFF; netlogon->logon1.lm20_token = 0xFFFF; break; case 2: case 3: netlogon->logon3.type = (user?19+2:19); netlogon->logon3.pdc_name = pdc_name; netlogon->logon3.user_name = user; netlogon->logon3.domain_name = flatname; netlogon->logon3.domain_uuid = domain_uuid; netlogon->logon3.forest = realm; netlogon->logon3.dns_domain = dns_domain; netlogon->logon3.pdc_dns_name = pdc_dns_name; netlogon->logon3.pdc_ip = pdc_ip; netlogon->logon3.server_type = server_type; netlogon->logon3.lmnt_token = 0xFFFF; netlogon->logon3.lm20_token = 0xFFFF; break; case 4: case 5: case 6: case 7: netlogon->logon5.type = (user?23+2:23); netlogon->logon5.server_type = server_type; netlogon->logon5.domain_uuid = domain_uuid; netlogon->logon5.forest = realm; netlogon->logon5.dns_domain = dns_domain; netlogon->logon5.pdc_dns_name = pdc_dns_name; netlogon->logon5.domain = flatname; netlogon->logon5.pdc_name = lp_netbios_name(); netlogon->logon5.user_name = user; netlogon->logon5.server_site = server_site; netlogon->logon5.client_site = client_site; netlogon->logon5.lmnt_token = 0xFFFF; netlogon->logon5.lm20_token = 0xFFFF; break; default: netlogon->logon13.type = (user?23+2:23); netlogon->logon13.server_type = server_type; netlogon->logon13.domain_uuid = domain_uuid; netlogon->logon13.forest = realm; netlogon->logon13.dns_domain = dns_domain; netlogon->logon13.pdc_dns_name = pdc_dns_name; netlogon->logon13.domain = flatname; netlogon->logon13.pdc_name = lp_netbios_name(); netlogon->logon13.user_name = user; netlogon->logon13.server_site = server_site; netlogon->logon13.client_site = client_site; netlogon->logon13.unknown = 10; netlogon->logon13.unknown2 = 2; netlogon->logon13.pdc_ip = pdc_ip; netlogon->logon13.lmnt_token = 0xFFFF; netlogon->logon13.lm20_token = 0xFFFF; break; } return NT_STATUS_OK; }
/* samr_ChangePasswordUser3 */ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser3 *r) { NTSTATUS status; DATA_BLOB new_password; struct ldb_context *sam_ctx = NULL; struct ldb_dn *user_dn; int ret; struct ldb_message **res; const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL }; struct samr_Password *nt_pwd, *lm_pwd; DATA_BLOB nt_pwd_blob; struct samr_DomInfo1 *dominfo = NULL; struct userPwdChangeFailureInformation *reject = NULL; enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR; uint8_t new_nt_hash[16], new_lm_hash[16]; struct samr_Password nt_verifier, lm_verifier; *r->out.dominfo = NULL; *r->out.reject = NULL; if (r->in.nt_password == NULL || r->in.nt_verifier == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* Connect to a SAMDB with system privileges for fetching the old pw * hashes. */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm and nt password hashes in order to decrypt the incoming passwords */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ status = NT_STATUS_WRONG_PASSWORD; goto failed; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(status) ) { goto failed; } if (!nt_pwd) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* decrypt the password we have been given */ nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash)); arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob); data_blob_free(&nt_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) { DEBUG(3,("samr: failed to decode password buffer\n")); status = NT_STATUS_WRONG_PASSWORD; goto failed; } if (r->in.nt_verifier == NULL) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check NT verifier */ mdfour(new_nt_hash, new_password.data, new_password.length); E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash); if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check LM verifier (really not needed as we just checked the * much stronger NT hash, but the RPC-SAMR test checks for * this) */ if (lm_pwd && r->in.lm_verifier != NULL) { char *new_pass; if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_UTF16, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } } } /* Connect to a SAMDB with user privileges for the password change */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } ret = ldb_transaction_start(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* Performs the password modification. We pass the old hashes read out * from the database since they were already checked against the user- * provided ones. */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, &new_password, NULL, NULL, lm_pwd, nt_pwd, /* this is a user password change */ &reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); goto failed; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); status = NT_STATUS_TRANSACTION_ABORTED; goto failed; } return NT_STATUS_OK; failed: reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation); if (reject != NULL) { reject->extendedFailureReason = reason; *r->out.reject = reject; } *r->out.dominfo = dominfo; return status; }
/* samr_OemChangePasswordUser2 */ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_OemChangePasswordUser2 *r) { NTSTATUS status; DATA_BLOB new_password, new_unicode_password; char *new_pass; struct samr_CryptPassword *pwbuf = r->in.password; struct ldb_context *sam_ctx; struct ldb_dn *user_dn; int ret; struct ldb_message **res; const char * const attrs[] = { "objectSid", "dBCSPwd", NULL }; struct samr_Password *lm_pwd; DATA_BLOB lm_pwd_blob; uint8_t new_lm_hash[16]; struct samr_Password lm_verifier; size_t unicode_pw_len; if (pwbuf == NULL) { return NT_STATUS_INVALID_PARAMETER; } if (r->in.hash == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* this call can only work with lanman auth */ if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) { return NT_STATUS_WRONG_PASSWORD; } /* Connect to a SAMDB with system privileges for fetching the old pw * hashes. */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm password hash in order to decrypt the incoming password */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ return NT_STATUS_WRONG_PASSWORD; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, NULL); if (!NT_STATUS_IS_OK(status) || !lm_pwd) { return NT_STATUS_WRONG_PASSWORD; } /* decrypt the password we have been given */ lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash)); arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob); data_blob_free(&lm_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) { DEBUG(3,("samr: failed to decode password buffer\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UTF16, (const char *)new_password.data, new_password.length, (void **)&new_unicode_password.data, &unicode_pw_len, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n")); return NT_STATUS_WRONG_PASSWORD; } new_unicode_password.length = unicode_pw_len; E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) { return NT_STATUS_WRONG_PASSWORD; } /* Connect to a SAMDB with user privileges for the password change */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* Start transaction */ ret = ldb_transaction_start(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* Performs the password modification. We pass the old hashes read out * from the database since they were already checked against the user- * provided ones. */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, &new_unicode_password, NULL, NULL, lm_pwd, NULL, /* this is a user password change */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); return status; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } return NT_STATUS_OK; }
/* samr_ChangePasswordUser3 */ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser3 *r) { NTSTATUS status; DATA_BLOB new_password; struct ldb_context *sam_ctx = NULL; struct ldb_dn *user_dn; int ret; struct ldb_message **res, *mod; const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL }; struct samr_Password *nt_pwd, *lm_pwd; DATA_BLOB nt_pwd_blob; struct samr_DomInfo1 *dominfo = NULL; struct samr_ChangeReject *reject = NULL; enum samr_RejectReason reason = SAMR_REJECT_OTHER; uint8_t new_nt_hash[16], new_lm_hash[16]; struct samr_Password nt_verifier, lm_verifier; *r->out.dominfo = NULL; *r->out.reject = NULL; if (r->in.nt_password == NULL || r->in.nt_verifier == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* To change a password we need to open as system */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx)); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } ret = ldb_transaction_start(sam_ctx); if (ret) { talloc_free(sam_ctx); DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm and nt password hashes in order to decrypt the incoming passwords */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ status = NT_STATUS_WRONG_PASSWORD; goto failed; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(status) ) { goto failed; } if (!nt_pwd) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* decrypt the password we have been given */ nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash)); arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob); data_blob_free(&nt_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) { ldb_transaction_cancel(sam_ctx); DEBUG(3,("samr: failed to decode password buffer\n")); return NT_STATUS_WRONG_PASSWORD; } if (r->in.nt_verifier == NULL) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check NT verifier */ mdfour(new_nt_hash, new_password.data, new_password.length); E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash); if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check LM verifier (really not needed as we just checked the * much stronger NT hash, but the RPC-SAMR test checks for * this) */ if (lm_pwd && r->in.lm_verifier != NULL) { char *new_pass; if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_UTF16, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } } } mod = ldb_msg_new(mem_ctx); if (mod == NULL) { status = NT_STATUS_NO_MEMORY; goto failed; } mod->dn = ldb_dn_copy(mod, user_dn); if (!mod->dn) { status = NT_STATUS_NO_MEMORY; goto failed; } /* set the password on the user DN specified. This may fail * due to password policies */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, mod, &new_password, NULL, NULL, true, /* this is a user password change */ &reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { goto failed; } /* The above call only setup the modifications, this actually * makes the write to the database. */ ret = samdb_replace(sam_ctx, mem_ctx, mod); if (ret != 0) { DEBUG(2,("samdb_replace failed to change password for %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); status = NT_STATUS_UNSUCCESSFUL; goto failed; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != 0) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); status = NT_STATUS_TRANSACTION_ABORTED; goto failed; } return NT_STATUS_OK; failed: ldb_transaction_cancel(sam_ctx); talloc_free(sam_ctx); reject = talloc(mem_ctx, struct samr_ChangeReject); *r->out.dominfo = dominfo; *r->out.reject = reject; if (reject == NULL) { return status; } ZERO_STRUCTP(reject); reject->reason = reason; return status; }
/* samr_OemChangePasswordUser2 */ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_OemChangePasswordUser2 *r) { NTSTATUS status; DATA_BLOB new_password, new_unicode_password; char *new_pass; struct samr_CryptPassword *pwbuf = r->in.password; struct ldb_context *sam_ctx; struct ldb_dn *user_dn; int ret; struct ldb_message **res, *mod; const char * const attrs[] = { "objectSid", "dBCSPwd", NULL }; struct samr_Password *lm_pwd; DATA_BLOB lm_pwd_blob; uint8_t new_lm_hash[16]; struct samr_Password lm_verifier; size_t unicode_pw_len; if (pwbuf == NULL) { return NT_STATUS_INVALID_PARAMETER; } if (r->in.hash == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* To change a password we need to open as system */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx)); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } ret = ldb_transaction_start(sam_ctx); if (ret) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm password hash in order to decrypt the incoming password */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { ldb_transaction_cancel(sam_ctx); /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ return NT_STATUS_WRONG_PASSWORD; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, NULL); if (!NT_STATUS_IS_OK(status) || !lm_pwd) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } /* decrypt the password we have been given */ lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash)); arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob); data_blob_free(&lm_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) { ldb_transaction_cancel(sam_ctx); DEBUG(3,("samr: failed to decode password buffer\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n")); ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UTF16, (const char *)new_password.data, new_password.length, (void **)&new_unicode_password.data, &unicode_pw_len, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n")); ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } new_unicode_password.length = unicode_pw_len; E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } mod = ldb_msg_new(mem_ctx); if (mod == NULL) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_NO_MEMORY; } mod->dn = ldb_dn_copy(mod, user_dn); if (!mod->dn) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_NO_MEMORY; } /* set the password on the user DN specified. This may fail * due to password policies */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, mod, &new_unicode_password, NULL, NULL, true, /* this is a user password change */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); return status; } /* The above call only setup the modifications, this actually * makes the write to the database. */ ret = samdb_replace(sam_ctx, mem_ctx, mod); if (ret != 0) { DEBUG(2,("Failed to modify record to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); ldb_transaction_cancel(sam_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != 0) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } return NT_STATUS_OK; }