2 Unix SMB/CIFS implementation.
4 interface functions for the sam database
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "librpc/gen_ndr/ndr_netlogon.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "system/time.h"
27 #include "system/filesys.h"
31 connect to the SAM database
32 return an opaque context pointer on success, or NULL on failure
34 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx)
36 return ldb_wrap_connect(mem_ctx, lp_sam_url(), 0, NULL);
40 search the sam for the specified attributes - varargs variant
42 int samdb_search(struct ldb_context *sam_ldb,
45 struct ldb_message ***res,
46 const char * const *attrs,
47 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
53 count = gendb_search_v(sam_ldb, mem_ctx, basedn, res, attrs, format, ap);
60 search the sam for the specified attributes in a specific domain, filter on
61 objectSid being in domain_sid.
63 int samdb_search_domain(struct ldb_context *sam_ldb,
66 struct ldb_message ***res,
67 const char * const *attrs,
68 const struct dom_sid *domain_sid,
69 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
75 count = gendb_search_v(sam_ldb, mem_ctx, basedn, res, attrs,
82 struct dom_sid *entry_sid;
84 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i],
87 if ((entry_sid == NULL) ||
88 (!dom_sid_in_domain(domain_sid, entry_sid))) {
90 /* Delete that entry from the result set */
91 (*res)[i] = (*res)[count-1];
102 free up a search result
104 int samdb_search_free(struct ldb_context *sam_ldb,
105 TALLOC_CTX *mem_ctx, struct ldb_message **res)
107 return ldb_search_free(sam_ldb, res);
111 search the sam for a single string attribute in exactly 1 record
113 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
116 const char *attr_name,
117 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
120 const char * const attrs[2] = { attr_name, NULL };
121 struct ldb_message **res = NULL;
123 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
125 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
126 attr_name, format, count));
129 samdb_search_free(sam_ldb, mem_ctx, res);
133 return samdb_result_string(res[0], attr_name, NULL);
138 search the sam for a single string attribute in exactly 1 record
140 const char *samdb_search_string(struct ldb_context *sam_ldb,
143 const char *attr_name,
144 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
149 va_start(ap, format);
150 str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
157 return the count of the number of records in the sam matching the query
159 int samdb_search_count(struct ldb_context *sam_ldb,
162 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
165 struct ldb_message **res;
166 const char * const attrs[] = { NULL };
169 va_start(ap, format);
170 ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
178 search the sam for a single integer attribute in exactly 1 record
180 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
182 uint_t default_value,
184 const char *attr_name,
185 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
189 struct ldb_message **res;
190 const char * const attrs[2] = { attr_name, NULL };
192 va_start(ap, format);
193 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
197 return default_value;
200 return samdb_result_uint(res[0], attr_name, default_value);
204 search the sam for a single signed 64 bit integer attribute in exactly 1 record
206 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
208 int64_t default_value,
210 const char *attr_name,
211 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
215 struct ldb_message **res;
216 const char * const attrs[2] = { attr_name, NULL };
218 va_start(ap, format);
219 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
223 return default_value;
226 return samdb_result_int64(res[0], attr_name, default_value);
230 search the sam for multipe records each giving a single string attribute
231 return the number of matches, or -1 on error
233 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
237 const char *attr_name,
238 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
242 const char * const attrs[2] = { attr_name, NULL };
243 struct ldb_message **res = NULL;
245 va_start(ap, format);
246 count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
253 /* make sure its single valued */
254 for (i=0;i<count;i++) {
255 if (res[i]->num_elements != 1) {
256 DEBUG(1,("samdb: search for %s %s not single valued\n",
258 samdb_search_free(sam_ldb, mem_ctx, res);
263 *strs = talloc_array(mem_ctx, const char *, count+1);
265 samdb_search_free(sam_ldb, mem_ctx, res);
269 for (i=0;i<count;i++) {
270 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
272 (*strs)[count] = NULL;
278 pull a uint from a result set.
280 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
282 return ldb_msg_find_uint(msg, attr, default_value);
286 pull a (signed) int64 from a result set.
288 int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value)
290 return ldb_msg_find_int64(msg, attr, default_value);
294 pull a string from a result set.
296 const char *samdb_result_string(struct ldb_message *msg, const char *attr,
297 const char *default_value)
299 return ldb_msg_find_string(msg, attr, default_value);
303 pull a rid from a objectSid in a result set.
305 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
306 const char *attr, uint32_t default_value)
309 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
310 if (!sidstr) return default_value;
312 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
313 if (!sid) return default_value;
315 return sid->sub_auths[sid->num_auths-1];
319 pull a dom_sid structure from a objectSid in a result set.
321 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
324 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
325 if (!sidstr) return NULL;
327 return dom_sid_parse_talloc(mem_ctx, sidstr);
331 pull a guid structure from a objectGUID in a result set.
333 struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr)
337 const char *guidstr = ldb_msg_find_string(msg, attr, NULL);
341 if (!guidstr) return guid;
343 status = GUID_from_string(guidstr, &guid);
344 if (!NT_STATUS_IS_OK(status)) {
353 pull a sid prefix from a objectSid in a result set.
354 this is used to find the domain sid for a user
356 const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
359 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
360 if (!sid || sid->num_auths < 1) return NULL;
364 return dom_sid_string(mem_ctx, sid);
368 pull a NTTIME in a result set.
370 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value)
372 const char *str = ldb_msg_find_string(msg, attr, default_value);
373 return nttime_from_string(str);
377 pull a uint64_t from a result set.
379 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
381 return ldb_msg_find_uint64(msg, attr, default_value);
386 construct the allow_password_change field from the PwdLastSet attribute and the
387 domain password settings
389 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
391 const char *domain_dn,
392 struct ldb_message *msg,
395 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
398 if (attr_time == 0) {
402 minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, NULL,
403 "minPwdAge", "dn=%s", domain_dn);
405 /* yes, this is a -= not a += as minPwdAge is stored as the negative
406 of the number of 100-nano-seconds */
407 attr_time -= minPwdAge;
413 construct the force_password_change field from the PwdLastSet attribute and the
414 domain password settings
416 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb,
418 const char *domain_dn,
419 struct ldb_message *msg,
422 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
425 if (attr_time == 0) {
429 maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, NULL, "maxPwdAge", "dn=%s", domain_dn);
430 if (maxPwdAge == 0) {
433 attr_time -= maxPwdAge;
440 pull a samr_Password structutre from a result set.
442 struct samr_Password samdb_result_hash(struct ldb_message *msg, const char *attr)
444 struct samr_Password hash;
445 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
448 memcpy(hash.hash, val->data, MIN(val->length, sizeof(hash.hash)));
454 pull an array of samr_Password structutres from a result set.
456 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
457 const char *attr, struct samr_Password **hashes)
460 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
467 count = val->length / 16;
472 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
477 for (i=0;i<count;i++) {
478 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
484 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
485 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
488 const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
490 struct samr_Password *lmPwdHash, *ntPwdHash;
493 ntPwdHash = talloc(mem_ctx, struct samr_Password);
495 return NT_STATUS_NO_MEMORY;
498 E_md4hash(unicodePwd, ntPwdHash->hash);
505 lmPwdHash = talloc(mem_ctx, struct samr_Password);
507 return NT_STATUS_NO_MEMORY;
510 /* compute the new nt and lm hashes */
511 lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
522 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
525 } else if (num_nt > 1) {
526 return NT_STATUS_INTERNAL_DB_CORRUPTION;
528 *nt_pwd = &ntPwdHash[0];
533 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
536 } else if (num_lm > 1) {
537 return NT_STATUS_INTERNAL_DB_CORRUPTION;
539 *lm_pwd = &lmPwdHash[0];
548 pull a samr_LogonHours structutre from a result set.
550 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
552 struct samr_LogonHours hours;
553 const int units_per_week = 168;
554 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
556 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
560 hours.units_per_week = units_per_week;
561 memset(hours.bits, 0xFF, units_per_week);
563 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
569 pull a set of account_flags from a result set.
571 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
573 uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
574 return samdb_uf2acb(userAccountControl);
578 copy from a template record to a message
580 int samdb_copy_template(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
581 struct ldb_message *msg, const char *expression)
583 struct ldb_message **res, *t;
587 /* pull the template record */
588 ret = samdb_search(sam_ldb, mem_ctx, NULL, &res, NULL, "%s", expression);
590 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n",
596 for (i=0;i<t->num_elements;i++) {
597 struct ldb_message_element *el = &t->elements[i];
598 /* some elements should not be copied from the template */
599 if (strcasecmp(el->name, "cn") == 0 ||
600 strcasecmp(el->name, "name") == 0 ||
601 strcasecmp(el->name, "sAMAccountName") == 0) {
604 for (j=0;j<el->num_values;j++) {
605 if (strcasecmp(el->name, "objectClass") == 0 &&
606 (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
607 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
608 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
609 strcasecmp((char *)el->values[j].data, "foreignSecurityTemplate") == 0 ||
610 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
611 strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
612 strcasecmp((char *)el->values[j].data, "secretTemplate") == 0)) {
615 samdb_msg_add_string(sam_ldb, mem_ctx, msg, el->name,
616 (char *)el->values[j].data);
625 allocate a new id, attempting to do it atomically
626 return 0 on failure, the id on success
628 static NTSTATUS _samdb_allocate_next_id(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const char *dn,
629 const char *attr, uint32_t *id)
631 struct ldb_message msg;
634 struct ldb_val vals[2];
635 struct ldb_message_element els[2];
637 str = samdb_search_string(sam_ldb, mem_ctx, NULL, attr, "dn=%s", dn);
639 DEBUG(1,("id not found at %s %s\n", dn, attr));
640 return NT_STATUS_OBJECT_NAME_INVALID;
643 *id = strtol(str, NULL, 0);
646 return NT_STATUS_INSUFFICIENT_RESOURCES;
649 /* we do a delete and add as a single operation. That prevents
652 msg.dn = talloc_strdup(mem_ctx, dn);
654 return NT_STATUS_NO_MEMORY;
656 msg.num_elements = 2;
659 els[0].num_values = 1;
660 els[0].values = &vals[0];
661 els[0].flags = LDB_FLAG_MOD_DELETE;
662 els[0].name = talloc_strdup(mem_ctx, attr);
664 return NT_STATUS_NO_MEMORY;
667 els[1].num_values = 1;
668 els[1].values = &vals[1];
669 els[1].flags = LDB_FLAG_MOD_ADD;
670 els[1].name = els[0].name;
672 vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
674 return NT_STATUS_NO_MEMORY;
676 vals[0].length = strlen(vals[0].data);
678 vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
680 return NT_STATUS_NO_MEMORY;
682 vals[1].length = strlen(vals[1].data);
684 ret = ldb_modify(sam_ldb, &msg);
686 return NT_STATUS_UNEXPECTED_IO_ERROR;
695 allocate a new id, attempting to do it atomically
696 return 0 on failure, the id on success
698 NTSTATUS samdb_allocate_next_id(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
704 /* we need to try multiple times to cope with two account
705 creations at the same time */
707 status = _samdb_allocate_next_id(sam_ldb, mem_ctx, dn, attr, id);
708 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
713 if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
714 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
722 add a string element to a message
724 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
725 const char *attr_name, const char *str)
727 char *s = talloc_strdup(mem_ctx, str);
728 char *a = talloc_strdup(mem_ctx, attr_name);
729 if (s == NULL || a == NULL) {
732 return ldb_msg_add_string(sam_ldb, msg, a, s);
736 add a delete element operation to a message
738 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
739 const char *attr_name)
741 char *a = talloc_strdup(mem_ctx, attr_name);
745 /* we use an empty replace rather than a delete, as it allows for
746 samdb_replace() to be used everywhere */
747 return ldb_msg_add_empty(sam_ldb, msg, a, LDB_FLAG_MOD_REPLACE);
751 add a add attribute value to a message
753 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
754 const char *attr_name, const char *value)
756 struct ldb_message_element *el;
759 a = talloc_strdup(mem_ctx, attr_name);
762 v = talloc_strdup(mem_ctx, value);
765 ret = ldb_msg_add_string(sam_ldb, msg, a, v);
768 el = ldb_msg_find_element(msg, a);
771 el->flags = LDB_FLAG_MOD_ADD;
776 add a delete attribute value to a message
778 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
779 const char *attr_name, const char *value)
781 struct ldb_message_element *el;
784 a = talloc_strdup(mem_ctx, attr_name);
787 v = talloc_strdup(mem_ctx, value);
790 ret = ldb_msg_add_string(sam_ldb, msg, a, v);
793 el = ldb_msg_find_element(msg, a);
796 el->flags = LDB_FLAG_MOD_DELETE;
801 add a uint_t element to a message
803 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
804 const char *attr_name, uint_t v)
806 const char *s = talloc_asprintf(mem_ctx, "%u", v);
807 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
811 add a (signed) int64_t element to a message
813 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
814 const char *attr_name, int64_t v)
816 const char *s = talloc_asprintf(mem_ctx, "%lld", v);
817 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
821 add a uint64_t element to a message
823 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
824 const char *attr_name, uint64_t v)
826 const char *s = talloc_asprintf(mem_ctx, "%llu", v);
827 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
831 add a samr_Password element to a message
833 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
834 const char *attr_name, struct samr_Password *hash)
837 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
842 return ldb_msg_add_value(sam_ldb, msg, attr_name, &val);
846 add a samr_Password array to a message
848 int samdb_msg_add_hashes(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
849 const char *attr_name, struct samr_Password *hashes, uint_t count)
853 val.data = talloc_array_size(mem_ctx, 16, count);
854 val.length = count*16;
858 for (i=0;i<count;i++) {
859 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
861 return ldb_msg_add_value(sam_ldb, msg, attr_name, &val);
865 add a acct_flags element to a message
867 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
868 const char *attr_name, uint32_t v)
870 return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
874 add a logon_hours element to a message
876 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
877 const char *attr_name, struct samr_LogonHours *hours)
880 val.length = hours->units_per_week / 8;
881 val.data = hours->bits;
882 return ldb_msg_add_value(sam_ldb, msg, attr_name, &val);
886 add a general value element to a message
888 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
889 const char *attr_name, const struct ldb_val *val)
891 return ldb_msg_add_value(sam_ldb, msg, attr_name, val);
895 sets a general value element to a message
897 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
898 const char *attr_name, const struct ldb_val *val)
900 struct ldb_message_element *el;
902 el = ldb_msg_find_element(msg, attr_name);
906 return ldb_msg_add_value(sam_ldb, msg, attr_name, val);
910 set a string element in a message
912 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
913 const char *attr_name, const char *str)
915 struct ldb_message_element *el;
917 el = ldb_msg_find_element(msg, attr_name);
921 return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
925 set a ldaptime element in a message
927 int samdb_msg_set_ldaptime(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
928 const char *attr_name, time_t t)
930 char *str = ldap_timestring(mem_ctx, t);
934 return samdb_msg_set_string(sam_ldb, mem_ctx, msg, attr_name, str);
940 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
944 time_t now = time(NULL);
946 guid = GUID_random();
947 guidstr = GUID_string(mem_ctx, &guid);
952 samdb_msg_add_string(sam_ldb, mem_ctx, msg, "objectGUID", guidstr);
953 samdb_msg_set_ldaptime(sam_ldb, mem_ctx, msg, "whenCreated", now);
954 samdb_msg_set_ldaptime(sam_ldb, mem_ctx, msg, "whenChanged", now);
955 return ldb_add(sam_ldb, msg);
961 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const char *dn)
963 return ldb_delete(sam_ldb, dn);
969 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
971 time_t now = time(NULL);
972 samdb_msg_set_ldaptime(sam_ldb, mem_ctx, msg, "whenChanged", now);
973 return ldb_modify(sam_ldb, msg);
977 replace elements in a record
979 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
983 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
984 for (i=0;i<msg->num_elements;i++) {
985 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
988 /* modify the samdb record */
989 return samdb_modify(sam_ldb, mem_ctx, msg);
993 return a default security descriptor
995 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
997 struct security_descriptor *sd;
999 sd = security_descriptor_initialise(mem_ctx);