s4-dsdb: check the type of session_info from the opaque
[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         /* Run the new request */
75         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
76                 ret = ldb_next_request(module, req);
77         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
78                 ret = ldb_request(ldb_module_get_ctx(module), req);
79         } else {
80                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
81                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
82                 ret = ops->modify(module, req);
83         }
84         if (ret == LDB_SUCCESS) {
85                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
86         }
87
88         if (ret != LDB_SUCCESS) {
89                 talloc_free(tmp_ctx);
90                 return ret;
91         }
92
93         if (res->count != 1) {
94                 /* we may be reading a DB that does not have the 'check base on search' option... */
95                 ret = LDB_ERR_NO_SUCH_OBJECT;
96                 ldb_asprintf_errstring(ldb_module_get_ctx(module), 
97                                        "dsdb_module_search_dn: did not find base dn %s (%d results)", 
98                                        ldb_dn_get_linearized(basedn), res->count);
99         } else {
100                 *_res = talloc_steal(mem_ctx, res);
101         }
102         talloc_free(tmp_ctx);
103         return ret;
104 }
105
106 /*
107   search for attrs in the modules below
108  */
109 int dsdb_module_search(struct ldb_module *module,
110                        TALLOC_CTX *mem_ctx,
111                        struct ldb_result **_res,
112                        struct ldb_dn *basedn, enum ldb_scope scope, 
113                        const char * const *attrs,
114                        int dsdb_flags, 
115                        const char *format, ...) _PRINTF_ATTRIBUTE(8, 9)
116 {
117         int ret;
118         struct ldb_request *req;
119         TALLOC_CTX *tmp_ctx;
120         struct ldb_result *res;
121         va_list ap;
122         char *expression;
123
124         tmp_ctx = talloc_new(mem_ctx);
125
126         if (format) {
127                 va_start(ap, format);
128                 expression = talloc_vasprintf(tmp_ctx, format, ap);
129                 va_end(ap);
130
131                 if (!expression) {
132                         talloc_free(tmp_ctx);
133                         return ldb_oom(ldb_module_get_ctx(module));
134                 }
135         } else {
136                 expression = NULL;
137         }
138
139         res = talloc_zero(tmp_ctx, struct ldb_result);
140         if (!res) {
141                 talloc_free(tmp_ctx);
142                 return ldb_oom(ldb_module_get_ctx(module));
143         }
144
145         ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
146                                    basedn,
147                                    scope,
148                                    expression,
149                                    attrs,
150                                    NULL,
151                                    res,
152                                    ldb_search_default_callback,
153                                    NULL);
154         if (ret != LDB_SUCCESS) {
155                 talloc_free(tmp_ctx);
156                 return ret;
157         }
158
159         ret = dsdb_request_add_controls(req, dsdb_flags);
160         if (ret != LDB_SUCCESS) {
161                 talloc_free(tmp_ctx);
162                 return ret;
163         }
164
165         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
166                 ret = ldb_next_request(module, req);
167         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
168                 ret = ldb_request(ldb_module_get_ctx(module), req);
169         } else {
170                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
171                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
172                 ret = ops->search(module, req);
173         }
174         if (ret == LDB_SUCCESS) {
175                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
176         }
177
178         talloc_free(req);
179         if (ret == LDB_SUCCESS) {
180                 *_res = talloc_steal(mem_ctx, res);
181         }
182         talloc_free(tmp_ctx);
183         return ret;
184 }
185
186 /*
187   find a DN given a GUID. This searches across all partitions
188  */
189 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
190                            const struct GUID *guid, struct ldb_dn **dn)
191 {
192         struct ldb_result *res;
193         const char *attrs[] = { NULL };
194         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
195         int ret;
196
197         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
198                                  attrs,
199                                  DSDB_FLAG_NEXT_MODULE |
200                                  DSDB_SEARCH_SHOW_DELETED |
201                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
202                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
203                                  "objectGUID=%s", GUID_string(tmp_ctx, guid));
204         if (ret != LDB_SUCCESS) {
205                 talloc_free(tmp_ctx);
206                 return ret;
207         }
208         if (res->count == 0) {
209                 talloc_free(tmp_ctx);
210                 return LDB_ERR_NO_SUCH_OBJECT;
211         }
212         if (res->count != 1) {
213                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
214                                        GUID_string(tmp_ctx, guid));
215                 talloc_free(tmp_ctx);
216                 return LDB_ERR_OPERATIONS_ERROR;
217         }
218
219         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
220
221         talloc_free(tmp_ctx);
222         return LDB_SUCCESS;
223 }
224
225 /*
226   find a GUID given a DN.
227  */
228 int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid)
229 {
230         const char *attrs[] = { NULL };
231         struct ldb_result *res;
232         TALLOC_CTX *tmp_ctx = talloc_new(module);
233         int ret;
234         NTSTATUS status;
235
236         ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
237                                     DSDB_FLAG_NEXT_MODULE |
238                                     DSDB_SEARCH_SHOW_DELETED |
239                                     DSDB_SEARCH_SHOW_EXTENDED_DN);
240         if (ret != LDB_SUCCESS) {
241                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
242                                        ldb_dn_get_linearized(dn));
243                 talloc_free(tmp_ctx);
244                 return ret;
245         }
246
247         status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
248         if (!NT_STATUS_IS_OK(status)) {
249                 talloc_free(tmp_ctx);
250                 return ldb_operr(ldb_module_get_ctx(module));
251         }
252
253         talloc_free(tmp_ctx);
254         return LDB_SUCCESS;
255 }
256
257 /*
258   a ldb_modify request operating on modules below the
259   current module
260  */
261 int dsdb_module_modify(struct ldb_module *module,
262                        const struct ldb_message *message,
263                        uint32_t dsdb_flags)
264 {
265         struct ldb_request *mod_req;
266         int ret;
267         struct ldb_context *ldb = ldb_module_get_ctx(module);
268         TALLOC_CTX *tmp_ctx = talloc_new(module);
269         struct ldb_result *res;
270
271         res = talloc_zero(tmp_ctx, struct ldb_result);
272         if (!res) {
273                 talloc_free(tmp_ctx);
274                 return ldb_oom(ldb_module_get_ctx(module));
275         }
276
277         ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
278                                 message,
279                                 NULL,
280                                 res,
281                                 ldb_modify_default_callback,
282                                 NULL);
283         if (ret != LDB_SUCCESS) {
284                 talloc_free(tmp_ctx);
285                 return ret;
286         }
287
288         ret = dsdb_request_add_controls(mod_req, dsdb_flags);
289         if (ret != LDB_SUCCESS) {
290                 talloc_free(tmp_ctx);
291                 return ret;
292         }
293
294         /* Run the new request */
295         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
296                 ret = ldb_next_request(module, mod_req);
297         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
298                 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
299         } else {
300                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
301                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
302                 ret = ops->modify(module, mod_req);
303         }
304         if (ret == LDB_SUCCESS) {
305                 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
306         }
307
308         talloc_free(tmp_ctx);
309         return ret;
310 }
311
312
313
314 /*
315   a ldb_rename request operating on modules below the
316   current module
317  */
318 int dsdb_module_rename(struct ldb_module *module,
319                       struct ldb_dn *olddn, struct ldb_dn *newdn,
320                       uint32_t dsdb_flags)
321 {
322         struct ldb_request *req;
323         int ret;
324         struct ldb_context *ldb = ldb_module_get_ctx(module);
325         TALLOC_CTX *tmp_ctx = talloc_new(module);
326         struct ldb_result *res;
327
328         res = talloc_zero(tmp_ctx, struct ldb_result);
329         if (!res) {
330                 talloc_free(tmp_ctx);
331                 return ldb_oom(ldb_module_get_ctx(module));
332         }
333
334         ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
335                                    olddn,
336                                    newdn,
337                                    NULL,
338                                    res,
339                                    ldb_modify_default_callback,
340                                    NULL);
341         if (ret != LDB_SUCCESS) {
342                 talloc_free(tmp_ctx);
343                 return ret;
344         }
345
346         ret = dsdb_request_add_controls(req, dsdb_flags);
347         if (ret != LDB_SUCCESS) {
348                 talloc_free(tmp_ctx);
349                 return ret;
350         }
351
352         /* Run the new request */
353         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
354                 ret = ldb_next_request(module, req);
355         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
356                 ret = ldb_request(ldb_module_get_ctx(module), req);
357         } else {
358                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
359                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
360                 ret = ops->rename(module, req);
361         }
362         if (ret == LDB_SUCCESS) {
363                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
364         }
365
366         talloc_free(tmp_ctx);
367         return ret;
368 }
369
370 /*
371   a ldb_add request operating on modules below the
372   current module
373  */
374 int dsdb_module_add(struct ldb_module *module,
375                     const struct ldb_message *message,
376                     uint32_t dsdb_flags)
377 {
378         struct ldb_request *req;
379         int ret;
380         struct ldb_context *ldb = ldb_module_get_ctx(module);
381         TALLOC_CTX *tmp_ctx = talloc_new(module);
382         struct ldb_result *res;
383
384         res = talloc_zero(tmp_ctx, struct ldb_result);
385         if (!res) {
386                 talloc_free(tmp_ctx);
387                 return ldb_oom(ldb_module_get_ctx(module));
388         }
389
390         ret = ldb_build_add_req(&req, ldb, tmp_ctx,
391                                 message,
392                                 NULL,
393                                 res,
394                                 ldb_modify_default_callback,
395                                 NULL);
396         if (ret != LDB_SUCCESS) {
397                 talloc_free(tmp_ctx);
398                 return ret;
399         }
400
401         ret = dsdb_request_add_controls(req, dsdb_flags);
402         if (ret != LDB_SUCCESS) {
403                 talloc_free(tmp_ctx);
404                 return ret;
405         }
406
407         /* Run the new request */
408         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
409                 ret = ldb_next_request(module, req);
410         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
411                 ret = ldb_request(ldb_module_get_ctx(module), req);
412         } else {
413                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
414                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
415                 ret = ops->add(module, req);
416         }
417         if (ret == LDB_SUCCESS) {
418                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
419         }
420
421         talloc_free(tmp_ctx);
422         return ret;
423 }
424
425 /*
426   a ldb_delete request operating on modules below the
427   current module
428  */
429 int dsdb_module_del(struct ldb_module *module,
430                     struct ldb_dn *dn,
431                     uint32_t dsdb_flags)
432 {
433         struct ldb_request *req;
434         int ret;
435         struct ldb_context *ldb = ldb_module_get_ctx(module);
436         TALLOC_CTX *tmp_ctx = talloc_new(module);
437         struct ldb_result *res;
438
439         res = talloc_zero(tmp_ctx, struct ldb_result);
440         if (!res) {
441                 talloc_free(tmp_ctx);
442                 return ldb_oom(ldb);
443         }
444
445         ret = ldb_build_del_req(&req, ldb, tmp_ctx,
446                                 dn,
447                                 NULL,
448                                 res,
449                                 ldb_modify_default_callback,
450                                 NULL);
451         if (ret != LDB_SUCCESS) {
452                 talloc_free(tmp_ctx);
453                 return ret;
454         }
455
456         ret = dsdb_request_add_controls(req, dsdb_flags);
457         if (ret != LDB_SUCCESS) {
458                 talloc_free(tmp_ctx);
459                 return ret;
460         }
461
462         /* Run the new request */
463         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
464                 ret = ldb_next_request(module, req);
465         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
466                 ret = ldb_request(ldb_module_get_ctx(module), req);
467         } else {
468                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
469                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
470                 ret = ops->del(module, req);
471         }
472         if (ret == LDB_SUCCESS) {
473                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
474         }
475
476         talloc_free(tmp_ctx);
477         return ret;
478 }
479
480 const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *schema,const struct ldb_message_element *element)
481 {
482         const struct dsdb_class *last_class = NULL;
483         unsigned int i;
484
485         for (i = 0; i < element->num_values; i++){
486                 const struct dsdb_class *tmp_class = dsdb_class_by_lDAPDisplayName_ldb_val(schema, &element->values[i]);
487
488                 if(tmp_class == NULL) {
489                         continue;
490                 }
491
492                 if(tmp_class->objectClassCategory > 1) {
493                         continue;
494                 }
495
496                 if (!last_class) {
497                         last_class = tmp_class;
498                 } else {
499                         if (tmp_class->subClass_order > last_class->subClass_order)
500                                 last_class = tmp_class;
501                 }
502         }
503
504         return last_class;
505 }
506
507 /*
508   check if a single valued link has multiple non-deleted values
509
510   This is needed when we will be using the RELAX control to stop
511   ldb_tdb from checking single valued links
512  */
513 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
514                                   const struct ldb_message_element *el)
515 {
516         bool found_active = false;
517         unsigned int i;
518
519         if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
520             el->num_values < 2) {
521                 return LDB_SUCCESS;
522         }
523
524         for (i=0; i<el->num_values; i++) {
525                 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
526                         if (found_active) {
527                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
528                         }
529                         found_active = true;
530                 }
531         }
532
533         return LDB_SUCCESS;
534 }
535
536 int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
537                                         struct GUID op_feature_guid, bool *feature_enabled)
538 {
539         TALLOC_CTX *tmp_ctx;
540         struct ldb_context *ldb = ldb_module_get_ctx(module);
541         struct ldb_result *res;
542         struct ldb_dn *search_dn;
543         struct GUID search_guid;
544         const char *attrs[] = {"msDS-EnabledFeature", NULL};
545         int ret;
546         unsigned int i;
547         struct ldb_message_element *el;
548
549         *feature_enabled = false;
550
551         tmp_ctx = talloc_new(ldb);
552
553         ret = ldb_search(ldb, tmp_ctx, &res,
554                                         scope, LDB_SCOPE_BASE, attrs,
555                                         NULL);
556         if (ret != LDB_SUCCESS) {
557                 ldb_asprintf_errstring(ldb,
558                                 "Could no find the scope object - dn: %s\n",
559                                 ldb_dn_get_linearized(scope));
560                 talloc_free(tmp_ctx);
561                 return LDB_ERR_OPERATIONS_ERROR;
562         }
563         if (res->msgs[0]->num_elements > 0) {
564
565                 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
566
567                 attrs[0] = "msDS-OptionalFeatureGUID";
568
569                 for (i=0; i<el->num_values; i++) {
570                         search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
571
572                         ret = ldb_search(ldb, tmp_ctx, &res,
573                                                         search_dn, LDB_SCOPE_BASE, attrs,
574                                                         NULL);
575                         if (ret != LDB_SUCCESS) {
576                                 ldb_asprintf_errstring(ldb,
577                                                 "Could no find object dn: %s\n",
578                                                 ldb_dn_get_linearized(search_dn));
579                                 talloc_free(tmp_ctx);
580                                 return LDB_ERR_OPERATIONS_ERROR;
581                         }
582
583                         search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
584
585                         if (GUID_compare(&search_guid, &op_feature_guid) == 0){
586                                 *feature_enabled = true;
587                                 break;
588                         }
589                 }
590         }
591         talloc_free(tmp_ctx);
592         return LDB_SUCCESS;
593 }
594
595 /*
596   find a 'reference' DN that points at another object
597   (eg. serverReference, rIDManagerReference etc)
598  */
599 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
600                              const char *attribute, struct ldb_dn **dn)
601 {
602         const char *attrs[2];
603         struct ldb_result *res;
604         int ret;
605
606         attrs[0] = attribute;
607         attrs[1] = NULL;
608
609         ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs,
610                                     DSDB_FLAG_NEXT_MODULE);
611         if (ret != LDB_SUCCESS) {
612                 return ret;
613         }
614
615         *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
616                                       mem_ctx, res->msgs[0], attribute);
617         if (!*dn) {
618                 talloc_free(res);
619                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
620         }
621
622         talloc_free(res);
623         return LDB_SUCCESS;
624 }
625
626 /*
627   find the RID Manager$ DN via the rIDManagerReference attribute in the
628   base DN
629  */
630 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
631 {
632         return dsdb_module_reference_dn(module, mem_ctx,
633                                         ldb_get_default_basedn(ldb_module_get_ctx(module)),
634                                         "rIDManagerReference", dn);
635 }
636
637
638 /*
639   update an integer attribute safely via a constrained delete/add
640  */
641 int dsdb_module_constrainted_update_integer(struct ldb_module *module, struct ldb_dn *dn,
642                                             const char *attr, uint64_t old_val, uint64_t new_val)
643 {
644         struct ldb_message *msg;
645         struct ldb_message_element *el;
646         struct ldb_val v1, v2;
647         int ret;
648         char *vstring;
649
650         msg = ldb_msg_new(module);
651         msg->dn = dn;
652
653         ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
654         if (ret != LDB_SUCCESS) {
655                 talloc_free(msg);
656                 return ret;
657         }
658         el->num_values = 1;
659         el->values = &v1;
660         vstring = talloc_asprintf(msg, "%llu", (unsigned long long)old_val);
661         if (!vstring) {
662                 talloc_free(msg);
663                 return ldb_module_oom(module);
664         }
665         v1 = data_blob_string_const(vstring);
666
667         ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
668         if (ret != LDB_SUCCESS) {
669                 talloc_free(msg);
670                 return ret;
671         }
672         el->num_values = 1;
673         el->values = &v2;
674         vstring = talloc_asprintf(msg, "%llu", (unsigned long long)new_val);
675         if (!vstring) {
676                 talloc_free(msg);
677                 return ldb_module_oom(module);
678         }
679         v2 = data_blob_string_const(vstring);
680
681         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
682         talloc_free(msg);
683         return ret;
684 }
685
686 /*
687   used to chain to the callers callback
688  */
689 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
690 {
691         struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
692
693         talloc_steal(up_req, req);
694         return up_req->callback(up_req, ares);
695 }
696
697
698 /*
699   set an integer attribute
700  */
701 int dsdb_module_set_integer(struct ldb_module *module, struct ldb_dn *dn,
702                             const char *attr, uint64_t new_val)
703 {
704         struct ldb_message *msg;
705         int ret;
706
707         msg = ldb_msg_new(module);
708         msg->dn = dn;
709
710         ret = ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)new_val);
711         if (ret != LDB_SUCCESS) {
712                 talloc_free(msg);
713                 return ret;
714         }
715         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
716
717         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
718         talloc_free(msg);
719         return ret;
720 }
721
722 /*
723   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
724   object for a partition
725  */
726 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
727                                   uint64_t *uSN, uint64_t *urgent_uSN)
728 {
729         struct ldb_context *ldb = ldb_module_get_ctx(module);
730         struct ldb_request *req;
731         int ret;
732         TALLOC_CTX *tmp_ctx = talloc_new(module);
733         struct dsdb_control_current_partition *p_ctrl;
734         struct ldb_result *res;
735
736         res = talloc_zero(tmp_ctx, struct ldb_result);
737         if (!res) {
738                 talloc_free(tmp_ctx);
739                 return ldb_module_oom(module);
740         }
741
742         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
743                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
744                                    LDB_SCOPE_BASE,
745                                    NULL, NULL,
746                                    NULL,
747                                    res, ldb_search_default_callback,
748                                    NULL);
749         if (ret != LDB_SUCCESS) {
750                 talloc_free(tmp_ctx);
751                 return ret;
752         }
753
754         p_ctrl = talloc(req, struct dsdb_control_current_partition);
755         if (p_ctrl == NULL) {
756                 talloc_free(tmp_ctx);
757                 return ldb_module_oom(module);
758         }
759         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
760         p_ctrl->dn = dn;
761
762
763         ret = ldb_request_add_control(req,
764                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
765                                       false, p_ctrl);
766         if (ret != LDB_SUCCESS) {
767                 talloc_free(tmp_ctx);
768                 return ret;
769         }
770
771         /* Run the new request */
772         ret = ldb_next_request(module, req);
773
774         if (ret == LDB_SUCCESS) {
775                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
776         }
777
778         if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
779                 /* it hasn't been created yet, which means
780                    an implicit value of zero */
781                 *uSN = 0;
782                 talloc_free(tmp_ctx);
783                 return LDB_SUCCESS;
784         }
785
786         if (ret != LDB_SUCCESS) {
787                 talloc_free(tmp_ctx);
788                 return ret;
789         }
790
791         if (res->count != 1) {
792                 *uSN = 0;
793                 if (urgent_uSN) {
794                         *urgent_uSN = 0;
795                 }
796         } else {
797                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
798                 if (urgent_uSN) {
799                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
800                 }
801         }
802
803         talloc_free(tmp_ctx);
804
805         return LDB_SUCCESS;
806 }
807
808 /*
809   save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
810   partition
811  */
812 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
813                                    uint64_t uSN, uint64_t urgent_uSN)
814 {
815         struct ldb_context *ldb = ldb_module_get_ctx(module);
816         struct ldb_request *req;
817         struct ldb_message *msg;
818         struct dsdb_control_current_partition *p_ctrl;
819         int ret;
820         struct ldb_result *res;
821
822         msg = ldb_msg_new(module);
823         if (msg == NULL) {
824                 return ldb_module_oom(module);
825         }
826
827         msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
828         if (msg->dn == NULL) {
829                 talloc_free(msg);
830                 return ldb_operr(ldb_module_get_ctx(module));
831         }
832
833         res = talloc_zero(msg, struct ldb_result);
834         if (!res) {
835                 talloc_free(msg);
836                 return ldb_module_oom(module);
837         }
838
839         ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
840         if (ret != LDB_SUCCESS) {
841                 talloc_free(msg);
842                 return ret;
843         }
844         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
845
846         /* urgent_uSN is optional so may not be stored */
847         if (urgent_uSN) {
848                 ret = ldb_msg_add_fmt(msg, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN);
849                 if (ret != LDB_SUCCESS) {
850                         talloc_free(msg);
851                         return ret;
852                 }
853                 msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
854         }
855
856
857         p_ctrl = talloc(msg, struct dsdb_control_current_partition);
858         if (p_ctrl == NULL) {
859                 talloc_free(msg);
860                 return ldb_oom(ldb);
861         }
862         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
863         p_ctrl->dn = dn;
864         ret = ldb_build_mod_req(&req, ldb, msg,
865                                 msg,
866                                 NULL,
867                                 res,
868                                 ldb_modify_default_callback,
869                                 NULL);
870 again:
871         if (ret != LDB_SUCCESS) {
872                 talloc_free(msg);
873                 return ret;
874         }
875
876         ret = ldb_request_add_control(req,
877                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
878                                       false, p_ctrl);
879         if (ret != LDB_SUCCESS) {
880                 talloc_free(msg);
881                 return ret;
882         }
883
884         /* Run the new request */
885         ret = ldb_next_request(module, req);
886
887         if (ret == LDB_SUCCESS) {
888                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
889         }
890         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
891                 ret = ldb_build_add_req(&req, ldb, msg,
892                                         msg,
893                                         NULL,
894                                         res,
895                                         ldb_modify_default_callback,
896                                         NULL);
897                 goto again;
898         }
899
900         talloc_free(msg);
901
902         return ret;
903 }
904
905 bool dsdb_module_am_system(struct ldb_module *module)
906 {
907         struct ldb_context *ldb = ldb_module_get_ctx(module);
908         struct auth_session_info *session_info
909                 = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
910         return security_session_user_level(session_info, NULL) == SECURITY_SYSTEM;
911 }
912
913 bool dsdb_module_am_administrator(struct ldb_module *module)
914 {
915         struct ldb_context *ldb = ldb_module_get_ctx(module);
916         struct auth_session_info *session_info
917                 = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
918         return security_session_user_level(session_info, NULL) == SECURITY_ADMINISTRATOR;
919 }
920
921 /*
922   check if the recyclebin is enabled
923  */
924 int dsdb_recyclebin_enabled(struct ldb_module *module, bool *enabled)
925 {
926         struct ldb_context *ldb = ldb_module_get_ctx(module);
927         struct ldb_dn *partitions_dn;
928         struct GUID recyclebin_guid;
929         int ret;
930
931         partitions_dn = samdb_partitions_dn(ldb, module);
932
933         GUID_from_string(DS_GUID_FEATURE_RECYCLE_BIN, &recyclebin_guid);
934
935         ret = dsdb_check_optional_feature(module, partitions_dn, recyclebin_guid, enabled);
936         if (ret != LDB_SUCCESS) {
937                 ldb_asprintf_errstring(ldb, "Could not verify if Recycle Bin is enabled \n");
938                 talloc_free(partitions_dn);
939                 return LDB_ERR_UNWILLING_TO_PERFORM;
940         }
941
942         talloc_free(partitions_dn);
943         return LDB_SUCCESS;
944 }
945
946 bool is_attr_in_list(const char * const * attrs, const char *attr)
947 {
948         unsigned int i;
949
950         for (i = 0; attrs[i]; i++) {
951                 if (ldb_attr_cmp(attrs[i], attr) == 0)
952                         return true;
953         }
954
955         return false;
956 }
957
958 int dsdb_msg_constrainted_update_int32(struct ldb_module *module,
959                                        struct ldb_message *msg,
960                                        const char *attr,
961                                        const int32_t *old_val,
962                                        const int32_t *new_val)
963 {
964         struct ldb_message_element *el;
965         int ret;
966         char *vstring;
967
968         if (old_val) {
969                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
970                 if (ret != LDB_SUCCESS) {
971                         return ret;
972                 }
973                 el->num_values = 1;
974                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
975                 if (!el->values) {
976                         return ldb_module_oom(module);
977                 }
978                 vstring = talloc_asprintf(el->values, "%ld", (long)*old_val);
979                 if (!vstring) {
980                         return ldb_module_oom(module);
981                 }
982                 *el->values = data_blob_string_const(vstring);
983         }
984
985         if (new_val) {
986                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
987                 if (ret != LDB_SUCCESS) {
988                         return ret;
989                 }
990                 el->num_values = 1;
991                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
992                 if (!el->values) {
993                         return ldb_module_oom(module);
994                 }
995                 vstring = talloc_asprintf(el->values, "%ld", (long)*new_val);
996                 if (!vstring) {
997                         return ldb_module_oom(module);
998                 }
999                 *el->values = data_blob_string_const(vstring);
1000         }
1001
1002         return LDB_SUCCESS;
1003 }
1004
1005 int dsdb_msg_constrainted_update_uint32(struct ldb_module *module,
1006                                         struct ldb_message *msg,
1007                                         const char *attr,
1008                                         const uint32_t *old_val,
1009                                         const uint32_t *new_val)
1010 {
1011         return dsdb_msg_constrainted_update_int32(module, msg, attr,
1012                                                   (const int32_t *)old_val,
1013                                                   (const int32_t *)new_val);
1014 }
1015
1016 int dsdb_msg_constrainted_update_int64(struct ldb_module *module,
1017                                        struct ldb_message *msg,
1018                                        const char *attr,
1019                                        const int64_t *old_val,
1020                                        const int64_t *new_val)
1021 {
1022         struct ldb_message_element *el;
1023         int ret;
1024         char *vstring;
1025
1026         if (old_val) {
1027                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
1028                 if (ret != LDB_SUCCESS) {
1029                         return ret;
1030                 }
1031                 el->num_values = 1;
1032                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1033                 if (!el->values) {
1034                         return ldb_module_oom(module);
1035                 }
1036                 vstring = talloc_asprintf(el->values, "%lld", (long long)*old_val);
1037                 if (!vstring) {
1038                         return ldb_module_oom(module);
1039                 }
1040                 *el->values = data_blob_string_const(vstring);
1041         }
1042
1043         if (new_val) {
1044                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
1045                 if (ret != LDB_SUCCESS) {
1046                         return ret;
1047                 }
1048                 el->num_values = 1;
1049                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1050                 if (!el->values) {
1051                         return ldb_module_oom(module);
1052                 }
1053                 vstring = talloc_asprintf(el->values, "%lld", (long long)*new_val);
1054                 if (!vstring) {
1055                         return ldb_module_oom(module);
1056                 }
1057                 *el->values = data_blob_string_const(vstring);
1058         }
1059
1060         return LDB_SUCCESS;
1061 }
1062
1063 int dsdb_msg_constrainted_update_uint64(struct ldb_module *module,
1064                                         struct ldb_message *msg,
1065                                         const char *attr,
1066                                         const uint64_t *old_val,
1067                                         const uint64_t *new_val)
1068 {
1069         return dsdb_msg_constrainted_update_int64(module, msg, attr,
1070                                                   (const int64_t *)old_val,
1071                                                   (const int64_t *)new_val);
1072 }
1073
1074 /*
1075   update an int32 attribute safely via a constrained delete/add
1076  */
1077 int dsdb_module_constrainted_update_int32(struct ldb_module *module,
1078                                           struct ldb_dn *dn,
1079                                           const char *attr,
1080                                           const int32_t *old_val,
1081                                           const int32_t *new_val)
1082 {
1083         struct ldb_message *msg;
1084         int ret;
1085
1086         msg = ldb_msg_new(module);
1087         msg->dn = dn;
1088
1089         ret = dsdb_msg_constrainted_update_int32(module,
1090                                                  msg, attr,
1091                                                  old_val,
1092                                                  new_val);
1093         if (ret != LDB_SUCCESS) {
1094                 talloc_free(msg);
1095                 return ret;
1096         }
1097
1098         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
1099         talloc_free(msg);
1100         return ret;
1101 }
1102
1103 int dsdb_module_constrainted_update_uint32(struct ldb_module *module,
1104                                            struct ldb_dn *dn,
1105                                            const char *attr,
1106                                            const uint32_t *old_val,
1107                                            const uint32_t *new_val)
1108 {
1109         return dsdb_module_constrainted_update_int32(module, dn, attr,
1110                                                      (const int32_t *)old_val,
1111                                                      (const int32_t *)new_val);
1112 }
1113
1114 /*
1115   update an int64 attribute safely via a constrained delete/add
1116  */
1117 int dsdb_module_constrainted_update_int64(struct ldb_module *module,
1118                                           struct ldb_dn *dn,
1119                                           const char *attr,
1120                                           const int64_t *old_val,
1121                                           const int64_t *new_val)
1122 {
1123         struct ldb_message *msg;
1124         int ret;
1125
1126         msg = ldb_msg_new(module);
1127         msg->dn = dn;
1128
1129         ret = dsdb_msg_constrainted_update_int64(module,
1130                                                  msg, attr,
1131                                                  old_val,
1132                                                  new_val);
1133         if (ret != LDB_SUCCESS) {
1134                 talloc_free(msg);
1135                 return ret;
1136         }
1137
1138         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE);
1139         talloc_free(msg);
1140         return ret;
1141 }
1142
1143 int dsdb_module_constrainted_update_uint64(struct ldb_module *module,
1144                                            struct ldb_dn *dn,
1145                                            const char *attr,
1146                                            const uint64_t *old_val,
1147                                            const uint64_t *new_val)
1148 {
1149         return dsdb_module_constrainted_update_int64(module, dn, attr,
1150                                                      (const int64_t *)old_val,
1151                                                      (const int64_t *)new_val);
1152 }