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