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