diff options
author | Jelmer Vernooij <jelmer@samba.org> | 2007-12-17 04:22:44 +0100 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2007-12-21 05:50:41 +0100 |
commit | 71e2cafe96f4755b67d01ced497bf5b63aad30f6 (patch) | |
tree | 6b0ba3ef5aaec87871d1642a554bb97c9754f316 /source4/dsdb | |
parent | 20a6fcf726d6e0ed656f0e26977eef6be8b8b862 (diff) | |
download | samba-71e2cafe96f4755b67d01ced497bf5b63aad30f6.tar.gz samba-71e2cafe96f4755b67d01ced497bf5b63aad30f6.tar.bz2 samba-71e2cafe96f4755b67d01ced497bf5b63aad30f6.zip |
r26483: Merge ldb module dependency fixes, fix auth python module.
(This used to be commit 85eeecf997a071ca7e7ad0247e8d34d49b7ffcbb)
Diffstat (limited to 'source4/dsdb')
-rw-r--r-- | source4/dsdb/common/util.c | 1895 | ||||
-rw-r--r-- | source4/dsdb/config.mk | 19 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/config.mk | 35 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/partition.c | 22 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/schema.c | 4 | ||||
-rw-r--r-- | source4/dsdb/samdb/samdb.c | 1859 | ||||
-rw-r--r-- | source4/dsdb/samdb/samdb.h | 1 | ||||
-rw-r--r-- | source4/dsdb/schema/schema.h | 2 |
8 files changed, 1946 insertions, 1891 deletions
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c new file mode 100644 index 0000000000..efc1b20ae0 --- /dev/null +++ b/source4/dsdb/common/util.c @@ -0,0 +1,1895 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Volker Lendecke 2004 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006 + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "ldb.h" +#include "ldb_errors.h" +#include "lib/util/util_ldb.h" +#include "dsdb/samdb/samdb.h" +#include "libcli/security/security.h" +#include "librpc/gen_ndr/ndr_security.h" +#include "dsdb/common/flags.h" +#include "dsdb/common/proto.h" +#include "libcli/ldap/ldap_ndr.h" +#include "libcli/auth/libcli_auth.h" + +/* + search the sam for the specified attributes in a specific domain, filter on + objectSid being in domain_sid. +*/ +int samdb_search_domain(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *basedn, + struct ldb_message ***res, + const char * const *attrs, + const struct dom_sid *domain_sid, + const char *format, ...) _PRINTF_ATTRIBUTE(7,8) +{ + va_list ap; + int i, count; + + va_start(ap, format); + count = gendb_search_v(sam_ldb, mem_ctx, basedn, + res, attrs, format, ap); + va_end(ap); + + i=0; + + while (i<count) { + struct dom_sid *entry_sid; + + entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid"); + + if ((entry_sid == NULL) || + (!dom_sid_in_domain(domain_sid, entry_sid))) { + /* Delete that entry from the result set */ + (*res)[i] = (*res)[count-1]; + count -= 1; + talloc_free(entry_sid); + continue; + } + talloc_free(entry_sid); + i += 1; + } + + return count; +} + +/* + search the sam for a single string attribute in exactly 1 record +*/ +const char *samdb_search_string_v(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *basedn, + const char *attr_name, + const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0) +{ + int count; + const char *attrs[2] = { NULL, NULL }; + struct ldb_message **res = NULL; + + attrs[0] = attr_name; + + count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); + if (count > 1) { + DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", + attr_name, format, count)); + } + if (count != 1) { + talloc_free(res); + return NULL; + } + + return samdb_result_string(res[0], attr_name, NULL); +} + + +/* + search the sam for a single string attribute in exactly 1 record +*/ +const char *samdb_search_string(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *basedn, + const char *attr_name, + const char *format, ...) _PRINTF_ATTRIBUTE(5,6) +{ + va_list ap; + const char *str; + + va_start(ap, format); + str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap); + va_end(ap); + + return str; +} + +struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *basedn, + const char *format, ...) _PRINTF_ATTRIBUTE(4,5) +{ + va_list ap; + struct ldb_dn *ret; + struct ldb_message **res = NULL; + int count; + + va_start(ap, format); + count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap); + va_end(ap); + + if (count != 1) return NULL; + + ret = talloc_steal(mem_ctx, res[0]->dn); + talloc_free(res); + + return ret; +} + +/* + search the sam for a dom_sid attribute in exactly 1 record +*/ +struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *basedn, + const char *attr_name, + const char *format, ...) _PRINTF_ATTRIBUTE(5,6) +{ + va_list ap; + int count; + struct ldb_message **res; + const char *attrs[2] = { NULL, NULL }; + struct dom_sid *sid; + + attrs[0] = attr_name; + + va_start(ap, format); + count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); + va_end(ap); + if (count > 1) { + DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", + attr_name, format, count)); + } + if (count != 1) { + talloc_free(res); + return NULL; + } + sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name); + talloc_free(res); + return sid; +} + +/* + return the count of the number of records in the sam matching the query +*/ +int samdb_search_count(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *basedn, + const char *format, ...) _PRINTF_ATTRIBUTE(4,5) +{ + va_list ap; + struct ldb_message **res; + const char * const attrs[] = { NULL }; + int ret; + + va_start(ap, format); + ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); + va_end(ap); + + return ret; +} + + +/* + search the sam for a single integer attribute in exactly 1 record +*/ +uint_t samdb_search_uint(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + uint_t default_value, + struct ldb_dn *basedn, + const char *attr_name, + const char *format, ...) _PRINTF_ATTRIBUTE(6,7) +{ + va_list ap; + int count; + struct ldb_message **res; + const char *attrs[2] = { NULL, NULL }; + + attrs[0] = attr_name; + + va_start(ap, format); + count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); + va_end(ap); + + if (count != 1) { + return default_value; + } + + return samdb_result_uint(res[0], attr_name, default_value); +} + +/* + search the sam for a single signed 64 bit integer attribute in exactly 1 record +*/ +int64_t samdb_search_int64(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + int64_t default_value, + struct ldb_dn *basedn, + const char *attr_name, + const char *format, ...) _PRINTF_ATTRIBUTE(6,7) +{ + va_list ap; + int count; + struct ldb_message **res; + const char *attrs[2] = { NULL, NULL }; + + attrs[0] = attr_name; + + va_start(ap, format); + count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); + va_end(ap); + + if (count != 1) { + return default_value; + } + + return samdb_result_int64(res[0], attr_name, default_value); +} + +/* + search the sam for multipe records each giving a single string attribute + return the number of matches, or -1 on error +*/ +int samdb_search_string_multiple(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *basedn, + const char ***strs, + const char *attr_name, + const char *format, ...) _PRINTF_ATTRIBUTE(6,7) +{ + va_list ap; + int count, i; + const char *attrs[2] = { NULL, NULL }; + struct ldb_message **res = NULL; + + attrs[0] = attr_name; + + va_start(ap, format); + count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); + va_end(ap); + + if (count <= 0) { + return count; + } + + /* make sure its single valued */ + for (i=0;i<count;i++) { + if (res[i]->num_elements != 1) { + DEBUG(1,("samdb: search for %s %s not single valued\n", + attr_name, format)); + talloc_free(res); + return -1; + } + } + + *strs = talloc_array(mem_ctx, const char *, count+1); + if (! *strs) { + talloc_free(res); + return -1; + } + + for (i=0;i<count;i++) { + (*strs)[i] = samdb_result_string(res[i], attr_name, NULL); + } + (*strs)[count] = NULL; + + return count; +} + +/* + pull a uint from a result set. +*/ +uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value) +{ + return ldb_msg_find_attr_as_uint(msg, attr, default_value); +} + +/* + pull a (signed) int64 from a result set. +*/ +int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value) +{ + return ldb_msg_find_attr_as_int64(msg, attr, default_value); +} + +/* + pull a string from a result set. +*/ +const char *samdb_result_string(const struct ldb_message *msg, const char *attr, + const char *default_value) +{ + return ldb_msg_find_attr_as_string(msg, attr, default_value); +} + +struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, + const char *attr, struct ldb_dn *default_value) +{ + struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr); + if (!ret_dn) { + return default_value; + } + return ret_dn; +} + +/* + pull a rid from a objectSid in a result set. +*/ +uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, + const char *attr, uint32_t default_value) +{ + struct dom_sid *sid; + uint32_t rid; + + sid = samdb_result_dom_sid(mem_ctx, msg, attr); + if (sid == NULL) { + return default_value; + } + rid = sid->sub_auths[sid->num_auths-1]; + talloc_free(sid); + return rid; +} + +/* + pull a dom_sid structure from a objectSid in a result set. +*/ +struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, + const char *attr) +{ + const struct ldb_val *v; + struct dom_sid *sid; + enum ndr_err_code ndr_err; + v = ldb_msg_find_ldb_val(msg, attr); + if (v == NULL) { + return NULL; + } + sid = talloc(mem_ctx, struct dom_sid); + if (sid == NULL) { + return NULL; + } + ndr_err = ndr_pull_struct_blob(v, sid, sid, + (ndr_pull_flags_fn_t)ndr_pull_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(sid); + return NULL; + } + return sid; +} + +/* + pull a guid structure from a objectGUID in a result set. +*/ +struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr) +{ + const struct ldb_val *v; + enum ndr_err_code ndr_err; + struct GUID guid; + TALLOC_CTX *mem_ctx; + + ZERO_STRUCT(guid); + + v = ldb_msg_find_ldb_val(msg, attr); + if (!v) return guid; + + mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid"); + if (!mem_ctx) return guid; + ndr_err = ndr_pull_struct_blob(v, mem_ctx, &guid, + (ndr_pull_flags_fn_t)ndr_pull_GUID); + talloc_free(mem_ctx); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return guid; + } + + return guid; +} + +/* + pull a sid prefix from a objectSid in a result set. + this is used to find the domain sid for a user +*/ +struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, + const char *attr) +{ + struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr); + if (!sid || sid->num_auths < 1) return NULL; + sid->num_auths--; + return sid; +} + +/* + pull a NTTIME in a result set. +*/ +NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value) +{ + return ldb_msg_find_attr_as_uint64(msg, attr, default_value); +} + +/* + pull a uint64_t from a result set. +*/ +uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value) +{ + return ldb_msg_find_attr_as_uint64(msg, attr, default_value); +} + + +/* + construct the allow_password_change field from the PwdLastSet attribute and the + domain password settings +*/ +NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *domain_dn, + struct ldb_message *msg, + const char *attr) +{ + uint64_t attr_time = samdb_result_uint64(msg, attr, 0); + int64_t minPwdAge; + + if (attr_time == 0) { + return 0; + } + + minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL); + + /* yes, this is a -= not a += as minPwdAge is stored as the negative + of the number of 100-nano-seconds */ + attr_time -= minPwdAge; + + return attr_time; +} + +/* + construct the force_password_change field from the PwdLastSet attribute and the + domain password settings +*/ +NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_dn *domain_dn, + struct ldb_message *msg) +{ + uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0); + uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0); + int64_t maxPwdAge; + + if (user_flags & UF_DONT_EXPIRE_PASSWD) { + return 0x7FFFFFFFFFFFFFFFULL; + } + + if (attr_time == 0) { + return 0; + } + + maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL); + if (maxPwdAge == 0) { + return 0; + } else { + attr_time -= maxPwdAge; + } + + return attr_time; +} + +/* + pull a samr_Password structutre from a result set. +*/ +struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr) +{ + struct samr_Password *hash = NULL; + const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); + if (val && (val->length >= sizeof(hash->hash))) { + hash = talloc(mem_ctx, struct samr_Password); + memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash))); + } + return hash; +} + +/* + pull an array of samr_Password structutres from a result set. +*/ +uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr, struct samr_Password **hashes) +{ + uint_t count = 0; + const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); + int i; + + *hashes = NULL; + if (!val) { + return 0; + } + count = val->length / 16; + if (count == 0) { + return 0; + } + + *hashes = talloc_array(mem_ctx, struct samr_Password, count); + if (! *hashes) { + return 0; + } + + for (i=0;i<count;i++) { + memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16); + } + + return count; +} + +NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, + struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) +{ + struct samr_Password *lmPwdHash, *ntPwdHash; + if (nt_pwd) { + int num_nt; + num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash); + if (num_nt == 0) { + *nt_pwd = NULL; + } else if (num_nt > 1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } else { + *nt_pwd = &ntPwdHash[0]; + } + } + if (lm_pwd) { + int num_lm; + num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash); + if (num_lm == 0) { + *lm_pwd = NULL; + } else if (num_lm > 1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } else { + *lm_pwd = &lmPwdHash[0]; + } + } + return NT_STATUS_OK; +} + +/* + pull a samr_LogonHours structutre from a result set. +*/ +struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr) +{ + struct samr_LogonHours hours; + const int units_per_week = 168; + const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); + ZERO_STRUCT(hours); + hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week); + if (!hours.bits) { + return hours; + } + hours.units_per_week = units_per_week; + memset(hours.bits, 0xFF, units_per_week); + if (val) { + memcpy(hours.bits, val->data, MIN(val->length, units_per_week)); + } + return hours; +} + +/* + pull a set of account_flags from a result set. +*/ +uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr) +{ + uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0); + return samdb_uf2acb(userAccountControl); +} + + +/* Find an attribute, with a particular value */ + +/* The current callers of this function expect a very specific + * behaviour: In particular, objectClass subclass equivilance is not + * wanted. This means that we should not lookup the schema for the + * comparison function */ +struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, + const struct ldb_message *msg, + const char *name, const char *value) +{ + int i; + struct ldb_message_element *el = ldb_msg_find_element(msg, name); + + if (!el) { + return NULL; + } + + for (i=0;i<el->num_values;i++) { + if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) { + return el; + } + } + + return NULL; +} + +int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value) +{ + if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) { + return samdb_msg_add_string(ldb, msg, msg, name, set_value); + } + return LDB_SUCCESS; +} + +int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value) +{ + struct ldb_message_element *el; + + el = ldb_msg_find_element(msg, name); + if (el) { + return LDB_SUCCESS; + } + + return samdb_msg_add_string(ldb, msg, msg, name, set_value); +} + + + +/* + add a string element to a message +*/ +int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const char *str) +{ + char *s = talloc_strdup(mem_ctx, str); + char *a = talloc_strdup(mem_ctx, attr_name); + if (s == NULL || a == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + return ldb_msg_add_string(msg, a, s); +} + +/* + add a dom_sid element to a message +*/ +int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, struct dom_sid *sid) +{ + struct ldb_val v; + enum ndr_err_code ndr_err; + + ndr_err = ndr_push_struct_blob(&v, mem_ctx, sid, + (ndr_push_flags_fn_t)ndr_push_dom_sid); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + return -1; + } + return ldb_msg_add_value(msg, attr_name, &v, NULL); +} + + +/* + add a delete element operation to a message +*/ +int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name) +{ + /* we use an empty replace rather than a delete, as it allows for + samdb_replace() to be used everywhere */ + return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL); +} + +/* + add a add attribute value to a message +*/ +int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const char *value) +{ + struct ldb_message_element *el; + char *a, *v; + int ret; + a = talloc_strdup(mem_ctx, attr_name); + if (a == NULL) + return -1; + v = talloc_strdup(mem_ctx, value); + if (v == NULL) + return -1; + ret = ldb_msg_add_string(msg, a, v); + if (ret != 0) + return ret; + el = ldb_msg_find_element(msg, a); + if (el == NULL) + return -1; + el->flags = LDB_FLAG_MOD_ADD; + return 0; +} + +/* + add a delete attribute value to a message +*/ +int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const char *value) +{ + struct ldb_message_element *el; + char *a, *v; + int ret; + a = talloc_strdup(mem_ctx, attr_name); + if (a == NULL) + return -1; + v = talloc_strdup(mem_ctx, value); + if (v == NULL) + return -1; + ret = ldb_msg_add_string(msg, a, v); + if (ret != 0) + return ret; + el = ldb_msg_find_element(msg, a); + if (el == NULL) + return -1; + el->flags = LDB_FLAG_MOD_DELETE; + return 0; +} + +/* + add a int element to a message +*/ +int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, int v) +{ + const char *s = talloc_asprintf(mem_ctx, "%d", v); + return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); +} + +/* + add a uint_t element to a message +*/ +int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, uint_t v) +{ + const char *s = talloc_asprintf(mem_ctx, "%u", v); + return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); +} + +/* + add a (signed) int64_t element to a message +*/ +int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, int64_t v) +{ + const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v); + return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); +} + +/* + add a uint64_t element to a message +*/ +int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, uint64_t v) +{ + const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v); + return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); +} + +/* + add a samr_Password element to a message +*/ +int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, struct samr_Password *hash) +{ + struct ldb_val val; + val.data = talloc_memdup(mem_ctx, hash->hash, 16); + if (!val.data) { + return -1; + } + val.length = 16; + return ldb_msg_add_value(msg, attr_name, &val, NULL); +} + +/* + add a samr_Password array to a message +*/ +int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, struct samr_Password *hashes, uint_t count) +{ + struct ldb_val val; + int i; + val.data = talloc_array_size(mem_ctx, 16, count); + val.length = count*16; + if (!val.data) { + return -1; + } + for (i=0;i<count;i++) { + memcpy(i*16 + (char *)val.data, hashes[i].hash, 16); + } + return ldb_msg_add_value(msg, attr_name, &val, NULL); +} + +/* + add a acct_flags element to a message +*/ +int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, uint32_t v) +{ + return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v)); +} + +/* + add a logon_hours element to a message +*/ +int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, struct samr_LogonHours *hours) +{ + struct ldb_val val; + val.length = hours->units_per_week / 8; + val.data = hours->bits; + return ldb_msg_add_value(msg, attr_name, &val, NULL); +} + +/* + add a general value element to a message +*/ +int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const struct ldb_val *val) +{ + return ldb_msg_add_value(msg, attr_name, val, NULL); +} + +/* + sets a general value element to a message +*/ +int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const struct ldb_val *val) +{ + struct ldb_message_element *el; + + el = ldb_msg_find_element(msg, attr_name); + if (el) { + el->num_values = 0; + } + return ldb_msg_add_value(msg, attr_name, val, NULL); +} + +/* + set a string element in a message +*/ +int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const char *str) +{ + struct ldb_message_element *el; + + el = ldb_msg_find_element(msg, attr_name); + if (el) { + el->num_values = 0; + } + return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str); +} + +/* + replace elements in a record +*/ +int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg) +{ + int i; + + /* mark all the message elements as LDB_FLAG_MOD_REPLACE */ + for (i=0;i<msg->num_elements;i++) { + msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + } + + /* modify the samdb record */ + return ldb_modify(sam_ldb, msg); +} + +/* + return a default security descriptor +*/ +struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx) +{ + struct security_descriptor *sd; + + sd = security_descriptor_initialise(mem_ctx); + + return sd; +} + +struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) +{ + return ldb_get_default_basedn(sam_ctx); +} + +struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) +{ + return ldb_get_config_basedn(sam_ctx); +} + +struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) +{ + return ldb_get_schema_basedn(sam_ctx); +} + +struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) +{ + return ldb_get_root_basedn(sam_ctx); +} + +struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) +{ + struct ldb_dn *new_dn; + + new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx)); + if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) { + talloc_free(new_dn); + return NULL; + } + return new_dn; +} + +struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) +{ + struct ldb_dn *new_dn; + + new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx)); + if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) { + talloc_free(new_dn); + return NULL; + } + return new_dn; +} + +/* + work out the domain sid for the current open ldb +*/ +const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb) +{ + TALLOC_CTX *tmp_ctx; + struct dom_sid *domain_sid; + + /* see if we have a cached copy */ + domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid"); + if (domain_sid) { + return domain_sid; + } + + tmp_ctx = talloc_new(ldb); + if (tmp_ctx == NULL) { + goto failed; + } + + /* find the domain_sid */ + domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb), + "objectSid", "objectClass=domainDNS"); + if (domain_sid == NULL) { + goto failed; + } + + /* cache the domain_sid in the ldb */ + if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) { + goto failed; + } + + talloc_steal(ldb, domain_sid); + talloc_free(tmp_ctx); + + return domain_sid; + +failed: + DEBUG(1,("Failed to find domain_sid for open ldb\n")); + talloc_free(tmp_ctx); + return NULL; +} + +bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in) +{ + TALLOC_CTX *tmp_ctx; + struct dom_sid *dom_sid_new; + struct dom_sid *dom_sid_old; + + /* see if we have a cached copy */ + dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, + "cache.domain_sid"), struct dom_sid); + + tmp_ctx = talloc_new(ldb); + if (tmp_ctx == NULL) { + goto failed; + } + + dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in); + if (!dom_sid_new) { + goto failed; + } + + /* cache the domain_sid in the ldb */ + if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) { + goto failed; + } + + talloc_steal(ldb, dom_sid_new); + talloc_free(tmp_ctx); + talloc_free(dom_sid_old); + + return true; + +failed: + DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n")); + talloc_free(tmp_ctx); + return false; +} + +/* Obtain the short name of the flexible single master operator + * (FSMO), such as the PDC Emulator */ +const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, + const char *attr) +{ + /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */ + struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr); + const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1); + const char *name = ldb_dn_get_component_name(fsmo_dn, 1); + + if (!name || (ldb_attr_cmp(name, "cn") != 0)) { + /* Ensure this matches the format. This gives us a + * bit more confidence that a 'cn' value will be a + * ascii string */ + return NULL; + } + if (val) { + return (char *)val->data; + } + return NULL; +} + +/* + work out the ntds settings dn for the current open ldb +*/ +struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb) +{ + TALLOC_CTX *tmp_ctx; + const char *root_attrs[] = { "dsServiceName", NULL }; + int ret; + struct ldb_result *root_res; + struct ldb_dn *settings_dn; + + /* see if we have a cached copy */ + settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn"); + if (settings_dn) { + return settings_dn; + } + + tmp_ctx = talloc_new(ldb); + if (tmp_ctx == NULL) { + goto failed; + } + + + ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res); + if (ret) { + DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", + ldb_errstring(ldb))); + goto failed; + } + talloc_steal(tmp_ctx, root_res); + + if (root_res->count != 1) { + goto failed; + } + + settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName"); + + /* cache the domain_sid in the ldb */ + if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) { + goto failed; + } + + talloc_steal(ldb, settings_dn); + talloc_free(tmp_ctx); + + return settings_dn; + +failed: + DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n")); + talloc_free(tmp_ctx); + return NULL; +} + +/* + work out the ntds settings invocationId for the current open ldb +*/ +const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb) +{ + TALLOC_CTX *tmp_ctx; + const char *attrs[] = { "invocationId", NULL }; + int ret; + struct ldb_result *res; + struct GUID *invocation_id; + + /* see if we have a cached copy */ + invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id"); + if (invocation_id) { + return invocation_id; + } + + tmp_ctx = talloc_new(ldb); + if (tmp_ctx == NULL) { + goto failed; + } + + ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res); + if (ret) { + goto failed; + } + talloc_steal(tmp_ctx, res); + + if (res->count != 1) { + goto failed; + } + + invocation_id = talloc(tmp_ctx, struct GUID); + if (!invocation_id) { + goto failed; + } + + *invocation_id = samdb_result_guid(res->msgs[0], "invocationId"); + + /* cache the domain_sid in the ldb */ + if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) { + goto failed; + } + + talloc_steal(ldb, invocation_id); + talloc_free(tmp_ctx); + + return invocation_id; + +failed: + DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n")); + talloc_free(tmp_ctx); + return NULL; +} + +bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in) +{ + TALLOC_CTX *tmp_ctx; + struct GUID *invocation_id_new; + struct GUID *invocation_id_old; + + /* see if we have a cached copy */ + invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, + "cache.invocation_id"); + + tmp_ctx = talloc_new(ldb); + if (tmp_ctx == NULL) { + goto failed; + } + + invocation_id_new = talloc(tmp_ctx, struct GUID); + if (!invocation_id_new) { + goto failed; + } + + *invocation_id_new = *invocation_id_in; + + /* cache the domain_sid in the ldb */ + if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) { + goto failed; + } + + talloc_steal(ldb, invocation_id_new); + talloc_free(tmp_ctx); + talloc_free(invocation_id_old); + + return true; + +failed: + DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n")); + talloc_free(tmp_ctx); + return false; +} + +/* + work out the ntds settings objectGUID for the current open ldb +*/ +const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb) +{ + TALLOC_CTX *tmp_ctx; + const char *attrs[] = { "objectGUID", NULL }; + int ret; + struct ldb_result *res; + struct GUID *ntds_guid; + + /* see if we have a cached copy */ + ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid"); + if (ntds_guid) { + return ntds_guid; + } + + tmp_ctx = talloc_new(ldb); + if (tmp_ctx == NULL) { + goto failed; + } + + ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res); + if (ret) { + goto failed; + } + talloc_steal(tmp_ctx, res); + + if (res->count != 1) { + goto failed; + } + + ntds_guid = talloc(tmp_ctx, struct GUID); + if (!ntds_guid) { + goto failed; + } + + *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID"); + + /* cache the domain_sid in the ldb */ + if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) { + goto failed; + } + + talloc_steal(ldb, ntds_guid); + talloc_free(tmp_ctx); + + return ntds_guid; + +failed: + DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n")); + talloc_free(tmp_ctx); + return NULL; +} + +bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in) +{ + TALLOC_CTX *tmp_ctx; + struct GUID *ntds_guid_new; + struct GUID *ntds_guid_old; + + /* see if we have a cached copy */ + ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid"); + + tmp_ctx = talloc_new(ldb); + if (tmp_ctx == NULL) { + goto failed; + } + + ntds_guid_new = talloc(tmp_ctx, struct GUID); + if (!ntds_guid_new) { + goto failed; + } + + *ntds_guid_new = *ntds_guid_in; + + /* cache the domain_sid in the ldb */ + if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) { + goto failed; + } + + talloc_steal(ldb, ntds_guid_new); + talloc_free(tmp_ctx); + talloc_free(ntds_guid_old); + + return true; + +failed: + DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n")); + talloc_free(tmp_ctx); + return false; +} + +/* + work out the server dn for the current open ldb +*/ +struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) +{ + return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb)); +} + +/* + work out the server dn for the current open ldb +*/ +struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) +{ + struct ldb_dn *server_dn; + struct ldb_dn *server_site_dn; + + server_dn = samdb_server_dn(ldb, mem_ctx); + if (!server_dn) return NULL; + + server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn); + + talloc_free(server_dn); + return server_site_dn; +} + +/* + work out if we are the PDC for the domain of the current open ldb +*/ +bool samdb_is_pdc(struct ldb_context *ldb) +{ + const char *dom_attrs[] = { "fSMORoleOwner", NULL }; + int ret; + struct ldb_result *dom_res; + TALLOC_CTX *tmp_ctx; + bool is_pdc; + struct ldb_dn *pdc; + + tmp_ctx = talloc_new(ldb); + if (tmp_ctx == NULL) { + DEBUG(1, ("talloc_new failed in samdb_is_pdc")); + return false; + } + + ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res); + if (ret) { + DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", + ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), + ldb_errstring(ldb))); + goto failed; + } + talloc_steal(tmp_ctx, dom_res); + if (dom_res->count != 1) { + goto failed; + } + + pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner"); + + if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) { + is_pdc = true; + } else { + is_pdc = false; + } + + talloc_free(tmp_ctx); + + return is_pdc; + +failed: + DEBUG(1,("Failed to find if we are the PDC for this ldb\n")); + talloc_free(tmp_ctx); + return false; +} + + +/* Find a domain object in the parents of a particular DN. */ +int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, + struct ldb_dn **parent_dn, const char **errstring) +{ + TALLOC_CTX *local_ctx; + struct ldb_dn *sdn = dn; + struct ldb_result *res = NULL; + int ret = 0; + const char *attrs[] = { NULL }; + + local_ctx = talloc_new(mem_ctx); + if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR; + + while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) { + ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE, + "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res); + if (ret == LDB_SUCCESS) { + talloc_steal(local_ctx, res); + if (res->count == 1) { + break; + } + } else { + break; + } + } + + if (ret != LDB_SUCCESS) { + *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s", + ldb_dn_get_linearized(dn), + ldb_dn_get_linearized(sdn), + ldb_errstring(ldb)); + talloc_free(local_ctx); + return ret; + } + if (res->count != 1) { + *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object", + ldb_dn_get_linearized(dn)); + talloc_free(local_ctx); + return LDB_ERR_CONSTRAINT_VIOLATION; + } + + *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn); + talloc_free(local_ctx); + return ret; +} + +/* + check that a password is sufficiently complex +*/ +static bool samdb_password_complexity_ok(const char *pass) +{ + return check_password_quality(pass); +} + + + +/* + set the user password using plaintext, obeying any user or domain + password restrictions + + note that this function doesn't actually store the result in the + database, it just fills in the "mod" structure with ldb modify + elements to setup the correct change when samdb_replace() is + called. This allows the caller to combine the change with other + changes (as is needed by some of the set user info levels) + + The caller should probably have a transaction wrapping this +*/ +_PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, + struct ldb_dn *user_dn, + struct ldb_dn *domain_dn, + struct ldb_message *mod, + const char *new_pass, + struct samr_Password *lmNewHash, + struct samr_Password *ntNewHash, + bool user_change, + enum samr_RejectReason *reject_reason, + struct samr_DomInfo1 **_dominfo) +{ + const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", + "ntPwdHistory", + "dBCSPwd", "unicodePwd", + "objectSid", + "pwdLastSet", NULL }; + const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", + "maxPwdAge", "minPwdAge", + "minPwdLength", NULL }; + NTTIME pwdLastSet; + int64_t minPwdAge; + uint_t minPwdLength, pwdProperties, pwdHistoryLength; + uint_t userAccountControl; + struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash; + struct samr_Password local_lmNewHash, local_ntNewHash; + int sambaLMPwdHistory_len, sambaNTPwdHistory_len; + struct dom_sid *domain_sid; + struct ldb_message **res; + bool restrictions; + int count; + time_t now = time(NULL); + NTTIME now_nt; + int i; + + /* we need to know the time to compute password age */ + unix_to_nt_time(&now_nt, now); + + /* pull all the user parameters */ + count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs); + if (count != 1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0); + sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], + "lmPwdHistory", &sambaLMPwdHistory); + sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], + "ntPwdHistory", &sambaNTPwdHistory); + lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd"); + ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd"); + pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0); + + /* Only non-trust accounts have restrictions (possibly this + * test is the wrong way around, but I like to be restrictive + * if possible */ + restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT + |UF_WORKSTATION_TRUST_ACCOUNT + |UF_SERVER_TRUST_ACCOUNT)); + + if (domain_dn) { + /* pull the domain parameters */ + count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs); + if (count != 1) { + DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", + ldb_dn_get_linearized(domain_dn), + ldb_dn_get_linearized(user_dn))); + return NT_STATUS_NO_SUCH_DOMAIN; + } + } else { + /* work out the domain sid, and pull the domain from there */ + domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid"); + if (domain_sid == NULL) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, + "(objectSid=%s)", + ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); + if (count != 1) { + DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", + dom_sid_string(mem_ctx, domain_sid), + ldb_dn_get_linearized(user_dn))); + return NT_STATUS_NO_SUCH_DOMAIN; + } + } + + pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0); + pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0); + minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0); + minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0); + + if (_dominfo) { + struct samr_DomInfo1 *dominfo; + /* on failure we need to fill in the reject reasons */ + dominfo = talloc(mem_ctx, struct samr_DomInfo1); + if (dominfo == NULL) { + return NT_STATUS_NO_MEMORY; + } + dominfo->min_password_length = minPwdLength; + dominfo->password_properties = pwdProperties; + dominfo->password_history_length = pwdHistoryLength; + dominfo->max_password_age = minPwdAge; + dominfo->min_password_age = minPwdAge; + *_dominfo = dominfo; + } + + if (restrictions && new_pass) { + + /* check the various password restrictions */ + if (restrictions && minPwdLength > strlen_m(new_pass)) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_TOO_SHORT; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + + /* possibly check password complexity */ + if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX && + !samdb_password_complexity_ok(new_pass)) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_COMPLEXITY; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + + /* compute the new nt and lm hashes */ + if (E_deshash(new_pass, local_lmNewHash.hash)) { + lmNewHash = &local_lmNewHash; + } + if (!E_md4hash(new_pass, local_ntNewHash.hash)) { + /* If we can't convert this password to UCS2, then we should not accept it */ + if (reject_reason) { + *reject_reason = SAMR_REJECT_OTHER; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + ntNewHash = &local_ntNewHash; + } + + if (user_change) { + /* are all password changes disallowed? */ + if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_OTHER; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + + /* can this user change password? */ + if (userAccountControl & UF_PASSWD_CANT_CHANGE) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_OTHER; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + + /* yes, this is a minus. The ages are in negative 100nsec units! */ + if (pwdLastSet - minPwdAge > now_nt) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_OTHER; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + + /* check the immediately past password */ + if (pwdHistoryLength > 0) { + if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_IN_HISTORY; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_IN_HISTORY; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + } + + /* check the password history */ + sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength); + sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength); + + for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) { + if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_IN_HISTORY; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + } + for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) { + if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) { + if (reject_reason) { + *reject_reason = SAMR_REJECT_IN_HISTORY; + } + return NT_STATUS_PASSWORD_RESTRICTION; + } + } + } + +#define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0) + + /* the password is acceptable. Start forming the new fields */ + if (new_pass) { + /* if we know the cleartext, then only set it. + * Modules in ldb will set all the appropriate + * hashes */ + CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, + "sambaPassword", new_pass)); + } else { + /* We don't have the cleartext, so delete the old one + * and set what we have of the hashes */ + CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword")); + + if (lmNewHash) { + CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash)); + } else { + CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd")); + } + + if (ntNewHash) { + CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash)); + } else { + CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd")); + } + } + + return NT_STATUS_OK; +} + + +/* + set the user password using plaintext, obeying any user or domain + password restrictions + + This wrapper function takes a SID as input, rather than a user DN, + and actually performs the password change + +*/ +_PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, + const struct dom_sid *user_sid, + const char *new_pass, + struct samr_Password *lmNewHash, + struct samr_Password *ntNewHash, + bool user_change, + enum samr_RejectReason *reject_reason, + struct samr_DomInfo1 **_dominfo) +{ + NTSTATUS nt_status; + struct ldb_dn *user_dn; + struct ldb_message *msg; + int ret; + + ret = ldb_transaction_start(ctx); + if (ret) { + DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx))); + return NT_STATUS_TRANSACTION_ABORTED; + } + + user_dn = samdb_search_dn(ctx, mem_ctx, NULL, + "(&(objectSid=%s)(objectClass=user))", + ldap_encode_ndr_dom_sid(mem_ctx, user_sid)); + if (!user_dn) { + ldb_transaction_cancel(ctx); + DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n", + dom_sid_string(mem_ctx, user_sid))); + return NT_STATUS_NO_SUCH_USER; + } + + msg = ldb_msg_new(mem_ctx); + if (msg == NULL) { + ldb_transaction_cancel(ctx); + return NT_STATUS_NO_MEMORY; + } + + msg->dn = ldb_dn_copy(msg, user_dn); + if (!msg->dn) { + ldb_transaction_cancel(ctx); + return NT_STATUS_NO_MEMORY; + } + + nt_status = samdb_set_password(ctx, mem_ctx, + user_dn, NULL, + msg, new_pass, + lmNewHash, ntNewHash, + user_change, /* This is a password set, not change */ + reject_reason, _dominfo); + if (!NT_STATUS_IS_OK(nt_status)) { + ldb_transaction_cancel(ctx); + return nt_status; + } + + /* modify the samdb record */ + ret = samdb_replace(ctx, mem_ctx, msg); + if (ret != 0) { + ldb_transaction_cancel(ctx); + return NT_STATUS_ACCESS_DENIED; + } + + ret = ldb_transaction_commit(ctx); + if (ret != 0) { + DEBUG(0,("Failed to commit transaction to change password on %s: %s\n", + ldb_dn_get_linearized(msg->dn), + ldb_errstring(ctx))); + return NT_STATUS_TRANSACTION_ABORTED; + } + return NT_STATUS_OK; +} + + + +NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, + struct dom_sid *sid, struct ldb_dn **ret_dn) +{ + struct ldb_message *msg; + struct ldb_dn *basedn; + const char *sidstr; + int ret; + + sidstr = dom_sid_string(mem_ctx, sid); + NT_STATUS_HAVE_NO_MEMORY(sidstr); + + /* We might have to create a ForeignSecurityPrincipal, even if this user + * is in our own domain */ + + msg = ldb_msg_new(mem_ctx); + if (msg == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* TODO: Hmmm. This feels wrong. How do I find the base dn to + * put the ForeignSecurityPrincipals? d_state->domain_dn does + * not work, this is wrong for the Builtin domain, there's no + * cn=For...,cn=Builtin,dc={BASEDN}. -- vl + */ + + basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL, + "(&(objectClass=container)(cn=ForeignSecurityPrincipals))"); + + if (basedn == NULL) { + DEBUG(0, ("Failed to find DN for " + "ForeignSecurityPrincipal container\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + /* add core elements to the ldb_message for the alias */ + msg->dn = ldb_dn_copy(mem_ctx, basedn); + if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) + return NT_STATUS_NO_MEMORY; + + samdb_msg_add_string(sam_ctx, mem_ctx, msg, + "objectClass", + "foreignSecurityPrincipal"); + + /* create the alias */ + ret = ldb_add(sam_ctx, msg); + if (ret != 0) { + DEBUG(0,("Failed to create foreignSecurityPrincipal " + "record %s: %s\n", + ldb_dn_get_linearized(msg->dn), + ldb_errstring(sam_ctx))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + *ret_dn = msg->dn; + return NT_STATUS_OK; +} + + +/* + Find the DN of a domain, assuming it to be a dotted.dns name +*/ + +struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) +{ + int i; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + const char *binary_encoded; + const char **split_realm; + struct ldb_dn *dn; + + if (!tmp_ctx) { + return NULL; + } + + split_realm = str_list_make(tmp_ctx, dns_domain, "."); + if (!split_realm) { + talloc_free(tmp_ctx); + return NULL; + } + dn = ldb_dn_new(mem_ctx, ldb, NULL); + for (i=0; split_realm[i]; i++) { + binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]); + if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) { + DEBUG(2, ("Failed to add dc=%s element to DN %s\n", + binary_encoded, ldb_dn_get_linearized(dn))); + talloc_free(tmp_ctx); + return NULL; + } + } + if (!ldb_dn_validate(dn)) { + DEBUG(2, ("Failed to validated DN %s\n", + ldb_dn_get_linearized(dn))); + return NULL; + } + return dn; +} +/* + Find the DN of a domain, be it the netbios or DNS name +*/ + +struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, + const char *domain_name) +{ + const char * const domain_ref_attrs[] = { + "ncName", NULL + }; + const char * const domain_ref2_attrs[] = { + NULL + }; + struct ldb_result *res_domain_ref; + char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name); + /* find the domain's DN */ + int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, + &res_domain_ref, + samdb_partitions_dn(ldb, mem_ctx), + LDB_SCOPE_ONELEVEL, + domain_ref_attrs, + "(&(nETBIOSName=%s)(objectclass=crossRef))", + escaped_domain); + if (ret_domain != 0) { + return NULL; + } + + if (res_domain_ref->count == 0) { + ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, + &res_domain_ref, + samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name), + LDB_SCOPE_BASE, + domain_ref2_attrs, + "(objectclass=domain)"); + if (ret_domain != 0) { + return NULL; + } + + if (res_domain_ref->count == 1) { + return res_domain_ref->msgs[0]->dn; + } + return NULL; + } + + if (res_domain_ref->count > 1) { + DEBUG(0,("Found %d records matching domain [%s]\n", + ret_domain, domain_name)); + return NULL; + } + + return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL); + +} diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index ad9721458f..83d1ee3bea 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -9,20 +9,29 @@ PUBLIC_PROTO_HEADER = samdb/samdb_proto.h PUBLIC_HEADERS = samdb/samdb.h PUBLIC_DEPENDENCIES = HEIMDAL_KRB5 PRIVATE_DEPENDENCIES = LIBNDR NDR_MISC NDR_DRSUAPI NDR_DRSBLOBS NSS_WRAPPER \ - auth_system_session LDAP_ENCODE + auth_system_session LDAP_ENCODE LIBCLI_AUTH LIBNDR \ + SAMDB_SCHEMA LDB_WRAP SAMDB_COMMON OBJ_FILES = \ samdb/samdb.o \ samdb/samdb_privilege.o \ samdb/cracknames.o \ + repl/replicated_objects.o + +[SUBSYSTEM::SAMDB_COMMON] +PUBLIC_PROTO_HEADER = common/proto.h +OBJ_FILES = \ common/sidmap.o \ common/flag_mapping.o \ + common/util.o + +[SUBSYSTEM::SAMDB_SCHEMA] +PUBLIC_PROTO_HEADER = schema/proto.h +PUBLIC_HEADERS = schema/schema.h +PRIVATE_DEPENDENCIES = SAMDB_COMMON +OBJ_FILES = \ schema/schema_init.o \ schema/schema_syntax.o \ schema/schema_constructed.o \ - repl/replicated_objects.o -# -# End SUBSYSTEM SAMDB -################################################ ####################### # Start SUBSYSTEM DREPL_SRV diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index 8350b77b29..95bb7de06c 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -11,11 +11,12 @@ OBJ_FILES = \ ################################################ ################################################ -# Start MODULE ldb_repl_mata_data +# Start MODULE ldb_repl_meta_data [MODULE::ldb_repl_meta_data] SUBSYSTEM = LIBLDB OUTPUT_TYPE = SHARED_LIBRARY -PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBNDR NDR_MISC NDR_DRSUAPI NDR_DRSBLOBS +PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBNDR NDR_MISC NDR_DRSUAPI \ + NDR_DRSBLOBS LIBNDR INIT_FUNCTION = repl_meta_data_module_init OBJ_FILES = \ repl_meta_data.o @@ -75,7 +76,7 @@ OBJ_FILES = \ [MODULE::ldb_samldb] SUBSYSTEM = LIBLDB OUTPUT_TYPE = SHARED_LIBRARY -PRIVATE_DEPENDENCIES = LIBTALLOC LDAP_ENCODE +PRIVATE_DEPENDENCIES = LIBTALLOC LDAP_ENCODE NDR_MISC SAMDB INIT_FUNCTION = samldb_module_init OBJ_FILES = \ samldb.o @@ -89,7 +90,8 @@ OBJ_FILES = \ SUBSYSTEM = LIBLDB OUTPUT_TYPE = SHARED_LIBRARY INIT_FUNCTION = ldb_samba3sam_module_init -PRIVATE_DEPENDENCIES = LIBTALLOC ldb_map SMBPASSWD NSS_WRAPPER +PRIVATE_DEPENDENCIES = LIBTALLOC ldb_map SMBPASSWD NSS_WRAPPER LIBSECURITY \ + NDR_SECURITY OBJ_FILES = \ samba3sam.o # @@ -102,7 +104,7 @@ OBJ_FILES = \ SUBSYSTEM = LIBLDB OUTPUT_TYPE = SHARED_LIBRARY INIT_FUNCTION = ldb_simple_ldap_map_module_init -PRIVATE_DEPENDENCIES = LIBTALLOC ldb_map +PRIVATE_DEPENDENCIES = LIBTALLOC ldb_map LIBNDR NDR_MISC ENABLE = YES ALIASES = entryuuid nsuniqueid OBJ_FILES = \ @@ -127,7 +129,7 @@ OBJ_FILES = \ # Start MODULE ldb_rootdse [MODULE::ldb_rootdse] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = LIBTALLOC +PRIVATE_DEPENDENCIES = LIBTALLOC SAMDB OUTPUT_TYPE = SHARED_LIBRARY INIT_FUNCTION = rootdse_module_init OBJ_FILES = \ @@ -143,7 +145,8 @@ SUBSYSTEM = LIBLDB OUTPUT_TYPE = SHARED_LIBRARY INIT_FUNCTION = password_hash_module_init OBJ_FILES = password_hash.o -PRIVATE_DEPENDENCIES = HEIMDAL_HDB_KEYS LIBTALLOC HEIMDAL_KRB5 LDAP_ENCODE +PRIVATE_DEPENDENCIES = HEIMDAL_HDB_KEYS LIBTALLOC HEIMDAL_KRB5 LDAP_ENCODE \ + LIBCLI_AUTH NDR_DRSBLOBS KERBEROS SAMDB # # End MODULE ldb_password_hash ################################################ @@ -151,7 +154,7 @@ PRIVATE_DEPENDENCIES = HEIMDAL_HDB_KEYS LIBTALLOC HEIMDAL_KRB5 LDAP_ENCODE ################################################ # Start MODULE ldb_local_password [MODULE::ldb_local_password] -PRIVATE_DEPENDENCIES = LIBTALLOC +PRIVATE_DEPENDENCIES = LIBTALLOC LIBNDR SAMDB OUTPUT_TYPE = SHARED_LIBRARY SUBSYSTEM = LIBLDB INIT_FUNCTION = local_password_module_init @@ -163,7 +166,7 @@ OBJ_FILES = local_password.o ################################################ # Start MODULE ldb_kludge_acl [MODULE::ldb_kludge_acl] -PRIVATE_DEPENDENCIES = LIBTALLOC LIBSECURITY +PRIVATE_DEPENDENCIES = LIBTALLOC LIBSECURITY SAMDB OUTPUT_TYPE = SHARED_LIBRARY SUBSYSTEM = LIBLDB INIT_FUNCTION = ldb_kludge_acl_init @@ -178,7 +181,7 @@ OBJ_FILES = \ [MODULE::ldb_extended_dn] SUBSYSTEM = LIBLDB OUTPUT_TYPE = SHARED_LIBRARY -PRIVATE_DEPENDENCIES = LIBTALLOC +PRIVATE_DEPENDENCIES = LIBTALLOC LIBNDR LIBSECURITY SAMDB INIT_FUNCTION = ldb_extended_dn_init OBJ_FILES = \ extended_dn.o @@ -204,7 +207,7 @@ OBJ_FILES = \ [MODULE::ldb_partition] SUBSYSTEM = LIBLDB OUTPUT_TYPE = SHARED_LIBRARY -PRIVATE_DEPENDENCIES = LIBTALLOC +PRIVATE_DEPENDENCIES = LIBTALLOC SAMDB INIT_FUNCTION = ldb_partition_init OBJ_FILES = \ partition.o @@ -217,7 +220,7 @@ OBJ_FILES = \ [MODULE::ldb_schema] SUBSYSTEM = LIBLDB OUTPUT_TYPE = SHARED_LIBRARY -PRIVATE_DEPENDENCIES = LIBTALLOC +PRIVATE_DEPENDENCIES = LIBTALLOC LIBLDB INIT_FUNCTION = ldb_schema_init OBJ_FILES = \ schema.o schema_syntax.o @@ -230,7 +233,7 @@ OBJ_FILES = \ [MODULE::ldb_update_keytab] SUBSYSTEM = LIBLDB OUTPUT_TYPE = SHARED_LIBRARY -PRIVATE_DEPENDENCIES = LIBTALLOC CREDENTIALS_KRB5 +PRIVATE_DEPENDENCIES = LIBTALLOC CREDENTIALS #Also depends on credentials, but that would loop INIT_FUNCTION = ldb_update_kt_init OBJ_FILES = \ @@ -245,7 +248,7 @@ OBJ_FILES = \ INIT_FUNCTION = ldb_objectclass_init OUTPUT_TYPE = SHARED_LIBRARY CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC +PRIVATE_DEPENDENCIES = LIBTALLOC LIBSECURITY NDR_SECURITY SAMDB SUBSYSTEM = LIBLDB OBJ_FILES = \ objectclass.o @@ -284,7 +287,7 @@ OBJ_FILES = \ INIT_FUNCTION = ldb_linked_attributes_init CFLAGS = -Ilib/ldb/include OUTPUT_TYPE = SHARED_LIBRARY -PRIVATE_DEPENDENCIES = LIBTALLOC SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC SAMDB SUBSYSTEM = LIBLDB OBJ_FILES = \ linked_attributes.o @@ -310,7 +313,7 @@ OBJ_FILES = \ INIT_FUNCTION = ldb_anr_init CFLAGS = -Ilib/ldb/include OUTPUT_TYPE = SHARED_LIBRARY -PRIVATE_DEPENDENCIES = LIBTALLOC +PRIVATE_DEPENDENCIES = LIBTALLOC LIBSAMBA-UTIL SAMDB SUBSYSTEM = LIBLDB OBJ_FILES = \ anr.o diff --git a/source4/dsdb/samdb/ldb_modules/partition.c b/source4/dsdb/samdb/ldb_modules/partition.c index bf4421ab0d..4586810d96 100644 --- a/source4/dsdb/samdb/ldb_modules/partition.c +++ b/source4/dsdb/samdb/ldb_modules/partition.c @@ -117,9 +117,9 @@ static struct dsdb_control_current_partition *find_partition(struct partition_pr return NULL; }; -/* - fire the caller's callback for every entry, but only send 'done' once. -*/ +/** + * fire the caller's callback for every entry, but only send 'done' once. + */ static int partition_search_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) { struct partition_context *ac; @@ -139,9 +139,9 @@ static int partition_search_callback(struct ldb_context *ldb, void *context, str } } -/* - only fire the 'last' callback, and only for START-TLS for now -*/ +/** + * only fire the 'last' callback, and only for START-TLS for now + */ static int partition_other_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares) { struct partition_context *ac; @@ -248,7 +248,9 @@ static int partition_send_request(struct partition_context *ac, struct ldb_contr return LDB_SUCCESS; } -/* Send a request down to all the partitions */ +/** + * Send a request down to all the partitions + */ static int partition_send_all(struct ldb_module *module, struct partition_context *ac, struct ldb_control *remove_control, @@ -270,8 +272,10 @@ static int partition_send_all(struct ldb_module *module, return LDB_SUCCESS; } -/* Figure out which backend a request needs to be aimed at. Some - * requests must be replicated to all backends */ +/** + * Figure out which backend a request needs to be aimed at. Some + * requests must be replicated to all backends + */ static int partition_replicate(struct ldb_module *module, struct ldb_request *req, struct ldb_dn *dn) { unsigned i; diff --git a/source4/dsdb/samdb/ldb_modules/schema.c b/source4/dsdb/samdb/ldb_modules/schema.c index cf923d673b..525193ac8c 100644 --- a/source4/dsdb/samdb/ldb_modules/schema.c +++ b/source4/dsdb/samdb/ldb_modules/schema.c @@ -329,7 +329,7 @@ done: static int schema_init_classes(struct ldb_module *module, struct schema_private_data *data) { - static const char *schema_attrs[] = { "governsID", + const char *schema_attrs[] = { "governsID", "lDAPDisplayName", "objectClassCategory", "defaultObjectCategory", @@ -542,7 +542,7 @@ static int schema_add_check_parent(struct ldb_context *ldb, void *context, struc static int schema_add_build_parent_req(struct schema_context *sctx) { - static const char * const parent_attrs[] = { "objectClass", NULL }; + const char * const parent_attrs[] = { "objectClass", NULL }; int ret; sctx->parent_req = talloc_zero(sctx, struct ldb_request); diff --git a/source4/dsdb/samdb/samdb.c b/source4/dsdb/samdb/samdb.c index 4366b7d0b9..b042d1d3b7 100644 --- a/source4/dsdb/samdb/samdb.c +++ b/source4/dsdb/samdb/samdb.c @@ -86,623 +86,6 @@ struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx, } /* - search the sam for the specified attributes in a specific domain, filter on - objectSid being in domain_sid. -*/ -int samdb_search_domain(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - struct ldb_dn *basedn, - struct ldb_message ***res, - const char * const *attrs, - const struct dom_sid *domain_sid, - const char *format, ...) _PRINTF_ATTRIBUTE(7,8) -{ - va_list ap; - int i, count; - - va_start(ap, format); - count = gendb_search_v(sam_ldb, mem_ctx, basedn, - res, attrs, format, ap); - va_end(ap); - - i=0; - - while (i<count) { - struct dom_sid *entry_sid; - - entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid"); - - if ((entry_sid == NULL) || - (!dom_sid_in_domain(domain_sid, entry_sid))) { - /* Delete that entry from the result set */ - (*res)[i] = (*res)[count-1]; - count -= 1; - talloc_free(entry_sid); - continue; - } - talloc_free(entry_sid); - i += 1; - } - - return count; -} - -/* - search the sam for a single string attribute in exactly 1 record -*/ -const char *samdb_search_string_v(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - struct ldb_dn *basedn, - const char *attr_name, - const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0) -{ - int count; - const char *attrs[2] = { NULL, NULL }; - struct ldb_message **res = NULL; - - attrs[0] = attr_name; - - count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); - if (count > 1) { - DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", - attr_name, format, count)); - } - if (count != 1) { - talloc_free(res); - return NULL; - } - - return samdb_result_string(res[0], attr_name, NULL); -} - - -/* - search the sam for a single string attribute in exactly 1 record -*/ -const char *samdb_search_string(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - struct ldb_dn *basedn, - const char *attr_name, - const char *format, ...) _PRINTF_ATTRIBUTE(5,6) -{ - va_list ap; - const char *str; - - va_start(ap, format); - str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap); - va_end(ap); - - return str; -} - -struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - struct ldb_dn *basedn, - const char *format, ...) _PRINTF_ATTRIBUTE(4,5) -{ - va_list ap; - struct ldb_dn *ret; - struct ldb_message **res = NULL; - int count; - - va_start(ap, format); - count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap); - va_end(ap); - - if (count != 1) return NULL; - - ret = talloc_steal(mem_ctx, res[0]->dn); - talloc_free(res); - - return ret; -} - -/* - search the sam for a dom_sid attribute in exactly 1 record -*/ -struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - struct ldb_dn *basedn, - const char *attr_name, - const char *format, ...) _PRINTF_ATTRIBUTE(5,6) -{ - va_list ap; - int count; - struct ldb_message **res; - const char *attrs[2] = { NULL, NULL }; - struct dom_sid *sid; - - attrs[0] = attr_name; - - va_start(ap, format); - count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); - va_end(ap); - if (count > 1) { - DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", - attr_name, format, count)); - } - if (count != 1) { - talloc_free(res); - return NULL; - } - sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name); - talloc_free(res); - return sid; -} - -/* - return the count of the number of records in the sam matching the query -*/ -int samdb_search_count(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - struct ldb_dn *basedn, - const char *format, ...) _PRINTF_ATTRIBUTE(4,5) -{ - va_list ap; - struct ldb_message **res; - const char * const attrs[] = { NULL }; - int ret; - - va_start(ap, format); - ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); - va_end(ap); - - return ret; -} - - -/* - search the sam for a single integer attribute in exactly 1 record -*/ -uint_t samdb_search_uint(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - uint_t default_value, - struct ldb_dn *basedn, - const char *attr_name, - const char *format, ...) _PRINTF_ATTRIBUTE(6,7) -{ - va_list ap; - int count; - struct ldb_message **res; - const char *attrs[2] = { NULL, NULL }; - - attrs[0] = attr_name; - - va_start(ap, format); - count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); - va_end(ap); - - if (count != 1) { - return default_value; - } - - return samdb_result_uint(res[0], attr_name, default_value); -} - -/* - search the sam for a single signed 64 bit integer attribute in exactly 1 record -*/ -int64_t samdb_search_int64(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - int64_t default_value, - struct ldb_dn *basedn, - const char *attr_name, - const char *format, ...) _PRINTF_ATTRIBUTE(6,7) -{ - va_list ap; - int count; - struct ldb_message **res; - const char *attrs[2] = { NULL, NULL }; - - attrs[0] = attr_name; - - va_start(ap, format); - count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); - va_end(ap); - - if (count != 1) { - return default_value; - } - - return samdb_result_int64(res[0], attr_name, default_value); -} - -/* - search the sam for multipe records each giving a single string attribute - return the number of matches, or -1 on error -*/ -int samdb_search_string_multiple(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - struct ldb_dn *basedn, - const char ***strs, - const char *attr_name, - const char *format, ...) _PRINTF_ATTRIBUTE(6,7) -{ - va_list ap; - int count, i; - const char *attrs[2] = { NULL, NULL }; - struct ldb_message **res = NULL; - - attrs[0] = attr_name; - - va_start(ap, format); - count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap); - va_end(ap); - - if (count <= 0) { - return count; - } - - /* make sure its single valued */ - for (i=0;i<count;i++) { - if (res[i]->num_elements != 1) { - DEBUG(1,("samdb: search for %s %s not single valued\n", - attr_name, format)); - talloc_free(res); - return -1; - } - } - - *strs = talloc_array(mem_ctx, const char *, count+1); - if (! *strs) { - talloc_free(res); - return -1; - } - - for (i=0;i<count;i++) { - (*strs)[i] = samdb_result_string(res[i], attr_name, NULL); - } - (*strs)[count] = NULL; - - return count; -} - -/* - pull a uint from a result set. -*/ -uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value) -{ - return ldb_msg_find_attr_as_uint(msg, attr, default_value); -} - -/* - pull a (signed) int64 from a result set. -*/ -int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value) -{ - return ldb_msg_find_attr_as_int64(msg, attr, default_value); -} - -/* - pull a string from a result set. -*/ -const char *samdb_result_string(const struct ldb_message *msg, const char *attr, - const char *default_value) -{ - return ldb_msg_find_attr_as_string(msg, attr, default_value); -} - -struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, - const char *attr, struct ldb_dn *default_value) -{ - struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr); - if (!ret_dn) { - return default_value; - } - return ret_dn; -} - -/* - pull a rid from a objectSid in a result set. -*/ -uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, - const char *attr, uint32_t default_value) -{ - struct dom_sid *sid; - uint32_t rid; - - sid = samdb_result_dom_sid(mem_ctx, msg, attr); - if (sid == NULL) { - return default_value; - } - rid = sid->sub_auths[sid->num_auths-1]; - talloc_free(sid); - return rid; -} - -/* - pull a dom_sid structure from a objectSid in a result set. -*/ -struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, - const char *attr) -{ - const struct ldb_val *v; - struct dom_sid *sid; - enum ndr_err_code ndr_err; - v = ldb_msg_find_ldb_val(msg, attr); - if (v == NULL) { - return NULL; - } - sid = talloc(mem_ctx, struct dom_sid); - if (sid == NULL) { - return NULL; - } - ndr_err = ndr_pull_struct_blob(v, sid, sid, - (ndr_pull_flags_fn_t)ndr_pull_dom_sid); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - talloc_free(sid); - return NULL; - } - return sid; -} - -/* - pull a guid structure from a objectGUID in a result set. -*/ -struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr) -{ - const struct ldb_val *v; - enum ndr_err_code ndr_err; - struct GUID guid; - TALLOC_CTX *mem_ctx; - - ZERO_STRUCT(guid); - - v = ldb_msg_find_ldb_val(msg, attr); - if (!v) return guid; - - mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid"); - if (!mem_ctx) return guid; - ndr_err = ndr_pull_struct_blob(v, mem_ctx, &guid, - (ndr_pull_flags_fn_t)ndr_pull_GUID); - talloc_free(mem_ctx); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return guid; - } - - return guid; -} - -/* - pull a sid prefix from a objectSid in a result set. - this is used to find the domain sid for a user -*/ -struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, - const char *attr) -{ - struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr); - if (!sid || sid->num_auths < 1) return NULL; - sid->num_auths--; - return sid; -} - -/* - pull a NTTIME in a result set. -*/ -NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value) -{ - return ldb_msg_find_attr_as_uint64(msg, attr, default_value); -} - -/* - pull a uint64_t from a result set. -*/ -uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value) -{ - return ldb_msg_find_attr_as_uint64(msg, attr, default_value); -} - - -/* - construct the allow_password_change field from the PwdLastSet attribute and the - domain password settings -*/ -NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - struct ldb_dn *domain_dn, - struct ldb_message *msg, - const char *attr) -{ - uint64_t attr_time = samdb_result_uint64(msg, attr, 0); - int64_t minPwdAge; - - if (attr_time == 0) { - return 0; - } - - minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL); - - /* yes, this is a -= not a += as minPwdAge is stored as the negative - of the number of 100-nano-seconds */ - attr_time -= minPwdAge; - - return attr_time; -} - -/* - construct the force_password_change field from the PwdLastSet attribute and the - domain password settings -*/ -NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, - TALLOC_CTX *mem_ctx, - struct ldb_dn *domain_dn, - struct ldb_message *msg) -{ - uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0); - uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0); - int64_t maxPwdAge; - - if (user_flags & UF_DONT_EXPIRE_PASSWD) { - return 0x7FFFFFFFFFFFFFFFULL; - } - - if (attr_time == 0) { - return 0; - } - - maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL); - if (maxPwdAge == 0) { - return 0; - } else { - attr_time -= maxPwdAge; - } - - return attr_time; -} - -/* - pull a samr_Password structutre from a result set. -*/ -struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr) -{ - struct samr_Password *hash = NULL; - const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); - if (val && (val->length >= sizeof(hash->hash))) { - hash = talloc(mem_ctx, struct samr_Password); - memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash))); - } - return hash; -} - -/* - pull an array of samr_Password structutres from a result set. -*/ -uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr, struct samr_Password **hashes) -{ - uint_t count = 0; - const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); - int i; - - *hashes = NULL; - if (!val) { - return 0; - } - count = val->length / 16; - if (count == 0) { - return 0; - } - - *hashes = talloc_array(mem_ctx, struct samr_Password, count); - if (! *hashes) { - return 0; - } - - for (i=0;i<count;i++) { - memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16); - } - - return count; -} - -NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, - struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) -{ - struct samr_Password *lmPwdHash, *ntPwdHash; - if (nt_pwd) { - int num_nt; - num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash); - if (num_nt == 0) { - *nt_pwd = NULL; - } else if (num_nt > 1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } else { - *nt_pwd = &ntPwdHash[0]; - } - } - if (lm_pwd) { - int num_lm; - num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash); - if (num_lm == 0) { - *lm_pwd = NULL; - } else if (num_lm > 1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } else { - *lm_pwd = &lmPwdHash[0]; - } - } - return NT_STATUS_OK; -} - -/* - pull a samr_LogonHours structutre from a result set. -*/ -struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr) -{ - struct samr_LogonHours hours; - const int units_per_week = 168; - const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); - ZERO_STRUCT(hours); - hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week); - if (!hours.bits) { - return hours; - } - hours.units_per_week = units_per_week; - memset(hours.bits, 0xFF, units_per_week); - if (val) { - memcpy(hours.bits, val->data, MIN(val->length, units_per_week)); - } - return hours; -} - -/* - pull a set of account_flags from a result set. -*/ -uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr) -{ - uint_t userAccountControl = ldb_msg_find_attr_as_uint(msg, attr, 0); - return samdb_uf2acb(userAccountControl); -} - - -/* Find an attribute, with a particular value */ - -/* The current callers of this function expect a very specific - * behaviour: In particular, objectClass subclass equivilance is not - * wanted. This means that we should not lookup the schema for the - * comparison function */ -struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, - const struct ldb_message *msg, - const char *name, const char *value) -{ - int i; - struct ldb_message_element *el = ldb_msg_find_element(msg, name); - - if (!el) { - return NULL; - } - - for (i=0;i<el->num_values;i++) { - if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) { - return el; - } - } - - return NULL; -} - -int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value) -{ - if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) { - return samdb_msg_add_string(ldb, msg, msg, name, set_value); - } - return LDB_SUCCESS; -} - -int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value) -{ - struct ldb_message_element *el; - - el = ldb_msg_find_element(msg, name); - if (el) { - return LDB_SUCCESS; - } - - return samdb_msg_add_string(ldb, msg, msg, name, set_value); -} - - -/* copy from a template record to a message */ int samdb_copy_template(struct ldb_context *ldb, @@ -795,1098 +178,6 @@ int samdb_copy_template(struct ldb_context *ldb, } -/* - add a string element to a message -*/ -int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, const char *str) -{ - char *s = talloc_strdup(mem_ctx, str); - char *a = talloc_strdup(mem_ctx, attr_name); - if (s == NULL || a == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - return ldb_msg_add_string(msg, a, s); -} - -/* - add a dom_sid element to a message -*/ -int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, struct dom_sid *sid) -{ - struct ldb_val v; - enum ndr_err_code ndr_err; - - ndr_err = ndr_push_struct_blob(&v, mem_ctx, sid, - (ndr_push_flags_fn_t)ndr_push_dom_sid); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return -1; - } - return ldb_msg_add_value(msg, attr_name, &v, NULL); -} - - -/* - add a delete element operation to a message -*/ -int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name) -{ - /* we use an empty replace rather than a delete, as it allows for - samdb_replace() to be used everywhere */ - return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL); -} - -/* - add a add attribute value to a message -*/ -int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, const char *value) -{ - struct ldb_message_element *el; - char *a, *v; - int ret; - a = talloc_strdup(mem_ctx, attr_name); - if (a == NULL) - return -1; - v = talloc_strdup(mem_ctx, value); - if (v == NULL) - return -1; - ret = ldb_msg_add_string(msg, a, v); - if (ret != 0) - return ret; - el = ldb_msg_find_element(msg, a); - if (el == NULL) - return -1; - el->flags = LDB_FLAG_MOD_ADD; - return 0; -} - -/* - add a delete attribute value to a message -*/ -int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, const char *value) -{ - struct ldb_message_element *el; - char *a, *v; - int ret; - a = talloc_strdup(mem_ctx, attr_name); - if (a == NULL) - return -1; - v = talloc_strdup(mem_ctx, value); - if (v == NULL) - return -1; - ret = ldb_msg_add_string(msg, a, v); - if (ret != 0) - return ret; - el = ldb_msg_find_element(msg, a); - if (el == NULL) - return -1; - el->flags = LDB_FLAG_MOD_DELETE; - return 0; -} - -/* - add a int element to a message -*/ -int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, int v) -{ - const char *s = talloc_asprintf(mem_ctx, "%d", v); - return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); -} - -/* - add a uint_t element to a message -*/ -int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, uint_t v) -{ - const char *s = talloc_asprintf(mem_ctx, "%u", v); - return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); -} - -/* - add a (signed) int64_t element to a message -*/ -int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, int64_t v) -{ - const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v); - return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); -} - -/* - add a uint64_t element to a message -*/ -int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, uint64_t v) -{ - const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v); - return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s); -} - -/* - add a samr_Password element to a message -*/ -int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, struct samr_Password *hash) -{ - struct ldb_val val; - val.data = talloc_memdup(mem_ctx, hash->hash, 16); - if (!val.data) { - return -1; - } - val.length = 16; - return ldb_msg_add_value(msg, attr_name, &val, NULL); -} - -/* - add a samr_Password array to a message -*/ -int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, struct samr_Password *hashes, uint_t count) -{ - struct ldb_val val; - int i; - val.data = talloc_array_size(mem_ctx, 16, count); - val.length = count*16; - if (!val.data) { - return -1; - } - for (i=0;i<count;i++) { - memcpy(i*16 + (char *)val.data, hashes[i].hash, 16); - } - return ldb_msg_add_value(msg, attr_name, &val, NULL); -} - -/* - add a acct_flags element to a message -*/ -int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, uint32_t v) -{ - return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v)); -} - -/* - add a logon_hours element to a message -*/ -int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, struct samr_LogonHours *hours) -{ - struct ldb_val val; - val.length = hours->units_per_week / 8; - val.data = hours->bits; - return ldb_msg_add_value(msg, attr_name, &val, NULL); -} - -/* - add a general value element to a message -*/ -int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, const struct ldb_val *val) -{ - return ldb_msg_add_value(msg, attr_name, val, NULL); -} - -/* - sets a general value element to a message -*/ -int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, const struct ldb_val *val) -{ - struct ldb_message_element *el; - - el = ldb_msg_find_element(msg, attr_name); - if (el) { - el->num_values = 0; - } - return ldb_msg_add_value(msg, attr_name, val, NULL); -} - -/* - set a string element in a message -*/ -int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg, - const char *attr_name, const char *str) -{ - struct ldb_message_element *el; - - el = ldb_msg_find_element(msg, attr_name); - if (el) { - el->num_values = 0; - } - return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str); -} - -/* - replace elements in a record -*/ -int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg) -{ - int i; - - /* mark all the message elements as LDB_FLAG_MOD_REPLACE */ - for (i=0;i<msg->num_elements;i++) { - msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; - } - - /* modify the samdb record */ - return ldb_modify(sam_ldb, msg); -} - -/* - return a default security descriptor -*/ -struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx) -{ - struct security_descriptor *sd; - - sd = security_descriptor_initialise(mem_ctx); - - return sd; -} - -struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) -{ - return ldb_get_default_basedn(sam_ctx); -} - -struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) -{ - return ldb_get_config_basedn(sam_ctx); -} - -struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) -{ - return ldb_get_schema_basedn(sam_ctx); -} - -struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) -{ - return ldb_get_root_basedn(sam_ctx); -} - -struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) -{ - struct ldb_dn *new_dn; - - new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx)); - if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) { - talloc_free(new_dn); - return NULL; - } - return new_dn; -} - -struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx) -{ - struct ldb_dn *new_dn; - - new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx)); - if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) { - talloc_free(new_dn); - return NULL; - } - return new_dn; -} - -/* - work out the domain sid for the current open ldb -*/ -const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb) -{ - TALLOC_CTX *tmp_ctx; - struct dom_sid *domain_sid; - - /* see if we have a cached copy */ - domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid"); - if (domain_sid) { - return domain_sid; - } - - tmp_ctx = talloc_new(ldb); - if (tmp_ctx == NULL) { - goto failed; - } - - /* find the domain_sid */ - domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, ldb_get_default_basedn(ldb), - "objectSid", "objectClass=domainDNS"); - if (domain_sid == NULL) { - goto failed; - } - - /* cache the domain_sid in the ldb */ - if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) { - goto failed; - } - - talloc_steal(ldb, domain_sid); - talloc_free(tmp_ctx); - - return domain_sid; - -failed: - DEBUG(1,("Failed to find domain_sid for open ldb\n")); - talloc_free(tmp_ctx); - return NULL; -} - -bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in) -{ - TALLOC_CTX *tmp_ctx; - struct dom_sid *dom_sid_new; - struct dom_sid *dom_sid_old; - - /* see if we have a cached copy */ - dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, - "cache.domain_sid"), struct dom_sid); - - tmp_ctx = talloc_new(ldb); - if (tmp_ctx == NULL) { - goto failed; - } - - dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in); - if (!dom_sid_new) { - goto failed; - } - - /* cache the domain_sid in the ldb */ - if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) { - goto failed; - } - - talloc_steal(ldb, dom_sid_new); - talloc_free(tmp_ctx); - talloc_free(dom_sid_old); - - return true; - -failed: - DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n")); - talloc_free(tmp_ctx); - return false; -} - -/* Obtain the short name of the flexible single master operator - * (FSMO), such as the PDC Emulator */ -const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, - const char *attr) -{ - /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */ - struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr); - const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1); - const char *name = ldb_dn_get_component_name(fsmo_dn, 1); - - if (!name || (ldb_attr_cmp(name, "cn") != 0)) { - /* Ensure this matches the format. This gives us a - * bit more confidence that a 'cn' value will be a - * ascii string */ - return NULL; - } - if (val) { - return (char *)val->data; - } - return NULL; -} - -/* - work out the ntds settings dn for the current open ldb -*/ -struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb) -{ - TALLOC_CTX *tmp_ctx; - const char *root_attrs[] = { "dsServiceName", NULL }; - int ret; - struct ldb_result *root_res; - struct ldb_dn *settings_dn; - - /* see if we have a cached copy */ - settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn"); - if (settings_dn) { - return settings_dn; - } - - tmp_ctx = talloc_new(ldb); - if (tmp_ctx == NULL) { - goto failed; - } - - - ret = ldb_search(ldb, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, NULL, root_attrs, &root_res); - if (ret) { - DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", - ldb_errstring(ldb))); - goto failed; - } - talloc_steal(tmp_ctx, root_res); - - if (root_res->count != 1) { - goto failed; - } - - settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName"); - - /* cache the domain_sid in the ldb */ - if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) { - goto failed; - } - - talloc_steal(ldb, settings_dn); - talloc_free(tmp_ctx); - - return settings_dn; - -failed: - DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n")); - talloc_free(tmp_ctx); - return NULL; -} - -/* - work out the ntds settings invocationId for the current open ldb -*/ -const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb) -{ - TALLOC_CTX *tmp_ctx; - const char *attrs[] = { "invocationId", NULL }; - int ret; - struct ldb_result *res; - struct GUID *invocation_id; - - /* see if we have a cached copy */ - invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id"); - if (invocation_id) { - return invocation_id; - } - - tmp_ctx = talloc_new(ldb); - if (tmp_ctx == NULL) { - goto failed; - } - - ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res); - if (ret) { - goto failed; - } - talloc_steal(tmp_ctx, res); - - if (res->count != 1) { - goto failed; - } - - invocation_id = talloc(tmp_ctx, struct GUID); - if (!invocation_id) { - goto failed; - } - - *invocation_id = samdb_result_guid(res->msgs[0], "invocationId"); - - /* cache the domain_sid in the ldb */ - if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) { - goto failed; - } - - talloc_steal(ldb, invocation_id); - talloc_free(tmp_ctx); - - return invocation_id; - -failed: - DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n")); - talloc_free(tmp_ctx); - return NULL; -} - -bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in) -{ - TALLOC_CTX *tmp_ctx; - struct GUID *invocation_id_new; - struct GUID *invocation_id_old; - - /* see if we have a cached copy */ - invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, - "cache.invocation_id"); - - tmp_ctx = talloc_new(ldb); - if (tmp_ctx == NULL) { - goto failed; - } - - invocation_id_new = talloc(tmp_ctx, struct GUID); - if (!invocation_id_new) { - goto failed; - } - - *invocation_id_new = *invocation_id_in; - - /* cache the domain_sid in the ldb */ - if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) { - goto failed; - } - - talloc_steal(ldb, invocation_id_new); - talloc_free(tmp_ctx); - talloc_free(invocation_id_old); - - return true; - -failed: - DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n")); - talloc_free(tmp_ctx); - return false; -} - -/* - work out the ntds settings objectGUID for the current open ldb -*/ -const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb) -{ - TALLOC_CTX *tmp_ctx; - const char *attrs[] = { "objectGUID", NULL }; - int ret; - struct ldb_result *res; - struct GUID *ntds_guid; - - /* see if we have a cached copy */ - ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid"); - if (ntds_guid) { - return ntds_guid; - } - - tmp_ctx = talloc_new(ldb); - if (tmp_ctx == NULL) { - goto failed; - } - - ret = ldb_search(ldb, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, NULL, attrs, &res); - if (ret) { - goto failed; - } - talloc_steal(tmp_ctx, res); - - if (res->count != 1) { - goto failed; - } - - ntds_guid = talloc(tmp_ctx, struct GUID); - if (!ntds_guid) { - goto failed; - } - - *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID"); - - /* cache the domain_sid in the ldb */ - if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) { - goto failed; - } - - talloc_steal(ldb, ntds_guid); - talloc_free(tmp_ctx); - - return ntds_guid; - -failed: - DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n")); - talloc_free(tmp_ctx); - return NULL; -} - -bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in) -{ - TALLOC_CTX *tmp_ctx; - struct GUID *ntds_guid_new; - struct GUID *ntds_guid_old; - - /* see if we have a cached copy */ - ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid"); - - tmp_ctx = talloc_new(ldb); - if (tmp_ctx == NULL) { - goto failed; - } - - ntds_guid_new = talloc(tmp_ctx, struct GUID); - if (!ntds_guid_new) { - goto failed; - } - - *ntds_guid_new = *ntds_guid_in; - - /* cache the domain_sid in the ldb */ - if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) { - goto failed; - } - - talloc_steal(ldb, ntds_guid_new); - talloc_free(tmp_ctx); - talloc_free(ntds_guid_old); - - return true; - -failed: - DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n")); - talloc_free(tmp_ctx); - return false; -} - -/* - work out the server dn for the current open ldb -*/ -struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) -{ - return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb)); -} - -/* - work out the server dn for the current open ldb -*/ -struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) -{ - struct ldb_dn *server_dn; - struct ldb_dn *server_site_dn; - - server_dn = samdb_server_dn(ldb, mem_ctx); - if (!server_dn) return NULL; - - server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn); - - talloc_free(server_dn); - return server_site_dn; -} - -/* - work out if we are the PDC for the domain of the current open ldb -*/ -bool samdb_is_pdc(struct ldb_context *ldb) -{ - const char *dom_attrs[] = { "fSMORoleOwner", NULL }; - int ret; - struct ldb_result *dom_res; - TALLOC_CTX *tmp_ctx; - bool is_pdc; - struct ldb_dn *pdc; - - tmp_ctx = talloc_new(ldb); - if (tmp_ctx == NULL) { - DEBUG(1, ("talloc_new failed in samdb_is_pdc")); - return false; - } - - ret = ldb_search(ldb, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, NULL, dom_attrs, &dom_res); - if (ret) { - DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", - ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), - ldb_errstring(ldb))); - goto failed; - } - talloc_steal(tmp_ctx, dom_res); - if (dom_res->count != 1) { - goto failed; - } - - pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner"); - - if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) { - is_pdc = true; - } else { - is_pdc = false; - } - - talloc_free(tmp_ctx); - - return is_pdc; - -failed: - DEBUG(1,("Failed to find if we are the PDC for this ldb\n")); - talloc_free(tmp_ctx); - return false; -} - - -/* Find a domain object in the parents of a particular DN. */ -int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, - struct ldb_dn **parent_dn, const char **errstring) -{ - TALLOC_CTX *local_ctx; - struct ldb_dn *sdn = dn; - struct ldb_result *res = NULL; - int ret = 0; - const char *attrs[] = { NULL }; - - local_ctx = talloc_new(mem_ctx); - if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR; - - while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) { - ret = ldb_search(ldb, sdn, LDB_SCOPE_BASE, - "(|(objectClass=domain)(objectClass=builtinDomain))", attrs, &res); - if (ret == LDB_SUCCESS) { - talloc_steal(local_ctx, res); - if (res->count == 1) { - break; - } - } else { - break; - } - } - - if (ret != LDB_SUCCESS) { - *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s", - ldb_dn_get_linearized(dn), - ldb_dn_get_linearized(sdn), - ldb_errstring(ldb)); - talloc_free(local_ctx); - return ret; - } - if (res->count != 1) { - *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object", - ldb_dn_get_linearized(dn)); - talloc_free(local_ctx); - return LDB_ERR_CONSTRAINT_VIOLATION; - } - - *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn); - talloc_free(local_ctx); - return ret; -} - -/* - check that a password is sufficiently complex -*/ -static bool samdb_password_complexity_ok(const char *pass) -{ - return check_password_quality(pass); -} - - - -/* - set the user password using plaintext, obeying any user or domain - password restrictions - - note that this function doesn't actually store the result in the - database, it just fills in the "mod" structure with ldb modify - elements to setup the correct change when samdb_replace() is - called. This allows the caller to combine the change with other - changes (as is needed by some of the set user info levels) - - The caller should probably have a transaction wrapping this -*/ -_PUBLIC_ NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, - struct ldb_dn *user_dn, - struct ldb_dn *domain_dn, - struct ldb_message *mod, - const char *new_pass, - struct samr_Password *lmNewHash, - struct samr_Password *ntNewHash, - bool user_change, - enum samr_RejectReason *reject_reason, - struct samr_DomInfo1 **_dominfo) -{ - const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", - "ntPwdHistory", - "dBCSPwd", "unicodePwd", - "objectSid", - "pwdLastSet", NULL }; - const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", - "maxPwdAge", "minPwdAge", - "minPwdLength", NULL }; - NTTIME pwdLastSet; - int64_t minPwdAge; - uint_t minPwdLength, pwdProperties, pwdHistoryLength; - uint_t userAccountControl; - struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash; - struct samr_Password local_lmNewHash, local_ntNewHash; - int sambaLMPwdHistory_len, sambaNTPwdHistory_len; - struct dom_sid *domain_sid; - struct ldb_message **res; - bool restrictions; - int count; - time_t now = time(NULL); - NTTIME now_nt; - int i; - - /* we need to know the time to compute password age */ - unix_to_nt_time(&now_nt, now); - - /* pull all the user parameters */ - count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs); - if (count != 1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - userAccountControl = samdb_result_uint(res[0], "userAccountControl", 0); - sambaLMPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], - "lmPwdHistory", &sambaLMPwdHistory); - sambaNTPwdHistory_len = samdb_result_hashes(mem_ctx, res[0], - "ntPwdHistory", &sambaNTPwdHistory); - lmPwdHash = samdb_result_hash(mem_ctx, res[0], "dBCSPwd"); - ntPwdHash = samdb_result_hash(mem_ctx, res[0], "unicodePwd"); - pwdLastSet = samdb_result_uint64(res[0], "pwdLastSet", 0); - - /* Only non-trust accounts have restrictions (possibly this - * test is the wrong way around, but I like to be restrictive - * if possible */ - restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT - |UF_WORKSTATION_TRUST_ACCOUNT - |UF_SERVER_TRUST_ACCOUNT)); - - if (domain_dn) { - /* pull the domain parameters */ - count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs); - if (count != 1) { - DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", - ldb_dn_get_linearized(domain_dn), - ldb_dn_get_linearized(user_dn))); - return NT_STATUS_NO_SUCH_DOMAIN; - } - } else { - /* work out the domain sid, and pull the domain from there */ - domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid"); - if (domain_sid == NULL) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, - "(objectSid=%s)", - ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)); - if (count != 1) { - DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", - dom_sid_string(mem_ctx, domain_sid), - ldb_dn_get_linearized(user_dn))); - return NT_STATUS_NO_SUCH_DOMAIN; - } - } - - pwdProperties = samdb_result_uint(res[0], "pwdProperties", 0); - pwdHistoryLength = samdb_result_uint(res[0], "pwdHistoryLength", 0); - minPwdLength = samdb_result_uint(res[0], "minPwdLength", 0); - minPwdAge = samdb_result_int64(res[0], "minPwdAge", 0); - - if (_dominfo) { - struct samr_DomInfo1 *dominfo; - /* on failure we need to fill in the reject reasons */ - dominfo = talloc(mem_ctx, struct samr_DomInfo1); - if (dominfo == NULL) { - return NT_STATUS_NO_MEMORY; - } - dominfo->min_password_length = minPwdLength; - dominfo->password_properties = pwdProperties; - dominfo->password_history_length = pwdHistoryLength; - dominfo->max_password_age = minPwdAge; - dominfo->min_password_age = minPwdAge; - *_dominfo = dominfo; - } - - if (restrictions && new_pass) { - - /* check the various password restrictions */ - if (restrictions && minPwdLength > strlen_m(new_pass)) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_TOO_SHORT; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* possibly check password complexity */ - if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX && - !samdb_password_complexity_ok(new_pass)) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_COMPLEXITY; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* compute the new nt and lm hashes */ - if (E_deshash(new_pass, local_lmNewHash.hash)) { - lmNewHash = &local_lmNewHash; - } - if (!E_md4hash(new_pass, local_ntNewHash.hash)) { - /* If we can't convert this password to UCS2, then we should not accept it */ - if (reject_reason) { - *reject_reason = SAMR_REJECT_OTHER; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - ntNewHash = &local_ntNewHash; - } - - if (user_change) { - /* are all password changes disallowed? */ - if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_OTHER; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* can this user change password? */ - if (userAccountControl & UF_PASSWD_CANT_CHANGE) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_OTHER; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* yes, this is a minus. The ages are in negative 100nsec units! */ - if (pwdLastSet - minPwdAge > now_nt) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_OTHER; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - - /* check the immediately past password */ - if (pwdHistoryLength > 0) { - if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_IN_HISTORY; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_IN_HISTORY; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - } - - /* check the password history */ - sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength); - sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength); - - for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) { - if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_IN_HISTORY; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - } - for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) { - if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) { - if (reject_reason) { - *reject_reason = SAMR_REJECT_IN_HISTORY; - } - return NT_STATUS_PASSWORD_RESTRICTION; - } - } - } - -#define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0) - - /* the password is acceptable. Start forming the new fields */ - if (new_pass) { - /* if we know the cleartext, then only set it. - * Modules in ldb will set all the appropriate - * hashes */ - CHECK_RET(samdb_msg_add_string(ctx, mem_ctx, mod, - "sambaPassword", new_pass)); - } else { - /* We don't have the cleartext, so delete the old one - * and set what we have of the hashes */ - CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "sambaPassword")); - - if (lmNewHash) { - CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash)); - } else { - CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd")); - } - - if (ntNewHash) { - CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash)); - } else { - CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd")); - } - } - - return NT_STATUS_OK; -} - - -/* - set the user password using plaintext, obeying any user or domain - password restrictions - - This wrapper function takes a SID as input, rather than a user DN, - and actually performs the password change - -*/ -_PUBLIC_ NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx, - const struct dom_sid *user_sid, - const char *new_pass, - struct samr_Password *lmNewHash, - struct samr_Password *ntNewHash, - bool user_change, - enum samr_RejectReason *reject_reason, - struct samr_DomInfo1 **_dominfo) -{ - NTSTATUS nt_status; - struct ldb_dn *user_dn; - struct ldb_message *msg; - int ret; - - ret = ldb_transaction_start(ctx); - if (ret) { - DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx))); - return NT_STATUS_TRANSACTION_ABORTED; - } - - user_dn = samdb_search_dn(ctx, mem_ctx, NULL, - "(&(objectSid=%s)(objectClass=user))", - ldap_encode_ndr_dom_sid(mem_ctx, user_sid)); - if (!user_dn) { - ldb_transaction_cancel(ctx); - DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n", - dom_sid_string(mem_ctx, user_sid))); - return NT_STATUS_NO_SUCH_USER; - } - - msg = ldb_msg_new(mem_ctx); - if (msg == NULL) { - ldb_transaction_cancel(ctx); - return NT_STATUS_NO_MEMORY; - } - - msg->dn = ldb_dn_copy(msg, user_dn); - if (!msg->dn) { - ldb_transaction_cancel(ctx); - return NT_STATUS_NO_MEMORY; - } - - nt_status = samdb_set_password(ctx, mem_ctx, - user_dn, NULL, - msg, new_pass, - lmNewHash, ntNewHash, - user_change, /* This is a password set, not change */ - reject_reason, _dominfo); - if (!NT_STATUS_IS_OK(nt_status)) { - ldb_transaction_cancel(ctx); - return nt_status; - } - - /* modify the samdb record */ - ret = samdb_replace(ctx, mem_ctx, msg); - if (ret != 0) { - ldb_transaction_cancel(ctx); - return NT_STATUS_ACCESS_DENIED; - } - - ret = ldb_transaction_commit(ctx); - if (ret != 0) { - DEBUG(0,("Failed to commit transaction to change password on %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(ctx))); - return NT_STATUS_TRANSACTION_ABORTED; - } - return NT_STATUS_OK; -} - /**************************************************************************** Create the SID list for this user. ****************************************************************************/ @@ -1961,153 +252,3 @@ NTSTATUS security_token_create(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } - - -NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, - struct dom_sid *sid, struct ldb_dn **ret_dn) -{ - struct ldb_message *msg; - struct ldb_dn *basedn; - const char *sidstr; - int ret; - - sidstr = dom_sid_string(mem_ctx, sid); - NT_STATUS_HAVE_NO_MEMORY(sidstr); - - /* We might have to create a ForeignSecurityPrincipal, even if this user - * is in our own domain */ - - msg = ldb_msg_new(mem_ctx); - if (msg == NULL) { - return NT_STATUS_NO_MEMORY; - } - - /* TODO: Hmmm. This feels wrong. How do I find the base dn to - * put the ForeignSecurityPrincipals? d_state->domain_dn does - * not work, this is wrong for the Builtin domain, there's no - * cn=For...,cn=Builtin,dc={BASEDN}. -- vl - */ - - basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL, - "(&(objectClass=container)(cn=ForeignSecurityPrincipals))"); - - if (basedn == NULL) { - DEBUG(0, ("Failed to find DN for " - "ForeignSecurityPrincipal container\n")); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - /* add core elements to the ldb_message for the alias */ - msg->dn = ldb_dn_copy(mem_ctx, basedn); - if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) - return NT_STATUS_NO_MEMORY; - - samdb_msg_add_string(sam_ctx, mem_ctx, msg, - "objectClass", - "foreignSecurityPrincipal"); - - /* create the alias */ - ret = ldb_add(sam_ctx, msg); - if (ret != 0) { - DEBUG(0,("Failed to create foreignSecurityPrincipal " - "record %s: %s\n", - ldb_dn_get_linearized(msg->dn), - ldb_errstring(sam_ctx))); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - *ret_dn = msg->dn; - return NT_STATUS_OK; -} - - -/* - Find the DN of a domain, assuming it to be a dotted.dns name -*/ - -struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) -{ - int i; - TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); - const char *binary_encoded; - const char **split_realm; - struct ldb_dn *dn; - - if (!tmp_ctx) { - return NULL; - } - - split_realm = str_list_make(tmp_ctx, dns_domain, "."); - if (!split_realm) { - talloc_free(tmp_ctx); - return NULL; - } - dn = ldb_dn_new(mem_ctx, ldb, NULL); - for (i=0; split_realm[i]; i++) { - binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]); - if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) { - DEBUG(2, ("Failed to add dc=%s element to DN %s\n", - binary_encoded, ldb_dn_get_linearized(dn))); - talloc_free(tmp_ctx); - return NULL; - } - } - if (!ldb_dn_validate(dn)) { - DEBUG(2, ("Failed to validated DN %s\n", - ldb_dn_get_linearized(dn))); - return NULL; - } - return dn; -} -/* - Find the DN of a domain, be it the netbios or DNS name -*/ - -struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, - const char *domain_name) -{ - const char * const domain_ref_attrs[] = { - "ncName", NULL - }; - const char * const domain_ref2_attrs[] = { - NULL - }; - struct ldb_result *res_domain_ref; - char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name); - /* find the domain's DN */ - int ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, - &res_domain_ref, - samdb_partitions_dn(ldb, mem_ctx), - LDB_SCOPE_ONELEVEL, - domain_ref_attrs, - "(&(nETBIOSName=%s)(objectclass=crossRef))", - escaped_domain); - if (ret_domain != 0) { - return NULL; - } - - if (res_domain_ref->count == 0) { - ret_domain = ldb_search_exp_fmt(ldb, mem_ctx, - &res_domain_ref, - samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name), - LDB_SCOPE_BASE, - domain_ref2_attrs, - "(objectclass=domain)"); - if (ret_domain != 0) { - return NULL; - } - - if (res_domain_ref->count == 1) { - return res_domain_ref->msgs[0]->dn; - } - return NULL; - } - - if (res_domain_ref->count > 1) { - DEBUG(0,("Found %d records matching domain [%s]\n", - ret_domain, domain_name)); - return NULL; - } - - return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL); - -} diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 54d1ce2e75..5d8694d2d4 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -35,6 +35,7 @@ struct loadparm_context; #include "librpc/gen_ndr/drsblobs.h" #include "dsdb/schema/schema.h" #include "dsdb/samdb/samdb_proto.h" +#include "dsdb/common/proto.h" #define DSDB_CONTROL_CURRENT_PARTITION_OID "1.3.6.1.4.1.7165.4.3.2" struct dsdb_control_current_partition { diff --git a/source4/dsdb/schema/schema.h b/source4/dsdb/schema/schema.h index 1125f775ff..1379ddee9f 100644 --- a/source4/dsdb/schema/schema.h +++ b/source4/dsdb/schema/schema.h @@ -151,4 +151,6 @@ struct dsdb_schema { struct dsdb_class *classes; }; +#include "dsdb/schema/proto.h" + #endif /* _DSDB_SCHEMA_H */ |