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