r14464: Don't include ndr_BASENAME.h files unless strictly required, instead
[kai/samba-autobuild/.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 "librpc/gen_ndr/ndr_misc.h"
26 #include "librpc/gen_ndr/ndr_security.h"
27 #include "lib/ldb/include/ldb.h"
28 #include "lib/ldb/include/ldb_errors.h"
29 #include "libcli/security/proto.h"
30 #include "system/time.h"
31 #include "system/filesys.h"
32 #include "db_wrap.h"
33 #include "dsdb/samdb/samdb.h"
34 #include "ads.h"
35
36 /*
37   connect to the SAM database
38   return an opaque context pointer on success, or NULL on failure
39  */
40 struct ldb_context *samdb_connect(TALLOC_CTX *mem_ctx, 
41                                   struct auth_session_info *session_info)
42 {
43         struct ldb_context *ldb;
44         ldb = ldb_wrap_connect(mem_ctx, lp_sam_url(), session_info,
45                                NULL, 0, NULL);
46         if (!ldb) {
47                 return NULL;
48         }
49         return ldb;
50 }
51
52 /*
53   search the sam for the specified attributes in a specific domain, filter on
54   objectSid being in domain_sid.
55 */
56 int samdb_search_domain(struct ldb_context *sam_ldb,
57                         TALLOC_CTX *mem_ctx, 
58                         const struct ldb_dn *basedn,
59                         struct ldb_message ***res,
60                         const char * const *attrs,
61                         const struct dom_sid *domain_sid,
62                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
63 {
64         va_list ap;
65         int i, count;
66
67         va_start(ap, format);
68         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
69                                res, attrs, format, ap);
70         va_end(ap);
71
72         i=0;
73
74         while (i<count) {
75                 struct dom_sid *entry_sid;
76
77                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
78
79                 if ((entry_sid == NULL) ||
80                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
81                         /* Delete that entry from the result set */
82                         (*res)[i] = (*res)[count-1];
83                         count -= 1;
84                         talloc_free(entry_sid);
85                         continue;
86                 }
87                 talloc_free(entry_sid);
88                 i += 1;
89         }
90
91         return count;
92 }
93
94 /*
95   search the sam for a single string attribute in exactly 1 record
96 */
97 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
98                                   TALLOC_CTX *mem_ctx,
99                                   const struct ldb_dn *basedn,
100                                   const char *attr_name,
101                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
102 {
103         int count;
104         const char *attrs[2] = { NULL, NULL };
105         struct ldb_message **res = NULL;
106
107         attrs[0] = attr_name;
108
109         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
110         if (count > 1) {                
111                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
112                          attr_name, format, count));
113         }
114         if (count != 1) {
115                 talloc_free(res);
116                 return NULL;
117         }
118
119         return samdb_result_string(res[0], attr_name, NULL);
120 }
121                                  
122
123 /*
124   search the sam for a single string attribute in exactly 1 record
125 */
126 const char *samdb_search_string(struct ldb_context *sam_ldb,
127                                 TALLOC_CTX *mem_ctx,
128                                 const struct ldb_dn *basedn,
129                                 const char *attr_name,
130                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
131 {
132         va_list ap;
133         const char *str;
134
135         va_start(ap, format);
136         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
137         va_end(ap);
138
139         return str;
140 }
141
142 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
143                                TALLOC_CTX *mem_ctx,
144                                const struct ldb_dn *basedn,
145                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
146 {
147         va_list ap;
148         struct ldb_dn *ret;
149         struct ldb_message **res = NULL;
150         int count;
151
152         va_start(ap, format);
153         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
154         va_end(ap);
155
156         if (count != 1) return NULL;
157
158         ret = talloc_steal(mem_ctx, res[0]->dn);
159         talloc_free(res);
160
161         return ret;
162 }
163
164 /*
165   search the sam for a dom_sid attribute in exactly 1 record
166 */
167 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
168                                      TALLOC_CTX *mem_ctx,
169                                      const struct ldb_dn *basedn,
170                                      const char *attr_name,
171                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
172 {
173         va_list ap;
174         int count;
175         struct ldb_message **res;
176         const char *attrs[2] = { NULL, NULL };
177         struct dom_sid *sid;
178
179         attrs[0] = attr_name;
180
181         va_start(ap, format);
182         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
183         va_end(ap);
184         if (count > 1) {                
185                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
186                          attr_name, format, count));
187         }
188         if (count != 1) {
189                 talloc_free(res);
190                 return NULL;
191         }
192         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
193         talloc_free(res);
194         return sid;     
195 }
196
197 /*
198   return the count of the number of records in the sam matching the query
199 */
200 int samdb_search_count(struct ldb_context *sam_ldb,
201                        TALLOC_CTX *mem_ctx,
202                        const struct ldb_dn *basedn,
203                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
204 {
205         va_list ap;
206         struct ldb_message **res;
207         const char * const attrs[] = { NULL };
208         int ret;
209
210         va_start(ap, format);
211         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
212         va_end(ap);
213
214         return ret;
215 }
216
217
218 /*
219   search the sam for a single integer attribute in exactly 1 record
220 */
221 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
222                          TALLOC_CTX *mem_ctx,
223                          uint_t default_value,
224                          const struct ldb_dn *basedn,
225                          const char *attr_name,
226                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
227 {
228         va_list ap;
229         int count;
230         struct ldb_message **res;
231         const char *attrs[2] = { NULL, NULL };
232
233         attrs[0] = attr_name;
234
235         va_start(ap, format);
236         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
237         va_end(ap);
238
239         if (count != 1) {
240                 return default_value;
241         }
242
243         return samdb_result_uint(res[0], attr_name, default_value);
244 }
245
246 /*
247   search the sam for a single signed 64 bit integer attribute in exactly 1 record
248 */
249 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
250                            TALLOC_CTX *mem_ctx,
251                            int64_t default_value,
252                            const struct ldb_dn *basedn,
253                            const char *attr_name,
254                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
255 {
256         va_list ap;
257         int count;
258         struct ldb_message **res;
259         const char *attrs[2] = { NULL, NULL };
260
261         attrs[0] = attr_name;
262
263         va_start(ap, format);
264         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
265         va_end(ap);
266
267         if (count != 1) {
268                 return default_value;
269         }
270
271         return samdb_result_int64(res[0], attr_name, default_value);
272 }
273
274 /*
275   search the sam for multipe records each giving a single string attribute
276   return the number of matches, or -1 on error
277 */
278 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
279                                  TALLOC_CTX *mem_ctx,
280                                  const struct ldb_dn *basedn,
281                                  const char ***strs,
282                                  const char *attr_name,
283                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
284 {
285         va_list ap;
286         int count, i;
287         const char *attrs[2] = { NULL, NULL };
288         struct ldb_message **res = NULL;
289
290         attrs[0] = attr_name;
291
292         va_start(ap, format);
293         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
294         va_end(ap);
295
296         if (count <= 0) {
297                 return count;
298         }
299
300         /* make sure its single valued */
301         for (i=0;i<count;i++) {
302                 if (res[i]->num_elements != 1) {
303                         DEBUG(1,("samdb: search for %s %s not single valued\n", 
304                                  attr_name, format));
305                         talloc_free(res);
306                         return -1;
307                 }
308         }
309
310         *strs = talloc_array(mem_ctx, const char *, count+1);
311         if (! *strs) {
312                 talloc_free(res);
313                 return -1;
314         }
315
316         for (i=0;i<count;i++) {
317                 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
318         }
319         (*strs)[count] = NULL;
320
321         return count;
322 }
323
324 /*
325   pull a uint from a result set. 
326 */
327 uint_t samdb_result_uint(struct ldb_message *msg, const char *attr, uint_t default_value)
328 {
329         return ldb_msg_find_uint(msg, attr, default_value);
330 }
331
332 /*
333   pull a (signed) int64 from a result set. 
334 */
335 int64_t samdb_result_int64(struct ldb_message *msg, const char *attr, int64_t default_value)
336 {
337         return ldb_msg_find_int64(msg, attr, default_value);
338 }
339
340 /*
341   pull a string from a result set. 
342 */
343 const char *samdb_result_string(struct ldb_message *msg, const char *attr, 
344                                 const char *default_value)
345 {
346         return ldb_msg_find_string(msg, attr, default_value);
347 }
348
349 struct ldb_dn *samdb_result_dn(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
350                                const char *attr, struct ldb_dn *default_value)
351 {
352         const char *string = samdb_result_string(msg, attr, NULL);
353         if (string == NULL) return default_value;
354         return ldb_dn_explode(mem_ctx, string);
355 }
356
357 /*
358   pull a rid from a objectSid in a result set. 
359 */
360 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
361                                    const char *attr, uint32_t default_value)
362 {
363         struct dom_sid *sid;
364         uint32_t rid;
365
366         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
367         if (sid == NULL) {
368                 return default_value;
369         }
370         rid = sid->sub_auths[sid->num_auths-1];
371         talloc_free(sid);
372         return rid;
373 }
374
375 /*
376   pull a dom_sid structure from a objectSid in a result set. 
377 */
378 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
379                                      const char *attr)
380 {
381         const struct ldb_val *v;
382         struct dom_sid *sid;
383         NTSTATUS status;
384         v = ldb_msg_find_ldb_val(msg, attr);
385         if (v == NULL) {
386                 return NULL;
387         }
388         sid = talloc(mem_ctx, struct dom_sid);
389         if (sid == NULL) {
390                 return NULL;
391         }
392         status = ndr_pull_struct_blob(v, sid, sid, 
393                                       (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
394         if (!NT_STATUS_IS_OK(status)) {
395                 talloc_free(sid);
396                 return NULL;
397         }
398         return sid;
399 }
400
401 /*
402   pull a guid structure from a objectGUID in a result set. 
403 */
404 struct GUID samdb_result_guid(struct ldb_message *msg, const char *attr)
405 {
406         const struct ldb_val *v;
407         NTSTATUS status;
408         struct GUID guid;
409         TALLOC_CTX *mem_ctx;
410
411         ZERO_STRUCT(guid);
412
413         v = ldb_msg_find_ldb_val(msg, attr);
414         if (!v) return guid;
415
416         mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
417         if (!mem_ctx) return guid;
418         status = ndr_pull_struct_blob(v, mem_ctx, &guid, 
419                                       (ndr_pull_flags_fn_t)ndr_pull_GUID);
420         talloc_free(mem_ctx);
421         if (!NT_STATUS_IS_OK(status)) {
422                 return guid;
423         }
424
425         return guid;
426 }
427
428 /*
429   pull a sid prefix from a objectSid in a result set. 
430   this is used to find the domain sid for a user
431 */
432 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
433                                         const char *attr)
434 {
435         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
436         if (!sid || sid->num_auths < 1) return NULL;
437         sid->num_auths--;
438         return sid;
439 }
440
441 /*
442   pull a NTTIME in a result set. 
443 */
444 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
445 {
446         const char *str = ldb_msg_find_string(msg, attr, NULL);
447         if (!str) return default_value;
448         return nttime_from_string(str);
449 }
450
451 /*
452   pull a uint64_t from a result set. 
453 */
454 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
455 {
456         return ldb_msg_find_uint64(msg, attr, default_value);
457 }
458
459
460 /*
461   construct the allow_password_change field from the PwdLastSet attribute and the 
462   domain password settings
463 */
464 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
465                                           TALLOC_CTX *mem_ctx, 
466                                           const struct ldb_dn *domain_dn, 
467                                           struct ldb_message *msg, 
468                                           const char *attr)
469 {
470         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
471         int64_t minPwdAge;
472
473         if (attr_time == 0) {
474                 return 0;
475         }
476
477         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
478
479         /* yes, this is a -= not a += as minPwdAge is stored as the negative
480            of the number of 100-nano-seconds */
481         attr_time -= minPwdAge;
482
483         return attr_time;
484 }
485
486 /*
487   construct the force_password_change field from the PwdLastSet attribute and the 
488   domain password settings
489 */
490 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, 
491                                           TALLOC_CTX *mem_ctx, 
492                                           const struct ldb_dn *domain_dn, 
493                                           struct ldb_message *msg)
494 {
495         uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
496         uint32_t user_flags = samdb_result_uint64(msg, "userAccountControl", 0);
497         int64_t maxPwdAge;
498
499         if (user_flags & UF_DONT_EXPIRE_PASSWD) {
500                 return 0x7FFFFFFFFFFFFFFFULL;
501         }
502
503         if (attr_time == 0) {
504                 return 0;
505         }
506
507         maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
508         if (maxPwdAge == 0) {
509                 return 0;
510         } else {
511                 attr_time -= maxPwdAge;
512         }
513
514         return attr_time;
515 }
516
517 /*
518   pull a samr_Password structutre from a result set. 
519 */
520 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
521 {
522         struct samr_Password *hash = NULL;
523         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
524         if (val && (val->length >= sizeof(hash->hash))) {
525                 hash = talloc(mem_ctx, struct samr_Password);
526                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
527         }
528         return hash;
529 }
530
531 /*
532   pull an array of samr_Password structutres from a result set. 
533 */
534 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
535                            const char *attr, struct samr_Password **hashes)
536 {
537         uint_t count = 0;
538         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
539         int i;
540
541         *hashes = NULL;
542         if (!val) {
543                 return 0;
544         }
545         count = val->length / 16;
546         if (count == 0) {
547                 return 0;
548         }
549
550         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
551         if (! *hashes) {
552                 return 0;
553         }
554
555         for (i=0;i<count;i++) {
556                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
557         }
558
559         return count;
560 }
561
562 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
563                                 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
564 {
565         struct samr_Password *lmPwdHash, *ntPwdHash;
566         if (nt_pwd) {
567                 int num_nt;
568                 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
569                 if (num_nt == 0) {
570                         *nt_pwd = NULL;
571                 } else if (num_nt > 1) {
572                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
573                 } else {
574                         *nt_pwd = &ntPwdHash[0];
575                 }
576         }
577         if (lm_pwd) {
578                 int num_lm;
579                 num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
580                 if (num_lm == 0) {
581                         *lm_pwd = NULL;
582                 } else if (num_lm > 1) {
583                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
584                 } else {
585                         *lm_pwd = &lmPwdHash[0];
586                 }
587         }
588         return NT_STATUS_OK;
589 }
590
591 /*
592   pull a samr_LogonHours structutre from a result set. 
593 */
594 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
595 {
596         struct samr_LogonHours hours;
597         const int units_per_week = 168;
598         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
599         ZERO_STRUCT(hours);
600         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
601         if (!hours.bits) {
602                 return hours;
603         }
604         hours.units_per_week = units_per_week;
605         memset(hours.bits, 0xFF, units_per_week);
606         if (val) {
607                 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
608         }
609         return hours;
610 }
611
612 /*
613   pull a set of account_flags from a result set. 
614 */
615 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
616 {
617         uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
618         return samdb_uf2acb(userAccountControl);
619 }
620
621 /*
622   copy from a template record to a message
623 */
624 int samdb_copy_template(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, 
625                         struct ldb_message *msg, const char *expression)
626 {
627         struct ldb_message **res, *t;
628         int ret, i, j;
629         
630
631         /* pull the template record */
632         ret = gendb_search(sam_ldb, mem_ctx, NULL, &res, NULL, "%s", expression);
633         if (ret != 1) {
634                 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n", 
635                          expression, ret));
636                 return -1;
637         }
638         t = res[0];
639
640         for (i=0;i<t->num_elements;i++) {
641                 struct ldb_message_element *el = &t->elements[i];
642                 /* some elements should not be copied from the template */
643                 if (strcasecmp(el->name, "cn") == 0 ||
644                     strcasecmp(el->name, "name") == 0 ||
645                     strcasecmp(el->name, "sAMAccountName") == 0) {
646                         continue;
647                 }
648                 for (j=0;j<el->num_values;j++) {
649                         if (strcasecmp(el->name, "objectClass") == 0 &&
650                             (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
651                              strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
652                              strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
653                              strcasecmp((char *)el->values[j].data, "foreignSecurityTemplate") == 0 ||
654                              strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 || 
655                              strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 || 
656                              strcasecmp((char *)el->values[j].data, "secretTemplate") == 0)) {
657                                 continue;
658                         }
659                         samdb_msg_add_string(sam_ldb, mem_ctx, msg, el->name, 
660                                              (char *)el->values[j].data);
661                 }
662         }
663
664         return 0;
665 }
666
667
668 /*
669   add a string element to a message
670 */
671 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
672                          const char *attr_name, const char *str)
673 {
674         char *s = talloc_strdup(mem_ctx, str);
675         char *a = talloc_strdup(mem_ctx, attr_name);
676         if (s == NULL || a == NULL) {
677                 return -1;
678         }
679         return ldb_msg_add_string(msg, a, s);
680 }
681
682 /*
683   add a dom_sid element to a message
684 */
685 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
686                          const char *attr_name, struct dom_sid *sid)
687 {
688         struct ldb_val v;
689         NTSTATUS status;
690         status = ndr_push_struct_blob(&v, mem_ctx, sid, 
691                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
692         if (!NT_STATUS_IS_OK(status)) {
693                 return -1;
694         }
695         return ldb_msg_add_value(msg, attr_name, &v);
696 }
697
698
699 /*
700   add a delete element operation to a message
701 */
702 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
703                          const char *attr_name)
704 {
705         /* we use an empty replace rather than a delete, as it allows for 
706            samdb_replace() to be used everywhere */
707         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE);
708 }
709
710 /*
711   add a add attribute value to a message
712 */
713 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
714                          const char *attr_name, const char *value)
715 {
716         struct ldb_message_element *el;
717         char *a, *v;
718         int ret;
719         a = talloc_strdup(mem_ctx, attr_name);
720         if (a == NULL)
721                 return -1;
722         v = talloc_strdup(mem_ctx, value);
723         if (v == NULL)
724                 return -1;
725         ret = ldb_msg_add_string(msg, a, v);
726         if (ret != 0)
727                 return ret;
728         el = ldb_msg_find_element(msg, a);
729         if (el == NULL)
730                 return -1;
731         el->flags = LDB_FLAG_MOD_ADD;
732         return 0;
733 }
734
735 /*
736   add a delete attribute value to a message
737 */
738 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
739                          const char *attr_name, const char *value)
740 {
741         struct ldb_message_element *el;
742         char *a, *v;
743         int ret;
744         a = talloc_strdup(mem_ctx, attr_name);
745         if (a == NULL)
746                 return -1;
747         v = talloc_strdup(mem_ctx, value);
748         if (v == NULL)
749                 return -1;
750         ret = ldb_msg_add_string(msg, a, v);
751         if (ret != 0)
752                 return ret;
753         el = ldb_msg_find_element(msg, a);
754         if (el == NULL)
755                 return -1;
756         el->flags = LDB_FLAG_MOD_DELETE;
757         return 0;
758 }
759
760 /*
761   add a uint_t element to a message
762 */
763 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
764                        const char *attr_name, uint_t v)
765 {
766         const char *s = talloc_asprintf(mem_ctx, "%u", v);
767         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
768 }
769
770 /*
771   add a (signed) int64_t element to a message
772 */
773 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
774                         const char *attr_name, int64_t v)
775 {
776         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
777         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
778 }
779
780 /*
781   add a uint64_t element to a message
782 */
783 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
784                         const char *attr_name, uint64_t v)
785 {
786         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
787         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
788 }
789
790 /*
791   add a samr_Password element to a message
792 */
793 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
794                        const char *attr_name, struct samr_Password *hash)
795 {
796         struct ldb_val val;
797         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
798         if (!val.data) {
799                 return -1;
800         }
801         val.length = 16;
802         return ldb_msg_add_value(msg, attr_name, &val);
803 }
804
805 /*
806   add a samr_Password array to a message
807 */
808 int samdb_msg_add_hashes(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
809                          const char *attr_name, struct samr_Password *hashes, uint_t count)
810 {
811         struct ldb_val val;
812         int i;
813         val.data = talloc_array_size(mem_ctx, 16, count);
814         val.length = count*16;
815         if (!val.data) {
816                 return -1;
817         }
818         for (i=0;i<count;i++) {
819                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
820         }
821         return ldb_msg_add_value(msg, attr_name, &val);
822 }
823
824 /*
825   add a acct_flags element to a message
826 */
827 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
828                              const char *attr_name, uint32_t v)
829 {
830         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
831 }
832
833 /*
834   add a logon_hours element to a message
835 */
836 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
837                               const char *attr_name, struct samr_LogonHours *hours)
838 {
839         struct ldb_val val;
840         val.length = hours->units_per_week / 8;
841         val.data = hours->bits;
842         return ldb_msg_add_value(msg, attr_name, &val);
843 }
844
845 /*
846   add a general value element to a message
847 */
848 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
849                               const char *attr_name, const struct ldb_val *val)
850 {
851         return ldb_msg_add_value(msg, attr_name, val);
852 }
853
854 /*
855   sets a general value element to a message
856 */
857 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
858                         const char *attr_name, const struct ldb_val *val)
859 {
860         struct ldb_message_element *el;
861
862         el = ldb_msg_find_element(msg, attr_name);
863         if (el) {
864                 el->num_values = 0;
865         }
866         return ldb_msg_add_value(msg, attr_name, val);
867 }
868
869 /*
870   set a string element in a message
871 */
872 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
873                          const char *attr_name, const char *str)
874 {
875         struct ldb_message_element *el;
876
877         el = ldb_msg_find_element(msg, attr_name);
878         if (el) {
879                 el->num_values = 0;
880         }
881         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
882 }
883
884 /*
885   add a record
886 */
887 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
888 {
889         return ldb_add(sam_ldb, msg);
890 }
891
892 /*
893   delete a record
894 */
895 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const struct ldb_dn *dn)
896 {
897         return ldb_delete(sam_ldb, dn);
898 }
899
900 /*
901   modify a record
902 */
903 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
904 {
905         return ldb_modify(sam_ldb, msg);
906 }
907
908 /*
909   replace elements in a record
910 */
911 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
912 {
913         int i;
914
915         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
916         for (i=0;i<msg->num_elements;i++) {
917                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
918         }
919
920         /* modify the samdb record */
921         return samdb_modify(sam_ldb, mem_ctx, msg);
922 }
923
924 /*
925   return a default security descriptor
926 */
927 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
928 {
929         struct security_descriptor *sd;
930
931         sd = security_descriptor_initialise(mem_ctx);
932
933         return sd;
934 }
935
936 struct ldb_dn *samdb_base_dn(TALLOC_CTX *mem_ctx) 
937 {
938         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
939         int server_role = lp_server_role();
940         const char **split_realm;
941         struct ldb_dn *dn;
942         
943         if (!tmp_ctx) {
944                 return NULL;
945         }
946
947         if ((server_role == ROLE_DOMAIN_PDC)
948             || (server_role == ROLE_DOMAIN_BDC)) {
949                 int i;
950                 split_realm = str_list_make(tmp_ctx, lp_realm(), ".");
951                 if (!split_realm) {
952                         talloc_free(tmp_ctx);
953                         return NULL;
954                 }
955                 dn = NULL;
956                 i = str_list_length(split_realm);
957                 i--;
958                 for (; i >= 0; i--) {
959                         dn = ldb_dn_build_child(tmp_ctx, "dc", split_realm[i], dn);
960                         if (!dn) {
961                                 talloc_free(tmp_ctx);
962                                 return NULL;
963                         }
964                 }
965                 return dn;
966         }
967         return ldb_dn_string_compose(mem_ctx, NULL, "cn=%s", lp_netbios_name());
968 }
969
970
971 /*
972   work out the domain sid for the current open ldb
973 */
974 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
975 {
976         const char *attrs[] = { "rootDomainNamingContext", NULL };
977         int ret;
978         struct ldb_result *res = NULL;
979         TALLOC_CTX *tmp_ctx;
980         struct dom_sid *domain_sid;
981         const char *basedn_s;
982         struct ldb_dn *basedn;
983
984         /* see if we have a cached copy */
985         domain_sid = ldb_get_opaque(ldb, "cache.domain_sid");
986         if (domain_sid) {
987                 return domain_sid;
988         }
989
990         tmp_ctx = talloc_new(ldb);
991         if (tmp_ctx == NULL) {
992                 goto failed;
993         }
994
995         basedn = ldb_dn_explode(tmp_ctx, "");
996         if (basedn == NULL) {
997                 goto failed;
998         }
999         
1000         /* find the basedn of the domain from the rootdse */
1001         ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, attrs, &res);
1002         talloc_steal(tmp_ctx, res);
1003         if (ret != LDB_SUCCESS || res->count != 1) {
1004                 goto failed;
1005         }
1006
1007         basedn_s = ldb_msg_find_string(res->msgs[0], "rootDomainNamingContext", NULL);
1008         if (basedn_s == NULL) {
1009                 goto failed;
1010         }
1011
1012         basedn = ldb_dn_explode(tmp_ctx, basedn_s);
1013         if (basedn == NULL) {
1014                 goto failed;
1015         }
1016
1017         /* find the domain_sid */
1018         domain_sid = samdb_search_dom_sid(ldb, tmp_ctx, basedn, 
1019                                           "objectSid", "objectClass=domainDNS");
1020         if (domain_sid == NULL) {
1021                 goto failed;
1022         }
1023
1024         /* cache the domain_sid in the ldb */
1025         if (ldb_set_opaque(ldb, "cache.domain_sid", domain_sid) != LDB_SUCCESS) {
1026                 goto failed;
1027         }
1028
1029         talloc_steal(ldb, domain_sid);
1030         talloc_free(tmp_ctx);
1031
1032         return domain_sid;
1033
1034 failed:
1035         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1036         talloc_free(tmp_ctx);
1037         return NULL;
1038 }