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 free up a search result
60 int samdb_search_free(void *ctx,
61 TALLOC_CTX *mem_ctx, struct ldb_message **res)
63 struct ldb_wrap *sam_ctx = ctx;
64 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
65 return ldb_search_free(sam_ctx->ldb, res);
69 search the sam for a single string attribute in exactly 1 record
71 const char *samdb_search_string_v(void *ctx,
74 const char *attr_name,
75 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
77 struct ldb_wrap *sam_ctx = ctx;
79 const char * const attrs[2] = { attr_name, NULL };
80 struct ldb_message **res = NULL;
82 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
84 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
85 attr_name, format, count));
88 samdb_search_free(ctx, mem_ctx, res);
92 return samdb_result_string(res[0], attr_name, NULL);
97 search the sam for a single string attribute in exactly 1 record
99 const char *samdb_search_string(void *ctx,
102 const char *attr_name,
103 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
108 va_start(ap, format);
109 str = samdb_search_string_v(ctx, mem_ctx, basedn, attr_name, format, ap);
116 return the count of the number of records in the sam matching the query
118 int samdb_search_count(void *ctx,
121 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
123 struct ldb_wrap *samdb_ctx = ctx;
125 struct ldb_message **res;
126 const char * const attrs[] = { NULL };
129 va_start(ap, format);
130 ret = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
138 search the sam for a single integer attribute in exactly 1 record
140 uint_t samdb_search_uint(void *ctx,
142 uint_t default_value,
144 const char *attr_name,
145 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
147 struct ldb_wrap *samdb_ctx = ctx;
150 struct ldb_message **res;
151 const char * const attrs[2] = { attr_name, NULL };
153 va_start(ap, format);
154 count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
158 return default_value;
161 return samdb_result_uint(res[0], attr_name, default_value);
165 search the sam for a single signed 64 bit integer attribute in exactly 1 record
167 int64_t samdb_search_int64(void *ctx,
169 int64_t default_value,
171 const char *attr_name,
172 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
174 struct ldb_wrap *samdb_ctx = ctx;
177 struct ldb_message **res;
178 const char * const attrs[2] = { attr_name, NULL };
180 va_start(ap, format);
181 count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
185 return default_value;
188 return samdb_result_int64(res[0], attr_name, default_value);
192 search the sam for multipe records each giving a single string attribute
193 return the number of matches, or -1 on error
195 int samdb_search_string_multiple(void *ctx,
199 const char *attr_name,
200 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
202 struct ldb_wrap *samdb_ctx = ctx;
205 const char * const attrs[2] = { attr_name, NULL };
206 struct ldb_message **res = NULL;
208 va_start(ap, format);
209 count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
216 /* make sure its single valued */
217 for (i=0;i<count;i++) {
218 if (res[i]->num_elements != 1) {
219 DEBUG(1,("samdb: search for %s %s not single valued\n",
221 samdb_search_free(ctx, mem_ctx, res);
226 *strs = talloc_array_p(mem_ctx, const char *, count+1);
228 samdb_search_free(ctx, mem_ctx, res);
232 for (i=0;i<count;i++) {
233 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
235 (*strs)[count] = NULL;
241 pull a uint from a result set.
243 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
245 return ldb_msg_find_uint(msg, attr, default_value);
249 pull a (signed) int64 from a result set.
251 int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value)
253 return ldb_msg_find_int64(msg, attr, default_value);
257 pull a string from a result set.
259 const char *samdb_result_string(struct ldb_message *msg, const char *attr,
260 const char *default_value)
262 return ldb_msg_find_string(msg, attr, default_value);
266 pull a rid from a objectSid in a result set.
268 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
269 const char *attr, uint32_t default_value)
272 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
273 if (!sidstr) return default_value;
275 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
276 if (!sid) return default_value;
278 return sid->sub_auths[sid->num_auths-1];
282 pull a dom_sid structure from a objectSid in a result set.
284 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
287 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
288 if (!sidstr) return NULL;
290 return dom_sid_parse_talloc(mem_ctx, sidstr);
294 pull a guid structure from a objectGUID in a result set.
296 struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr)
300 const char *guidstr = ldb_msg_find_string(msg, attr, NULL);
304 if (!guidstr) return guid;
306 status = GUID_from_string(guidstr, &guid);
307 if (!NT_STATUS_IS_OK(status)) {
316 pull a sid prefix from a objectSid in a result set.
317 this is used to find the domain sid for a user
319 const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
322 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
323 if (!sid || sid->num_auths < 1) return NULL;
327 return dom_sid_string(mem_ctx, sid);
331 pull a NTTIME in a result set.
333 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value)
335 const char *str = ldb_msg_find_string(msg, attr, default_value);
336 return nttime_from_string(str);
340 pull a uint64_t from a result set.
342 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
344 return ldb_msg_find_uint64(msg, attr, default_value);
349 construct the allow_password_change field from the PwdLastSet attribute and the
350 domain password settings
352 NTTIME samdb_result_allow_password_change(void *ctx, TALLOC_CTX *mem_ctx,
353 const char *domain_dn,
354 struct ldb_message *msg,
357 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
360 if (attr_time == 0) {
364 minPwdAge = samdb_search_int64(ctx, mem_ctx, 0, NULL,
365 "minPwdAge", "dn=%s", domain_dn);
367 /* yes, this is a -= not a += as minPwdAge is stored as the negative
368 of the number of 100-nano-seconds */
369 attr_time -= minPwdAge;
375 construct the force_password_change field from the PwdLastSet attribute and the
376 domain password settings
378 NTTIME samdb_result_force_password_change(void *ctx, TALLOC_CTX *mem_ctx,
379 const char *domain_dn,
380 struct ldb_message *msg,
383 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
386 if (attr_time == 0) {
390 maxPwdAge = samdb_search_int64(ctx, mem_ctx, 0, NULL, "maxPwdAge", "dn=%s", domain_dn);
391 if (maxPwdAge == 0) {
394 attr_time -= maxPwdAge;
401 pull a samr_Password structutre from a result set.
403 struct samr_Password samdb_result_hash(struct ldb_message *msg, const char *attr)
405 struct samr_Password hash;
406 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
409 memcpy(hash.hash, val->data, MIN(val->length, sizeof(hash.hash)));
415 pull an array of samr_Password structutres from a result set.
417 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
418 const char *attr, struct samr_Password **hashes)
421 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
428 count = val->length / 16;
433 *hashes = talloc_array_p(mem_ctx, struct samr_Password, count);
438 for (i=0;i<count;i++) {
439 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
445 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
446 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
449 const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
451 struct samr_Password *lmPwdHash, *ntPwdHash;
454 ntPwdHash = talloc_p(mem_ctx, struct samr_Password);
456 return NT_STATUS_NO_MEMORY;
459 E_md4hash(unicodePwd, ntPwdHash->hash);
466 lmPwdHash = talloc_p(mem_ctx, struct samr_Password);
468 return NT_STATUS_NO_MEMORY;
471 /* compute the new nt and lm hashes */
472 lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
483 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
486 } else if (num_nt > 1) {
487 return NT_STATUS_INTERNAL_DB_CORRUPTION;
489 *nt_pwd = &ntPwdHash[0];
494 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
497 } else if (num_lm > 1) {
498 return NT_STATUS_INTERNAL_DB_CORRUPTION;
500 *lm_pwd = &lmPwdHash[0];
509 pull a samr_LogonHours structutre from a result set.
511 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
513 struct samr_LogonHours hours;
514 const int units_per_week = 168;
515 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
517 hours.bitmap = talloc_array_p(mem_ctx, uint8, units_per_week);
521 hours.units_per_week = units_per_week;
522 memset(hours.bitmap, 0xFF, units_per_week);
524 memcpy(hours.bitmap, val->data, MIN(val->length, units_per_week));
530 pull a set of account_flags from a result set.
532 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
534 uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
535 return samdb_uf2acb(userAccountControl);
539 copy from a template record to a message
541 int samdb_copy_template(void *ctx, TALLOC_CTX *mem_ctx,
542 struct ldb_message *msg, const char *expression)
544 struct ldb_message **res, *t;
548 /* pull the template record */
549 ret = samdb_search(ctx, mem_ctx, NULL, &res, NULL, "%s", expression);
551 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n",
557 for (i=0;i<t->num_elements;i++) {
558 struct ldb_message_element *el = &t->elements[i];
559 /* some elements should not be copied from the template */
560 if (strcasecmp(el->name, "cn") == 0 ||
561 strcasecmp(el->name, "name") == 0 ||
562 strcasecmp(el->name, "sAMAccountName") == 0) {
565 for (j=0;j<el->num_values;j++) {
566 if (strcasecmp(el->name, "objectClass") == 0 &&
567 (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
568 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
569 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0)) {
572 samdb_msg_add_string(ctx, mem_ctx, msg, el->name,
573 (char *)el->values[j].data);
582 allocate a new id, attempting to do it atomically
583 return 0 on failure, the id on success
585 static NTSTATUS _samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn,
586 const char *attr, uint32_t *id)
588 struct ldb_wrap *sam_ctx = ctx;
589 struct ldb_message msg;
592 struct ldb_val vals[2];
593 struct ldb_message_element els[2];
595 str = samdb_search_string(ctx, mem_ctx, NULL, attr, "dn=%s", dn);
597 DEBUG(1,("id not found at %s %s\n", dn, attr));
598 return NT_STATUS_OBJECT_NAME_INVALID;
601 *id = strtol(str, NULL, 0);
604 return NT_STATUS_INSUFFICIENT_RESOURCES;
607 /* we do a delete and add as a single operation. That prevents
610 msg.dn = talloc_strdup(mem_ctx, dn);
612 return NT_STATUS_NO_MEMORY;
614 msg.num_elements = 2;
617 els[0].num_values = 1;
618 els[0].values = &vals[0];
619 els[0].flags = LDB_FLAG_MOD_DELETE;
620 els[0].name = talloc_strdup(mem_ctx, attr);
622 return NT_STATUS_NO_MEMORY;
625 els[1].num_values = 1;
626 els[1].values = &vals[1];
627 els[1].flags = LDB_FLAG_MOD_ADD;
628 els[1].name = els[0].name;
630 vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
632 return NT_STATUS_NO_MEMORY;
634 vals[0].length = strlen(vals[0].data);
636 vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
638 return NT_STATUS_NO_MEMORY;
640 vals[1].length = strlen(vals[1].data);
642 ret = ldb_modify(sam_ctx->ldb, &msg);
644 return NT_STATUS_UNEXPECTED_IO_ERROR;
653 allocate a new id, attempting to do it atomically
654 return 0 on failure, the id on success
656 NTSTATUS samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
662 /* we need to try multiple times to cope with two account
663 creations at the same time */
665 status = _samdb_allocate_next_id(ctx, mem_ctx, dn, attr, id);
666 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
671 if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
672 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
680 add a string element to a message
682 int samdb_msg_add_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
683 const char *attr_name, const char *str)
685 struct ldb_wrap *sam_ctx = ctx;
686 char *s = talloc_strdup(mem_ctx, str);
687 char *a = talloc_strdup(mem_ctx, attr_name);
688 if (s == NULL || a == NULL) {
691 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
692 return ldb_msg_add_string(sam_ctx->ldb, msg, a, s);
696 add a delete element operation to a message
698 int samdb_msg_add_delete(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
699 const char *attr_name)
701 struct ldb_wrap *sam_ctx = ctx;
702 char *a = talloc_strdup(mem_ctx, attr_name);
706 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
707 /* we use an empty replace rather than a delete, as it allows for
708 samdb_replace() to be used everywhere */
709 return ldb_msg_add_empty(sam_ctx->ldb, msg, a, LDB_FLAG_MOD_REPLACE);
713 add a uint_t element to a message
715 int samdb_msg_add_uint(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
716 const char *attr_name, uint_t v)
718 const char *s = talloc_asprintf(mem_ctx, "%u", v);
719 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
723 add a (signed) int64_t element to a message
725 int samdb_msg_add_int64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
726 const char *attr_name, int64_t v)
728 const char *s = talloc_asprintf(mem_ctx, "%lld", v);
729 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
733 add a uint64_t element to a message
735 int samdb_msg_add_uint64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
736 const char *attr_name, uint64_t v)
738 const char *s = talloc_asprintf(mem_ctx, "%llu", v);
739 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
743 add a samr_Password element to a message
745 int samdb_msg_add_hash(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
746 const char *attr_name, struct samr_Password hash)
748 struct ldb_wrap *sam_ctx = ctx;
750 val.data = talloc(mem_ctx, 16);
755 memcpy(val.data, hash.hash, 16);
756 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
757 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
761 add a samr_Password array to a message
763 int samdb_msg_add_hashes(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
764 const char *attr_name, struct samr_Password *hashes, uint_t count)
766 struct ldb_wrap *sam_ctx = ctx;
769 val.data = talloc(mem_ctx, count*16);
770 val.length = count*16;
774 for (i=0;i<count;i++) {
775 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
777 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
778 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
782 add a acct_flags element to a message
784 int samdb_msg_add_acct_flags(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
785 const char *attr_name, uint32_t v)
787 return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v));
791 add a logon_hours element to a message
793 int samdb_msg_add_logon_hours(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
794 const char *attr_name, struct samr_LogonHours *hours)
796 struct ldb_wrap *sam_ctx = ctx;
798 val.length = hours->units_per_week / 8;
799 val.data = hours->bitmap;
800 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
801 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
805 set a string element in a message
807 int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
808 const char *attr_name, const char *str)
810 struct ldb_wrap *sam_ctx = ctx;
811 struct ldb_message_element *el;
813 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
815 el = ldb_msg_find_element(msg, attr_name);
819 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, str);
823 set a ldaptime element in a message
825 int samdb_msg_set_ldaptime(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
826 const char *attr_name, time_t t)
828 char *str = ldap_timestring(mem_ctx, t);
832 return samdb_msg_set_string(ctx, mem_ctx, msg, attr_name, str);
838 int samdb_add(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
840 struct ldb_wrap *sam_ctx = ctx;
842 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
843 return ldb_add(sam_ctx->ldb, msg);
849 int samdb_delete(void *ctx, TALLOC_CTX *mem_ctx, const char *dn)
851 struct ldb_wrap *sam_ctx = ctx;
853 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
854 return ldb_delete(sam_ctx->ldb, dn);
860 int samdb_modify(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
862 struct ldb_wrap *sam_ctx = ctx;
864 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
865 return ldb_modify(sam_ctx->ldb, msg);
869 replace elements in a record
871 int samdb_replace(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
875 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
876 for (i=0;i<msg->num_elements;i++) {
877 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
880 /* modify the samdb record */
881 return samdb_modify(ctx, mem_ctx, msg);
885 return a default security descriptor
887 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
889 struct security_descriptor *sd;
891 sd = security_descriptor_initialise(mem_ctx);