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;
31 this is used to catch debug messages from ldb
33 void samdb_debug(void *context, enum ldb_debug_level level, const char *fmt, va_list ap)
36 if (DEBUGLEVEL < 4 && level > LDB_DEBUG_WARNING) {
39 vasprintf(&s, fmt, ap);
41 DEBUG(level, ("samdb: %s\n", s));
46 connect to the SAM database
47 return an opaque context pointer on success, or NULL on failure
49 void *samdb_connect(void)
51 struct samdb_context *ctx;
53 the way that unix fcntl locking works forces us to have a
54 static ldb handle here rather than a much more sensible
55 approach of having the ldb handle as part of the
56 samr_Connect() pipe state. Otherwise we would try to open
57 the ldb more than once, and tdb would rightly refuse the
58 second open due to the broken nature of unix locking.
60 static struct ldb_context *static_sam_db;
62 if (static_sam_db == NULL) {
63 static_sam_db = ldb_connect(lp_sam_url(), 0, NULL);
64 if (static_sam_db == NULL) {
69 ldb_set_debug(static_sam_db, samdb_debug, NULL);
71 ctx = malloc_p(struct samdb_context);
77 ctx->ldb = static_sam_db;
82 /* close a connection to the sam */
83 void samdb_close(void *ctx)
85 struct samdb_context *sam_ctx = ctx;
86 /* we don't actually close due to broken posix locking semantics */
92 a alloc function for ldb
94 static void *samdb_alloc(void *context, void *ptr, size_t size)
96 return talloc_realloc((TALLOC_CTX *)context, ptr, size);
100 search the sam for the specified attributes - va_list varient
102 int samdb_search_v(void *ctx,
105 struct ldb_message ***res,
106 const char * const *attrs,
110 struct samdb_context *sam_ctx = ctx;
114 vasprintf(&expr, format, ap);
119 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
121 count = ldb_search(sam_ctx->ldb, basedn, LDB_SCOPE_SUBTREE, expr, attrs, res);
123 DEBUG(4,("samdb_search_v: %s %s -> %d\n", basedn?basedn:"NULL", expr, count));
132 search the sam for the specified attributes - varargs varient
134 int samdb_search(void *ctx,
137 struct ldb_message ***res,
138 const char * const *attrs,
139 const char *format, ...)
144 va_start(ap, format);
145 count = samdb_search_v(ctx, mem_ctx, basedn, res, attrs, format, ap);
152 free up a search result
154 int samdb_search_free(void *ctx,
155 TALLOC_CTX *mem_ctx, struct ldb_message **res)
157 struct samdb_context *sam_ctx = ctx;
158 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
159 return ldb_search_free(sam_ctx->ldb, res);
163 search the sam for a single string attribute in exactly 1 record
165 const char *samdb_search_string_v(void *ctx,
168 const char *attr_name,
169 const char *format, va_list ap)
172 const char * const attrs[2] = { attr_name, NULL };
173 struct ldb_message **res = NULL;
175 count = samdb_search_v(ctx, mem_ctx, basedn, &res, attrs, format, ap);
177 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
178 attr_name, format, count));
181 samdb_search_free(ctx, mem_ctx, res);
185 return samdb_result_string(res[0], attr_name, NULL);
190 search the sam for a single string attribute in exactly 1 record
192 const char *samdb_search_string(void *ctx,
195 const char *attr_name,
196 const char *format, ...)
201 va_start(ap, format);
202 str = samdb_search_string_v(ctx, mem_ctx, basedn, attr_name, format, ap);
210 search the sam for a single integer attribute in exactly 1 record
212 uint_t samdb_search_uint(void *ctx,
214 uint_t default_value,
216 const char *attr_name,
217 const char *format, ...)
221 struct ldb_message **res;
222 const char * const attrs[2] = { attr_name, NULL };
224 va_start(ap, format);
225 count = samdb_search_v(ctx, mem_ctx, basedn, &res, attrs, format, ap);
229 return default_value;
232 return samdb_result_uint(res[0], attr_name, default_value);
236 search the sam for a single signed 64 bit integer attribute in exactly 1 record
238 int64_t samdb_search_int64(void *ctx,
240 int64_t default_value,
242 const char *attr_name,
243 const char *format, ...)
247 struct ldb_message **res;
248 const char * const attrs[2] = { attr_name, NULL };
250 va_start(ap, format);
251 count = samdb_search_v(ctx, mem_ctx, basedn, &res, attrs, format, ap);
255 return default_value;
258 return samdb_result_int64(res[0], attr_name, default_value);
262 search the sam for multipe records each giving a single string attribute
263 return the number of matches, or -1 on error
265 int samdb_search_string_multiple(void *ctx,
269 const char *attr_name,
270 const char *format, ...)
274 const char * const attrs[2] = { attr_name, NULL };
275 struct ldb_message **res = NULL;
277 va_start(ap, format);
278 count = samdb_search_v(ctx, mem_ctx, basedn, &res, attrs, format, ap);
285 /* make sure its single valued */
286 for (i=0;i<count;i++) {
287 if (res[i]->num_elements != 1) {
288 DEBUG(1,("samdb: search for %s %s not single valued\n",
290 samdb_search_free(ctx, mem_ctx, res);
295 *strs = talloc_array_p(mem_ctx, const char *, count+1);
297 samdb_search_free(ctx, mem_ctx, res);
301 for (i=0;i<count;i++) {
302 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
304 (*strs)[count] = NULL;
310 pull a uint from a result set.
312 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
314 return ldb_msg_find_uint(msg, attr, default_value);
318 pull a (signed) int64 from a result set.
320 int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value)
322 return ldb_msg_find_int64(msg, attr, default_value);
326 pull a string from a result set.
328 const char *samdb_result_string(struct ldb_message *msg, const char *attr,
329 const char *default_value)
331 return ldb_msg_find_string(msg, attr, default_value);
335 pull a rid from a objectSid in a result set.
337 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
338 const char *attr, uint32_t default_value)
341 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
342 if (!sidstr) return default_value;
344 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
345 if (!sid) return default_value;
347 return sid->sub_auths[sid->num_auths-1];
351 pull a dom_sid structure from a objectSid in a result set.
353 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
356 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
357 if (!sidstr) return NULL;
359 return dom_sid_parse_talloc(mem_ctx, sidstr);
363 pull a sid prefix from a objectSid in a result set.
364 this is used to find the domain sid for a user
366 const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
369 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
370 if (!sid || sid->num_auths < 1) return NULL;
374 return dom_sid_string(mem_ctx, sid);
378 pull a NTTIME in a result set.
380 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value)
382 const char *str = ldb_msg_find_string(msg, attr, default_value);
383 return nttime_from_string(str);
387 pull a uint64_t from a result set.
389 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
391 return ldb_msg_find_uint64(msg, attr, default_value);
396 construct the allow_pwd_change field from the PwdLastSet attribute and the
397 domain password settings
399 NTTIME samdb_result_allow_pwd_change(void *ctx, TALLOC_CTX *mem_ctx,
400 const char *domain_dn, struct ldb_message *msg, const char *attr)
402 uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
405 if (attr_time == 0) {
409 minPwdAge = samdb_search_int64(ctx, mem_ctx, 0, "minPwdAge", "dn=%s", domain_dn);
411 /* yes, this is a -= not a += as minPwdAge is stored as the negative
412 of the number of 100-nano-seconds */
413 attr_time -= minPwdAge;
419 construct the force_pwd_change field from the PwdLastSet attribute and the
420 domain password settings
422 NTTIME samdb_result_force_pwd_change(void *ctx, TALLOC_CTX *mem_ctx,
423 const char *domain_dn, struct ldb_message *msg, const char *attr)
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, "maxPwdAge", "dn=%s", domain_dn);
433 if (maxPwdAge == 0) {
436 attr_time -= maxPwdAge;
443 pull a samr_Hash structutre from a result set.
445 struct samr_Hash samdb_result_hash(struct ldb_message *msg, const char *attr)
447 struct samr_Hash hash;
448 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
451 memcpy(hash.hash, val->data, MIN(val->length, 16));
457 pull an array of samr_Hash 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_Hash **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_Hash, 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 uint8 **lm_pwd, uint8 **nt_pwd)
491 const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
493 struct samr_Hash *lmPwdHash, *ntPwdHash;
496 ntPwdHash = talloc_p(mem_ctx, struct samr_Hash);
498 return NT_STATUS_NO_MEMORY;
501 E_md4hash(unicodePwd, ntPwdHash->hash);
502 *nt_pwd = ntPwdHash->hash;
508 lmPwdHash = talloc_p(mem_ctx, struct samr_Hash);
510 return NT_STATUS_NO_MEMORY;
513 /* compute the new nt and lm hashes */
514 lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
517 *lm_pwd = 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].hash;
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].hash;
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.bitmap = talloc_array_p(mem_ctx, uint8, units_per_week);
563 hours.units_per_week = units_per_week;
564 memset(hours.bitmap, 0xFF, units_per_week);
566 memcpy(hours.bitmap, 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, 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)) {
614 samdb_msg_add_string(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(void *ctx, TALLOC_CTX *mem_ctx, const char *dn,
628 const char *attr, uint32_t *id)
630 struct samdb_context *sam_ctx = ctx;
631 struct ldb_message msg;
634 struct ldb_val vals[2];
635 struct ldb_message_element els[2];
637 str = samdb_search_string(ctx, mem_ctx, NULL, attr, "dn=%s", dn);
639 DEBUG(1,("id not found at %s %s\n", dn, attr));
640 return NT_STATUS_OBJECT_NAME_INVALID;
643 *id = strtol(str, NULL, 0);
646 return NT_STATUS_INSUFFICIENT_RESOURCES;
649 /* we do a delete and add as a single operation. That prevents
652 msg.dn = talloc_strdup(mem_ctx, dn);
654 return NT_STATUS_NO_MEMORY;
656 msg.num_elements = 2;
659 els[0].num_values = 1;
660 els[0].values = &vals[0];
661 els[0].flags = LDB_FLAG_MOD_DELETE;
662 els[0].name = talloc_strdup(mem_ctx, attr);
664 return NT_STATUS_NO_MEMORY;
667 els[1].num_values = 1;
668 els[1].values = &vals[1];
669 els[1].flags = LDB_FLAG_MOD_ADD;
670 els[1].name = els[0].name;
672 vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
674 return NT_STATUS_NO_MEMORY;
676 vals[0].length = strlen(vals[0].data);
678 vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
680 return NT_STATUS_NO_MEMORY;
682 vals[1].length = strlen(vals[1].data);
684 ret = ldb_modify(sam_ctx->ldb, &msg);
686 return NT_STATUS_UNEXPECTED_IO_ERROR;
695 allocate a new id, attempting to do it atomically
696 return 0 on failure, the id on success
698 NTSTATUS samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
704 /* we need to try multiple times to cope with two account
705 creations at the same time */
707 status = _samdb_allocate_next_id(ctx, mem_ctx, dn, attr, id);
708 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
713 if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
714 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
722 add a string element to a message
724 int samdb_msg_add_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
725 const char *attr_name, const char *str)
727 struct samdb_context *sam_ctx = ctx;
728 char *s = talloc_strdup(mem_ctx, str);
729 char *a = talloc_strdup(mem_ctx, attr_name);
730 if (s == NULL || a == NULL) {
733 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
734 return ldb_msg_add_string(sam_ctx->ldb, msg, a, s);
738 add a delete element operation to a message
740 int samdb_msg_add_delete(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
741 const char *attr_name)
743 struct samdb_context *sam_ctx = ctx;
744 char *a = talloc_strdup(mem_ctx, attr_name);
748 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
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 uint_t element to a message
757 int samdb_msg_add_uint(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
758 const char *attr_name, uint_t v)
760 const char *s = talloc_asprintf(mem_ctx, "%u", v);
761 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
765 add a (signed) int64_t element to a message
767 int samdb_msg_add_int64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
768 const char *attr_name, int64_t v)
770 const char *s = talloc_asprintf(mem_ctx, "%lld", v);
771 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
775 add a uint64_t element to a message
777 int samdb_msg_add_uint64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
778 const char *attr_name, uint64_t v)
780 const char *s = talloc_asprintf(mem_ctx, "%llu", v);
781 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
785 add a samr_Hash element to a message
787 int samdb_msg_add_hash(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
788 const char *attr_name, struct samr_Hash hash)
790 struct samdb_context *sam_ctx = ctx;
792 val.data = talloc(mem_ctx, 16);
797 memcpy(val.data, hash.hash, 16);
798 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
799 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
803 add a samr_Hash array to a message
805 int samdb_msg_add_hashes(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
806 const char *attr_name, struct samr_Hash *hashes, uint_t count)
808 struct samdb_context *sam_ctx = ctx;
811 val.data = talloc(mem_ctx, count*16);
812 val.length = count*16;
816 for (i=0;i<count;i++) {
817 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
819 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
820 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
824 add a acct_flags element to a message
826 int samdb_msg_add_acct_flags(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
827 const char *attr_name, uint32_t v)
829 return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v));
833 add a logon_hours element to a message
835 int samdb_msg_add_logon_hours(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
836 const char *attr_name, struct samr_LogonHours hours)
838 struct samdb_context *sam_ctx = ctx;
840 val.length = hours.units_per_week / 8;
841 val.data = hours.bitmap;
842 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
843 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
847 set a string element in a message
849 int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
850 const char *attr_name, const char *str)
852 struct samdb_context *sam_ctx = ctx;
853 struct ldb_message_element *el;
855 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
857 el = ldb_msg_find_element(msg, attr_name);
861 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, str);
865 set a ldaptime element in a message
867 int samdb_msg_set_ldaptime(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
868 const char *attr_name, time_t t)
870 char *str = ldap_timestring(mem_ctx, t);
874 return samdb_msg_set_string(ctx, mem_ctx, msg, attr_name, str);
880 int samdb_add(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
882 struct samdb_context *sam_ctx = ctx;
884 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
885 return ldb_add(sam_ctx->ldb, msg);
891 int samdb_delete(void *ctx, TALLOC_CTX *mem_ctx, const char *dn)
893 struct samdb_context *sam_ctx = ctx;
895 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
896 return ldb_delete(sam_ctx->ldb, dn);
902 int samdb_modify(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
904 struct samdb_context *sam_ctx = ctx;
906 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
907 return ldb_modify(sam_ctx->ldb, msg);
911 replace elements in a record
913 int samdb_replace(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
917 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
918 for (i=0;i<msg->num_elements;i++) {
919 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
922 /* modify the samdb record */
923 return samdb_modify(ctx, mem_ctx, msg);