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