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