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.
25 struct samdb_context {
26 struct ldb_context *ldb;
27 struct samdb_context **static_ptr;
32 this is used to catch debug messages from ldb
34 void samdb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap) _PRINTF_ATTRIBUTE(3,0)
37 if (DEBUGLEVEL < 4 && level > LDB_DEBUG_WARNING) {
40 vasprintf(&s, fmt, ap);
42 DEBUG(level, ("samdb: %s\n", s));
46 /* destroy the last connection to the sam */
47 static int samdb_destructor(void *ctx)
49 struct samdb_context *sam_ctx = ctx;
50 ldb_close(sam_ctx->ldb);
51 *(sam_ctx->static_ptr) = NULL;
56 connect to the SAM database
57 return an opaque context pointer on success, or NULL on failure
59 void *samdb_connect(TALLOC_CTX *mem_ctx)
61 static struct samdb_context *ctx;
63 the way that unix fcntl locking works forces us to have a
64 static ldb handle here rather than a much more sensible
65 approach of having the ldb handle as part of the
66 samr_Connect() pipe state. Otherwise we would try to open
67 the ldb more than once, and tdb would rightly refuse the
68 second open due to the broken nature of unix locking.
71 return talloc_reference(mem_ctx, ctx);
74 ctx = talloc_p(mem_ctx, struct samdb_context);
80 ctx->static_ptr = &ctx;
82 ctx->ldb = ldb_connect(lp_sam_url(), 0, NULL);
83 if (ctx->ldb == NULL) {
88 talloc_set_destructor(ctx, samdb_destructor);
89 ldb_set_debug(ctx->ldb, samdb_debug, NULL);
95 search the sam for the specified attributes - varargs variant
97 int samdb_search(void *ctx,
100 struct ldb_message ***res,
101 const char * const *attrs,
102 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
104 struct samdb_context *sam_ctx = ctx;
108 va_start(ap, format);
109 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, res, attrs, format, ap);
116 free up a search result
118 int samdb_search_free(void *ctx,
119 TALLOC_CTX *mem_ctx, struct ldb_message **res)
121 struct samdb_context *sam_ctx = ctx;
122 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
123 return ldb_search_free(sam_ctx->ldb, res);
127 search the sam for a single string attribute in exactly 1 record
129 const char *samdb_search_string_v(void *ctx,
132 const char *attr_name,
133 const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
135 struct samdb_context *sam_ctx = ctx;
137 const char * const attrs[2] = { attr_name, NULL };
138 struct ldb_message **res = NULL;
140 count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
142 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
143 attr_name, format, count));
146 samdb_search_free(ctx, mem_ctx, res);
150 return samdb_result_string(res[0], attr_name, NULL);
155 search the sam for a single string attribute in exactly 1 record
157 const char *samdb_search_string(void *ctx,
160 const char *attr_name,
161 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
166 va_start(ap, format);
167 str = samdb_search_string_v(ctx, mem_ctx, basedn, attr_name, format, ap);
174 return the count of the number of records in the sam matching the query
176 int samdb_search_count(void *ctx,
179 const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
181 struct samdb_context *samdb_ctx = ctx;
183 struct ldb_message **res;
184 const char * const attrs[] = { NULL };
187 va_start(ap, format);
188 ret = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
196 search the sam for a single integer attribute in exactly 1 record
198 uint_t samdb_search_uint(void *ctx,
200 uint_t default_value,
202 const char *attr_name,
203 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
205 struct samdb_context *samdb_ctx = ctx;
208 struct ldb_message **res;
209 const char * const attrs[2] = { attr_name, NULL };
211 va_start(ap, format);
212 count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
216 return default_value;
219 return samdb_result_uint(res[0], attr_name, default_value);
223 search the sam for a single signed 64 bit integer attribute in exactly 1 record
225 int64_t samdb_search_int64(void *ctx,
227 int64_t default_value,
229 const char *attr_name,
230 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
232 struct samdb_context *samdb_ctx = ctx;
235 struct ldb_message **res;
236 const char * const attrs[2] = { attr_name, NULL };
238 va_start(ap, format);
239 count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
243 return default_value;
246 return samdb_result_int64(res[0], attr_name, default_value);
250 search the sam for multipe records each giving a single string attribute
251 return the number of matches, or -1 on error
253 int samdb_search_string_multiple(void *ctx,
257 const char *attr_name,
258 const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
260 struct samdb_context *samdb_ctx = ctx;
263 const char * const attrs[2] = { attr_name, NULL };
264 struct ldb_message **res = NULL;
266 va_start(ap, format);
267 count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
274 /* make sure its single valued */
275 for (i=0;i<count;i++) {
276 if (res[i]->num_elements != 1) {
277 DEBUG(1,("samdb: search for %s %s not single valued\n",
279 samdb_search_free(ctx, mem_ctx, res);
284 *strs = talloc_array_p(mem_ctx, const char *, count+1);
286 samdb_search_free(ctx, mem_ctx, res);
290 for (i=0;i<count;i++) {
291 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
293 (*strs)[count] = NULL;
299 pull a uint from a result set.
301 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
303 return ldb_msg_find_uint(msg, attr, default_value);
307 pull a (signed) int64 from a result set.
309 int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value)
311 return ldb_msg_find_int64(msg, attr, default_value);
315 pull a string from a result set.
317 const char *samdb_result_string(struct ldb_message *msg, const char *attr,
318 const char *default_value)
320 return ldb_msg_find_string(msg, attr, default_value);
324 pull a rid from a objectSid in a result set.
326 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
327 const char *attr, uint32_t default_value)
330 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
331 if (!sidstr) return default_value;
333 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
334 if (!sid) return default_value;
336 return sid->sub_auths[sid->num_auths-1];
340 pull a dom_sid structure from a objectSid in a result set.
342 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
345 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
346 if (!sidstr) return NULL;
348 return dom_sid_parse_talloc(mem_ctx, sidstr);
352 pull a guid structure from a objectGUID in a result set.
354 struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr)
358 const char *guidstr = ldb_msg_find_string(msg, attr, NULL);
362 if (!guidstr) return guid;
364 status = GUID_from_string(guidstr, &guid);
365 if (!NT_STATUS_IS_OK(status)) {
374 pull a sid prefix from a objectSid in a result set.
375 this is used to find the domain sid for a user
377 const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
380 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
381 if (!sid || sid->num_auths < 1) return NULL;
385 return dom_sid_string(mem_ctx, sid);
389 pull a NTTIME in a result set.
391 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value)
393 const char *str = ldb_msg_find_string(msg, attr, default_value);
394 return nttime_from_string(str);
398 pull a uint64_t from a result set.
400 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
402 return ldb_msg_find_uint64(msg, attr, default_value);
407 construct the allow_password_change field from the PwdLastSet attribute and the
408 domain password settings
410 NTTIME samdb_result_allow_password_change(void *ctx, TALLOC_CTX *mem_ctx,
411 const char *domain_dn,
412 struct ldb_message *msg,
415 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
418 if (attr_time == 0) {
422 minPwdAge = samdb_search_int64(ctx, mem_ctx, 0, NULL,
423 "minPwdAge", "dn=%s", domain_dn);
425 /* yes, this is a -= not a += as minPwdAge is stored as the negative
426 of the number of 100-nano-seconds */
427 attr_time -= minPwdAge;
433 construct the force_password_change field from the PwdLastSet attribute and the
434 domain password settings
436 NTTIME samdb_result_force_password_change(void *ctx, TALLOC_CTX *mem_ctx,
437 const char *domain_dn,
438 struct ldb_message *msg,
441 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
444 if (attr_time == 0) {
448 maxPwdAge = samdb_search_int64(ctx, mem_ctx, 0, NULL, "maxPwdAge", "dn=%s", domain_dn);
449 if (maxPwdAge == 0) {
452 attr_time -= maxPwdAge;
459 pull a samr_Password structutre from a result set.
461 struct samr_Password samdb_result_hash(struct ldb_message *msg, const char *attr)
463 struct samr_Password hash;
464 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
467 memcpy(hash.hash, val->data, MIN(val->length, sizeof(hash.hash)));
473 pull an array of samr_Password structutres from a result set.
475 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
476 const char *attr, struct samr_Password **hashes)
479 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
486 count = val->length / 16;
491 *hashes = talloc_array_p(mem_ctx, struct samr_Password, count);
496 for (i=0;i<count;i++) {
497 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
503 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
504 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
507 const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
509 struct samr_Password *lmPwdHash, *ntPwdHash;
512 ntPwdHash = talloc_p(mem_ctx, struct samr_Password);
514 return NT_STATUS_NO_MEMORY;
517 E_md4hash(unicodePwd, ntPwdHash->hash);
524 lmPwdHash = talloc_p(mem_ctx, struct samr_Password);
526 return NT_STATUS_NO_MEMORY;
529 /* compute the new nt and lm hashes */
530 lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
541 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
544 } else if (num_nt > 1) {
545 return NT_STATUS_INTERNAL_DB_CORRUPTION;
547 *nt_pwd = &ntPwdHash[0];
552 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
555 } else if (num_lm > 1) {
556 return NT_STATUS_INTERNAL_DB_CORRUPTION;
558 *lm_pwd = &lmPwdHash[0];
567 pull a samr_LogonHours structutre from a result set.
569 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
571 struct samr_LogonHours hours;
572 const int units_per_week = 168;
573 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
575 hours.bitmap = talloc_array_p(mem_ctx, uint8, units_per_week);
579 hours.units_per_week = units_per_week;
580 memset(hours.bitmap, 0xFF, units_per_week);
582 memcpy(hours.bitmap, val->data, MIN(val->length, units_per_week));
588 pull a set of account_flags from a result set.
590 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
592 uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
593 return samdb_uf2acb(userAccountControl);
597 copy from a template record to a message
599 int samdb_copy_template(void *ctx, TALLOC_CTX *mem_ctx,
600 struct ldb_message *msg, const char *expression)
602 struct ldb_message **res, *t;
606 /* pull the template record */
607 ret = samdb_search(ctx, mem_ctx, NULL, &res, NULL, "%s", expression);
609 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n",
615 for (i=0;i<t->num_elements;i++) {
616 struct ldb_message_element *el = &t->elements[i];
617 /* some elements should not be copied from the template */
618 if (strcasecmp(el->name, "cn") == 0 ||
619 strcasecmp(el->name, "name") == 0 ||
620 strcasecmp(el->name, "sAMAccountName") == 0) {
623 for (j=0;j<el->num_values;j++) {
624 if (strcasecmp(el->name, "objectClass") == 0 &&
625 (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
626 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
627 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0)) {
630 samdb_msg_add_string(ctx, mem_ctx, msg, el->name,
631 (char *)el->values[j].data);
640 allocate a new id, attempting to do it atomically
641 return 0 on failure, the id on success
643 static NTSTATUS _samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn,
644 const char *attr, uint32_t *id)
646 struct samdb_context *sam_ctx = ctx;
647 struct ldb_message msg;
650 struct ldb_val vals[2];
651 struct ldb_message_element els[2];
653 str = samdb_search_string(ctx, mem_ctx, NULL, attr, "dn=%s", dn);
655 DEBUG(1,("id not found at %s %s\n", dn, attr));
656 return NT_STATUS_OBJECT_NAME_INVALID;
659 *id = strtol(str, NULL, 0);
662 return NT_STATUS_INSUFFICIENT_RESOURCES;
665 /* we do a delete and add as a single operation. That prevents
668 msg.dn = talloc_strdup(mem_ctx, dn);
670 return NT_STATUS_NO_MEMORY;
672 msg.num_elements = 2;
675 els[0].num_values = 1;
676 els[0].values = &vals[0];
677 els[0].flags = LDB_FLAG_MOD_DELETE;
678 els[0].name = talloc_strdup(mem_ctx, attr);
680 return NT_STATUS_NO_MEMORY;
683 els[1].num_values = 1;
684 els[1].values = &vals[1];
685 els[1].flags = LDB_FLAG_MOD_ADD;
686 els[1].name = els[0].name;
688 vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
690 return NT_STATUS_NO_MEMORY;
692 vals[0].length = strlen(vals[0].data);
694 vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
696 return NT_STATUS_NO_MEMORY;
698 vals[1].length = strlen(vals[1].data);
700 ret = ldb_modify(sam_ctx->ldb, &msg);
702 return NT_STATUS_UNEXPECTED_IO_ERROR;
711 allocate a new id, attempting to do it atomically
712 return 0 on failure, the id on success
714 NTSTATUS samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
720 /* we need to try multiple times to cope with two account
721 creations at the same time */
723 status = _samdb_allocate_next_id(ctx, mem_ctx, dn, attr, id);
724 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
729 if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
730 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
738 add a string element to a message
740 int samdb_msg_add_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
741 const char *attr_name, const char *str)
743 struct samdb_context *sam_ctx = ctx;
744 char *s = talloc_strdup(mem_ctx, str);
745 char *a = talloc_strdup(mem_ctx, attr_name);
746 if (s == NULL || a == NULL) {
749 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
750 return ldb_msg_add_string(sam_ctx->ldb, msg, a, s);
754 add a delete element operation to a message
756 int samdb_msg_add_delete(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
757 const char *attr_name)
759 struct samdb_context *sam_ctx = ctx;
760 char *a = talloc_strdup(mem_ctx, attr_name);
764 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
765 /* we use an empty replace rather than a delete, as it allows for
766 samdb_replace() to be used everywhere */
767 return ldb_msg_add_empty(sam_ctx->ldb, msg, a, LDB_FLAG_MOD_REPLACE);
771 add a uint_t element to a message
773 int samdb_msg_add_uint(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
774 const char *attr_name, uint_t v)
776 const char *s = talloc_asprintf(mem_ctx, "%u", v);
777 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
781 add a (signed) int64_t element to a message
783 int samdb_msg_add_int64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784 const char *attr_name, int64_t v)
786 const char *s = talloc_asprintf(mem_ctx, "%lld", v);
787 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
791 add a uint64_t element to a message
793 int samdb_msg_add_uint64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
794 const char *attr_name, uint64_t v)
796 const char *s = talloc_asprintf(mem_ctx, "%llu", v);
797 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
801 add a samr_Password element to a message
803 int samdb_msg_add_hash(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
804 const char *attr_name, struct samr_Password hash)
806 struct samdb_context *sam_ctx = ctx;
808 val.data = talloc(mem_ctx, 16);
813 memcpy(val.data, hash.hash, 16);
814 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
815 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
819 add a samr_Password array to a message
821 int samdb_msg_add_hashes(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
822 const char *attr_name, struct samr_Password *hashes, uint_t count)
824 struct samdb_context *sam_ctx = ctx;
827 val.data = talloc(mem_ctx, count*16);
828 val.length = count*16;
832 for (i=0;i<count;i++) {
833 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
835 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
836 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
840 add a acct_flags element to a message
842 int samdb_msg_add_acct_flags(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
843 const char *attr_name, uint32_t v)
845 return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v));
849 add a logon_hours element to a message
851 int samdb_msg_add_logon_hours(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
852 const char *attr_name, struct samr_LogonHours hours)
854 struct samdb_context *sam_ctx = ctx;
856 val.length = hours.units_per_week / 8;
857 val.data = hours.bitmap;
858 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
859 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
863 set a string element in a message
865 int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
866 const char *attr_name, const char *str)
868 struct samdb_context *sam_ctx = ctx;
869 struct ldb_message_element *el;
871 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
873 el = ldb_msg_find_element(msg, attr_name);
877 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, str);
881 set a ldaptime element in a message
883 int samdb_msg_set_ldaptime(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
884 const char *attr_name, time_t t)
886 char *str = ldap_timestring(mem_ctx, t);
890 return samdb_msg_set_string(ctx, mem_ctx, msg, attr_name, str);
896 int samdb_add(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
898 struct samdb_context *sam_ctx = ctx;
900 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
901 return ldb_add(sam_ctx->ldb, msg);
907 int samdb_delete(void *ctx, TALLOC_CTX *mem_ctx, const char *dn)
909 struct samdb_context *sam_ctx = ctx;
911 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
912 return ldb_delete(sam_ctx->ldb, dn);
918 int samdb_modify(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
920 struct samdb_context *sam_ctx = ctx;
922 ldb_set_alloc(sam_ctx->ldb, talloc_realloc_fn, mem_ctx);
923 return ldb_modify(sam_ctx->ldb, msg);
927 replace elements in a record
929 int samdb_replace(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
933 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
934 for (i=0;i<msg->num_elements;i++) {
935 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
938 /* modify the samdb record */
939 return samdb_modify(ctx, mem_ctx, msg);
943 return a default security descriptor
945 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
947 struct security_descriptor *sd;
949 sd = sd_initialise(mem_ctx);