fd542c5567f8e5f95dbd0e0b2c6c9f32b381742a
[sfrench/samba-autobuild/.git] / source4 / dsdb / samdb / samdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    interface functions for the sam database
5
6    Copyright (C) Andrew Tridgell 2004
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "librpc/gen_ndr/ndr_netlogon.h"
25 #include "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", "dn=%s", domain_dn);
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, 
451                                        "maxPwdAge", "dn=%s", domain_dn);
452         if (maxPwdAge == 0) {
453                 return 0;
454         } else {
455                 attr_time -= maxPwdAge;
456         }
457
458         return attr_time;
459 }
460
461 /*
462   pull a samr_Password structutre from a result set. 
463 */
464 struct samr_Password samdb_result_hash(struct ldb_message *msg, const char *attr)
465 {
466         struct samr_Password hash;
467         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
468         ZERO_STRUCT(hash);
469         if (val) {
470                 memcpy(hash.hash, val->data, MIN(val->length, sizeof(hash.hash)));
471         }
472         return hash;
473 }
474
475 /*
476   pull an array of samr_Password structutres from a result set. 
477 */
478 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
479                            const char *attr, struct samr_Password **hashes)
480 {
481         uint_t count = 0;
482         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
483         int i;
484
485         *hashes = NULL;
486         if (!val) {
487                 return 0;
488         }
489         count = val->length / 16;
490         if (count == 0) {
491                 return 0;
492         }
493
494         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
495         if (! *hashes) {
496                 return 0;
497         }
498
499         for (i=0;i<count;i++) {
500                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
501         }
502
503         return count;
504 }
505
506 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
507                                 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
508 {
509
510         const char *unicodePwd = samdb_result_string(msg, "unicodePwd", NULL);
511         
512         struct samr_Password *lmPwdHash, *ntPwdHash;
513         if (unicodePwd) {
514                 if (nt_pwd) {
515                         ntPwdHash = talloc(mem_ctx, struct samr_Password);
516                         if (!ntPwdHash) {
517                                 return NT_STATUS_NO_MEMORY;
518                         }
519                         
520                         E_md4hash(unicodePwd, ntPwdHash->hash);
521                         *nt_pwd = ntPwdHash;
522                 }
523
524                 if (lm_pwd) {
525                         BOOL lm_hash_ok;
526                 
527                         lmPwdHash = talloc(mem_ctx, struct samr_Password);
528                         if (!lmPwdHash) {
529                                 return NT_STATUS_NO_MEMORY;
530                         }
531                         
532                         /* compute the new nt and lm hashes */
533                         lm_hash_ok = E_deshash(unicodePwd, lmPwdHash->hash);
534                         
535                         if (lm_hash_ok) {
536                                 *lm_pwd = lmPwdHash;
537                         } else {
538                                 *lm_pwd = NULL;
539                         }
540                 }
541         } else {
542                 if (nt_pwd) {
543                         int num_nt;
544                         num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHash", &ntPwdHash);
545                         if (num_nt == 0) {
546                                 *nt_pwd = NULL;
547                         } else if (num_nt > 1) {
548                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
549                         } else {
550                                 *nt_pwd = &ntPwdHash[0];
551                         }
552                 }
553                 if (lm_pwd) {
554                         int num_lm;
555                         num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHash", &lmPwdHash);
556                         if (num_lm == 0) {
557                                 *lm_pwd = NULL;
558                         } else if (num_lm > 1) {
559                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
560                         } else {
561                                 *lm_pwd = &lmPwdHash[0];
562                         }
563                 }
564                 
565         }
566         return NT_STATUS_OK;
567 }
568
569 /*
570   pull a samr_LogonHours structutre from a result set. 
571 */
572 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
573 {
574         struct samr_LogonHours hours;
575         const int units_per_week = 168;
576         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
577         ZERO_STRUCT(hours);
578         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
579         if (!hours.bits) {
580                 return hours;
581         }
582         hours.units_per_week = units_per_week;
583         memset(hours.bits, 0xFF, units_per_week);
584         if (val) {
585                 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
586         }
587         return hours;
588 }
589
590 /*
591   pull a set of account_flags from a result set. 
592 */
593 uint16_t samdb_result_acct_flags(struct ldb_message *msg, const char *attr)
594 {
595         uint_t userAccountControl = ldb_msg_find_uint(msg, attr, 0);
596         return samdb_uf2acb(userAccountControl);
597 }
598
599 /*
600   copy from a template record to a message
601 */
602 int samdb_copy_template(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, 
603                         struct ldb_message *msg, const char *expression)
604 {
605         struct ldb_message **res, *t;
606         int ret, i, j;
607         
608
609         /* pull the template record */
610         ret = gendb_search(sam_ldb, mem_ctx, NULL, &res, NULL, "%s", expression);
611         if (ret != 1) {
612                 DEBUG(1,("samdb: ERROR: template '%s' matched %d records\n", 
613                          expression, ret));
614                 return -1;
615         }
616         t = res[0];
617
618         for (i=0;i<t->num_elements;i++) {
619                 struct ldb_message_element *el = &t->elements[i];
620                 /* some elements should not be copied from the template */
621                 if (strcasecmp(el->name, "cn") == 0 ||
622                     strcasecmp(el->name, "name") == 0 ||
623                     strcasecmp(el->name, "sAMAccountName") == 0) {
624                         continue;
625                 }
626                 for (j=0;j<el->num_values;j++) {
627                         if (strcasecmp(el->name, "objectClass") == 0 &&
628                             (strcasecmp((char *)el->values[j].data, "Template") == 0 ||
629                              strcasecmp((char *)el->values[j].data, "userTemplate") == 0 ||
630                              strcasecmp((char *)el->values[j].data, "groupTemplate") == 0 ||
631                              strcasecmp((char *)el->values[j].data, "foreignSecurityTemplate") == 0 ||
632                              strcasecmp((char *)el->values[j].data, "aliasTemplate") == 0 || 
633                              strcasecmp((char *)el->values[j].data, "trustedDomainTemplate") == 0 || 
634                              strcasecmp((char *)el->values[j].data, "secretTemplate") == 0)) {
635                                 continue;
636                         }
637                         samdb_msg_add_string(sam_ldb, mem_ctx, msg, el->name, 
638                                              (char *)el->values[j].data);
639                 }
640         }
641
642         return 0;
643 }
644
645
646 /*
647   allocate a new id, attempting to do it atomically
648   return 0 on failure, the id on success
649 */
650 static NTSTATUS _samdb_allocate_next_id(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const char *dn, 
651                                         const char *attr, uint32_t *id)
652 {
653         struct ldb_message msg;
654         int ret;
655         const char *str;
656         struct ldb_val vals[2];
657         struct ldb_message_element els[2];
658
659         str = samdb_search_string(sam_ldb, mem_ctx, dn, attr, "dn=%s", dn);
660         if (!str) {
661                 DEBUG(1,("id not found at %s %s\n", dn, attr));
662                 return NT_STATUS_OBJECT_NAME_INVALID;
663         }
664
665         *id = strtol(str, NULL, 0);
666         if ((*id)+1 == 0) {
667                 /* out of IDs ! */
668                 return NT_STATUS_INSUFFICIENT_RESOURCES;
669         }
670
671         /* we do a delete and add as a single operation. That prevents
672            a race */
673         ZERO_STRUCT(msg);
674         msg.dn = talloc_strdup(mem_ctx, dn);
675         if (!msg.dn) {
676                 return NT_STATUS_NO_MEMORY;
677         }
678         msg.num_elements = 2;
679         msg.elements = els;
680
681         els[0].num_values = 1;
682         els[0].values = &vals[0];
683         els[0].flags = LDB_FLAG_MOD_DELETE;
684         els[0].name = talloc_strdup(mem_ctx, attr);
685         if (!els[0].name) {
686                 return NT_STATUS_NO_MEMORY;
687         }
688
689         els[1].num_values = 1;
690         els[1].values = &vals[1];
691         els[1].flags = LDB_FLAG_MOD_ADD;
692         els[1].name = els[0].name;
693
694         vals[0].data = (uint8_t *)talloc_asprintf(mem_ctx, "%u", *id);
695         if (!vals[0].data) {
696                 return NT_STATUS_NO_MEMORY;
697         }
698         vals[0].length = strlen((const char *)vals[0].data);
699
700         vals[1].data =  (uint8_t *)talloc_asprintf(mem_ctx, "%u", (*id)+1);
701         if (!vals[1].data) {
702                 return NT_STATUS_NO_MEMORY;
703         }
704         vals[1].length = strlen((const char *)vals[1].data);
705
706         ret = ldb_modify(sam_ldb, &msg);
707         if (ret != 0) {
708                 return NT_STATUS_UNEXPECTED_IO_ERROR;
709         }
710
711         (*id)++;
712
713         return NT_STATUS_OK;
714 }
715
716 /*
717   allocate a new id, attempting to do it atomically
718   return 0 on failure, the id on success
719 */
720 NTSTATUS samdb_allocate_next_id(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const char *dn, const char *attr,
721                                 uint32_t *id)
722 {
723         int tries = 10;
724         NTSTATUS status;
725
726         /* we need to try multiple times to cope with two account
727            creations at the same time */
728         while (tries--) {
729                 status = _samdb_allocate_next_id(sam_ldb, mem_ctx, dn, attr, id);
730                 if (!NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
731                         break;
732                 }
733         }
734
735         if (NT_STATUS_EQUAL(NT_STATUS_UNEXPECTED_IO_ERROR, status)) {
736                 DEBUG(1,("Failed to increment id %s at %s\n", attr, dn));
737         }
738
739         return status;
740 }
741
742
743 /*
744   add a string element to a message
745 */
746 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
747                          const char *attr_name, const char *str)
748 {
749         char *s = talloc_strdup(mem_ctx, str);
750         char *a = talloc_strdup(mem_ctx, attr_name);
751         if (s == NULL || a == NULL) {
752                 return -1;
753         }
754         return ldb_msg_add_string(sam_ldb, msg, a, s);
755 }
756
757 /*
758   add a dom_sid element to a message
759 */
760 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
761                          const char *attr_name, struct dom_sid *sid)
762 {
763         struct ldb_val v;
764         NTSTATUS status;
765         status = ndr_push_struct_blob(&v, mem_ctx, sid, 
766                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
767         if (!NT_STATUS_IS_OK(status)) {
768                 return -1;
769         }
770         return ldb_msg_add_value(sam_ldb, msg, attr_name, &v);
771 }
772
773
774 /*
775   add a delete element operation to a message
776 */
777 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
778                          const char *attr_name)
779 {
780         char *a = talloc_strdup(mem_ctx, attr_name);
781         if (a == NULL) {
782                 return -1;
783         }
784         /* we use an empty replace rather than a delete, as it allows for 
785            samdb_replace() to be used everywhere */
786         return ldb_msg_add_empty(sam_ldb, msg, a, LDB_FLAG_MOD_REPLACE);
787 }
788
789 /*
790   add a add attribute value to a message
791 */
792 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
793                          const char *attr_name, const char *value)
794 {
795         struct ldb_message_element *el;
796         char *a, *v;
797         int ret;
798         a = talloc_strdup(mem_ctx, attr_name);
799         if (a == NULL)
800                 return -1;
801         v = talloc_strdup(mem_ctx, value);
802         if (v == NULL)
803                 return -1;
804         ret = ldb_msg_add_string(sam_ldb, msg, a, v);
805         if (ret != 0)
806                 return ret;
807         el = ldb_msg_find_element(msg, a);
808         if (el == NULL)
809                 return -1;
810         el->flags = LDB_FLAG_MOD_ADD;
811         return 0;
812 }
813
814 /*
815   add a delete attribute value to a message
816 */
817 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
818                          const char *attr_name, const char *value)
819 {
820         struct ldb_message_element *el;
821         char *a, *v;
822         int ret;
823         a = talloc_strdup(mem_ctx, attr_name);
824         if (a == NULL)
825                 return -1;
826         v = talloc_strdup(mem_ctx, value);
827         if (v == NULL)
828                 return -1;
829         ret = ldb_msg_add_string(sam_ldb, msg, a, v);
830         if (ret != 0)
831                 return ret;
832         el = ldb_msg_find_element(msg, a);
833         if (el == NULL)
834                 return -1;
835         el->flags = LDB_FLAG_MOD_DELETE;
836         return 0;
837 }
838
839 /*
840   add a uint_t element to a message
841 */
842 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
843                        const char *attr_name, uint_t v)
844 {
845         const char *s = talloc_asprintf(mem_ctx, "%u", v);
846         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
847 }
848
849 /*
850   add a (signed) int64_t element to a message
851 */
852 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
853                         const char *attr_name, int64_t v)
854 {
855         const char *s = talloc_asprintf(mem_ctx, "%lld", v);
856         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
857 }
858
859 /*
860   add a uint64_t element to a message
861 */
862 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
863                         const char *attr_name, uint64_t v)
864 {
865         const char *s = talloc_asprintf(mem_ctx, "%llu", v);
866         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
867 }
868
869 /*
870   add a samr_Password element to a message
871 */
872 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
873                        const char *attr_name, struct samr_Password *hash)
874 {
875         struct ldb_val val;
876         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
877         if (!val.data) {
878                 return -1;
879         }
880         val.length = 16;
881         return ldb_msg_add_value(sam_ldb, msg, attr_name, &val);
882 }
883
884 /*
885   add a samr_Password array to a message
886 */
887 int samdb_msg_add_hashes(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
888                          const char *attr_name, struct samr_Password *hashes, uint_t count)
889 {
890         struct ldb_val val;
891         int i;
892         val.data = talloc_array_size(mem_ctx, 16, count);
893         val.length = count*16;
894         if (!val.data) {
895                 return -1;
896         }
897         for (i=0;i<count;i++) {
898                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
899         }
900         return ldb_msg_add_value(sam_ldb, msg, attr_name, &val);
901 }
902
903 /*
904   add a acct_flags element to a message
905 */
906 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
907                              const char *attr_name, uint32_t v)
908 {
909         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
910 }
911
912 /*
913   add a logon_hours element to a message
914 */
915 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
916                               const char *attr_name, struct samr_LogonHours *hours)
917 {
918         struct ldb_val val;
919         val.length = hours->units_per_week / 8;
920         val.data = hours->bits;
921         return ldb_msg_add_value(sam_ldb, msg, attr_name, &val);
922 }
923
924 /*
925   add a general value element to a message
926 */
927 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
928                               const char *attr_name, const struct ldb_val *val)
929 {
930         return ldb_msg_add_value(sam_ldb, msg, attr_name, val);
931 }
932
933 /*
934   sets a general value element to a message
935 */
936 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
937                         const char *attr_name, const struct ldb_val *val)
938 {
939         struct ldb_message_element *el;
940
941         el = ldb_msg_find_element(msg, attr_name);
942         if (el) {
943                 el->num_values = 0;
944         }
945         return ldb_msg_add_value(sam_ldb, msg, attr_name, val);
946 }
947
948 /*
949   set a string element in a message
950 */
951 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
952                          const char *attr_name, const char *str)
953 {
954         struct ldb_message_element *el;
955
956         el = ldb_msg_find_element(msg, attr_name);
957         if (el) {
958                 el->num_values = 0;
959         }
960         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
961 }
962
963 /*
964   set a ldaptime element in a message
965 */
966 int samdb_msg_set_ldaptime(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
967                            const char *attr_name, time_t t)
968 {
969         char *str = ldap_timestring(mem_ctx, t);
970         if (!str) {
971                 return -1;
972         }
973         return samdb_msg_set_string(sam_ldb, mem_ctx, msg, attr_name, str);
974 }
975
976 /*
977   add a record
978 */
979 int samdb_add(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
980 {
981         int ret;
982         struct ldb_val v;
983         NTSTATUS status;
984         struct GUID guid = GUID_random();
985
986         status = ndr_push_struct_blob(&v, mem_ctx, &guid, 
987                                       (ndr_push_flags_fn_t)ndr_push_GUID);
988         if (!NT_STATUS_IS_OK(status)) {
989                 return -1;
990         }
991
992         ret = ldb_msg_add_value(sam_ldb, msg, "objectGUID", &v);
993         if (ret != 0) return ret;
994
995         return ldb_add(sam_ldb, msg);
996 }
997
998 /*
999   delete a record
1000 */
1001 int samdb_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, const char *dn)
1002 {
1003         return ldb_delete(sam_ldb, dn);
1004 }
1005
1006 /*
1007   modify a record
1008 */
1009 int samdb_modify(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1010 {
1011         return ldb_modify(sam_ldb, msg);
1012 }
1013
1014 /*
1015   replace elements in a record
1016 */
1017 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
1018 {
1019         int i;
1020
1021         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
1022         for (i=0;i<msg->num_elements;i++) {
1023                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1024         }
1025
1026         /* modify the samdb record */
1027         return samdb_modify(sam_ldb, mem_ctx, msg);
1028 }
1029
1030 /*
1031   return a default security descriptor
1032 */
1033 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
1034 {
1035         struct security_descriptor *sd;
1036
1037         sd = security_descriptor_initialise(mem_ctx);
1038
1039         return sd;
1040 }