s4:ldb_modules/util.c - fix two counter variables to be "unsigned"
[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
247         ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
248                                 message,
249                                 NULL,
250                                 NULL,
251                                 ldb_op_default_callback,
252                                 NULL);
253         if (ret != LDB_SUCCESS) {
254                 talloc_free(tmp_ctx);
255                 return ret;
256         }
257
258         ret = dsdb_request_add_controls(mod_req, dsdb_flags);
259         if (ret != LDB_SUCCESS) {
260                 talloc_free(tmp_ctx);
261                 return ret;
262         }
263
264         /* Run the new request */
265         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
266                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
267                 ret = ops->modify(module, mod_req);
268         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
269                 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
270         } else {
271                 ret = ldb_next_request(module, mod_req);
272         }
273         if (ret == LDB_SUCCESS) {
274                 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
275         }
276
277         talloc_free(tmp_ctx);
278         return ret;
279 }
280
281
282
283 /*
284   a ldb_rename request operating on modules below the
285   current module
286  */
287 int dsdb_module_rename(struct ldb_module *module,
288                       struct ldb_dn *olddn, struct ldb_dn *newdn,
289                       uint32_t dsdb_flags)
290 {
291         struct ldb_request *req;
292         int ret;
293         struct ldb_context *ldb = ldb_module_get_ctx(module);
294         TALLOC_CTX *tmp_ctx = talloc_new(module);
295
296         ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
297                                    olddn,
298                                    newdn,
299                                    NULL,
300                                    NULL,
301                                    ldb_op_default_callback,
302                                    NULL);
303         if (ret != LDB_SUCCESS) {
304                 talloc_free(tmp_ctx);
305                 return ret;
306         }
307
308         ret = dsdb_request_add_controls(req, dsdb_flags);
309         if (ret != LDB_SUCCESS) {
310                 talloc_free(tmp_ctx);
311                 return ret;
312         }
313
314         /* Run the new request */
315         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
316                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
317                 ret = ops->rename(module, req);
318         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
319                 ret = ldb_request(ldb_module_get_ctx(module), req);
320         } else {
321                 ret = ldb_next_request(module, req);
322         }
323         if (ret == LDB_SUCCESS) {
324                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
325         }
326
327         talloc_free(tmp_ctx);
328         return ret;
329 }
330
331 /*
332   a ldb_add request operating on modules below the
333   current module
334  */
335 int dsdb_module_add(struct ldb_module *module,
336                     const struct ldb_message *message,
337                     uint32_t dsdb_flags)
338 {
339         struct ldb_request *req;
340         int ret;
341         struct ldb_context *ldb = ldb_module_get_ctx(module);
342         TALLOC_CTX *tmp_ctx = talloc_new(module);
343
344         ret = ldb_build_add_req(&req, ldb, tmp_ctx,
345                                 message,
346                                 NULL,
347                                 NULL,
348                                 ldb_op_default_callback,
349                                 NULL);
350         if (ret != LDB_SUCCESS) {
351                 talloc_free(tmp_ctx);
352                 return ret;
353         }
354
355         ret = dsdb_request_add_controls(req, dsdb_flags);
356         if (ret != LDB_SUCCESS) {
357                 talloc_free(tmp_ctx);
358                 return ret;
359         }
360
361         /* Run the new request */
362         if (dsdb_flags & DSDB_FLAG_OWN_MODULE) {
363                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
364                 ret = ops->add(module, req);
365         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
366                 ret = ldb_request(ldb_module_get_ctx(module), req);
367         } else {
368                 ret = ldb_next_request(module, req);
369         }
370         if (ret == LDB_SUCCESS) {
371                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
372         }
373
374         talloc_free(tmp_ctx);
375         return ret;
376 }
377
378
379 const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element)
380 {
381         const struct dsdb_class *last_class = NULL;
382         unsigned int i;
383
384         for (i = 0; i < element->num_values; i++){
385                 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
386
387                 if(tmp_class == NULL) {
388                         continue;
389                 }
390
391                 if(tmp_class->objectClassCategory == 3) {
392                         continue;
393                 }
394
395                 if (!last_class) {
396                         last_class = tmp_class;
397                 } else {
398                         if (tmp_class->subClass_order > last_class->subClass_order)
399                                 last_class = tmp_class;
400                 }
401         }
402
403         return last_class;
404 }
405
406 /*
407   check if a single valued link has multiple non-deleted values
408
409   This is needed when we will be using the RELAX control to stop
410   ldb_tdb from checking single valued links
411  */
412 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
413                                   const struct ldb_message_element *el)
414 {
415         bool found_active = false;
416         unsigned int i;
417
418         if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
419             el->num_values < 2) {
420                 return LDB_SUCCESS;
421         }
422
423         for (i=0; i<el->num_values; i++) {
424                 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
425                         if (found_active) {
426                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
427                         }
428                         found_active = true;
429                 }
430         }
431
432         return LDB_SUCCESS;
433 }
434
435 int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
436                                         struct GUID op_feature_guid, bool *feature_enabled)
437 {
438         TALLOC_CTX *tmp_ctx;
439         struct ldb_context *ldb = ldb_module_get_ctx(module);
440         struct ldb_result *res;
441         struct ldb_dn *search_dn;
442         struct GUID search_guid;
443         const char *attrs[] = {"msDS-EnabledFeature", NULL};
444         int ret;
445         unsigned int i;
446         struct ldb_message_element *el;
447
448         *feature_enabled = false;
449
450         tmp_ctx = talloc_new(ldb);
451
452         ret = ldb_search(ldb, tmp_ctx, &res,
453                                         scope, LDB_SCOPE_BASE, attrs,
454                                         NULL);
455         if (ret != LDB_SUCCESS) {
456                 ldb_asprintf_errstring(ldb,
457                                 "Could no find the scope object - dn: %s\n",
458                                 ldb_dn_get_linearized(scope));
459                 talloc_free(tmp_ctx);
460                 return LDB_ERR_OPERATIONS_ERROR;
461         }
462         if (res->msgs[0]->num_elements > 0) {
463
464                 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
465
466                 attrs[0] = "msDS-OptionalFeatureGUID";
467
468                 for (i=0; i<el->num_values; i++) {
469                         search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
470
471                         ret = ldb_search(ldb, tmp_ctx, &res,
472                                                         search_dn, LDB_SCOPE_BASE, attrs,
473                                                         NULL);
474                         if (ret != LDB_SUCCESS) {
475                                 ldb_asprintf_errstring(ldb,
476                                                 "Could no find object dn: %s\n",
477                                                 ldb_dn_get_linearized(search_dn));
478                                 talloc_free(tmp_ctx);
479                                 return LDB_ERR_OPERATIONS_ERROR;
480                         }
481
482                         search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
483
484                         if (GUID_compare(&search_guid, &op_feature_guid) == 0){
485                                 *feature_enabled = true;
486                                 break;
487                         }
488                 }
489         }
490         talloc_free(tmp_ctx);
491         return LDB_SUCCESS;
492 }
493
494
495 /*
496   find a 'reference' DN that points at another object
497   (eg. serverReference, rIDManagerReference etc)
498  */
499 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
500                              const char *attribute, struct ldb_dn **dn)
501 {
502         const char *attrs[2];
503         struct ldb_result *res;
504         int ret;
505
506         attrs[0] = attribute;
507         attrs[1] = NULL;
508
509         ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs, 0);
510         if (ret != LDB_SUCCESS) {
511                 return ret;
512         }
513
514         *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
515                                       mem_ctx, res->msgs[0], attribute);
516         if (!*dn) {
517                 talloc_free(res);
518                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
519         }
520
521         talloc_free(res);
522         return LDB_SUCCESS;
523 }
524
525 /*
526   find the RID Manager$ DN via the rIDManagerReference attribute in the
527   base DN
528  */
529 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
530 {
531         return dsdb_module_reference_dn(module, mem_ctx,
532                                         samdb_base_dn(ldb_module_get_ctx(module)),
533                                         "rIDManagerReference", dn);
534 }
535
536
537 /*
538   update an integer attribute safely via a constrained delete/add
539  */
540 int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn,
541                                             const char *attr, uint64_t old_val, uint64_t new_val)
542 {
543         struct ldb_message *msg;
544         struct ldb_message_element *el;
545         struct ldb_val v1, v2;
546         int ret;
547         char *vstring;
548
549         msg = ldb_msg_new(module);
550         msg->dn = dn;
551
552         ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
553         if (ret != LDB_SUCCESS) {
554                 talloc_free(msg);
555                 return ret;
556         }
557         el->num_values = 1;
558         el->values = &v1;
559         vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val);
560         if (!vstring) {
561                 ldb_module_oom(module);
562                 talloc_free(msg);
563                 return LDB_ERR_OPERATIONS_ERROR;
564         }
565         v1 = data_blob_string_const(vstring);
566
567         ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
568         if (ret != LDB_SUCCESS) {
569                 talloc_free(msg);
570                 return ret;
571         }
572         el->num_values = 1;
573         el->values = &v2;
574         vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val);
575         if (!vstring) {
576                 ldb_module_oom(module);
577                 talloc_free(msg);
578                 return LDB_ERR_OPERATIONS_ERROR;
579         }
580         v2 = data_blob_string_const(vstring);
581
582         ret = dsdb_module_modify(module, msg, 0);
583         talloc_free(msg);
584         return ret;
585 }
586
587 /*
588   used to chain to the callers callback
589  */
590 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
591 {
592         struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
593
594         talloc_steal(up_req, req);
595         return up_req->callback(up_req, ares);
596 }
597
598
599 /*
600   set an integer attribute
601  */
602 int dsdb_module_set_integer(struct ldb_module *module, struct ldb_dn *dn,
603                             const char *attr, uint64_t new_val)
604 {
605         struct ldb_message *msg;
606         int ret;
607
608         msg = ldb_msg_new(module);
609         msg->dn = dn;
610
611         ret = ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)new_val);
612         if (ret != LDB_SUCCESS) {
613                 talloc_free(msg);
614                 return ret;
615         }
616         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
617
618         ret = dsdb_module_modify(module, msg, 0);
619         talloc_free(msg);
620         return ret;
621 }
622
623 /*
624   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
625   object for a partition
626  */
627 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
628                                   uint64_t *uSN, uint64_t *urgent_uSN)
629 {
630         struct ldb_context *ldb = ldb_module_get_ctx(module);
631         struct ldb_request *req;
632         int ret;
633         TALLOC_CTX *tmp_ctx = talloc_new(module);
634         struct dsdb_control_current_partition *p_ctrl;
635         struct ldb_result *res;
636
637         res = talloc_zero(tmp_ctx, struct ldb_result);
638         if (!res) {
639                 talloc_free(tmp_ctx);
640                 return LDB_ERR_OPERATIONS_ERROR;
641         }
642
643         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
644                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
645                                    LDB_SCOPE_BASE,
646                                    NULL, NULL,
647                                    NULL,
648                                    res, ldb_search_default_callback,
649                                    NULL);
650         if (ret != LDB_SUCCESS) {
651                 talloc_free(tmp_ctx);
652                 return ret;
653         }
654
655         p_ctrl = talloc(req, struct dsdb_control_current_partition);
656         if (p_ctrl == NULL) {
657                 talloc_free(res);
658                 return LDB_ERR_OPERATIONS_ERROR;
659         }
660         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
661         p_ctrl->dn = dn;
662
663
664         ret = ldb_request_add_control(req,
665                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
666                                       false, p_ctrl);
667         if (ret != LDB_SUCCESS) {
668                 talloc_free(tmp_ctx);
669                 return ret;
670         }
671
672         /* Run the new request */
673         ret = ldb_next_request(module, req);
674
675         if (ret == LDB_SUCCESS) {
676                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
677         }
678
679         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
680                 /* it hasn't been created yet, which means
681                    an implicit value of zero */
682                 *uSN = 0;
683                 talloc_free(tmp_ctx);
684                 return LDB_SUCCESS;
685         }
686
687         if (ret != LDB_SUCCESS) {
688                 talloc_free(tmp_ctx);
689                 return ret;
690         }
691
692         if (res->count < 1) {
693                 *uSN = 0;
694                 if (urgent_uSN) {
695                         *urgent_uSN = 0;
696                 }
697         } else {
698                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
699                 if (urgent_uSN) {
700                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
701                 }
702         }
703
704         talloc_free(tmp_ctx);
705
706         return LDB_SUCCESS;
707 }
708
709 /*
710   save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
711   partition
712  */
713 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
714                                    uint64_t uSN, uint64_t urgent_uSN)
715 {
716         struct ldb_context *ldb = ldb_module_get_ctx(module);
717         struct ldb_request *req;
718         struct ldb_message *msg;
719         struct dsdb_control_current_partition *p_ctrl;
720         int ret;
721
722         msg = ldb_msg_new(module);
723         if (msg == NULL) {
724                 return LDB_ERR_OPERATIONS_ERROR;
725         }
726
727         msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
728         if (msg->dn == NULL) {
729                 talloc_free(msg);
730                 return LDB_ERR_OPERATIONS_ERROR;
731         }
732
733         ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
734         if (ret != LDB_SUCCESS) {
735                 talloc_free(msg);
736                 return ret;
737         }
738         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
739
740         /* urgent_uSN is optional so may not be stored */
741         if (urgent_uSN) {
742                 ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN);
743                 if (ret != LDB_SUCCESS) {
744                         talloc_free(msg);
745                         return ret;
746                 }
747                 msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
748         }
749
750
751         p_ctrl = talloc(msg, struct dsdb_control_current_partition);
752         if (p_ctrl == NULL) {
753                 talloc_free(msg);
754                 return LDB_ERR_OPERATIONS_ERROR;
755         }
756         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
757         p_ctrl->dn = dn;
758
759         ret = ldb_build_mod_req(&req, ldb, msg,
760                                 msg,
761                                 NULL,
762                                 NULL, ldb_op_default_callback,
763                                 NULL);
764 again:
765         if (ret != LDB_SUCCESS) {
766                 talloc_free(msg);
767                 return ret;
768         }
769
770         ret = ldb_request_add_control(req,
771                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
772                                       false, p_ctrl);
773         if (ret != LDB_SUCCESS) {
774                 talloc_free(msg);
775                 return ret;
776         }
777
778         /* Run the new request */
779         ret = ldb_next_request(module, req);
780
781         if (ret == LDB_SUCCESS) {
782                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
783         }
784         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
785                 ret = ldb_build_add_req(&req, ldb, msg,
786                                         msg,
787                                         NULL,
788                                         NULL, ldb_op_default_callback,
789                                         NULL);
790                 goto again;
791         }
792
793         talloc_free(msg);
794
795         return ret;
796 }
797
798 bool dsdb_module_am_system(struct ldb_module *module)
799 {
800         struct ldb_context *ldb = ldb_module_get_ctx(module);
801         struct auth_session_info *session_info
802                 = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
803         return security_session_user_level(session_info) == SECURITY_SYSTEM;
804 }