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