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