s4-source4/dsdb/samdb/ldb_modules/util.c Use DSDB_FLAG_NEXT_MODULE flag
[amitay/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_oom(ldb_module_get_ctx(module));
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_oom(ldb_module_get_ctx(module));
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_oom(ldb_module_get_ctx(module));
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_FLAG_NEXT_MODULE |
229                                     DSDB_SEARCH_SHOW_DELETED |
230                                     DSDB_SEARCH_SHOW_EXTENDED_DN);
231         if (ret != LDB_SUCCESS) {
232                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
233                                        ldb_dn_get_linearized(dn));
234                 talloc_free(tmp_ctx);
235                 return ret;
236         }
237
238         status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
239         if (!NT_STATUS_IS_OK(status)) {
240                 talloc_free(tmp_ctx);
241                 return ldb_operr(ldb_module_get_ctx(module));
242         }
243
244         talloc_free(tmp_ctx);
245         return LDB_SUCCESS;
246 }
247
248 /*
249   a ldb_modify request operating on modules below the
250   current module
251  */
252 int dsdb_module_modify(struct ldb_module *module,
253                        const struct ldb_message *message,
254                        uint32_t dsdb_flags)
255 {
256         struct ldb_request *mod_req;
257         int ret;
258         struct ldb_context *ldb = ldb_module_get_ctx(module);
259         TALLOC_CTX *tmp_ctx = talloc_new(module);
260         struct ldb_result *res;
261
262         res = talloc_zero(tmp_ctx, struct ldb_result);
263         if (!res) {
264                 talloc_free(tmp_ctx);
265                 return ldb_oom(ldb_module_get_ctx(module));
266         }
267
268         ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
269                                 message,
270                                 NULL,
271                                 res,
272                                 ldb_modify_default_callback,
273                                 NULL);
274         if (ret != LDB_SUCCESS) {
275                 talloc_free(tmp_ctx);
276                 return ret;
277         }
278
279         ret = dsdb_request_add_controls(mod_req, dsdb_flags);
280         if (ret != LDB_SUCCESS) {
281                 talloc_free(tmp_ctx);
282                 return ret;
283         }
284
285         /* Run the new request */
286         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
287                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
288                 ret = ops->modify(module, mod_req);
289         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
290                 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
291         } else {
292                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
293                 ret = ldb_next_request(module, mod_req);
294         }
295         if (ret == LDB_SUCCESS) {
296                 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
297         }
298
299         talloc_free(tmp_ctx);
300         return ret;
301 }
302
303
304
305 /*
306   a ldb_rename request operating on modules below the
307   current module
308  */
309 int dsdb_module_rename(struct ldb_module *module,
310                       struct ldb_dn *olddn, struct ldb_dn *newdn,
311                       uint32_t dsdb_flags)
312 {
313         struct ldb_request *req;
314         int ret;
315         struct ldb_context *ldb = ldb_module_get_ctx(module);
316         TALLOC_CTX *tmp_ctx = talloc_new(module);
317         struct ldb_result *res;
318
319         res = talloc_zero(tmp_ctx, struct ldb_result);
320         if (!res) {
321                 talloc_free(tmp_ctx);
322                 return ldb_oom(ldb_module_get_ctx(module));
323         }
324
325         ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
326                                    olddn,
327                                    newdn,
328                                    NULL,
329                                    res,
330                                    ldb_modify_default_callback,
331                                    NULL);
332         if (ret != LDB_SUCCESS) {
333                 talloc_free(tmp_ctx);
334                 return ret;
335         }
336
337         ret = dsdb_request_add_controls(req, dsdb_flags);
338         if (ret != LDB_SUCCESS) {
339                 talloc_free(tmp_ctx);
340                 return ret;
341         }
342
343         /* Run the new request */
344         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
345                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
346                 ret = ops->rename(module, req);
347         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
348                 ret = ldb_request(ldb_module_get_ctx(module), req);
349         } else {
350                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
351                 ret = ldb_next_request(module, req);
352         }
353         if (ret == LDB_SUCCESS) {
354                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
355         }
356
357         talloc_free(tmp_ctx);
358         return ret;
359 }
360
361 /*
362   a ldb_add request operating on modules below the
363   current module
364  */
365 int dsdb_module_add(struct ldb_module *module,
366                     const struct ldb_message *message,
367                     uint32_t dsdb_flags)
368 {
369         struct ldb_request *req;
370         int ret;
371         struct ldb_context *ldb = ldb_module_get_ctx(module);
372         TALLOC_CTX *tmp_ctx = talloc_new(module);
373         struct ldb_result *res;
374
375         res = talloc_zero(tmp_ctx, struct ldb_result);
376         if (!res) {
377                 talloc_free(tmp_ctx);
378                 return ldb_oom(ldb_module_get_ctx(module));
379         }
380
381         ret = ldb_build_add_req(&req, ldb, tmp_ctx,
382                                 message,
383                                 NULL,
384                                 res,
385                                 ldb_modify_default_callback,
386                                 NULL);
387         if (ret != LDB_SUCCESS) {
388                 talloc_free(tmp_ctx);
389                 return ret;
390         }
391
392         ret = dsdb_request_add_controls(req, dsdb_flags);
393         if (ret != LDB_SUCCESS) {
394                 talloc_free(tmp_ctx);
395                 return ret;
396         }
397
398         /* Run the new request */
399         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
400                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
401                 ret = ops->add(module, req);
402         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
403                 ret = ldb_request(ldb_module_get_ctx(module), req);
404         } else {
405                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
406                 ret = ldb_next_request(module, req);
407         }
408         if (ret == LDB_SUCCESS) {
409                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
410         }
411
412         talloc_free(tmp_ctx);
413         return ret;
414 }
415
416 /*
417   a ldb_delete request operating on modules below the
418   current module
419  */
420 int dsdb_module_del(struct ldb_module *module,
421                     struct ldb_dn *dn,
422                     uint32_t dsdb_flags)
423 {
424         struct ldb_request *req;
425         int ret;
426         struct ldb_context *ldb = ldb_module_get_ctx(module);
427         TALLOC_CTX *tmp_ctx = talloc_new(module);
428         struct ldb_result *res;
429
430         res = talloc_zero(tmp_ctx, struct ldb_result);
431         if (!res) {
432                 talloc_free(tmp_ctx);
433                 return ldb_oom(ldb);
434         }
435
436         ret = ldb_build_del_req(&req, ldb, tmp_ctx,
437                                 dn,
438                                 NULL,
439                                 res,
440                                 ldb_modify_default_callback,
441                                 NULL);
442         if (ret != LDB_SUCCESS) {
443                 talloc_free(tmp_ctx);
444                 return ret;
445         }
446
447         ret = dsdb_request_add_controls(req, dsdb_flags);
448         if (ret != LDB_SUCCESS) {
449                 talloc_free(tmp_ctx);
450                 return ret;
451         }
452
453         /* Run the new request */
454         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
455                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
456                 ret = ops->del(module, req);
457         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
458                 ret = ldb_request(ldb_module_get_ctx(module), req);
459         } else {
460                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_NEXT_MODULE);
461                 ret = ldb_next_request(module, req);
462         }
463         if (ret == LDB_SUCCESS) {
464                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
465         }
466
467         talloc_free(tmp_ctx);
468         return ret;
469 }
470
471 const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element)
472 {
473         const struct dsdb_class *last_class = NULL;
474         unsigned int i;
475
476         for (i = 0; i < element->num_values; i++){
477                 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
478
479                 if(tmp_class == NULL) {
480                         continue;
481                 }
482
483                 if(tmp_class->objectClassCategory > 1) {
484                         continue;
485                 }
486
487                 if (!last_class) {
488                         last_class = tmp_class;
489                 } else {
490                         if (tmp_class->subClass_order > last_class->subClass_order)
491                                 last_class = tmp_class;
492                 }
493         }
494
495         return last_class;
496 }
497
498 /*
499   check if a single valued link has multiple non-deleted values
500
501   This is needed when we will be using the RELAX control to stop
502   ldb_tdb from checking single valued links
503  */
504 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
505                                   const struct ldb_message_element *el)
506 {
507         bool found_active = false;
508         unsigned int i;
509
510         if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
511             el->num_values < 2) {
512                 return LDB_SUCCESS;
513         }
514
515         for (i=0; i<el->num_values; i++) {
516                 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
517                         if (found_active) {
518                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
519                         }
520                         found_active = true;
521                 }
522         }
523
524         return LDB_SUCCESS;
525 }
526
527 int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
528                                         struct GUID op_feature_guid, bool *feature_enabled)
529 {
530         TALLOC_CTX *tmp_ctx;
531         struct ldb_context *ldb = ldb_module_get_ctx(module);
532         struct ldb_result *res;
533         struct ldb_dn *search_dn;
534         struct GUID search_guid;
535         const char *attrs[] = {"msDS-EnabledFeature", NULL};
536         int ret;
537         unsigned int i;
538         struct ldb_message_element *el;
539
540         *feature_enabled = false;
541
542         tmp_ctx = talloc_new(ldb);
543
544         ret = ldb_search(ldb, tmp_ctx, &res,
545                                         scope, LDB_SCOPE_BASE, attrs,
546                                         NULL);
547         if (ret != LDB_SUCCESS) {
548                 ldb_asprintf_errstring(ldb,
549                                 "Could no find the scope object - dn: %s\n",
550                                 ldb_dn_get_linearized(scope));
551                 talloc_free(tmp_ctx);
552                 return LDB_ERR_OPERATIONS_ERROR;
553         }
554         if (res->msgs[0]->num_elements > 0) {
555
556                 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
557
558                 attrs[0] = "msDS-OptionalFeatureGUID";
559
560                 for (i=0; i<el->num_values; i++) {
561                         search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
562
563                         ret = ldb_search(ldb, tmp_ctx, &res,
564                                                         search_dn, LDB_SCOPE_BASE, attrs,
565                                                         NULL);
566                         if (ret != LDB_SUCCESS) {
567                                 ldb_asprintf_errstring(ldb,
568                                                 "Could no find object dn: %s\n",
569                                                 ldb_dn_get_linearized(search_dn));
570                                 talloc_free(tmp_ctx);
571                                 return LDB_ERR_OPERATIONS_ERROR;
572                         }
573
574                         search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
575
576                         if (GUID_compare(&search_guid, &op_feature_guid) == 0){
577                                 *feature_enabled = true;
578                                 break;
579                         }
580                 }
581         }
582         talloc_free(tmp_ctx);
583         return LDB_SUCCESS;
584 }
585
586 /*
587   find a 'reference' DN that points at another object
588   (eg. serverReference, rIDManagerReference etc)
589  */
590 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
591                              const char *attribute, struct ldb_dn **dn)
592 {
593         const char *attrs[2];
594         struct ldb_result *res;
595         int ret;
596
597         attrs[0] = attribute;
598         attrs[1] = NULL;
599
600         ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs,
601                                     DSDB_FLAG_NEXT_MODULE);
602         if (ret != LDB_SUCCESS) {
603                 return ret;
604         }
605
606         *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
607                                       mem_ctx, res->msgs[0], attribute);
608         if (!*dn) {
609                 talloc_free(res);
610                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
611         }
612
613         talloc_free(res);
614         return LDB_SUCCESS;
615 }
616
617 /*
618   find the RID Manager$ DN via the rIDManagerReference attribute in the
619   base DN
620  */
621 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
622 {
623         return dsdb_module_reference_dn(module, mem_ctx,
624                                         ldb_get_default_basedn(ldb_module_get_ctx(module)),
625                                         "rIDManagerReference", dn);
626 }
627
628
629 /*
630   update an integer attribute safely via a constrained delete/add
631  */
632 int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn,
633                                             const char *attr, uint64_t old_val, uint64_t new_val)
634 {
635         struct ldb_message *msg;
636         struct ldb_message_element *el;
637         struct ldb_val v1, v2;
638         int ret;
639         char *vstring;
640
641         msg = ldb_msg_new(module);
642         msg->dn = dn;
643
644         ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
645         if (ret != LDB_SUCCESS) {
646                 talloc_free(msg);
647                 return ret;
648         }
649         el->num_values = 1;
650         el->values = &v1;
651         vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val);
652         if (!vstring) {
653                 talloc_free(msg);
654                 return ldb_module_oom(module);
655         }
656         v1 = data_blob_string_const(vstring);
657
658         ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
659         if (ret != LDB_SUCCESS) {
660                 talloc_free(msg);
661                 return ret;
662         }
663         el->num_values = 1;
664         el->values = &v2;
665         vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val);
666         if (!vstring) {
667                 talloc_free(msg);
668                 return ldb_module_oom(module);
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_module_oom(module);
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_module_oom(module);
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_module_oom(module);
816         }
817
818         msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
819         if (msg->dn == NULL) {
820                 talloc_free(msg);
821                 return ldb_operr(ldb_module_get_ctx(module));
822         }
823
824         res = talloc_zero(msg, struct ldb_result);
825         if (!res) {
826                 talloc_free(msg);
827                 return ldb_module_oom(module);
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_oom(ldb);
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 }