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