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