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