ae08c0025f1f5149857ac377a05725ec8741fc86
[kai/samba.git] / source4 / dsdb / samdb / ldb_modules / util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Samba utility functions
4
5    Copyright (C) Andrew Tridgell 2009
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "ldb.h"
24 #include "ldb_module.h"
25 #include "librpc/ndr/libndr.h"
26 #include "dsdb/samdb/ldb_modules/util.h"
27 #include "dsdb/samdb/samdb.h"
28 #include "util.h"
29 #include "libcli/security/security.h"
30
31 /*
32   search for attrs on one DN, in the modules below
33  */
34 int dsdb_module_search_dn(struct ldb_module *module,
35                           TALLOC_CTX *mem_ctx,
36                           struct ldb_result **_res,
37                           struct ldb_dn *basedn,
38                           const char * const *attrs,
39                           uint32_t dsdb_flags)
40 {
41         int ret;
42         struct ldb_request *req;
43         TALLOC_CTX *tmp_ctx;
44         struct ldb_result *res;
45
46         tmp_ctx = talloc_new(mem_ctx);
47
48         res = talloc_zero(tmp_ctx, struct ldb_result);
49         if (!res) {
50                 talloc_free(tmp_ctx);
51                 return LDB_ERR_OPERATIONS_ERROR;
52         }
53
54         ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
55                                    basedn,
56                                    LDB_SCOPE_BASE,
57                                    NULL,
58                                    attrs,
59                                    NULL,
60                                    res,
61                                    ldb_search_default_callback,
62                                    NULL);
63         if (ret != LDB_SUCCESS) {
64                 talloc_free(tmp_ctx);
65                 return ret;
66         }
67
68         ret = dsdb_request_add_controls(req, dsdb_flags);
69         if (ret != LDB_SUCCESS) {
70                 talloc_free(tmp_ctx);
71                 return ret;
72         }
73
74         ret = ldb_next_request(module, req);
75         if (ret == LDB_SUCCESS) {
76                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
77         }
78
79         if (ret != LDB_SUCCESS) {
80                 talloc_free(tmp_ctx);
81                 return ret;
82         }
83
84         if (res->count != 1) {
85                 /* we may be reading a DB that does not have the 'check base on search' option... */
86                 ret = LDB_ERR_NO_SUCH_OBJECT;
87                 ldb_asprintf_errstring(ldb_module_get_ctx(module), 
88                                        "dsdb_module_search_dn: did not find base dn %s (%d results)", 
89                                        ldb_dn_get_linearized(basedn), res->count);
90         } else {
91                 *_res = talloc_steal(mem_ctx, res);
92         }
93         talloc_free(tmp_ctx);
94         return ret;
95 }
96
97 /*
98   search for attrs in the modules below
99  */
100 int dsdb_module_search(struct ldb_module *module,
101                        TALLOC_CTX *mem_ctx,
102                        struct ldb_result **_res,
103                        struct ldb_dn *basedn, enum ldb_scope scope, 
104                        const char * const *attrs,
105                        int dsdb_flags, 
106                        const char *format, ...) _PRINTF_ATTRIBUTE(8, 9)
107 {
108         int ret;
109         struct ldb_request *req;
110         TALLOC_CTX *tmp_ctx;
111         struct ldb_result *res;
112         va_list ap;
113         char *expression;
114
115         tmp_ctx = talloc_new(mem_ctx);
116
117         if (format) {
118                 va_start(ap, format);
119                 expression = talloc_vasprintf(tmp_ctx, format, ap);
120                 va_end(ap);
121
122                 if (!expression) {
123                         talloc_free(tmp_ctx);
124                         return LDB_ERR_OPERATIONS_ERROR;
125                 }
126         } else {
127                 expression = NULL;
128         }
129
130         res = talloc_zero(tmp_ctx, struct ldb_result);
131         if (!res) {
132                 talloc_free(tmp_ctx);
133                 return LDB_ERR_OPERATIONS_ERROR;
134         }
135
136         ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
137                                    basedn,
138                                    scope,
139                                    expression,
140                                    attrs,
141                                    NULL,
142                                    res,
143                                    ldb_search_default_callback,
144                                    NULL);
145         if (ret != LDB_SUCCESS) {
146                 talloc_free(tmp_ctx);
147                 return ret;
148         }
149
150         ret = dsdb_request_add_controls(req, dsdb_flags);
151         if (ret != LDB_SUCCESS) {
152                 talloc_free(tmp_ctx);
153                 return ret;
154         }
155
156         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
157                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
158                 ret = ops->search(module, req);
159         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
160                 ret = ldb_request(ldb_module_get_ctx(module), req);
161         } else {
162                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
163                 ret = ldb_next_request(module, req);
164         }
165         if (ret == LDB_SUCCESS) {
166                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
167         }
168
169         talloc_free(req);
170         if (ret == LDB_SUCCESS) {
171                 *_res = talloc_steal(mem_ctx, res);
172         }
173         talloc_free(tmp_ctx);
174         return ret;
175 }
176
177 /*
178   find a DN given a GUID. This searches across all partitions
179  */
180 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
181                            const struct GUID *guid, struct ldb_dn **dn)
182 {
183         struct ldb_result *res;
184         const char *attrs[] = { NULL };
185         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
186         int ret;
187
188         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
189                                  attrs,
190                                  DSDB_FLAG_NEXT_MODULE |
191                                  DSDB_SEARCH_SHOW_DELETED |
192                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
193                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
194                                  "objectGUID=%s", GUID_string(tmp_ctx, guid));
195         if (ret != LDB_SUCCESS) {
196                 talloc_free(tmp_ctx);
197                 return ret;
198         }
199         if (res->count == 0) {
200                 talloc_free(tmp_ctx);
201                 return LDB_ERR_NO_SUCH_OBJECT;
202         }
203         if (res->count != 1) {
204                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
205                                        GUID_string(tmp_ctx, guid));
206                 talloc_free(tmp_ctx);
207                 return LDB_ERR_OPERATIONS_ERROR;
208         }
209
210         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
211
212         talloc_free(tmp_ctx);
213         return LDB_SUCCESS;
214 }
215
216 /*
217   find a GUID given a DN.
218  */
219 int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid)
220 {
221         const char *attrs[] = { NULL };
222         struct ldb_result *res;
223         TALLOC_CTX *tmp_ctx = talloc_new(module);
224         int ret;
225         NTSTATUS status;
226
227         ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
228                                     DSDB_SEARCH_SHOW_DELETED|
229                                     DSDB_SEARCH_SHOW_EXTENDED_DN);
230         if (ret != LDB_SUCCESS) {
231                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
232                                        ldb_dn_get_linearized(dn));
233                 talloc_free(tmp_ctx);
234                 return ret;
235         }
236
237         status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
238         if (!NT_STATUS_IS_OK(status)) {
239                 talloc_free(tmp_ctx);
240                 return LDB_ERR_OPERATIONS_ERROR;
241         }
242
243         talloc_free(tmp_ctx);
244         return LDB_SUCCESS;
245 }
246
247 /*
248   a ldb_modify request operating on modules below the
249   current module
250  */
251 int dsdb_module_modify(struct ldb_module *module,
252                        const struct ldb_message *message,
253                        uint32_t dsdb_flags)
254 {
255         struct ldb_request *mod_req;
256         int ret;
257         struct ldb_context *ldb = ldb_module_get_ctx(module);
258         TALLOC_CTX *tmp_ctx = talloc_new(module);
259         struct ldb_result *res;
260
261         res = talloc_zero(tmp_ctx, struct ldb_result);
262         if (!res) {
263                 talloc_free(tmp_ctx);
264                 return LDB_ERR_OPERATIONS_ERROR;
265         }
266
267         ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
268                                 message,
269                                 NULL,
270                                 res,
271                                 ldb_modify_default_callback,
272                                 NULL);
273         if (ret != LDB_SUCCESS) {
274                 talloc_free(tmp_ctx);
275                 return ret;
276         }
277
278         ret = dsdb_request_add_controls(mod_req, dsdb_flags);
279         if (ret != LDB_SUCCESS) {
280                 talloc_free(tmp_ctx);
281                 return ret;
282         }
283
284         /* Run the new request */
285         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
286                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
287                 ret = ops->modify(module, mod_req);
288         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
289                 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
290         } else {
291                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
292                 ret = ldb_next_request(module, mod_req);
293         }
294         if (ret == LDB_SUCCESS) {
295                 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
296         }
297
298         talloc_free(tmp_ctx);
299         return ret;
300 }
301
302
303
304 /*
305   a ldb_rename request operating on modules below the
306   current module
307  */
308 int dsdb_module_rename(struct ldb_module *module,
309                       struct ldb_dn *olddn, struct ldb_dn *newdn,
310                       uint32_t dsdb_flags)
311 {
312         struct ldb_request *req;
313         int ret;
314         struct ldb_context *ldb = ldb_module_get_ctx(module);
315         TALLOC_CTX *tmp_ctx = talloc_new(module);
316         struct ldb_result *res;
317
318         res = talloc_zero(tmp_ctx, struct ldb_result);
319         if (!res) {
320                 talloc_free(tmp_ctx);
321                 return LDB_ERR_OPERATIONS_ERROR;
322         }
323
324         ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
325                                    olddn,
326                                    newdn,
327                                    NULL,
328                                    res,
329                                    ldb_modify_default_callback,
330                                    NULL);
331         if (ret != LDB_SUCCESS) {
332                 talloc_free(tmp_ctx);
333                 return ret;
334         }
335
336         ret = dsdb_request_add_controls(req, dsdb_flags);
337         if (ret != LDB_SUCCESS) {
338                 talloc_free(tmp_ctx);
339                 return ret;
340         }
341
342         /* Run the new request */
343         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
344                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
345                 ret = ops->rename(module, req);
346         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
347                 ret = ldb_request(ldb_module_get_ctx(module), req);
348         } else {
349                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
350                 ret = ldb_next_request(module, req);
351         }
352         if (ret == LDB_SUCCESS) {
353                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
354         }
355
356         talloc_free(tmp_ctx);
357         return ret;
358 }
359
360 /*
361   a ldb_add request operating on modules below the
362   current module
363  */
364 int dsdb_module_add(struct ldb_module *module,
365                     const struct ldb_message *message,
366                     uint32_t dsdb_flags)
367 {
368         struct ldb_request *req;
369         int ret;
370         struct ldb_context *ldb = ldb_module_get_ctx(module);
371         TALLOC_CTX *tmp_ctx = talloc_new(module);
372         struct ldb_result *res;
373
374         res = talloc_zero(tmp_ctx, struct ldb_result);
375         if (!res) {
376                 talloc_free(tmp_ctx);
377                 return LDB_ERR_OPERATIONS_ERROR;
378         }
379
380         ret = ldb_build_add_req(&req, ldb, tmp_ctx,
381                                 message,
382                                 NULL,
383                                 res,
384                                 ldb_modify_default_callback,
385                                 NULL);
386         if (ret != LDB_SUCCESS) {
387                 talloc_free(tmp_ctx);
388                 return ret;
389         }
390
391         ret = dsdb_request_add_controls(req, dsdb_flags);
392         if (ret != LDB_SUCCESS) {
393                 talloc_free(tmp_ctx);
394                 return ret;
395         }
396
397         /* Run the new request */
398         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
399                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
400                 ret = ops->add(module, req);
401         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
402                 ret = ldb_request(ldb_module_get_ctx(module), req);
403         } else {
404                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
405                 ret = ldb_next_request(module, req);
406         }
407         if (ret == LDB_SUCCESS) {
408                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
409         }
410
411         talloc_free(tmp_ctx);
412         return ret;
413 }
414
415 /*
416   a ldb_delete request operating on modules below the
417   current module
418  */
419 int dsdb_module_del(struct ldb_module *module,
420                     struct ldb_dn *dn,
421                     uint32_t dsdb_flags)
422 {
423         struct ldb_request *req;
424         int ret;
425         struct ldb_context *ldb = ldb_module_get_ctx(module);
426         TALLOC_CTX *tmp_ctx = talloc_new(module);
427         struct ldb_result *res;
428
429         res = talloc_zero(tmp_ctx, struct ldb_result);
430         if (!res) {
431                 talloc_free(tmp_ctx);
432                 return LDB_ERR_OPERATIONS_ERROR;
433         }
434
435         ret = ldb_build_del_req(&req, ldb, tmp_ctx,
436                                 dn,
437                                 NULL,
438                                 res,
439                                 ldb_modify_default_callback,
440                                 NULL);
441         if (ret != LDB_SUCCESS) {
442                 talloc_free(tmp_ctx);
443                 return ret;
444         }
445
446         ret = dsdb_request_add_controls(req, dsdb_flags);
447         if (ret != LDB_SUCCESS) {
448                 talloc_free(tmp_ctx);
449                 return ret;
450         }
451
452         /* Run the new request */
453         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
454                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
455                 ret = ops->del(module, req);
456         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
457                 ret = ldb_request(ldb_module_get_ctx(module), req);
458         } else {
459                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
460                 ret = ldb_next_request(module, req);
461         }
462         if (ret == LDB_SUCCESS) {
463                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
464         }
465
466         talloc_free(tmp_ctx);
467         return ret;
468 }
469
470 const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element)
471 {
472         const struct dsdb_class *last_class = NULL;
473         unsigned int i;
474
475         for (i = 0; i < element->num_values; i++){
476                 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
477
478                 if(tmp_class == NULL) {
479                         continue;
480                 }
481
482                 if(tmp_class->objectClassCategory > 1) {
483                         continue;
484                 }
485
486                 if (!last_class) {
487                         last_class = tmp_class;
488                 } else {
489                         if (tmp_class->subClass_order > last_class->subClass_order)
490                                 last_class = tmp_class;
491                 }
492         }
493
494         return last_class;
495 }
496
497 /*
498   check if a single valued link has multiple non-deleted values
499
500   This is needed when we will be using the RELAX control to stop
501   ldb_tdb from checking single valued links
502  */
503 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
504                                   const struct ldb_message_element *el)
505 {
506         bool found_active = false;
507         unsigned int i;
508
509         if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
510             el->num_values < 2) {
511                 return LDB_SUCCESS;
512         }
513
514         for (i=0; i<el->num_values; i++) {
515                 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
516                         if (found_active) {
517                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
518                         }
519                         found_active = true;
520                 }
521         }
522
523         return LDB_SUCCESS;
524 }
525
526 int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
527                                         struct GUID op_feature_guid, bool *feature_enabled)
528 {
529         TALLOC_CTX *tmp_ctx;
530         struct ldb_context *ldb = ldb_module_get_ctx(module);
531         struct ldb_result *res;
532         struct ldb_dn *search_dn;
533         struct GUID search_guid;
534         const char *attrs[] = {"msDS-EnabledFeature", NULL};
535         int ret;
536         unsigned int i;
537         struct ldb_message_element *el;
538
539         *feature_enabled = false;
540
541         tmp_ctx = talloc_new(ldb);
542
543         ret = ldb_search(ldb, tmp_ctx, &res,
544                                         scope, LDB_SCOPE_BASE, attrs,
545                                         NULL);
546         if (ret != LDB_SUCCESS) {
547                 ldb_asprintf_errstring(ldb,
548                                 "Could no find the scope object - dn: %s\n",
549                                 ldb_dn_get_linearized(scope));
550                 talloc_free(tmp_ctx);
551                 return LDB_ERR_OPERATIONS_ERROR;
552         }
553         if (res->msgs[0]->num_elements > 0) {
554
555                 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
556
557                 attrs[0] = "msDS-OptionalFeatureGUID";
558
559                 for (i=0; i<el->num_values; i++) {
560                         search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
561
562                         ret = ldb_search(ldb, tmp_ctx, &res,
563                                                         search_dn, LDB_SCOPE_BASE, attrs,
564                                                         NULL);
565                         if (ret != LDB_SUCCESS) {
566                                 ldb_asprintf_errstring(ldb,
567                                                 "Could no find object dn: %s\n",
568                                                 ldb_dn_get_linearized(search_dn));
569                                 talloc_free(tmp_ctx);
570                                 return LDB_ERR_OPERATIONS_ERROR;
571                         }
572
573                         search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
574
575                         if (GUID_compare(&search_guid, &op_feature_guid) == 0){
576                                 *feature_enabled = true;
577                                 break;
578                         }
579                 }
580         }
581         talloc_free(tmp_ctx);
582         return LDB_SUCCESS;
583 }
584
585 /*
586   find a 'reference' DN that points at another object
587   (eg. serverReference, rIDManagerReference etc)
588  */
589 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
590                              const char *attribute, struct ldb_dn **dn)
591 {
592         const char *attrs[2];
593         struct ldb_result *res;
594         int ret;
595
596         attrs[0] = attribute;
597         attrs[1] = NULL;
598
599         ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs, 0);
600         if (ret != LDB_SUCCESS) {
601                 return ret;
602         }
603
604         *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
605                                       mem_ctx, res->msgs[0], attribute);
606         if (!*dn) {
607                 talloc_free(res);
608                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
609         }
610
611         talloc_free(res);
612         return LDB_SUCCESS;
613 }
614
615 /*
616   find the RID Manager$ DN via the rIDManagerReference attribute in the
617   base DN
618  */
619 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
620 {
621         return dsdb_module_reference_dn(module, mem_ctx,
622                                         ldb_get_default_basedn(ldb_module_get_ctx(module)),
623                                         "rIDManagerReference", dn);
624 }
625
626
627 /*
628   update an integer attribute safely via a constrained delete/add
629  */
630 int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn,
631                                             const char *attr, uint64_t old_val, uint64_t new_val)
632 {
633         struct ldb_message *msg;
634         struct ldb_message_element *el;
635         struct ldb_val v1, v2;
636         int ret;
637         char *vstring;
638
639         msg = ldb_msg_new(module);
640         msg->dn = dn;
641
642         ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
643         if (ret != LDB_SUCCESS) {
644                 talloc_free(msg);
645                 return ret;
646         }
647         el->num_values = 1;
648         el->values = &v1;
649         vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val);
650         if (!vstring) {
651                 ldb_module_oom(module);
652                 talloc_free(msg);
653                 return LDB_ERR_OPERATIONS_ERROR;
654         }
655         v1 = data_blob_string_const(vstring);
656
657         ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
658         if (ret != LDB_SUCCESS) {
659                 talloc_free(msg);
660                 return ret;
661         }
662         el->num_values = 1;
663         el->values = &v2;
664         vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val);
665         if (!vstring) {
666                 ldb_module_oom(module);
667                 talloc_free(msg);
668                 return LDB_ERR_OPERATIONS_ERROR;
669         }
670         v2 = data_blob_string_const(vstring);
671
672         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
673         talloc_free(msg);
674         return ret;
675 }
676
677 /*
678   used to chain to the callers callback
679  */
680 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
681 {
682         struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
683
684         talloc_steal(up_req, req);
685         return up_req->callback(up_req, ares);
686 }
687
688
689 /*
690   set an integer attribute
691  */
692 int dsdb_module_set_integer(struct ldb_module *module, struct ldb_dn *dn,
693                             const char *attr, uint64_t new_val)
694 {
695         struct ldb_message *msg;
696         int ret;
697
698         msg = ldb_msg_new(module);
699         msg->dn = dn;
700
701         ret = ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)new_val);
702         if (ret != LDB_SUCCESS) {
703                 talloc_free(msg);
704                 return ret;
705         }
706         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
707
708         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
709         talloc_free(msg);
710         return ret;
711 }
712
713 /*
714   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
715   object for a partition
716  */
717 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
718                                   uint64_t *uSN, uint64_t *urgent_uSN)
719 {
720         struct ldb_context *ldb = ldb_module_get_ctx(module);
721         struct ldb_request *req;
722         int ret;
723         TALLOC_CTX *tmp_ctx = talloc_new(module);
724         struct dsdb_control_current_partition *p_ctrl;
725         struct ldb_result *res;
726
727         res = talloc_zero(tmp_ctx, struct ldb_result);
728         if (!res) {
729                 talloc_free(tmp_ctx);
730                 return LDB_ERR_OPERATIONS_ERROR;
731         }
732
733         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
734                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
735                                    LDB_SCOPE_BASE,
736                                    NULL, NULL,
737                                    NULL,
738                                    res, ldb_search_default_callback,
739                                    NULL);
740         if (ret != LDB_SUCCESS) {
741                 talloc_free(tmp_ctx);
742                 return ret;
743         }
744
745         p_ctrl = talloc(req, struct dsdb_control_current_partition);
746         if (p_ctrl == NULL) {
747                 talloc_free(tmp_ctx);
748                 return LDB_ERR_OPERATIONS_ERROR;
749         }
750         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
751         p_ctrl->dn = dn;
752
753
754         ret = ldb_request_add_control(req,
755                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
756                                       false, p_ctrl);
757         if (ret != LDB_SUCCESS) {
758                 talloc_free(tmp_ctx);
759                 return ret;
760         }
761
762         /* Run the new request */
763         ret = ldb_next_request(module, req);
764
765         if (ret == LDB_SUCCESS) {
766                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
767         }
768
769         if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
770                 /* it hasn't been created yet, which means
771                    an implicit value of zero */
772                 *uSN = 0;
773                 talloc_free(tmp_ctx);
774                 return LDB_SUCCESS;
775         }
776
777         if (ret != LDB_SUCCESS) {
778                 talloc_free(tmp_ctx);
779                 return ret;
780         }
781
782         if (res->count < 1) {
783                 *uSN = 0;
784                 if (urgent_uSN) {
785                         *urgent_uSN = 0;
786                 }
787         } else {
788                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
789                 if (urgent_uSN) {
790                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
791                 }
792         }
793
794         talloc_free(tmp_ctx);
795
796         return LDB_SUCCESS;
797 }
798
799 /*
800   save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
801   partition
802  */
803 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
804                                    uint64_t uSN, uint64_t urgent_uSN)
805 {
806         struct ldb_context *ldb = ldb_module_get_ctx(module);
807         struct ldb_request *req;
808         struct ldb_message *msg;
809         struct dsdb_control_current_partition *p_ctrl;
810         int ret;
811         struct ldb_result *res;
812
813         msg = ldb_msg_new(module);
814         if (msg == NULL) {
815                 return LDB_ERR_OPERATIONS_ERROR;
816         }
817
818         msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
819         if (msg->dn == NULL) {
820                 talloc_free(msg);
821                 return LDB_ERR_OPERATIONS_ERROR;
822         }
823
824         res = talloc_zero(msg, struct ldb_result);
825         if (!res) {
826                 talloc_free(msg);
827                 return LDB_ERR_OPERATIONS_ERROR;
828         }
829
830         ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
831         if (ret != LDB_SUCCESS) {
832                 talloc_free(msg);
833                 return ret;
834         }
835         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
836
837         /* urgent_uSN is optional so may not be stored */
838         if (urgent_uSN) {
839                 ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN);
840                 if (ret != LDB_SUCCESS) {
841                         talloc_free(msg);
842                         return ret;
843                 }
844                 msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
845         }
846
847
848         p_ctrl = talloc(msg, struct dsdb_control_current_partition);
849         if (p_ctrl == NULL) {
850                 talloc_free(msg);
851                 return LDB_ERR_OPERATIONS_ERROR;
852         }
853         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
854         p_ctrl->dn = dn;
855         ret = ldb_build_mod_req(&req, ldb, msg,
856                                 msg,
857                                 NULL,
858                                 res,
859                                 ldb_modify_default_callback,
860                                 NULL);
861 again:
862         if (ret != LDB_SUCCESS) {
863                 talloc_free(msg);
864                 return ret;
865         }
866
867         ret = ldb_request_add_control(req,
868                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
869                                       false, p_ctrl);
870         if (ret != LDB_SUCCESS) {
871                 talloc_free(msg);
872                 return ret;
873         }
874
875         /* Run the new request */
876         ret = ldb_next_request(module, req);
877
878         if (ret == LDB_SUCCESS) {
879                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
880         }
881         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
882                 ret = ldb_build_add_req(&req, ldb, msg,
883                                         msg,
884                                         NULL,
885                                         res,
886                                         ldb_modify_default_callback,
887                                         NULL);
888                 goto again;
889         }
890
891         talloc_free(msg);
892
893         return ret;
894 }
895
896 bool dsdb_module_am_system(struct ldb_module *module)
897 {
898         struct ldb_context *ldb = ldb_module_get_ctx(module);
899         struct auth_session_info *session_info
900                 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
901         return security_session_user_level(session_info, NULL) == SECURITY_SYSTEM;
902 }
903
904 /*
905   check if the recyclebin is enabled
906  */
907 int dsdb_recyclebin_enabled(struct ldb_module *module, bool *enabled)
908 {
909         struct ldb_context *ldb = ldb_module_get_ctx(module);
910         struct ldb_dn *partitions_dn;
911         struct GUID recyclebin_guid;
912         int ret;
913
914         partitions_dn = samdb_partitions_dn(ldb, module);
915
916         GUID_from_string(DS_GUID_FEATURE_RECYCLE_BIN, &recyclebin_guid);
917
918         ret = dsdb_check_optional_feature(module, partitions_dn, recyclebin_guid, enabled);
919         if (ret != LDB_SUCCESS) {
920                 ldb_asprintf_errstring(ldb, "Could not verify if Recycle Bin is enabled \n");
921                 talloc_free(partitions_dn);
922                 return LDB_ERR_UNWILLING_TO_PERFORM;
923         }
924
925         talloc_free(partitions_dn);
926         return LDB_SUCCESS;
927 }
928
929 bool is_attr_in_list(const char * const * attrs, const char *attr)
930 {
931         unsigned int i;
932
933         for (i = 0; attrs[i]; i++) {
934                 if (ldb_attr_cmp(attrs[i], attr) == 0)
935                         return true;
936         }
937
938         return false;
939 }