diff options
author | Stefan Metzmacher <metze@samba.org> | 2004-12-08 08:21:35 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:06:26 -0500 |
commit | 8d0c3eefbc49bffdf73d90a1d1f89db4f7977dab (patch) | |
tree | aeb94029726e83c094c631ff74504b034c2c98cc /source4/dsdb | |
parent | 071439c1e1c5a7e6deb7866ff9716977e527e826 (diff) | |
download | samba-8d0c3eefbc49bffdf73d90a1d1f89db4f7977dab.tar.gz samba-8d0c3eefbc49bffdf73d90a1d1f89db4f7977dab.tar.bz2 samba-8d0c3eefbc49bffdf73d90a1d1f89db4f7977dab.zip |
r4096: move the samdb code to source/dsdb/
the idea is to have a directory service db layer
which will be used by the ldap server, samr server, drsuapi server
authentification...
I plan to make different implementations of this interface possible
- current default will be the current samdb code with sam.ldb
- a compat implementation for samba3 (if someone wants to write one)
- a new dsdb implementation which:
- understands naming contexts (directory parrtitions)
- do schema and acl checking checking
- maintain objectGUID, timestamps and USN number,
maybe linked attributes ('member' and 'memberOf' attributes)
- store metadata on a attribute=value combination...
metze
(This used to be commit 893a8b8bca2f020fbbe6f469aaa8dd4478249eb8)
Diffstat (limited to 'source4/dsdb')
-rw-r--r-- | source4/dsdb/common/flag_mapping.c | 135 | ||||
-rw-r--r-- | source4/dsdb/samdb/samdb.c | 894 |
2 files changed, 1029 insertions, 0 deletions
diff --git a/source4/dsdb/common/flag_mapping.c b/source4/dsdb/common/flag_mapping.c new file mode 100644 index 0000000000..30c5b0cf13 --- /dev/null +++ b/source4/dsdb/common/flag_mapping.c @@ -0,0 +1,135 @@ +/* + Unix SMB/CIFS implementation. + helper mapping functions for the SAMDB server + + Copyright (C) Stefan (metze) Metzmacher 2002 + Copyright (C) Andrew Tridgell 2004 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_samr.h" + +/* +translated the ACB_CTRL Flags to UserFlags (userAccountControl) +*/ +/* mapping between ADS userAccountControl and SAMR acct_flags */ +static const struct { + uint32_t uf; + uint16_t acb; +} acct_flags_map[] = { + { UF_ACCOUNTDISABLE, ACB_DISABLED }, + { UF_HOMEDIR_REQUIRED, ACB_HOMDIRREQ }, + { UF_PASSWD_NOTREQD, ACB_PWNOTREQ }, + { UF_TEMP_DUPLICATE_ACCOUNT, ACB_TEMPDUP }, + { UF_NORMAL_ACCOUNT, ACB_NORMAL }, + { UF_MNS_LOGON_ACCOUNT, ACB_MNS }, + { UF_INTERDOMAIN_TRUST_ACCOUNT, ACB_DOMTRUST }, + { UF_WORKSTATION_TRUST_ACCOUNT, ACB_WSTRUST }, + { UF_SERVER_TRUST_ACCOUNT, ACB_SVRTRUST }, + { UF_DONT_EXPIRE_PASSWD, ACB_PWNOEXP }, + { UF_LOCKOUT, ACB_AUTOLOCK } +}; + +uint32_t samdb_acb2uf(uint16_t acb) +{ + uint32_t i, ret = 0; + for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) { + if (acct_flags_map[i].acb & acb) { + ret |= acct_flags_map[i].uf; + } + } + return ret; +} + +/* +translated the UserFlags (userAccountControl) to ACB_CTRL Flags +*/ +uint16_t samdb_uf2acb(uint32_t uf) +{ + uint32_t i; + uint16_t ret = 0; + for (i=0;i<ARRAY_SIZE(acct_flags_map);i++) { + if (acct_flags_map[i].uf & uf) { + ret |= acct_flags_map[i].acb; + } + } + return ret; +} + +/* +get the accountType from the UserFlags +*/ +uint32_t samdb_uf2atype(uint32_t uf) +{ + uint32_t atype = 0x00000000; + + if (uf & UF_NORMAL_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT; + else if (uf & UF_TEMP_DUPLICATE_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT; + else if (uf & UF_SERVER_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST; + else if (uf & UF_WORKSTATION_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST; + else if (uf & UF_INTERDOMAIN_TRUST_ACCOUNT) atype = ATYPE_INTERDOMAIN_TRUST; + + return atype; +} + +/* +get the accountType from the groupType +*/ +uint32_t samdb_gtype2atype(uint32_t gtype) +{ + uint32_t atype = 0x00000000; + + switch(gtype) { + case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP: + atype = ATYPE_SECURITY_LOCAL_GROUP; + break; + case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP: + atype = ATYPE_SECURITY_LOCAL_GROUP; + break; + case GTYPE_SECURITY_GLOBAL_GROUP: + atype = ATYPE_SECURITY_GLOBAL_GROUP; + break; + + case GTYPE_DISTRIBUTION_GLOBAL_GROUP: + atype = ATYPE_DISTRIBUTION_GLOBAL_GROUP; + break; + case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP: + atype = ATYPE_DISTRIBUTION_UNIVERSAL_GROUP; + break; + case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP: + atype = ATYPE_DISTRIBUTION_LOCAL_GROUP; + break; + } + + return atype; +} + +/* turn a sAMAccountType into a SID_NAME_USE */ +enum samr_SidType samdb_atype_map(uint32_t atype) +{ + switch (atype & 0xF0000000) { + case ATYPE_GLOBAL_GROUP: + return SID_NAME_DOM_GRP; + case ATYPE_SECURITY_LOCAL_GROUP: + return SID_NAME_ALIAS; + case ATYPE_ACCOUNT: + return SID_NAME_USER; + default: + DEBUG(1,("hmm, need to map account type 0x%x\n", atype)); + } + return SID_NAME_UNKNOWN; +} diff --git a/source4/dsdb/samdb/samdb.c b/source4/dsdb/samdb/samdb.c new file mode 100644 index 0000000000..7501d94ae6 --- /dev/null +++ b/source4/dsdb/samdb/samdb.c @@ -0,0 +1,894 @@ +/* + Unix SMB/CIFS implementation. + + interface functions for the sam database + + Copyright (C) Andrew Tridgell 2004 + + 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 2 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, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_netlogon.h" +#include "lib/ldb/include/ldb.h" + +/* + connect to the SAM database + return an opaque context pointer on success, or NULL on failure + */ +void *samdb_connect(TALLOC_CTX *mem_ctx) +{ + return ldb_wrap_connect(mem_ctx, lp_sam_url(), 0, NULL); +} + +/* + search the sam for the specified attributes - varargs variant +*/ +int samdb_search(void *ctx, + TALLOC_CTX *mem_ctx, + const char *basedn, + struct ldb_message ***res, + const char * const *attrs, + const char *format, ...) _PRINTF_ATTRIBUTE(6,7) +{ + struct ldb_wrap *sam_ctx = ctx; + va_list ap; + int count; + + va_start(ap, format); + count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, res, attrs, format, ap); + va_end(ap); + + return count; +} + +/* + free up a search result +*/ +int samdb_search_free(void *ctx, + TALLOC_CTX *mem_ctx, struct ldb_message **res) +{ + struct ldb_wrap *sam_ctx = ctx; + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + return ldb_search_free(sam_ctx->ldb, res); +} + +/* + search the sam for a single string attribute in exactly 1 record +*/ +const char *samdb_search_string_v(void *ctx, + TALLOC_CTX *mem_ctx, + const char *basedn, + const char *attr_name, + const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0) +{ + struct ldb_wrap *sam_ctx = ctx; + int count; + const char * const attrs[2] = { attr_name, NULL }; + struct ldb_message **res = NULL; + + count = gendb_search_v(sam_ctx->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) { + samdb_search_free(ctx, mem_ctx, 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(void *ctx, + TALLOC_CTX *mem_ctx, + const char *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(ctx, mem_ctx, basedn, attr_name, format, ap); + va_end(ap); + + return str; +} + +/* + return the count of the number of records in the sam matching the query +*/ +int samdb_search_count(void *ctx, + TALLOC_CTX *mem_ctx, + const char *basedn, + const char *format, ...) _PRINTF_ATTRIBUTE(4,5) +{ + struct ldb_wrap *samdb_ctx = ctx; + va_list ap; + struct ldb_message **res; + const char * const attrs[] = { NULL }; + int ret; + + va_start(ap, format); + ret = gendb_search_v(samdb_ctx->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(void *ctx, + TALLOC_CTX *mem_ctx, + uint_t default_value, + const char *basedn, + const char *attr_name, + const char *format, ...) _PRINTF_ATTRIBUTE(6,7) +{ + struct ldb_wrap *samdb_ctx = ctx; + va_list ap; + int count; + struct ldb_message **res; + const char * const attrs[2] = { attr_name, NULL }; + + va_start(ap, format); + count = gendb_search_v(samdb_ctx->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(void *ctx, + TALLOC_CTX *mem_ctx, + int64_t default_value, + const char *basedn, + const char *attr_name, + const char *format, ...) _PRINTF_ATTRIBUTE(6,7) +{ + struct ldb_wrap *samdb_ctx = ctx; + va_list ap; + int count; + struct ldb_message **res; + const char * const attrs[2] = { attr_name, NULL }; + + va_start(ap, format); + count = gendb_search_v(samdb_ctx->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(void *ctx, + TALLOC_CTX *mem_ctx, + const char *basedn, + const char ***strs, + const char *attr_name, + const char *format, ...) _PRINTF_ATTRIBUTE(6,7) +{ + struct ldb_wrap *samdb_ctx = ctx; + va_list ap; + int count, i; + const char * const attrs[2] = { attr_name, NULL }; + struct ldb_message **res = NULL; + + va_start(ap, format); + count = gendb_search_v(samdb_ctx->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)); + samdb_search_free(ctx, mem_ctx, res); + return -1; + } + } + + *strs = talloc_array_p(mem_ctx, const char *, count+1); + if (! *strs) { + samdb_search_free(ctx, mem_ctx, 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(struct ldb_message *msg, const char *attr, uint_t default_value) +{ + return ldb_msg_find_uint(msg, attr, default_value); +} + +/* + pull a (signed) int64 from a result set. +*/ +int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value) +{ + return ldb_msg_find_int64(msg, attr, default_value); +} + +/* + pull a string from a result set. +*/ +const char *samdb_result_string(struct ldb_message *msg, const char *attr, + const char *default_value) +{ + return ldb_msg_find_string(msg, attr, default_value); +} + +/* + pull a rid from a objectSid in a result set. +*/ +uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr, uint32_t default_value) +{ + struct dom_sid *sid; + const char *sidstr = ldb_msg_find_string(msg, attr, NULL); + if (!sidstr) return default_value; + + sid = dom_sid_parse_talloc(mem_ctx, sidstr); + if (!sid) return default_value; + + return sid->sub_auths[sid->num_auths-1]; +} + +/* + pull a dom_sid structure from a objectSid in a result set. +*/ +struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr) +{ + const char *sidstr = ldb_msg_find_string(msg, attr, NULL); + if (!sidstr) return NULL; + + return dom_sid_parse_talloc(mem_ctx, sidstr); +} + +/* + pull a guid structure from a objectGUID in a result set. +*/ +struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr) +{ + NTSTATUS status; + struct GUID guid; + const char *guidstr = ldb_msg_find_string(msg, attr, NULL); + + ZERO_STRUCT(guid); + + if (!guidstr) return guid; + + status = GUID_from_string(guidstr, &guid); + if (!NT_STATUS_IS_OK(status)) { + ZERO_STRUCT(guid); + 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 +*/ +const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, 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 dom_sid_string(mem_ctx, sid); +} + +/* + pull a NTTIME in a result set. +*/ +NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value) +{ + const char *str = ldb_msg_find_string(msg, attr, default_value); + return nttime_from_string(str); +} + +/* + 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_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(void *ctx, TALLOC_CTX *mem_ctx, + const char *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(ctx, mem_ctx, 0, NULL, + "minPwdAge", "dn=%s", domain_dn); + + /* 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(void *ctx, TALLOC_CTX *mem_ctx, + const char *domain_dn, + struct ldb_message *msg, + const char *attr) +{ + uint64_t attr_time = samdb_result_uint64(msg, attr, 0); + int64_t maxPwdAge; + + if (attr_time == 0) { + return 0; + } + + maxPwdAge = samdb_search_int64(ctx, mem_ctx, 0, NULL, "maxPwdAge", "dn=%s", domain_dn); + 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(struct ldb_message *msg, const char *attr) +{ + struct samr_Password hash; + const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr); + ZERO_STRUCT(hash); + if (val) { + 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_p(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) +{ + + const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL); + + struct samr_Password *lmPwdHash, *ntPwdHash; + if (unicodePwd) { + if (nt_pwd) { + ntPwdHash = talloc_p(mem_ctx, struct samr_Password); + if (!ntPwdHash) { + return NT_STATUS_NO_MEMORY; + } + + E_md4hash(unicodePwd, ntPwdHash->hash); + *nt_pwd = ntPwdHash; + } + + if (lm_pwd) { + BOOL lm_hash_ok; + + lmPwdHash = talloc_p(mem_ctx, struct samr_Password); + if (!lmPwdHash) { + return NT_STATUS_NO_MEMORY; + } + + /* compute the new nt and lm hashes */ + lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash); + + if (lm_hash_ok) { + *lm_pwd = lmPwdHash; + } else { + *lm_pwd = NULL; + } + } + } else { + if (nt_pwd) { + int num_nt; + num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &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, "lmPwdHash", &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.bitmap = talloc_array_p(mem_ctx, uint8, units_per_week); + if (!hours.bitmap) { + return hours; + } + hours.units_per_week = units_per_week; + memset(hours.bitmap, 0xFF, units_per_week); + if (val) { + memcpy(hours.bitmap, 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_uint(msg, attr, 0); + return samdb_uf2acb(userAccountControl); +} + +/* + copy from a template record to a message +*/ +int samdb_copy_template(void *ctx, TALLOC_CTX *mem_ctx, + struct ldb_message *msg, const char *expression) +{ + struct ldb_message **res, *t; + int ret, i, j; + + + /* pull the template record */ + ret = samdb_search(ctx, mem_ctx, NULL, &res, NULL, "%s", expression); + if (ret != 1) { + DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n", + expression, ret)); + return -1; + } + t = res[0]; + + for (i=0;i<t->num_elements;i++) { + struct ldb_message_element *el = &t->elements[i]; + /* some elements should not be copied from the template */ + if (strcasecmp(el->name, "cn") == 0 || + strcasecmp(el->name, "name") == 0 || + strcasecmp(el->name, "sAMAccountName") == 0) { + continue; + } + for (j=0;j<el->num_values;j++) { + if (strcasecmp(el->name, "objectClass") == 0 && + (strcasecmp((char *)el->values[j].data, "Template") == 0 || + strcasecmp((char *)el->values[j].data, "userTemplate") == 0 || + strcasecmp((char *)el->values[j].data, "groupTemplate") == 0)) { + continue; + } + samdb_msg_add_string(ctx, mem_ctx, msg, el->name, + (char *)el->values[j].data); + } + } + + return 0; +} + + +/* + allocate a new id, attempting to do it atomically + return 0 on failure, the id on success +*/ +static NTSTATUS _samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, + const char *attr, uint32_t *id) +{ + struct ldb_wrap *sam_ctx = ctx; + struct ldb_message msg; + int ret; + const char *str; + struct ldb_val vals[2]; + struct ldb_message_element els[2]; + + str = samdb_search_string(ctx, mem_ctx, NULL, attr, "dn=%s", dn); + if (!str) { + DEBUG(1,("id not found at %s %s\n", dn, attr)); + return NT_STATUS_OBJECT_NAME_INVALID; + } + + *id = strtol(str, NULL, 0); + if ((*id)+1 == 0) { + /* out of IDs ! */ + return NT_STATUS_INSUFFICIENT_RESOURCES; + } + + /* we do a delete and add as a single operation. That prevents + a race */ + ZERO_STRUCT(msg); + msg.dn = talloc_strdup(mem_ctx, dn); + if (!msg.dn) { + return NT_STATUS_NO_MEMORY; + } + msg.num_elements = 2; + msg.elements = els; + + els[0].num_values = 1; + els[0].values = &vals[0]; + els[0].flags = LDB_FLAG_MOD_DELETE; + els[0].name = talloc_strdup(mem_ctx, attr); + if (!els[0].name) { + return NT_STATUS_NO_MEMORY; + } + + els[1].num_values = 1; + els[1].values = &vals[1]; + els[1].flags = LDB_FLAG_MOD_ADD; + els[1].name = els[0].name; + + vals[0].data = talloc_asprintf(mem_ctx, "%u", *id); + if (!vals[0].data) { + return NT_STATUS_NO_MEMORY; + } + vals[0].length = strlen(vals[0].data); + + vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1); + if (!vals[1].data) { + return NT_STATUS_NO_MEMORY; + } + vals[1].length = strlen(vals[1].data); + + ret = ldb_modify(sam_ctx->ldb, &msg); + if (ret != 0) { + return NT_STATUS_UNEXPECTED_IO_ERROR; + } + + (*id)++; + + return NT_STATUS_OK; +} + +/* + allocate a new id, attempting to do it atomically + return 0 on failure, the id on success +*/ +NTSTATUS samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr, + uint32_t *id) +{ + int tries = 10; + NTSTATUS status; + + /* we need to try multiple times to cope with two account + creations at the same time */ + while (tries--) { + status = _samdb_allocate_next_id(ctx, mem_ctx, dn, attr, id); + if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) { + break; + } + } + + if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) { + DEBUG(1,("Failed to increment id %s at %s\n", attr, dn)); + } + + return status; +} + + +/* + add a string element to a message +*/ +int samdb_msg_add_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const char *str) +{ + struct ldb_wrap *sam_ctx = ctx; + char *s = talloc_strdup(mem_ctx, str); + char *a = talloc_strdup(mem_ctx, attr_name); + if (s == NULL || a == NULL) { + return -1; + } + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + return ldb_msg_add_string(sam_ctx->ldb, msg, a, s); +} + +/* + add a delete element operation to a message +*/ +int samdb_msg_add_delete(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name) +{ + struct ldb_wrap *sam_ctx = ctx; + char *a = talloc_strdup(mem_ctx, attr_name); + if (a == NULL) { + return -1; + } + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + /* we use an empty replace rather than a delete, as it allows for + samdb_replace() to be used everywhere */ + return ldb_msg_add_empty(sam_ctx->ldb, msg, a, LDB_FLAG_MOD_REPLACE); +} + +/* + add a uint_t element to a message +*/ +int samdb_msg_add_uint(void *ctx, 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(ctx, mem_ctx, msg, attr_name, s); +} + +/* + add a (signed) int64_t element to a message +*/ +int samdb_msg_add_int64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, int64_t v) +{ + const char *s = talloc_asprintf(mem_ctx, "%lld", v); + return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s); +} + +/* + add a uint64_t element to a message +*/ +int samdb_msg_add_uint64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, uint64_t v) +{ + const char *s = talloc_asprintf(mem_ctx, "%llu", v); + return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s); +} + +/* + add a samr_Password element to a message +*/ +int samdb_msg_add_hash(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, struct samr_Password hash) +{ + struct ldb_wrap *sam_ctx = ctx; + struct ldb_val val; + val.data = talloc(mem_ctx, 16); + val.length = 16; + if (!val.data) { + return -1; + } + memcpy(val.data, hash.hash, 16); + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val); +} + +/* + add a samr_Password array to a message +*/ +int samdb_msg_add_hashes(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, struct samr_Password *hashes, uint_t count) +{ + struct ldb_wrap *sam_ctx = ctx; + struct ldb_val val; + int i; + val.data = talloc(mem_ctx, count*16); + 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); + } + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val); +} + +/* + add a acct_flags element to a message +*/ +int samdb_msg_add_acct_flags(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, uint32_t v) +{ + return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v)); +} + +/* + add a logon_hours element to a message +*/ +int samdb_msg_add_logon_hours(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, struct samr_LogonHours *hours) +{ + struct ldb_wrap *sam_ctx = ctx; + struct ldb_val val; + val.length = hours->units_per_week / 8; + val.data = hours->bitmap; + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val); +} + +/* + set a string element in a message +*/ +int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, const char *str) +{ + struct ldb_wrap *sam_ctx = ctx; + struct ldb_message_element *el; + + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + + el = ldb_msg_find_element(msg, attr_name); + if (el) { + el->num_values = 0; + } + return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, str); +} + +/* + set a ldaptime element in a message +*/ +int samdb_msg_set_ldaptime(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg, + const char *attr_name, time_t t) +{ + char *str = ldap_timestring(mem_ctx, t); + if (!str) { + return -1; + } + return samdb_msg_set_string(ctx, mem_ctx, msg, attr_name, str); +} + +/* + add a record +*/ +int samdb_add(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg) +{ + struct ldb_wrap *sam_ctx = ctx; + + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + return ldb_add(sam_ctx->ldb, msg); +} + +/* + delete a record +*/ +int samdb_delete(void *ctx, TALLOC_CTX *mem_ctx, const char *dn) +{ + struct ldb_wrap *sam_ctx = ctx; + + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + return ldb_delete(sam_ctx->ldb, dn); +} + +/* + modify a record +*/ +int samdb_modify(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg) +{ + struct ldb_wrap *sam_ctx = ctx; + + ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx); + return ldb_modify(sam_ctx->ldb, msg); +} + +/* + replace elements in a record +*/ +int samdb_replace(void *ctx, 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 samdb_modify(ctx, mem_ctx, 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; +} |