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