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