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"
30 connect to the SAM database
31 return an opaque context pointer on success, or NULL on failure
33 struct ldb_wrap *samdb_connect(TALLOC_CTX *mem_ctx)
35 return ldb_wrap_connect(mem_ctx, lp_sam_url(), 0, NULL);
39 search the sam for the specified attributes - varargs variant
41 int samdb_search(struct ldb_wrap *sam_ctx,
44 struct ldb_message ***res,
45 const char * const *attrs,
46 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
52 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, res, attrs, format, ap);
59 search the sam for the specified attributes in a specific domain, filter on
60 objectSid being in domain_sid.
62 int samdb_search_domain(struct ldb_wrap *sam_ctx,
65 struct ldb_message ***res,
66 const char * const *attrs,
67 const struct dom_sid *domain_sid,
68 const char *format, ...) _PRINTF_ATTRIBUTE(7,8)
74 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, res, attrs,
81 struct dom_sid *entry_sid;
83 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i],
86 if ((entry_sid == NULL) ||
87 (!dom_sid_in_domain(domain_sid, entry_sid))) {
89 /* Delete that entry from the result set */
90 (*res)[i] = (*res)[count-1];
101 free up a search result
103 int samdb_search_free(struct ldb_wrap *sam_ctx,
104 TALLOC_CTX *mem_ctx, struct ldb_message **res)
106 return ldb_search_free(sam_ctx->ldb, res);
110 search the sam for a single string attribute in exactly 1 record
112 const char *samdb_search_string_v(struct ldb_wrap *sam_ctx,
115 const char *attr_name,
116 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
119 const char * const attrs[2] = { attr_name, NULL };
120 struct ldb_message **res = NULL;
122 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
124 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
125 attr_name, format, count));
128 samdb_search_free(sam_ctx, mem_ctx, res);
132 return samdb_result_string(res[0], attr_name, NULL);
137 search the sam for a single string attribute in exactly 1 record
139 const char *samdb_search_string(struct ldb_wrap *sam_ctx,
142 const char *attr_name,
143 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
148 va_start(ap, format);
149 str = samdb_search_string_v(sam_ctx, mem_ctx, basedn, attr_name, format, ap);
156 return the count of the number of records in the sam matching the query
158 int samdb_search_count(struct ldb_wrap *sam_ctx,
161 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
164 struct ldb_message **res;
165 const char * const attrs[] = { NULL };
168 va_start(ap, format);
169 ret = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
177 search the sam for a single integer attribute in exactly 1 record
179 uint_t samdb_search_uint(struct ldb_wrap *sam_ctx,
181 uint_t default_value,
183 const char *attr_name,
184 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
188 struct ldb_message **res;
189 const char * const attrs[2] = { attr_name, NULL };
191 va_start(ap, format);
192 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
196 return default_value;
199 return samdb_result_uint(res[0], attr_name, default_value);
203 search the sam for a single signed 64 bit integer attribute in exactly 1 record
205 int64_t samdb_search_int64(struct ldb_wrap *sam_ctx,
207 int64_t default_value,
209 const char *attr_name,
210 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
214 struct ldb_message **res;
215 const char * const attrs[2] = { attr_name, NULL };
217 va_start(ap, format);
218 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
222 return default_value;
225 return samdb_result_int64(res[0], attr_name, default_value);
229 search the sam for multipe records each giving a single string attribute
230 return the number of matches, or -1 on error
232 int samdb_search_string_multiple(struct ldb_wrap *sam_ctx,
236 const char *attr_name,
237 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
241 const char * const attrs[2] = { attr_name, NULL };
242 struct ldb_message **res = NULL;
244 va_start(ap, format);
245 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
252 /* make sure its single valued */
253 for (i=0;i<count;i++) {
254 if (res[i]->num_elements != 1) {
255 DEBUG(1,("samdb: search for %s %s not single valued\n",
257 samdb_search_free(sam_ctx, mem_ctx, res);
262 *strs = talloc_array(mem_ctx, const char *, count+1);
264 samdb_search_free(sam_ctx, mem_ctx, res);
268 for (i=0;i<count;i++) {
269 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
271 (*strs)[count] = NULL;
277 pull a uint from a result set.
279 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
281 return ldb_msg_find_uint(msg, attr, default_value);
285 pull a (signed) int64 from a result set.
287 int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value)
289 return ldb_msg_find_int64(msg, attr, default_value);
293 pull a string from a result set.
295 const char *samdb_result_string(struct ldb_message *msg, const char *attr,
296 const char *default_value)
298 return ldb_msg_find_string(msg, attr, default_value);
302 pull a rid from a objectSid in a result set.
304 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
305 const char *attr, uint32_t default_value)
308 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
309 if (!sidstr) return default_value;
311 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
312 if (!sid) return default_value;
314 return sid->sub_auths[sid->num_auths-1];
318 pull a dom_sid structure from a objectSid in a result set.
320 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
323 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
324 if (!sidstr) return NULL;
326 return dom_sid_parse_talloc(mem_ctx, sidstr);
330 pull a guid structure from a objectGUID in a result set.
332 struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr)
336 const char *guidstr = ldb_msg_find_string(msg, attr, NULL);
340 if (!guidstr) return guid;
342 status = GUID_from_string(guidstr, &guid);
343 if (!NT_STATUS_IS_OK(status)) {
352 pull a sid prefix from a objectSid in a result set.
353 this is used to find the domain sid for a user
355 const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
358 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
359 if (!sid || sid->num_auths < 1) return NULL;
363 return dom_sid_string(mem_ctx, sid);
367 pull a NTTIME in a result set.
369 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value)
371 const char *str = ldb_msg_find_string(msg, attr, default_value);
372 return nttime_from_string(str);
376 pull a uint64_t from a result set.
378 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
380 return ldb_msg_find_uint64(msg, attr, default_value);
385 construct the allow_password_change field from the PwdLastSet attribute and the
386 domain password settings
388 NTTIME samdb_result_allow_password_change(struct ldb_wrap *sam_ctx,
390 const char *domain_dn,
391 struct ldb_message *msg,
394 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
397 if (attr_time == 0) {
401 minPwdAge = samdb_search_int64(sam_ctx, mem_ctx, 0, NULL,
402 "minPwdAge", "dn=%s", domain_dn);
404 /* yes, this is a -= not a += as minPwdAge is stored as the negative
405 of the number of 100-nano-seconds */
406 attr_time -= minPwdAge;
412 construct the force_password_change field from the PwdLastSet attribute and the
413 domain password settings
415 NTTIME samdb_result_force_password_change(struct ldb_wrap *sam_ctx,
417 const char *domain_dn,
418 struct ldb_message *msg,
421 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
424 if (attr_time == 0) {
428 maxPwdAge = samdb_search_int64(sam_ctx, mem_ctx, 0, NULL, "maxPwdAge", "dn=%s", domain_dn);
429 if (maxPwdAge == 0) {
432 attr_time -= maxPwdAge;
439 pull a samr_Password structutre from a result set.
441 struct samr_Password samdb_result_hash(struct ldb_message *msg, const char *attr)
443 struct samr_Password hash;
444 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
447 memcpy(hash.hash, val->data, MIN(val->length, sizeof(hash.hash)));
453 pull an array of samr_Password structutres from a result set.
455 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
456 const char *attr, struct samr_Password **hashes)
459 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
466 count = val->length / 16;
471 *hashes = talloc_array(mem_ctx, struct samr_Password, count);
476 for (i=0;i<count;i++) {
477 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
483 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
484 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
487 const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
489 struct samr_Password *lmPwdHash, *ntPwdHash;
492 ntPwdHash = talloc(mem_ctx, struct samr_Password);
494 return NT_STATUS_NO_MEMORY;
497 E_md4hash(unicodePwd, ntPwdHash->hash);
504 lmPwdHash = talloc(mem_ctx, struct samr_Password);
506 return NT_STATUS_NO_MEMORY;
509 /* compute the new nt and lm hashes */
510 lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
521 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
524 } else if (num_nt > 1) {
525 return NT_STATUS_INTERNAL_DB_CORRUPTION;
527 *nt_pwd = &ntPwdHash[0];
532 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
535 } else if (num_lm > 1) {
536 return NT_STATUS_INTERNAL_DB_CORRUPTION;
538 *lm_pwd = &lmPwdHash[0];
547 pull a samr_LogonHours structutre from a result set.
549 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
551 struct samr_LogonHours hours;
552 const int units_per_week = 168;
553 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
555 hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
559 hours.units_per_week = units_per_week;
560 memset(hours.bits, 0xFF, units_per_week);
562 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
568 pull a set of account_flags from a result set.
570 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
572 uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
573 return samdb_uf2acb(userAccountControl);
577 copy from a template record to a message
579 int samdb_copy_template(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx,
580 struct ldb_message *msg, const char *expression)
582 struct ldb_message **res, *t;
586 /* pull the template record */
587 ret = samdb_search(sam_ctx, mem_ctx, NULL, &res, NULL, "%s", expression);
589 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n",
595 for (i=0;i<t->num_elements;i++) {
596 struct ldb_message_element *el = &t->elements[i];
597 /* some elements should not be copied from the template */
598 if (strcasecmp(el->name, "cn") == 0 ||
599 strcasecmp(el->name, "name") == 0 ||
600 strcasecmp(el->name, "sAMAccountName") == 0) {
603 for (j=0;j<el->num_values;j++) {
604 if (strcasecmp(el->name, "objectClass") == 0 &&
605 (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
606 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
607 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
608 strcasecmp((char *)el->values[j].data, "foreignSecurityTemplate") == 0 ||
609 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 ||
610 strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 ||
611 strcasecmp((char *)el->values[j].data, "secretTemplate") == 0)) {
614 samdb_msg_add_string(sam_ctx, mem_ctx, msg, el->name,
615 (char *)el->values[j].data);
624 allocate a new id, attempting to do it atomically
625 return 0 on failure, the id on success
627 static NTSTATUS _samdb_allocate_next_id(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, const char *dn,
628 const char *attr, uint32_t *id)
630 struct ldb_message msg;
633 struct ldb_val vals[2];
634 struct ldb_message_element els[2];
636 str = samdb_search_string(sam_ctx, mem_ctx, NULL, attr, "dn=%s", dn);
638 DEBUG(1,("id not found at %s %s\n", dn, attr));
639 return NT_STATUS_OBJECT_NAME_INVALID;
642 *id = strtol(str, NULL, 0);
645 return NT_STATUS_INSUFFICIENT_RESOURCES;
648 /* we do a delete and add as a single operation. That prevents
651 msg.dn = talloc_strdup(mem_ctx, dn);
653 return NT_STATUS_NO_MEMORY;
655 msg.num_elements = 2;
658 els[0].num_values = 1;
659 els[0].values = &vals[0];
660 els[0].flags = LDB_FLAG_MOD_DELETE;
661 els[0].name = talloc_strdup(mem_ctx, attr);
663 return NT_STATUS_NO_MEMORY;
666 els[1].num_values = 1;
667 els[1].values = &vals[1];
668 els[1].flags = LDB_FLAG_MOD_ADD;
669 els[1].name = els[0].name;
671 vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
673 return NT_STATUS_NO_MEMORY;
675 vals[0].length = strlen(vals[0].data);
677 vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
679 return NT_STATUS_NO_MEMORY;
681 vals[1].length = strlen(vals[1].data);
683 ret = ldb_modify(sam_ctx->ldb, &msg);
685 return NT_STATUS_UNEXPECTED_IO_ERROR;
694 allocate a new id, attempting to do it atomically
695 return 0 on failure, the id on success
697 NTSTATUS samdb_allocate_next_id(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
703 /* we need to try multiple times to cope with two account
704 creations at the same time */
706 status = _samdb_allocate_next_id(sam_ctx, mem_ctx, dn, attr, id);
707 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
712 if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
713 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
721 add a string element to a message
723 int samdb_msg_add_string(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
724 const char *attr_name, const char *str)
726 char *s = talloc_strdup(mem_ctx, str);
727 char *a = talloc_strdup(mem_ctx, attr_name);
728 if (s == NULL || a == NULL) {
731 return ldb_msg_add_string(sam_ctx->ldb, msg, a, s);
735 add a delete element operation to a message
737 int samdb_msg_add_delete(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
738 const char *attr_name)
740 char *a = talloc_strdup(mem_ctx, attr_name);
744 /* we use an empty replace rather than a delete, as it allows for
745 samdb_replace() to be used everywhere */
746 return ldb_msg_add_empty(sam_ctx->ldb, msg, a, LDB_FLAG_MOD_REPLACE);
750 add a add attribute value to a message
752 int samdb_msg_add_addval(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
753 const char *attr_name, const char *value)
755 struct ldb_message_element *el;
758 a = talloc_strdup(mem_ctx, attr_name);
761 v = talloc_strdup(mem_ctx, value);
764 ret = ldb_msg_add_string(sam_ctx->ldb, msg, a, v);
767 el = ldb_msg_find_element(msg, a);
770 el->flags = LDB_FLAG_MOD_ADD;
775 add a delete attribute value to a message
777 int samdb_msg_add_delval(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
778 const char *attr_name, const char *value)
780 struct ldb_message_element *el;
783 a = talloc_strdup(mem_ctx, attr_name);
786 v = talloc_strdup(mem_ctx, value);
789 ret = ldb_msg_add_string(sam_ctx->ldb, msg, a, v);
792 el = ldb_msg_find_element(msg, a);
795 el->flags = LDB_FLAG_MOD_DELETE;
800 add a uint_t element to a message
802 int samdb_msg_add_uint(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
803 const char *attr_name, uint_t v)
805 const char *s = talloc_asprintf(mem_ctx, "%u", v);
806 return samdb_msg_add_string(sam_ctx, mem_ctx, msg, attr_name, s);
810 add a (signed) int64_t element to a message
812 int samdb_msg_add_int64(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
813 const char *attr_name, int64_t v)
815 const char *s = talloc_asprintf(mem_ctx, "%lld", v);
816 return samdb_msg_add_string(sam_ctx, mem_ctx, msg, attr_name, s);
820 add a uint64_t element to a message
822 int samdb_msg_add_uint64(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
823 const char *attr_name, uint64_t v)
825 const char *s = talloc_asprintf(mem_ctx, "%llu", v);
826 return samdb_msg_add_string(sam_ctx, mem_ctx, msg, attr_name, s);
830 add a samr_Password element to a message
832 int samdb_msg_add_hash(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
833 const char *attr_name, struct samr_Password *hash)
836 val.data = talloc_memdup(mem_ctx, hash->hash, 16);
841 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
845 add a samr_Password array to a message
847 int samdb_msg_add_hashes(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
848 const char *attr_name, struct samr_Password *hashes, uint_t count)
852 val.data = talloc_array_size(mem_ctx, 16, count);
853 val.length = count*16;
857 for (i=0;i<count;i++) {
858 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
860 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
864 add a acct_flags element to a message
866 int samdb_msg_add_acct_flags(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
867 const char *attr_name, uint32_t v)
869 return samdb_msg_add_uint(sam_ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v));
873 add a logon_hours element to a message
875 int samdb_msg_add_logon_hours(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
876 const char *attr_name, struct samr_LogonHours *hours)
879 val.length = hours->units_per_week / 8;
880 val.data = hours->bits;
881 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
885 add a general value element to a message
887 int samdb_msg_add_value(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
888 const char *attr_name, const struct ldb_val *val)
890 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, val);
894 sets a general value element to a message
896 int samdb_msg_set_value(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
897 const char *attr_name, const struct ldb_val *val)
899 struct ldb_message_element *el;
901 el = ldb_msg_find_element(msg, attr_name);
905 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, val);
909 set a string element in a message
911 int samdb_msg_set_string(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
912 const char *attr_name, const char *str)
914 struct ldb_message_element *el;
916 el = ldb_msg_find_element(msg, attr_name);
920 return samdb_msg_add_string(sam_ctx, mem_ctx, msg, attr_name, str);
924 set a ldaptime element in a message
926 int samdb_msg_set_ldaptime(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
927 const char *attr_name, time_t t)
929 char *str = ldap_timestring(mem_ctx, t);
933 return samdb_msg_set_string(sam_ctx, mem_ctx, msg, attr_name, str);
939 int samdb_add(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
943 time_t now = time(NULL);
945 guid = GUID_random();
946 guidstr = GUID_string(mem_ctx, &guid);
951 samdb_msg_add_string(sam_ctx, mem_ctx, msg, "objectGUID", guidstr);
952 samdb_msg_set_ldaptime(sam_ctx, mem_ctx, msg, "whenCreated", now);
953 samdb_msg_set_ldaptime(sam_ctx, mem_ctx, msg, "whenChanged", now);
954 return ldb_add(sam_ctx->ldb, msg);
960 int samdb_delete(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, const char *dn)
962 return ldb_delete(sam_ctx->ldb, dn);
968 int samdb_modify(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
970 time_t now = time(NULL);
971 samdb_msg_set_ldaptime(sam_ctx, mem_ctx, msg, "whenChanged", now);
972 return ldb_modify(sam_ctx->ldb, msg);
976 replace elements in a record
978 int samdb_replace(struct ldb_wrap *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
982 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
983 for (i=0;i<msg->num_elements;i++) {
984 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
987 /* modify the samdb record */
988 return samdb_modify(sam_ctx, mem_ctx, msg);
992 return a default security descriptor
994 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
996 struct security_descriptor *sd;
998 sd = security_descriptor_initialise(mem_ctx);