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"
28 connect to the SAM database
29 return an opaque context pointer on success, or NULL on failure
31 void *samdb_connect(TALLOC_CTX *mem_ctx)
33 return ldb_wrap_connect(mem_ctx, lp_sam_url(), 0, NULL);
37 search the sam for the specified attributes - varargs variant
39 int samdb_search(void *ctx,
42 struct ldb_message ***res,
43 const char * const *attrs,
44 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
46 struct ldb_wrap *sam_ctx = ctx;
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(void *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)
69 struct ldb_wrap *sam_ctx = ctx;
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(void *ctx,
104 TALLOC_CTX *mem_ctx, struct ldb_message **res)
106 struct ldb_wrap *sam_ctx = ctx;
107 return ldb_search_free(sam_ctx->ldb, res);
111 search the sam for a single string attribute in exactly 1 record
113 const char *samdb_search_string_v(void *ctx,
116 const char *attr_name,
117 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
119 struct ldb_wrap *sam_ctx = ctx;
121 const char * const attrs[2] = { attr_name, NULL };
122 struct ldb_message **res = NULL;
124 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
126 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
127 attr_name, format, count));
130 samdb_search_free(ctx, mem_ctx, res);
134 return samdb_result_string(res[0], attr_name, NULL);
139 search the sam for a single string attribute in exactly 1 record
141 const char *samdb_search_string(void *ctx,
144 const char *attr_name,
145 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
150 va_start(ap, format);
151 str = samdb_search_string_v(ctx, mem_ctx, basedn, attr_name, format, ap);
158 return the count of the number of records in the sam matching the query
160 int samdb_search_count(void *ctx,
163 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
165 struct ldb_wrap *samdb_ctx = ctx;
167 struct ldb_message **res;
168 const char * const attrs[] = { NULL };
171 va_start(ap, format);
172 ret = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
180 search the sam for a single integer attribute in exactly 1 record
182 uint_t samdb_search_uint(void *ctx,
184 uint_t default_value,
186 const char *attr_name,
187 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
189 struct ldb_wrap *samdb_ctx = ctx;
192 struct ldb_message **res;
193 const char * const attrs[2] = { attr_name, NULL };
195 va_start(ap, format);
196 count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
200 return default_value;
203 return samdb_result_uint(res[0], attr_name, default_value);
207 search the sam for a single signed 64 bit integer attribute in exactly 1 record
209 int64_t samdb_search_int64(void *ctx,
211 int64_t default_value,
213 const char *attr_name,
214 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
216 struct ldb_wrap *samdb_ctx = ctx;
219 struct ldb_message **res;
220 const char * const attrs[2] = { attr_name, NULL };
222 va_start(ap, format);
223 count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
227 return default_value;
230 return samdb_result_int64(res[0], attr_name, default_value);
234 search the sam for multipe records each giving a single string attribute
235 return the number of matches, or -1 on error
237 int samdb_search_string_multiple(void *ctx,
241 const char *attr_name,
242 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
244 struct ldb_wrap *samdb_ctx = ctx;
247 const char * const attrs[2] = { attr_name, NULL };
248 struct ldb_message **res = NULL;
250 va_start(ap, format);
251 count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
258 /* make sure its single valued */
259 for (i=0;i<count;i++) {
260 if (res[i]->num_elements != 1) {
261 DEBUG(1,("samdb: search for %s %s not single valued\n",
263 samdb_search_free(ctx, mem_ctx, res);
268 *strs = talloc_array_p(mem_ctx, const char *, count+1);
270 samdb_search_free(ctx, mem_ctx, res);
274 for (i=0;i<count;i++) {
275 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
277 (*strs)[count] = NULL;
283 pull a uint from a result set.
285 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
287 return ldb_msg_find_uint(msg, attr, default_value);
291 pull a (signed) int64 from a result set.
293 int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value)
295 return ldb_msg_find_int64(msg, attr, default_value);
299 pull a string from a result set.
301 const char *samdb_result_string(struct ldb_message *msg, const char *attr,
302 const char *default_value)
304 return ldb_msg_find_string(msg, attr, default_value);
308 pull a rid from a objectSid in a result set.
310 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
311 const char *attr, uint32_t default_value)
314 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
315 if (!sidstr) return default_value;
317 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
318 if (!sid) return default_value;
320 return sid->sub_auths[sid->num_auths-1];
324 pull a dom_sid structure from a objectSid in a result set.
326 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
329 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
330 if (!sidstr) return NULL;
332 return dom_sid_parse_talloc(mem_ctx, sidstr);
336 pull a guid structure from a objectGUID in a result set.
338 struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr)
342 const char *guidstr = ldb_msg_find_string(msg, attr, NULL);
346 if (!guidstr) return guid;
348 status = GUID_from_string(guidstr, &guid);
349 if (!NT_STATUS_IS_OK(status)) {
358 pull a sid prefix from a objectSid in a result set.
359 this is used to find the domain sid for a user
361 const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
364 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
365 if (!sid || sid->num_auths < 1) return NULL;
369 return dom_sid_string(mem_ctx, sid);
373 pull a NTTIME in a result set.
375 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value)
377 const char *str = ldb_msg_find_string(msg, attr, default_value);
378 return nttime_from_string(str);
382 pull a uint64_t from a result set.
384 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
386 return ldb_msg_find_uint64(msg, attr, default_value);
391 construct the allow_password_change field from the PwdLastSet attribute and the
392 domain password settings
394 NTTIME samdb_result_allow_password_change(void *ctx, TALLOC_CTX *mem_ctx,
395 const char *domain_dn,
396 struct ldb_message *msg,
399 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
402 if (attr_time == 0) {
406 minPwdAge = samdb_search_int64(ctx, mem_ctx, 0, NULL,
407 "minPwdAge", "dn=%s", domain_dn);
409 /* yes, this is a -= not a += as minPwdAge is stored as the negative
410 of the number of 100-nano-seconds */
411 attr_time -= minPwdAge;
417 construct the force_password_change field from the PwdLastSet attribute and the
418 domain password settings
420 NTTIME samdb_result_force_password_change(void *ctx, TALLOC_CTX *mem_ctx,
421 const char *domain_dn,
422 struct ldb_message *msg,
425 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
428 if (attr_time == 0) {
432 maxPwdAge = samdb_search_int64(ctx, mem_ctx, 0, NULL, "maxPwdAge", "dn=%s", domain_dn);
433 if (maxPwdAge == 0) {
436 attr_time -= maxPwdAge;
443 pull a samr_Password structutre from a result set.
445 struct samr_Password samdb_result_hash(struct ldb_message *msg, const char *attr)
447 struct samr_Password hash;
448 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
451 memcpy(hash.hash, val->data, MIN(val->length, sizeof(hash.hash)));
457 pull an array of samr_Password structutres from a result set.
459 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
460 const char *attr, struct samr_Password **hashes)
463 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
470 count = val->length / 16;
475 *hashes = talloc_array_p(mem_ctx, struct samr_Password, count);
480 for (i=0;i<count;i++) {
481 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
487 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
488 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
491 const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
493 struct samr_Password *lmPwdHash, *ntPwdHash;
496 ntPwdHash = talloc_p(mem_ctx, struct samr_Password);
498 return NT_STATUS_NO_MEMORY;
501 E_md4hash(unicodePwd, ntPwdHash->hash);
508 lmPwdHash = talloc_p(mem_ctx, struct samr_Password);
510 return NT_STATUS_NO_MEMORY;
513 /* compute the new nt and lm hashes */
514 lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
525 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
528 } else if (num_nt > 1) {
529 return NT_STATUS_INTERNAL_DB_CORRUPTION;
531 *nt_pwd = &ntPwdHash[0];
536 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
539 } else if (num_lm > 1) {
540 return NT_STATUS_INTERNAL_DB_CORRUPTION;
542 *lm_pwd = &lmPwdHash[0];
551 pull a samr_LogonHours structutre from a result set.
553 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
555 struct samr_LogonHours hours;
556 const int units_per_week = 168;
557 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
559 hours.bits = talloc_array_p(mem_ctx, uint8, units_per_week);
563 hours.units_per_week = units_per_week;
564 memset(hours.bits, 0xFF, units_per_week);
566 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
572 pull a set of account_flags from a result set.
574 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
576 uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
577 return samdb_uf2acb(userAccountControl);
581 copy from a template record to a message
583 int samdb_copy_template(void *ctx, TALLOC_CTX *mem_ctx,
584 struct ldb_message *msg, const char *expression)
586 struct ldb_message **res, *t;
590 /* pull the template record */
591 ret = samdb_search(ctx, mem_ctx, NULL, &res, NULL, "%s", expression);
593 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n",
599 for (i=0;i<t->num_elements;i++) {
600 struct ldb_message_element *el = &t->elements[i];
601 /* some elements should not be copied from the template */
602 if (strcasecmp(el->name, "cn") == 0 ||
603 strcasecmp(el->name, "name") == 0 ||
604 strcasecmp(el->name, "sAMAccountName") == 0) {
607 for (j=0;j<el->num_values;j++) {
608 if (strcasecmp(el->name, "objectClass") == 0 &&
609 (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
610 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
611 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
612 strcasecmp((char *)el->values[j].data, "foreignSecurityTemplate") == 0 ||
613 strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0)) {
616 samdb_msg_add_string(ctx, mem_ctx, msg, el->name,
617 (char *)el->values[j].data);
626 allocate a new id, attempting to do it atomically
627 return 0 on failure, the id on success
629 static NTSTATUS _samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn,
630 const char *attr, uint32_t *id)
632 struct ldb_wrap *sam_ctx = ctx;
633 struct ldb_message msg;
636 struct ldb_val vals[2];
637 struct ldb_message_element els[2];
639 str = samdb_search_string(ctx, mem_ctx, NULL, attr, "dn=%s", dn);
641 DEBUG(1,("id not found at %s %s\n", dn, attr));
642 return NT_STATUS_OBJECT_NAME_INVALID;
645 *id = strtol(str, NULL, 0);
648 return NT_STATUS_INSUFFICIENT_RESOURCES;
651 /* we do a delete and add as a single operation. That prevents
654 msg.dn = talloc_strdup(mem_ctx, dn);
656 return NT_STATUS_NO_MEMORY;
658 msg.num_elements = 2;
661 els[0].num_values = 1;
662 els[0].values = &vals[0];
663 els[0].flags = LDB_FLAG_MOD_DELETE;
664 els[0].name = talloc_strdup(mem_ctx, attr);
666 return NT_STATUS_NO_MEMORY;
669 els[1].num_values = 1;
670 els[1].values = &vals[1];
671 els[1].flags = LDB_FLAG_MOD_ADD;
672 els[1].name = els[0].name;
674 vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
676 return NT_STATUS_NO_MEMORY;
678 vals[0].length = strlen(vals[0].data);
680 vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
682 return NT_STATUS_NO_MEMORY;
684 vals[1].length = strlen(vals[1].data);
686 ret = ldb_modify(sam_ctx->ldb, &msg);
688 return NT_STATUS_UNEXPECTED_IO_ERROR;
697 allocate a new id, attempting to do it atomically
698 return 0 on failure, the id on success
700 NTSTATUS samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
706 /* we need to try multiple times to cope with two account
707 creations at the same time */
709 status = _samdb_allocate_next_id(ctx, mem_ctx, dn, attr, id);
710 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
715 if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
716 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
724 add a string element to a message
726 int samdb_msg_add_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
727 const char *attr_name, const char *str)
729 struct ldb_wrap *sam_ctx = ctx;
730 char *s = talloc_strdup(mem_ctx, str);
731 char *a = talloc_strdup(mem_ctx, attr_name);
732 if (s == NULL || a == NULL) {
735 return ldb_msg_add_string(sam_ctx->ldb, msg, a, s);
739 add a delete element operation to a message
741 int samdb_msg_add_delete(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
742 const char *attr_name)
744 struct ldb_wrap *sam_ctx = ctx;
745 char *a = talloc_strdup(mem_ctx, attr_name);
749 /* we use an empty replace rather than a delete, as it allows for
750 samdb_replace() to be used everywhere */
751 return ldb_msg_add_empty(sam_ctx->ldb, msg, a, LDB_FLAG_MOD_REPLACE);
755 add a add attribute value to a message
757 int samdb_msg_add_addval(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
758 const char *attr_name, const char *value)
760 struct ldb_wrap *sam_ctx = ctx;
761 struct ldb_message_element *el;
764 a = talloc_strdup(mem_ctx, attr_name);
767 v = talloc_strdup(mem_ctx, value);
770 ret = ldb_msg_add_string(sam_ctx->ldb, msg, a, v);
773 el = ldb_msg_find_element(msg, a);
776 el->flags = LDB_FLAG_MOD_ADD;
781 add a delete attribute value to a message
783 int samdb_msg_add_delval(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784 const char *attr_name, const char *value)
786 struct ldb_wrap *sam_ctx = ctx;
787 struct ldb_message_element *el;
790 a = talloc_strdup(mem_ctx, attr_name);
793 v = talloc_strdup(mem_ctx, value);
796 ret = ldb_msg_add_string(sam_ctx->ldb, msg, a, v);
799 el = ldb_msg_find_element(msg, a);
802 el->flags = LDB_FLAG_MOD_DELETE;
807 add a uint_t element to a message
809 int samdb_msg_add_uint(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
810 const char *attr_name, uint_t v)
812 const char *s = talloc_asprintf(mem_ctx, "%u", v);
813 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
817 add a (signed) int64_t element to a message
819 int samdb_msg_add_int64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
820 const char *attr_name, int64_t v)
822 const char *s = talloc_asprintf(mem_ctx, "%lld", v);
823 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
827 add a uint64_t element to a message
829 int samdb_msg_add_uint64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
830 const char *attr_name, uint64_t v)
832 const char *s = talloc_asprintf(mem_ctx, "%llu", v);
833 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
837 add a samr_Password element to a message
839 int samdb_msg_add_hash(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
840 const char *attr_name, struct samr_Password hash)
842 struct ldb_wrap *sam_ctx = ctx;
844 val.data = talloc_memdup(mem_ctx, hash.hash, 16);
849 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
853 add a samr_Password array to a message
855 int samdb_msg_add_hashes(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
856 const char *attr_name, struct samr_Password *hashes, uint_t count)
858 struct ldb_wrap *sam_ctx = ctx;
861 val.data = talloc_array(mem_ctx, 16, count, __location__);
862 val.length = count*16;
866 for (i=0;i<count;i++) {
867 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
869 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
873 add a acct_flags element to a message
875 int samdb_msg_add_acct_flags(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
876 const char *attr_name, uint32_t v)
878 return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v));
882 add a logon_hours element to a message
884 int samdb_msg_add_logon_hours(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
885 const char *attr_name, struct samr_LogonHours *hours)
887 struct ldb_wrap *sam_ctx = ctx;
889 val.length = hours->units_per_week / 8;
890 val.data = hours->bits;
891 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
895 set a string element in a message
897 int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
898 const char *attr_name, const char *str)
900 struct ldb_message_element *el;
902 el = ldb_msg_find_element(msg, attr_name);
906 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, str);
910 set a ldaptime element in a message
912 int samdb_msg_set_ldaptime(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
913 const char *attr_name, time_t t)
915 char *str = ldap_timestring(mem_ctx, t);
919 return samdb_msg_set_string(ctx, mem_ctx, msg, attr_name, str);
925 int samdb_add(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
927 struct ldb_wrap *sam_ctx = ctx;
929 return ldb_add(sam_ctx->ldb, msg);
935 int samdb_delete(void *ctx, TALLOC_CTX *mem_ctx, const char *dn)
937 struct ldb_wrap *sam_ctx = ctx;
939 return ldb_delete(sam_ctx->ldb, dn);
945 int samdb_modify(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
947 struct ldb_wrap *sam_ctx = ctx;
949 return ldb_modify(sam_ctx->ldb, msg);
953 replace elements in a record
955 int samdb_replace(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
959 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
960 for (i=0;i<msg->num_elements;i++) {
961 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
964 /* modify the samdb record */
965 return samdb_modify(ctx, mem_ctx, msg);
969 return a default security descriptor
971 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
973 struct security_descriptor *sd;
975 sd = security_descriptor_initialise(mem_ctx);