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