r4475: fixed smbd to work with the small changes in the ldb API (the most important
[samba.git] / source4 / dsdb / samdb / samdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    interface functions for the sam database
5
6    Copyright (C) Andrew Tridgell 2004
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24 #include "librpc/gen_ndr/ndr_netlogon.h"
25 #include "lib/ldb/include/ldb.h"
26
27 /*
28   connect to the SAM database
29   return an opaque context pointer on success, or NULL on failure
30  */
31 void *samdb_connect(TALLOC_CTX *mem_ctx)
32 {
33         return ldb_wrap_connect(mem_ctx, lp_sam_url(), 0, NULL);
34 }
35
36 /*
37   search the sam for the specified attributes - varargs variant
38 */
39 int samdb_search(void *ctx,
40                  TALLOC_CTX *mem_ctx, 
41                  const char *basedn,
42                  struct ldb_message ***res,
43                  const char * const *attrs,
44                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
45 {
46         struct ldb_wrap *sam_ctx = ctx;
47         va_list ap;
48         int count;
49
50         va_start(ap, format);
51         count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, res, attrs, format, ap);
52         va_end(ap);
53
54         return count;
55 }
56
57 /*
58   search the sam for the specified attributes in a specific domain, filter on
59   objectSid being in domain_sid.
60 */
61 int samdb_search_domain(void *ctx,
62                         TALLOC_CTX *mem_ctx, 
63                         const char *basedn,
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)
68 {
69         struct ldb_wrap *sam_ctx = ctx;
70         va_list ap;
71         int i, count;
72
73         va_start(ap, format);
74         count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, res, attrs,
75                                format, ap);
76         va_end(ap);
77
78         i=0;
79
80         while (i<count) {
81                 struct dom_sid *entry_sid;
82
83                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i],
84                                                  "objectSid");
85
86                 if ((entry_sid == NULL) ||
87                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
88
89                         /* Delete that entry from the result set */
90                         (*res)[i] = (*res)[count-1];
91                         count -= 1;
92                         continue;
93                 }
94                 i += 1;
95         }
96
97         return count;
98 }
99
100 /*
101   free up a search result
102 */
103 int samdb_search_free(void *ctx,
104                       TALLOC_CTX *mem_ctx, struct ldb_message **res)
105 {
106         struct ldb_wrap *sam_ctx = ctx;
107         return ldb_search_free(sam_ctx->ldb, res);
108 }
109
110 /*
111   search the sam for a single string attribute in exactly 1 record
112 */
113 const char *samdb_search_string_v(void *ctx,
114                                   TALLOC_CTX *mem_ctx,
115                                   const char *basedn,
116                                   const char *attr_name,
117                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
118 {
119         struct ldb_wrap *sam_ctx = ctx;
120         int count;
121         const char * const attrs[2] = { attr_name, NULL };
122         struct ldb_message **res = NULL;
123
124         count = gendb_search_v(sam_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
125         if (count > 1) {                
126                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
127                          attr_name, format, count));
128         }
129         if (count != 1) {
130                 samdb_search_free(ctx, mem_ctx, res);
131                 return NULL;
132         }
133
134         return samdb_result_string(res[0], attr_name, NULL);
135 }
136                                  
137
138 /*
139   search the sam for a single string attribute in exactly 1 record
140 */
141 const char *samdb_search_string(void *ctx,
142                                 TALLOC_CTX *mem_ctx,
143                                 const char *basedn,
144                                 const char *attr_name,
145                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
146 {
147         va_list ap;
148         const char *str;
149
150         va_start(ap, format);
151         str = samdb_search_string_v(ctx, mem_ctx, basedn, attr_name, format, ap);
152         va_end(ap);
153
154         return str;
155 }
156
157 /*
158   return the count of the number of records in the sam matching the query
159 */
160 int samdb_search_count(void *ctx,
161                        TALLOC_CTX *mem_ctx,
162                        const char *basedn,
163                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
164 {
165         struct ldb_wrap *samdb_ctx = ctx;
166         va_list ap;
167         struct ldb_message **res;
168         const char * const attrs[] = { NULL };
169         int ret;
170
171         va_start(ap, format);
172         ret = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
173         va_end(ap);
174
175         return ret;
176 }
177
178
179 /*
180   search the sam for a single integer attribute in exactly 1 record
181 */
182 uint_t samdb_search_uint(void *ctx,
183                          TALLOC_CTX *mem_ctx,
184                          uint_t default_value,
185                          const char *basedn,
186                          const char *attr_name,
187                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
188 {
189         struct ldb_wrap *samdb_ctx = ctx;
190         va_list ap;
191         int count;
192         struct ldb_message **res;
193         const char * const attrs[2] = { attr_name, NULL };
194
195         va_start(ap, format);
196         count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
197         va_end(ap);
198
199         if (count != 1) {
200                 return default_value;
201         }
202
203         return samdb_result_uint(res[0], attr_name, default_value);
204 }
205
206 /*
207   search the sam for a single signed 64 bit integer attribute in exactly 1 record
208 */
209 int64_t samdb_search_int64(void *ctx,
210                            TALLOC_CTX *mem_ctx,
211                            int64_t default_value,
212                            const char *basedn,
213                            const char *attr_name,
214                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
215 {
216         struct ldb_wrap *samdb_ctx = ctx;
217         va_list ap;
218         int count;
219         struct ldb_message **res;
220         const char * const attrs[2] = { attr_name, NULL };
221
222         va_start(ap, format);
223         count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
224         va_end(ap);
225
226         if (count != 1) {
227                 return default_value;
228         }
229
230         return samdb_result_int64(res[0], attr_name, default_value);
231 }
232
233 /*
234   search the sam for multipe records each giving a single string attribute
235   return the number of matches, or -1 on error
236 */
237 int samdb_search_string_multiple(void *ctx,
238                                  TALLOC_CTX *mem_ctx,
239                                  const char *basedn,
240                                  const char ***strs,
241                                  const char *attr_name,
242                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
243 {
244         struct ldb_wrap *samdb_ctx = ctx;
245         va_list ap;
246         int count, i;
247         const char * const attrs[2] = { attr_name, NULL };
248         struct ldb_message **res = NULL;
249
250         va_start(ap, format);
251         count = gendb_search_v(samdb_ctx->ldb, mem_ctx, basedn, &res, attrs, format, ap);
252         va_end(ap);
253
254         if (count <= 0) {
255                 return count;
256         }
257
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", 
262                                  attr_name, format));
263                         samdb_search_free(ctx, mem_ctx, res);
264                         return -1;
265                 }
266         }
267
268         *strs = talloc_array_p(mem_ctx, const char *, count+1);
269         if (! *strs) {
270                 samdb_search_free(ctx, mem_ctx, res);
271                 return -1;
272         }
273
274         for (i=0;i<count;i++) {
275                 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
276         }
277         (*strs)[count] = NULL;
278
279         return count;
280 }
281
282 /*
283   pull a uint from a result set. 
284 */
285 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
286 {
287         return ldb_msg_find_uint(msg, attr, default_value);
288 }
289
290 /*
291   pull a (signed) int64 from a result set. 
292 */
293 int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value)
294 {
295         return ldb_msg_find_int64(msg, attr, default_value);
296 }
297
298 /*
299   pull a string from a result set. 
300 */
301 const char *samdb_result_string(struct ldb_message *msg, const char *attr, 
302                                 const char *default_value)
303 {
304         return ldb_msg_find_string(msg, attr, default_value);
305 }
306
307 /*
308   pull a rid from a objectSid in a result set. 
309 */
310 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
311                                  const char *attr, uint32_t default_value)
312 {
313         struct dom_sid *sid;
314         const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
315         if (!sidstr) return default_value;
316
317         sid = dom_sid_parse_talloc(mem_ctx, sidstr);
318         if (!sid) return default_value;
319
320         return sid->sub_auths[sid->num_auths-1];
321 }
322
323 /*
324   pull a dom_sid structure from a objectSid in a result set. 
325 */
326 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
327                                      const char *attr)
328 {
329         const char *sidstr = ldb_msg_find_string(msg, attr, NULL);
330         if (!sidstr) return NULL;
331
332         return dom_sid_parse_talloc(mem_ctx, sidstr);
333 }
334
335 /*
336   pull a guid structure from a objectGUID in a result set. 
337 */
338 struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr)
339 {
340         NTSTATUS status;
341         struct GUID guid;
342         const char *guidstr = ldb_msg_find_string(msg, attr, NULL);
343
344         ZERO_STRUCT(guid);
345
346         if (!guidstr) return guid;
347
348         status = GUID_from_string(guidstr, &guid);
349         if (!NT_STATUS_IS_OK(status)) {
350                 ZERO_STRUCT(guid);
351                 return guid;
352         }
353
354         return guid;
355 }
356
357 /*
358   pull a sid prefix from a objectSid in a result set. 
359   this is used to find the domain sid for a user
360 */
361 const char *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
362                                     const char *attr)
363 {
364         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
365         if (!sid || sid->num_auths < 1) return NULL;
366
367         sid->num_auths--;
368
369         return dom_sid_string(mem_ctx, sid);
370 }
371
372 /*
373   pull a NTTIME in a result set. 
374 */
375 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, const char *default_value)
376 {
377         const char *str = ldb_msg_find_string(msg, attr, default_value);
378         return nttime_from_string(str);
379 }
380
381 /*
382   pull a uint64_t from a result set. 
383 */
384 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
385 {
386         return ldb_msg_find_uint64(msg, attr, default_value);
387 }
388
389
390 /*
391   construct the allow_password_change field from the PwdLastSet attribute and the 
392   domain password settings
393 */
394 NTTIME samdb_result_allow_password_change(void *ctx, TALLOC_CTX *mem_ctx, 
395                                           const char *domain_dn, 
396                                           struct ldb_message *msg, 
397                                           const char *attr)
398 {
399         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
400         int64_t minPwdAge;
401
402         if (attr_time == 0) {
403                 return 0;
404         }
405
406         minPwdAge = samdb_search_int64(ctx, mem_ctx, 0, NULL, 
407                                        "minPwdAge", "dn=%s", domain_dn);
408
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;
412
413         return attr_time;
414 }
415
416 /*
417   construct the force_password_change field from the PwdLastSet attribute and the 
418   domain password settings
419 */
420 NTTIME samdb_result_force_password_change(void *ctx, TALLOC_CTX *mem_ctx, 
421                                           const char *domain_dn, 
422                                           struct ldb_message *msg, 
423                                           const char *attr)
424 {
425         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
426         int64_t maxPwdAge;
427
428         if (attr_time == 0) {
429                 return 0;
430         }
431
432         maxPwdAge = samdb_search_int64(ctx, mem_ctx, 0, NULL, "maxPwdAge", "dn=%s", domain_dn);
433         if (maxPwdAge == 0) {
434                 return 0;
435         } else {
436                 attr_time -= maxPwdAge;
437         }
438
439         return attr_time;
440 }
441
442 /*
443   pull a samr_Password structutre from a result set. 
444 */
445 struct samr_Password samdb_result_hash(struct ldb_message *msg, const char *attr)
446 {
447         struct samr_Password hash;
448         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
449         ZERO_STRUCT(hash);
450         if (val) {
451                 memcpy(hash.hash, val->data, MIN(val->length, sizeof(hash.hash)));
452         }
453         return hash;
454 }
455
456 /*
457   pull an array of samr_Password structutres from a result set. 
458 */
459 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
460                            const char *attr, struct samr_Password **hashes)
461 {
462         uint_t count = 0;
463         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
464         int i;
465
466         *hashes = NULL;
467         if (!val) {
468                 return 0;
469         }
470         count = val->length / 16;
471         if (count == 0) {
472                 return 0;
473         }
474
475         *hashes = talloc_array_p(mem_ctx, struct samr_Password, count);
476         if (! *hashes) {
477                 return 0;
478         }
479
480         for (i=0;i<count;i++) {
481                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
482         }
483
484         return count;
485 }
486
487 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
488                                 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
489 {
490
491         const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
492         
493         struct samr_Password *lmPwdHash, *ntPwdHash;
494         if (unicodePwd) {
495                 if (nt_pwd) {
496                         ntPwdHash = talloc_p(mem_ctx, struct samr_Password);
497                         if (!ntPwdHash) {
498                                 return NT_STATUS_NO_MEMORY;
499                         }
500                         
501                         E_md4hash(unicodePwd, ntPwdHash->hash);
502                         *nt_pwd = ntPwdHash;
503                 }
504
505                 if (lm_pwd) {
506                         BOOL lm_hash_ok;
507                 
508                         lmPwdHash = talloc_p(mem_ctx, struct samr_Password);
509                         if (!lmPwdHash) {
510                                 return NT_STATUS_NO_MEMORY;
511                         }
512                         
513                         /* compute the new nt and lm hashes */
514                         lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
515                         
516                         if (lm_hash_ok) {
517                                 *lm_pwd = lmPwdHash;
518                         } else {
519                                 *lm_pwd = NULL;
520                         }
521                 }
522         } else {
523                 if (nt_pwd) {
524                         int num_nt;
525                         num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
526                         if (num_nt == 0) {
527                                 *nt_pwd = NULL;
528                         } else if (num_nt > 1) {
529                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
530                         } else {
531                                 *nt_pwd = &ntPwdHash[0];
532                         }
533                 }
534                 if (lm_pwd) {
535                         int num_lm;
536                         num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
537                         if (num_lm == 0) {
538                                 *lm_pwd = NULL;
539                         } else if (num_lm > 1) {
540                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
541                         } else {
542                                 *lm_pwd = &lmPwdHash[0];
543                         }
544                 }
545                 
546         }
547         return NT_STATUS_OK;
548 }
549
550 /*
551   pull a samr_LogonHours structutre from a result set. 
552 */
553 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
554 {
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);
558         ZERO_STRUCT(hours);
559         hours.bitmap = talloc_array_p(mem_ctx, uint8, units_per_week);
560         if (!hours.bitmap) {
561                 return hours;
562         }
563         hours.units_per_week = units_per_week;
564         memset(hours.bitmap, 0xFF, units_per_week);
565         if (val) {
566                 memcpy(hours.bitmap, val->data, MIN(val->length, units_per_week));
567         }
568         return hours;
569 }
570
571 /*
572   pull a set of account_flags from a result set. 
573 */
574 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
575 {
576         uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
577         return samdb_uf2acb(userAccountControl);
578 }
579
580 /*
581   copy from a template record to a message
582 */
583 int samdb_copy_template(void *ctx, TALLOC_CTX *mem_ctx, 
584                         struct ldb_message *msg, const char *expression)
585 {
586         struct ldb_message **res, *t;
587         int ret, i, j;
588         
589
590         /* pull the template record */
591         ret = samdb_search(ctx, mem_ctx, NULL, &res, NULL, "%s", expression);
592         if (ret != 1) {
593                 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n", 
594                          expression, ret));
595                 return -1;
596         }
597         t = res[0];
598
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) {
605                         continue;
606                 }
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)) {
614                                 continue;
615                         }
616                         samdb_msg_add_string(ctx, mem_ctx, msg, el->name, 
617                                              (char *)el->values[j].data);
618                 }
619         }
620
621         return 0;
622 }
623
624
625 /*
626   allocate a new id, attempting to do it atomically
627   return 0 on failure, the id on success
628 */
629 static NTSTATUS _samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, 
630                                         const char *attr, uint32_t *id)
631 {
632         struct ldb_wrap *sam_ctx = ctx;
633         struct ldb_message msg;
634         int ret;
635         const char *str;
636         struct ldb_val vals[2];
637         struct ldb_message_element els[2];
638
639         str = samdb_search_string(ctx, mem_ctx, NULL, attr, "dn=%s", dn);
640         if (!str) {
641                 DEBUG(1,("id not found at %s %s\n", dn, attr));
642                 return NT_STATUS_OBJECT_NAME_INVALID;
643         }
644
645         *id = strtol(str, NULL, 0);
646         if ((*id)+1 == 0) {
647                 /* out of IDs ! */
648                 return NT_STATUS_INSUFFICIENT_RESOURCES;
649         }
650
651         /* we do a delete and add as a single operation. That prevents
652            a race */
653         ZERO_STRUCT(msg);
654         msg.dn = talloc_strdup(mem_ctx, dn);
655         if (!msg.dn) {
656                 return NT_STATUS_NO_MEMORY;
657         }
658         msg.num_elements = 2;
659         msg.elements = els;
660
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);
665         if (!els[0].name) {
666                 return NT_STATUS_NO_MEMORY;
667         }
668
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;
673
674         vals[0].data = talloc_asprintf(mem_ctx, "%u", *id);
675         if (!vals[0].data) {
676                 return NT_STATUS_NO_MEMORY;
677         }
678         vals[0].length = strlen(vals[0].data);
679
680         vals[1].data = talloc_asprintf(mem_ctx, "%u", (*id)+1);
681         if (!vals[1].data) {
682                 return NT_STATUS_NO_MEMORY;
683         }
684         vals[1].length = strlen(vals[1].data);
685
686         ret = ldb_modify(sam_ctx->ldb, &msg);
687         if (ret != 0) {
688                 return NT_STATUS_UNEXPECTED_IO_ERROR;
689         }
690
691         (*id)++;
692
693         return NT_STATUS_OK;
694 }
695
696 /*
697   allocate a new id, attempting to do it atomically
698   return 0 on failure, the id on success
699 */
700 NTSTATUS samdb_allocate_next_id(void *ctx, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
701                                 uint32_t *id)
702 {
703         int tries = 10;
704         NTSTATUS status;
705
706         /* we need to try multiple times to cope with two account
707            creations at the same time */
708         while (tries--) {
709                 status = _samdb_allocate_next_id(ctx, mem_ctx, dn, attr, id);
710                 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
711                         break;
712                 }
713         }
714
715         if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
716                 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
717         }
718
719         return status;
720 }
721
722
723 /*
724   add a string element to a message
725 */
726 int samdb_msg_add_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
727                          const char *attr_name, const char *str)
728 {
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) {
733                 return -1;
734         }
735         return ldb_msg_add_string(sam_ctx->ldb, msg, a, s);
736 }
737
738 /*
739   add a delete element operation to a message
740 */
741 int samdb_msg_add_delete(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
742                          const char *attr_name)
743 {
744         struct ldb_wrap *sam_ctx = ctx;
745         char *a = talloc_strdup(mem_ctx, attr_name);
746         if (a == NULL) {
747                 return -1;
748         }
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);
752 }
753
754 /*
755   add a add attribute value to a message
756 */
757 int samdb_msg_add_addval(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
758                          const char *attr_name, const char *value)
759 {
760         struct ldb_wrap *sam_ctx = ctx;
761         struct ldb_message_element *el;
762         char *a, *v;
763         int ret;
764         a = talloc_strdup(mem_ctx, attr_name);
765         if (a == NULL)
766                 return -1;
767         v = talloc_strdup(mem_ctx, value);
768         if (v == NULL)
769                 return -1;
770         ret = ldb_msg_add_string(sam_ctx->ldb, msg, a, v);
771         if (ret != 0)
772                 return ret;
773         el = ldb_msg_find_element(msg, a);
774         if (el == NULL)
775                 return -1;
776         el->flags = LDB_FLAG_MOD_ADD;
777         return 0;
778 }
779
780 /*
781   add a delete attribute value to a message
782 */
783 int samdb_msg_add_delval(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784                          const char *attr_name, const char *value)
785 {
786         struct ldb_wrap *sam_ctx = ctx;
787         struct ldb_message_element *el;
788         char *a, *v;
789         int ret;
790         a = talloc_strdup(mem_ctx, attr_name);
791         if (a == NULL)
792                 return -1;
793         v = talloc_strdup(mem_ctx, value);
794         if (v == NULL)
795                 return -1;
796         ret = ldb_msg_add_string(sam_ctx->ldb, msg, a, v);
797         if (ret != 0)
798                 return ret;
799         el = ldb_msg_find_element(msg, a);
800         if (el == NULL)
801                 return -1;
802         el->flags = LDB_FLAG_MOD_DELETE;
803         return 0;
804 }
805
806 /*
807   add a uint_t element to a message
808 */
809 int samdb_msg_add_uint(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
810                        const char *attr_name, uint_t v)
811 {
812         const char *s = talloc_asprintf(mem_ctx, "%u", v);
813         return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
814 }
815
816 /*
817   add a (signed) int64_t element to a message
818 */
819 int samdb_msg_add_int64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
820                         const char *attr_name, int64_t v)
821 {
822         const char *s = talloc_asprintf(mem_ctx, "%lld", v);
823         return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
824 }
825
826 /*
827   add a uint64_t element to a message
828 */
829 int samdb_msg_add_uint64(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
830                         const char *attr_name, uint64_t v)
831 {
832         const char *s = talloc_asprintf(mem_ctx, "%llu", v);
833         return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, s);
834 }
835
836 /*
837   add a samr_Password element to a message
838 */
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)
841 {
842         struct ldb_wrap *sam_ctx = ctx;
843         struct ldb_val val;
844         val.data = talloc(mem_ctx, 16);
845         val.length = 16;
846         if (!val.data) {
847                 return -1;
848         }
849         memcpy(val.data, hash.hash, 16);
850         return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
851 }
852
853 /*
854   add a samr_Password array to a message
855 */
856 int samdb_msg_add_hashes(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
857                          const char *attr_name, struct samr_Password *hashes, uint_t count)
858 {
859         struct ldb_wrap *sam_ctx = ctx;
860         struct ldb_val val;
861         int i;
862         val.data = talloc(mem_ctx, count*16);
863         val.length = count*16;
864         if (!val.data) {
865                 return -1;
866         }
867         for (i=0;i<count;i++) {
868                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
869         }
870         return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
871 }
872
873 /*
874   add a acct_flags element to a message
875 */
876 int samdb_msg_add_acct_flags(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
877                              const char *attr_name, uint32_t v)
878 {
879         return samdb_msg_add_uint(ctx, mem_ctx, msg, attr_name, samdb_acb2uf(v));
880 }
881
882 /*
883   add a logon_hours element to a message
884 */
885 int samdb_msg_add_logon_hours(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
886                               const char *attr_name, struct samr_LogonHours *hours)
887 {
888         struct ldb_wrap *sam_ctx = ctx;
889         struct ldb_val val;
890         val.length = hours->units_per_week / 8;
891         val.data = hours->bitmap;
892         return ldb_msg_add_value(sam_ctx->ldb, msg, attr_name, &val);
893 }
894
895 /*
896   set a string element in a message
897 */
898 int samdb_msg_set_string(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
899                          const char *attr_name, const char *str)
900 {
901         struct ldb_message_element *el;
902
903         el = ldb_msg_find_element(msg, attr_name);
904         if (el) {
905                 el->num_values = 0;
906         }
907         return samdb_msg_add_string(ctx, mem_ctx, msg, attr_name, str);
908 }
909
910 /*
911   set a ldaptime element in a message
912 */
913 int samdb_msg_set_ldaptime(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
914                            const char *attr_name, time_t t)
915 {
916         char *str = ldap_timestring(mem_ctx, t);
917         if (!str) {
918                 return -1;
919         }
920         return samdb_msg_set_string(ctx, mem_ctx, msg, attr_name, str);
921 }
922
923 /*
924   add a record
925 */
926 int samdb_add(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
927 {
928         struct ldb_wrap *sam_ctx = ctx;
929
930         return ldb_add(sam_ctx->ldb, msg);
931 }
932
933 /*
934   delete a record
935 */
936 int samdb_delete(void *ctx, TALLOC_CTX *mem_ctx, const char *dn)
937 {
938         struct ldb_wrap *sam_ctx = ctx;
939
940         return ldb_delete(sam_ctx->ldb, dn);
941 }
942
943 /*
944   modify a record
945 */
946 int samdb_modify(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
947 {
948         struct ldb_wrap *sam_ctx = ctx;
949
950         return ldb_modify(sam_ctx->ldb, msg);
951 }
952
953 /*
954   replace elements in a record
955 */
956 int samdb_replace(void *ctx, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
957 {
958         int i;
959
960         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
961         for (i=0;i<msg->num_elements;i++) {
962                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
963         }
964
965         /* modify the samdb record */
966         return samdb_modify(ctx, mem_ctx, msg);
967 }
968
969 /*
970   return a default security descriptor
971 */
972 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
973 {
974         struct security_descriptor *sd;
975
976         sd = security_descriptor_initialise(mem_ctx);
977
978         return sd;
979 }