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"
29 connect to the SAM database
30 return an opaque context pointer on success, or NULL on failure
32 struct ldb_wrap *samdb_connect(TALLOC_CTX *mem_ctx)
34 return ldb_wrap_connect(mem_ctx, lp_sam_url(), 0, NULL);
38 search the sam for the specified attributes - varargs variant
40 int samdb_search(struct ldb_wrap *sam_ctx,
43 struct ldb_message ***res,
44 const char * const *attrs,
45 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
51 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, res, attrs, format, ap);
58 search the sam for the specified attributes in a specific domain, filter on
59 objectSid being in domain_sid.
61 int samdb_search_domain(struct ldb_wrap *sam_ctx,
64 struct ldb_message ***res,
65 const char * const *attrs,
66 const struct dom_sid *domain_sid,
67 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
73 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, res, attrs,
80 struct dom_sid *entry_sid;
82 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i],
85 if ((entry_sid == NULL) ||
86 (!dom_sid_in_domain(domain_sid, entry_sid))) {
88 /* Delete that entry from the result set */
89 (*res)[i] = (*res)[count-1];
100 free up a search result
102 int samdb_search_free(struct ldb_wrap *sam_ctx,
103 TALLOC_CTX *mem_ctx, struct ldb_message **res)
105 return ldb_search_free(sam_ctx->ldb, res);
109 search the sam for a single string attribute in exactly 1 record
111 const char *samdb_search_string_v(struct ldb_wrap *sam_ctx,
114 const char *attr_name,
115 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
118 const char * const attrs[2] = { attr_name, NULL };
119 struct ldb_message **res = NULL;
121 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
123 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
124 attr_name, format, count));
127 samdb_search_free(sam_ctx, mem_ctx, res);
131 return samdb_result_string(res[0], attr_name, NULL);
136 search the sam for a single string attribute in exactly 1 record
138 const char *samdb_search_string(struct ldb_wrap *sam_ctx,
141 const char *attr_name,
142 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
147 va_start(ap, format);
148 str = samdb_search_string_v(sam_ctx, mem_ctx, basedn, attr_name, format, ap);
155 return the count of the number of records in the sam matching the query
157 int samdb_search_count(struct ldb_wrap *sam_ctx,
160 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
163 struct ldb_message **res;
164 const char * const attrs[] = { NULL };
167 va_start(ap, format);
168 ret = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
176 search the sam for a single integer attribute in exactly 1 record
178 uint_t samdb_search_uint(struct ldb_wrap *sam_ctx,
180 uint_t default_value,
182 const char *attr_name,
183 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
187 struct ldb_message **res;
188 const char * const attrs[2] = { attr_name, NULL };
190 va_start(ap, format);
191 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
195 return default_value;
198 return samdb_result_uint(res[0], attr_name, default_value);
202 search the sam for a single signed 64 bit integer attribute in exactly 1 record
204 int64_t samdb_search_int64(struct ldb_wrap *sam_ctx,
206 int64_t default_value,
208 const char *attr_name,
209 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
213 struct ldb_message **res;
214 const char * const attrs[2] = { attr_name, NULL };
216 va_start(ap, format);
217 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
221 return default_value;
224 return samdb_result_int64(res[0], attr_name, default_value);
228 search the sam for multipe records each giving a single string attribute
229 return the number of matches, or -1 on error
231 int samdb_search_string_multiple(struct ldb_wrap *sam_ctx,
235 const char *attr_name,
236 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
240 const char * const attrs[2] = { attr_name, NULL };
241 struct ldb_message **res = NULL;
243 va_start(ap, format);
244 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
251 /* make sure its single valued */
252 for (i=0;i<count;i++) {
253 if (res[i]->num_elements != 1) {
254 DEBUG(1,("samdb: search for %s %s not single valued\n",
256 samdb_search_free(sam_ctx, mem_ctx, res);
261 *strs = talloc_array(mem_ctx, const char *, count+1);
263 samdb_search_free(sam_ctx, mem_ctx, res);
267 for (i=0;i<count;i++) {
268 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
270 (*strs)[count] = NULL;
276 pull a uint from a result set.
278 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
280 return ldb_msg_find_uint(msg, attr, default_value);
284 pull a (signed) int64 from a result set.
286 int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value)
288 return ldb_msg_find_int64(msg, attr, default_value);
292 pull a string from a result set.
294 const char *samdb_result_string(struct ldb_message *msg, const char *attr,
295 const char *default_value)
297 return ldb_msg_find_string(msg, attr, default_value);
301 pull a rid from a objectSid in a result set.
303 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
304 const char *attr, uint32_t default_value)
307 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
308 if (!sidstr) return default_value;
310 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
311 if (!sid) return default_value;
313 return sid->sub_auths[sid->num_auths-1];
317 pull a dom_sid structure from a objectSid in a result set.
319 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
322 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
323 if (!sidstr) return NULL;
325 return dom_sid_parse_talloc(mem_ctx, sidstr);
329 pull a guid structure from a objectGUID in a result set.
331 struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr)
335 const char *guidstr = ldb_msg_find_string(msg, attr, NULL);
339 if (!guidstr) return guid;
341 status = GUID_from_string(guidstr, &guid);
342 if (!NT_STATUS_IS_OK(status)) {
351 pull a sid prefix from a objectSid in a result set.
352 this is used to find the domain sid for a user
354 const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
357 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
358 if (!sid || sid->num_auths < 1) return NULL;
362 return dom_sid_string(mem_ctx, sid);
366 pull a NTTIME in a result set.
368 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value)
370 const char *str = ldb_msg_find_string(msg, attr, default_value);
371 return nttime_from_string(str);
375 pull a uint64_t from a result set.
377 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
379 return ldb_msg_find_uint64(msg, attr, default_value);
384 construct the allow_password_change field from the PwdLastSet attribute and the
385 domain password settings
387 NTTIME samdb_result_allow_password_change(struct ldb_wrap *sam_ctx,
389 const char *domain_dn,
390 struct ldb_message *msg,
393 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
396 if (attr_time == 0) {
400 minPwdAge = samdb_search_int64(sam_ctx, mem_ctx, 0, NULL,
401 "minPwdAge", "dn=%s", domain_dn);
403 /* yes, this is a -= not a += as minPwdAge is stored as the negative
404 of the number of 100-nano-seconds */
405 attr_time -= minPwdAge;
411 construct the force_password_change field from the PwdLastSet attribute and the
412 domain password settings
414 NTTIME samdb_result_force_password_change(struct ldb_wrap *sam_ctx,
416 const char *domain_dn,
417 struct ldb_message *msg,
420 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
423 if (attr_time == 0) {
427 maxPwdAge = samdb_search_int64(sam_ctx, mem_ctx, 0, NULL, "maxPwdAge", "dn=%s", domain_dn);
428 if (maxPwdAge == 0) {
431 attr_time -= maxPwdAge;
438 pull a samr_Password structutre from a result set.
440 struct samr_Password samdb_result_hash(struct ldb_message *msg, const char *attr)
442 struct samr_Password hash;
443 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
446 memcpy(hash.hash, val->data, MIN(val->length, sizeof(hash.hash)));
452 pull an array of samr_Password structutres from a result set.
454 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
455 const char *attr, struct samr_Password **hashes)
458 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
465 count = val->length / 16;
470 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
475 for (i=0;i<count;i++) {
476 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
482 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
483 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
486 const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
488 struct samr_Password *lmPwdHash, *ntPwdHash;
491 ntPwdHash = talloc(mem_ctx, struct samr_Password);
493 return NT_STATUS_NO_MEMORY;
496 E_md4hash(unicodePwd, ntPwdHash->hash);
503 lmPwdHash = talloc(mem_ctx, struct samr_Password);
505 return NT_STATUS_NO_MEMORY;
508 /* compute the new nt and lm hashes */
509 lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
520 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
523 } else if (num_nt > 1) {
524 return NT_STATUS_INTERNAL_DB_CORRUPTION;
526 *nt_pwd = &ntPwdHash[0];
531 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
534 } else if (num_lm > 1) {
535 return NT_STATUS_INTERNAL_DB_CORRUPTION;
537 *lm_pwd = &lmPwdHash[0];
546 pull a samr_LogonHours structutre from a result set.
548 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
550 struct samr_LogonHours hours;
551 const int units_per_week = 168;
552 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
554 hours.bits = talloc_array(mem_ctx, uint8, units_per_week);
558 hours.units_per_week = units_per_week;
559 memset(hours.bits, 0xFF, units_per_week);
561 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
567 pull a set of account_flags from a result set.
569 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
571 uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
572 return samdb_uf2acb(userAccountControl);
576 copy from a template record to a message
578 int samdb_copy_template(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx,
579 struct ldb_message *msg, const char *expression)
581 struct ldb_message **res, *t;
585 /* pull the template record */
586 ret = samdb_search(sam_ctx, mem_ctx, NULL, &res, NULL, "%s", expression);
588 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n",
594 for (i=0;i<t->num_elements;i++) {
595 struct ldb_message_element *el = &t->elements[i];
596 /* some elements should not be copied from the template */
597 if (strcasecmp(el->name, "cn") == 0 ||
598 strcasecmp(el->name, "name") == 0 ||
599 strcasecmp(el->name, "sAMAccountName") == 0) {
602 for (j=0;j<el->num_values;j++) {
603 if (strcasecmp(el->name, "objectClass") == 0 &&
604 (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
605 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
606 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
607 strcasecmp((char *)el->values[j].data, "foreignSecurityTemplate") == 0 ||
608 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
609 strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
610 strcasecmp((char *)el->values[j].data, "secretTemplate") == 0)) {
613 samdb_msg_add_string(sam_ctx, mem_ctx, msg, el->name,
614 (char *)el->values[j].data);
623 allocate a new id, attempting to do it atomically
624 return 0 on failure, the id on success
626 static NTSTATUS _samdb_allocate_next_id(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, const char *dn,
627 const char *attr, uint32_t *id)
629 struct ldb_message msg;
632 struct ldb_val vals[2];
633 struct ldb_message_element els[2];
635 str = samdb_search_string(sam_ctx, mem_ctx, NULL, attr, "dn=%s", dn);
637 DEBUG(1,("id not found at %s %s\n", dn, attr));
638 return NT_STATUS_OBJECT_NAME_INVALID;
641 *id = strtol(str, NULL, 0);
644 return NT_STATUS_INSUFFICIENT_RESOURCES;
647 /* we do a delete and add as a single operation. That prevents
650 msg.dn = talloc_strdup(mem_ctx, dn);
652 return NT_STATUS_NO_MEMORY;
654 msg.num_elements = 2;
657 els[0].num_values = 1;
658 els[0].values = &vals[0];
659 els[0].flags = LDB_FLAG_MOD_DELETE;
660 els[0].name = talloc_strdup(mem_ctx, attr);
662 return NT_STATUS_NO_MEMORY;
665 els[1].num_values = 1;
666 els[1].values = &vals[1];
667 els[1].flags = LDB_FLAG_MOD_ADD;
668 els[1].name = els[0].name;
670 vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
672 return NT_STATUS_NO_MEMORY;
674 vals[0].length = strlen(vals[0].data);
676 vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
678 return NT_STATUS_NO_MEMORY;
680 vals[1].length = strlen(vals[1].data);
682 ret = ldb_modify(sam_ctx->ldb, &msg);
684 return NT_STATUS_UNEXPECTED_IO_ERROR;
693 allocate a new id, attempting to do it atomically
694 return 0 on failure, the id on success
696 NTSTATUS samdb_allocate_next_id(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
702 /* we need to try multiple times to cope with two account
703 creations at the same time */
705 status = _samdb_allocate_next_id(sam_ctx, mem_ctx, dn, attr, id);
706 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
711 if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
712 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
720 add a string element to a message
722 int samdb_msg_add_string(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
723 const char *attr_name, const char *str)
725 char *s = talloc_strdup(mem_ctx, str);
726 char *a = talloc_strdup(mem_ctx, attr_name);
727 if (s == NULL || a == NULL) {
730 return ldb_msg_add_string(sam_ctx->ldb, msg, a, s);
734 add a delete element operation to a message
736 int samdb_msg_add_delete(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
737 const char *attr_name)
739 char *a = talloc_strdup(mem_ctx, attr_name);
743 /* we use an empty replace rather than a delete, as it allows for
744 samdb_replace() to be used everywhere */
745 return ldb_msg_add_empty(sam_ctx->ldb, msg, a, LDB_FLAG_MOD_REPLACE);
749 add a add attribute value to a message
751 int samdb_msg_add_addval(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
752 const char *attr_name, const char *value)
754 struct ldb_message_element *el;
757 a = talloc_strdup(mem_ctx, attr_name);
760 v = talloc_strdup(mem_ctx, value);
763 ret = ldb_msg_add_string(sam_ctx->ldb, msg, a, v);
766 el = ldb_msg_find_element(msg, a);
769 el->flags = LDB_FLAG_MOD_ADD;
774 add a delete attribute value to a message
776 int samdb_msg_add_delval(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
777 const char *attr_name, const char *value)
779 struct ldb_message_element *el;
782 a = talloc_strdup(mem_ctx, attr_name);
785 v = talloc_strdup(mem_ctx, value);
788 ret = ldb_msg_add_string(sam_ctx->ldb, msg, a, v);
791 el = ldb_msg_find_element(msg, a);
794 el->flags = LDB_FLAG_MOD_DELETE;
799 add a uint_t element to a message
801 int samdb_msg_add_uint(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
802 const char *attr_name, uint_t v)
804 const char *s = talloc_asprintf(mem_ctx, "%u", v);
805 return samdb_msg_add_string(sam_ctx, mem_ctx, msg, attr_name, s);
809 add a (signed) int64_t element to a message
811 int samdb_msg_add_int64(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
812 const char *attr_name, int64_t v)
814 const char *s = talloc_asprintf(mem_ctx, "%lld", v);
815 return samdb_msg_add_string(sam_ctx, mem_ctx, msg, attr_name, s);
819 add a uint64_t element to a message
821 int samdb_msg_add_uint64(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
822 const char *attr_name, uint64_t v)
824 const char *s = talloc_asprintf(mem_ctx, "%llu", v);
825 return samdb_msg_add_string(sam_ctx, mem_ctx, msg, attr_name, s);
829 add a samr_Password element to a message
831 int samdb_msg_add_hash(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
832 const char *attr_name, struct samr_Password *hash)
835 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
840 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
844 add a samr_Password array to a message
846 int samdb_msg_add_hashes(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
847 const char *attr_name, struct samr_Password *hashes, uint_t count)
851 val.data = talloc_array_size(mem_ctx, 16, count);
852 val.length = count*16;
856 for (i=0;i<count;i++) {
857 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
859 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
863 add a acct_flags element to a message
865 int samdb_msg_add_acct_flags(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
866 const char *attr_name, uint32_t v)
868 return samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v));
872 add a logon_hours element to a message
874 int samdb_msg_add_logon_hours(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
875 const char *attr_name, struct samr_LogonHours *hours)
878 val.length = hours->units_per_week / 8;
879 val.data = hours->bits;
880 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
884 add a general value element to a message
886 int samdb_msg_add_value(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
887 const char *attr_name, const struct ldb_val *val)
889 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, val);
893 sets a general value element to a message
895 int samdb_msg_set_value(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
896 const char *attr_name, const struct ldb_val *val)
898 struct ldb_message_element *el;
900 el = ldb_msg_find_element(msg, attr_name);
904 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, val);
908 set a string element in a message
910 int samdb_msg_set_string(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
911 const char *attr_name, const char *str)
913 struct ldb_message_element *el;
915 el = ldb_msg_find_element(msg, attr_name);
919 return samdb_msg_add_string(sam_ctx, mem_ctx, msg, attr_name, str);
923 set a ldaptime element in a message
925 int samdb_msg_set_ldaptime(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
926 const char *attr_name, time_t t)
928 char *str = ldap_timestring(mem_ctx, t);
932 return samdb_msg_set_string(sam_ctx, mem_ctx, msg, attr_name, str);
938 int samdb_add(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
942 time_t now = time(NULL);
944 guid = GUID_random();
945 guidstr = GUID_string(mem_ctx, &guid);
950 samdb_msg_add_string(sam_ctx, mem_ctx, msg, "objectGUID", guidstr);
951 samdb_msg_set_ldaptime(sam_ctx, mem_ctx, msg, "whenCreated", now);
952 samdb_msg_set_ldaptime(sam_ctx, mem_ctx, msg, "whenChanged", now);
953 return ldb_add(sam_ctx->ldb, msg);
959 int samdb_delete(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, const char *dn)
961 return ldb_delete(sam_ctx->ldb, dn);
967 int samdb_modify(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
969 time_t now = time(NULL);
970 samdb_msg_set_ldaptime(sam_ctx, mem_ctx, msg, "whenChanged", now);
971 return ldb_modify(sam_ctx->ldb, msg);
975 replace elements in a record
977 int samdb_replace(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
981 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
982 for (i=0;i<msg->num_elements;i++) {
983 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
986 /* modify the samdb record */
987 return samdb_modify(sam_ctx, mem_ctx, msg);
991 return a default security descriptor
993 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
995 struct security_descriptor *sd;
997 sd = security_descriptor_initialise(mem_ctx);