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 multipe records each giving a single string attribute
237 return the number of matches, or -1 on error
239 int samdb_search_string_multiple(void *ctx,
243 const char *attr_name,
244 const char *format, ...)
248 const char * const attrs[2] = { attr_name, NULL };
249 struct ldb_message **res = NULL;
251 va_start(ap, format);
252 count = samdb_search_v(ctx, mem_ctx, basedn, &res, attrs, format, ap);
259 /* make sure its single valued */
260 for (i=0;i<count;i++) {
261 if (res[i]->num_elements != 1) {
262 DEBUG(1,("samdb: search for %s %s not single valued\n",
264 samdb_search_free(ctx, mem_ctx, res);
269 *strs = talloc_array_p(mem_ctx, const char *, count+1);
271 samdb_search_free(ctx, mem_ctx, res);
275 for (i=0;i<count;i++) {
276 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
278 (*strs)[count] = NULL;
284 pull a uint from a result set.
286 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
288 return ldb_msg_find_uint(msg, attr, default_value);
292 pull a string from a result set.
294 const char *samdb_result_string(struct ldb_message *msg, const char *attr,
295 const char *default_value)
297 return ldb_msg_find_string(msg, attr, default_value);
301 pull a rid from a objectSid in a result set.
303 uint32 samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
304 const char *attr, uint32 default_value)
307 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
308 if (!sidstr) return default_value;
310 sid = dom_sid_parse_talloc(mem_ctx, sidstr);
311 if (!sid) return default_value;
313 return sid->sub_auths[sid->num_auths-1];
317 pull a dom_sid structure from a objectSid in a result set.
319 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
322 const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
323 if (!sidstr) return NULL;
325 return dom_sid_parse_talloc(mem_ctx, sidstr);
329 pull a sid prefix from a objectSid in a result set.
330 this is used to find the domain sid for a user
332 const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
335 struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
336 if (!sid || sid->num_auths < 1) return NULL;
340 return dom_sid_string(mem_ctx, sid);
344 pull a NTTIME in a result set.
346 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value)
348 const char *str = ldb_msg_find_string(msg, attr, default_value);
349 return nttime_from_string(str);
353 pull a double (really a large integer) from a result set.
355 double samdb_result_double(struct ldb_message *msg, const char *attr, double default_value)
357 return ldb_msg_find_double(msg, attr, default_value);
362 construct the allow_pwd_change field from the PwdLastSet attribute and the
363 domain password settings
365 NTTIME samdb_result_allow_pwd_change(void *ctx, TALLOC_CTX *mem_ctx,
366 const char *domain_dn, struct ldb_message *msg, const char *attr)
368 double attr_time = samdb_result_double(msg, attr, 0);
370 const char *minPwdAge = samdb_search_string(ctx, mem_ctx, NULL, "minPwdAge",
373 /* yes, this is a -= not a += as minPwdAge is stored as the negative
374 of the number of 100-nano-seconds */
375 attr_time -= strtod(minPwdAge, NULL);
378 return nttime_from_double_nt(attr_time);
382 construct the force_pwd_change field from the PwdLastSet attribute and the
383 domain password settings
385 NTTIME samdb_result_force_pwd_change(void *ctx, TALLOC_CTX *mem_ctx,
386 const char *domain_dn, struct ldb_message *msg, const char *attr)
388 double attr_time = samdb_result_double(msg, attr, 0);
390 const char *maxPwdAge = samdb_search_string(ctx, mem_ctx, NULL, "maxPwdAge",
392 if (!maxPwdAge || strcmp(maxPwdAge, "0") == 0) {
395 attr_time -= strtod(maxPwdAge, NULL);
398 return nttime_from_double_nt(attr_time);
402 pull a samr_Hash structutre from a result set.
404 struct samr_Hash samdb_result_hash(struct ldb_message *msg, const char *attr)
406 struct samr_Hash hash;
407 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
410 memcpy(hash.hash, val->data, MIN(val->length, 16));
416 pull an array of samr_Hash structutres from a result set.
418 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
419 const char *attr, struct samr_Hash **hashes)
422 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
429 count = val->length / 16;
434 *hashes = talloc_array_p(mem_ctx, struct samr_Hash, count);
439 for (i=0;i<count;i++) {
440 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
446 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
447 uint8 **lm_pwd, uint8 **nt_pwd)
450 const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
452 struct samr_Hash *lmPwdHash, *ntPwdHash;
455 ntPwdHash = talloc_p(mem_ctx, struct samr_Hash);
457 return NT_STATUS_NO_MEMORY;
460 E_md4hash(unicodePwd, ntPwdHash->hash);
461 *nt_pwd = ntPwdHash->hash;
467 lmPwdHash = talloc_p(mem_ctx, struct samr_Hash);
469 return NT_STATUS_NO_MEMORY;
472 /* compute the new nt and lm hashes */
473 lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
476 *lm_pwd = lmPwdHash->hash;
484 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
487 } else if (num_nt > 1) {
488 return NT_STATUS_INTERNAL_DB_CORRUPTION;
490 *nt_pwd = ntPwdHash[0].hash;
495 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
498 } else if (num_lm > 1) {
499 return NT_STATUS_INTERNAL_DB_CORRUPTION;
501 *lm_pwd = lmPwdHash[0].hash;
510 pull a samr_LogonHours structutre from a result set.
512 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
514 struct samr_LogonHours hours;
515 const int units_per_week = 168;
516 const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
518 hours.bitmap = talloc_array_p(mem_ctx, uint8, units_per_week);
522 hours.units_per_week = units_per_week;
523 memset(hours.bitmap, 0xFF, units_per_week);
525 memcpy(hours.bitmap, val->data, MIN(val->length, units_per_week));
531 pull a set of account_flags from a result set.
533 uint16 samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
535 uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
536 return samdb_uf2acb(userAccountControl);
540 copy from a template record to a message
542 int samdb_copy_template(void *ctx, TALLOC_CTX *mem_ctx,
543 struct ldb_message *msg, const char *expression)
545 struct ldb_message **res, *t;
549 /* pull the template record */
550 ret = samdb_search(ctx, mem_ctx, NULL, &res, NULL, expression);
552 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n",
558 for (i=0;i<t->num_elements;i++) {
559 struct ldb_message_element *el = &t->elements[i];
560 /* some elements should not be copied from the template */
561 if (strcasecmp(el->name, "cn") == 0 ||
562 strcasecmp(el->name, "name") == 0 ||
563 strcasecmp(el->name, "sAMAccountName") == 0) {
566 for (j=0;j<el->num_values;j++) {
567 if (strcasecmp(el->name, "objectClass") == 0 &&
568 (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
569 strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
570 strcasecmp((char *)el->values[j].data, "groupTemplate") == 0)) {
573 samdb_msg_add_string(ctx, mem_ctx, msg, el->name,
574 (char *)el->values[j].data);
583 allocate a new id, attempting to do it atomically
584 return 0 on failure, the id on success
586 static NTSTATUS _samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn,
587 const char *attr, uint32 *id)
589 struct samdb_context *sam_ctx = ctx;
590 struct ldb_message msg;
593 struct ldb_val vals[2];
594 struct ldb_message_element els[2];
596 str = samdb_search_string(ctx, mem_ctx, NULL, attr, "dn=%s", dn);
598 DEBUG(1,("id not found at %s %s\n", dn, attr));
599 return NT_STATUS_OBJECT_NAME_INVALID;
602 *id = strtol(str, NULL, 0);
605 return NT_STATUS_INSUFFICIENT_RESOURCES;
608 /* we do a delete and add as a single operation. That prevents
611 msg.dn = talloc_strdup(mem_ctx, dn);
613 return NT_STATUS_NO_MEMORY;
615 msg.num_elements = 2;
618 els[0].num_values = 1;
619 els[0].values = &vals[0];
620 els[0].flags = LDB_FLAG_MOD_DELETE;
621 els[0].name = talloc_strdup(mem_ctx, attr);
623 return NT_STATUS_NO_MEMORY;
626 els[1].num_values = 1;
627 els[1].values = &vals[1];
628 els[1].flags = LDB_FLAG_MOD_ADD;
629 els[1].name = els[0].name;
631 vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
633 return NT_STATUS_NO_MEMORY;
635 vals[0].length = strlen(vals[0].data);
637 vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
639 return NT_STATUS_NO_MEMORY;
641 vals[1].length = strlen(vals[1].data);
643 ret = ldb_modify(sam_ctx->ldb, &msg);
645 return NT_STATUS_UNEXPECTED_IO_ERROR;
654 allocate a new id, attempting to do it atomically
655 return 0 on failure, the id on success
657 NTSTATUS samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
663 /* we need to try multiple times to cope with two account
664 creations at the same time */
666 status = _samdb_allocate_next_id(ctx, mem_ctx, dn, attr, id);
667 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
672 if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
673 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
681 add a string element to a message
683 int samdb_msg_add_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
684 const char *attr_name, const char *str)
686 struct samdb_context *sam_ctx = ctx;
687 char *s = talloc_strdup(mem_ctx, str);
688 char *a = talloc_strdup(mem_ctx, attr_name);
689 if (s == NULL || a == NULL) {
692 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
693 return ldb_msg_add_string(sam_ctx->ldb, msg, a, s);
697 add a delete element operation to a message
699 int samdb_msg_add_delete(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
700 const char *attr_name)
702 struct samdb_context *sam_ctx = ctx;
703 char *a = talloc_strdup(mem_ctx, attr_name);
707 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
708 /* we use an empty replace rather than a delete, as it allows for
709 samdb_replace() to be used everywhere */
710 return ldb_msg_add_empty(sam_ctx->ldb, msg, a, LDB_FLAG_MOD_REPLACE);
714 add a uint_t element to a message
716 int samdb_msg_add_uint(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
717 const char *attr_name, uint_t v)
719 const char *s = talloc_asprintf(mem_ctx, "%u", v);
720 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
724 add a double element to a message (actually a large integer)
726 int samdb_msg_add_double(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
727 const char *attr_name, double v)
729 const char *s = talloc_asprintf(mem_ctx, "%.0f", v);
730 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
734 add a samr_Hash element to a message
736 int samdb_msg_add_hash(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
737 const char *attr_name, struct samr_Hash hash)
739 struct samdb_context *sam_ctx = ctx;
741 val.data = talloc(mem_ctx, 16);
746 memcpy(val.data, hash.hash, 16);
747 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
748 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
752 add a samr_Hash array to a message
754 int samdb_msg_add_hashes(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
755 const char *attr_name, struct samr_Hash *hashes, uint_t count)
757 struct samdb_context *sam_ctx = ctx;
760 val.data = talloc(mem_ctx, count*16);
761 val.length = count*16;
765 for (i=0;i<count;i++) {
766 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
768 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
769 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
773 add a acct_flags element to a message
775 int samdb_msg_add_acct_flags(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
776 const char *attr_name, uint32 v)
778 return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v));
782 add a logon_hours element to a message
784 int samdb_msg_add_logon_hours(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
785 const char *attr_name, struct samr_LogonHours hours)
787 struct samdb_context *sam_ctx = ctx;
789 val.length = hours.units_per_week / 8;
790 val.data = hours.bitmap;
791 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
792 return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
796 set a string element in a message
798 int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
799 const char *attr_name, const char *str)
801 struct samdb_context *sam_ctx = ctx;
802 struct ldb_message_element *el;
804 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
806 el = ldb_msg_find_element(msg, attr_name);
810 return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, str);
814 set a ldaptime element in a message
816 int samdb_msg_set_ldaptime(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
817 const char *attr_name, time_t t)
819 char *str = ldap_timestring(mem_ctx, t);
823 return samdb_msg_set_string(ctx, mem_ctx, msg, attr_name, str);
829 int samdb_add(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
831 struct samdb_context *sam_ctx = ctx;
833 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
834 return ldb_add(sam_ctx->ldb, msg);
840 int samdb_delete(void *ctx, TALLOC_CTX *mem_ctx, const char *dn)
842 struct samdb_context *sam_ctx = ctx;
844 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
845 return ldb_delete(sam_ctx->ldb, dn);
851 int samdb_modify(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
853 struct samdb_context *sam_ctx = ctx;
855 ldb_set_alloc(sam_ctx->ldb, samdb_alloc, mem_ctx);
856 return ldb_modify(sam_ctx->ldb, msg);
860 replace elements in a record
862 int samdb_replace(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
866 /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
867 for (i=0;i<msg->num_elements;i++) {
868 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
871 /* modify the samdb record */
872 return samdb_modify(ctx, mem_ctx, msg);