s4-dsdb: fixed the check_optional_feature() call
[mat/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    Copyright (C) Matthieu Patou <mat@matws.net> 2011
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "ldb.h"
25 #include "ldb_module.h"
26 #include "librpc/ndr/libndr.h"
27 #include "dsdb/samdb/ldb_modules/util.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "dsdb/common/util.h"
30 #include "libcli/security/security.h"
31
32 /*
33   search for attrs on one DN, in the modules below
34  */
35 int dsdb_module_search_dn(struct ldb_module *module,
36                           TALLOC_CTX *mem_ctx,
37                           struct ldb_result **_res,
38                           struct ldb_dn *basedn,
39                           const char * const *attrs,
40                           uint32_t dsdb_flags,
41                           struct ldb_request *parent)
42 {
43         int ret;
44         struct ldb_request *req;
45         TALLOC_CTX *tmp_ctx;
46         struct ldb_result *res;
47
48         tmp_ctx = talloc_new(mem_ctx);
49
50         res = talloc_zero(tmp_ctx, struct ldb_result);
51         if (!res) {
52                 talloc_free(tmp_ctx);
53                 return ldb_oom(ldb_module_get_ctx(module));
54         }
55
56         ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
57                                    basedn,
58                                    LDB_SCOPE_BASE,
59                                    NULL,
60                                    attrs,
61                                    NULL,
62                                    res,
63                                    ldb_search_default_callback,
64                                    parent);
65         LDB_REQ_SET_LOCATION(req);
66         if (ret != LDB_SUCCESS) {
67                 talloc_free(tmp_ctx);
68                 return ret;
69         }
70
71         ret = dsdb_request_add_controls(req, dsdb_flags);
72         if (ret != LDB_SUCCESS) {
73                 talloc_free(tmp_ctx);
74                 return ret;
75         }
76
77         if (dsdb_flags & DSDB_FLAG_TRUSTED) {
78                 ldb_req_mark_trusted(req);
79         }
80
81         /* Run the new request */
82         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
83                 ret = ldb_next_request(module, req);
84         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
85                 ret = ldb_request(ldb_module_get_ctx(module), req);
86         } else {
87                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
88                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
89                 ret = ops->search(module, req);
90         }
91         if (ret == LDB_SUCCESS) {
92                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
93         }
94
95         if (ret != LDB_SUCCESS) {
96                 talloc_free(tmp_ctx);
97                 return ret;
98         }
99
100         if (res->count != 1) {
101                 /* we may be reading a DB that does not have the 'check base on search' option... */
102                 ret = LDB_ERR_NO_SUCH_OBJECT;
103                 ldb_asprintf_errstring(ldb_module_get_ctx(module), 
104                                        "dsdb_module_search_dn: did not find base dn %s (%d results)", 
105                                        ldb_dn_get_linearized(basedn), res->count);
106         } else {
107                 *_res = talloc_steal(mem_ctx, res);
108         }
109         talloc_free(tmp_ctx);
110         return ret;
111 }
112
113 int dsdb_module_search_tree(struct ldb_module *module,
114                        TALLOC_CTX *mem_ctx,
115                        struct ldb_result **_res,
116                        struct ldb_dn *basedn,
117                        enum ldb_scope scope,
118                        struct ldb_parse_tree *tree,
119                        const char * const *attrs,
120                        int dsdb_flags,
121                        struct ldb_request *parent)
122 {
123         int ret;
124         struct ldb_request *req;
125         TALLOC_CTX *tmp_ctx;
126         struct ldb_result *res;
127
128         tmp_ctx = talloc_new(mem_ctx);
129
130         /* cross-partitions searches with a basedn break multi-domain support */
131         SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
132
133         res = talloc_zero(tmp_ctx, struct ldb_result);
134         if (!res) {
135                 talloc_free(tmp_ctx);
136                 return ldb_oom(ldb_module_get_ctx(module));
137         }
138
139         ret = ldb_build_search_req_ex(&req, ldb_module_get_ctx(module), tmp_ctx,
140                                    basedn,
141                                    scope,
142                                    tree,
143                                    attrs,
144                                    NULL,
145                                    res,
146                                    ldb_search_default_callback,
147                                    parent);
148         LDB_REQ_SET_LOCATION(req);
149         if (ret != LDB_SUCCESS) {
150                 talloc_free(tmp_ctx);
151                 return ret;
152         }
153
154         ret = dsdb_request_add_controls(req, dsdb_flags);
155         if (ret != LDB_SUCCESS) {
156                 talloc_free(tmp_ctx);
157                 return ret;
158         }
159
160         if (dsdb_flags & DSDB_FLAG_TRUSTED) {
161                 ldb_req_mark_trusted(req);
162         }
163
164         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
165                 ret = ldb_next_request(module, req);
166         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
167                 ret = ldb_request(ldb_module_get_ctx(module), req);
168         } else {
169                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
170                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
171                 ret = ops->search(module, req);
172         }
173         if (ret == LDB_SUCCESS) {
174                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
175         }
176
177         talloc_free(req);
178         if (ret == LDB_SUCCESS) {
179                 *_res = talloc_steal(mem_ctx, res);
180         }
181         talloc_free(tmp_ctx);
182         return ret;
183 }
184
185 /*
186   search for attrs in the modules below
187  */
188 int dsdb_module_search(struct ldb_module *module,
189                        TALLOC_CTX *mem_ctx,
190                        struct ldb_result **_res,
191                        struct ldb_dn *basedn, enum ldb_scope scope,
192                        const char * const *attrs,
193                        int dsdb_flags,
194                        struct ldb_request *parent,
195                        const char *format, ...) _PRINTF_ATTRIBUTE(9, 10)
196 {
197         int ret;
198         TALLOC_CTX *tmp_ctx;
199         va_list ap;
200         char *expression;
201         struct ldb_parse_tree *tree;
202
203         /* cross-partitions searches with a basedn break multi-domain support */
204         SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
205
206         tmp_ctx = talloc_new(mem_ctx);
207
208         if (format) {
209                 va_start(ap, format);
210                 expression = talloc_vasprintf(tmp_ctx, format, ap);
211                 va_end(ap);
212
213                 if (!expression) {
214                         talloc_free(tmp_ctx);
215                         return ldb_oom(ldb_module_get_ctx(module));
216                 }
217         } else {
218                 expression = NULL;
219         }
220
221         tree = ldb_parse_tree(tmp_ctx, expression);
222         if (tree == NULL) {
223                 talloc_free(tmp_ctx);
224                 ldb_set_errstring(ldb_module_get_ctx(module),
225                                 "Unable to parse search expression");
226                 return LDB_ERR_OPERATIONS_ERROR;
227         }
228
229         ret = dsdb_module_search_tree(module,
230                        mem_ctx,
231                        _res,
232                        basedn,
233                        scope,
234                        tree,
235                        attrs,
236                        dsdb_flags,
237                        parent);
238
239         talloc_free(tmp_ctx);
240         return ret;
241 }
242
243 /*
244   find a DN given a GUID. This searches across all partitions
245  */
246 int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx,
247                            const struct GUID *guid, struct ldb_dn **dn,
248                            struct ldb_request *parent)
249 {
250         struct ldb_result *res;
251         const char *attrs[] = { NULL };
252         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
253         int ret;
254
255         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE,
256                                  attrs,
257                                  DSDB_FLAG_NEXT_MODULE |
258                                  DSDB_SEARCH_SHOW_RECYCLED |
259                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
260                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
261                                  parent,
262                                  "objectGUID=%s", GUID_string(tmp_ctx, guid));
263         if (ret != LDB_SUCCESS) {
264                 talloc_free(tmp_ctx);
265                 return ret;
266         }
267         if (res->count == 0) {
268                 talloc_free(tmp_ctx);
269                 return LDB_ERR_NO_SUCH_OBJECT;
270         }
271         if (res->count != 1) {
272                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
273                                        GUID_string(tmp_ctx, guid));
274                 talloc_free(tmp_ctx);
275                 return LDB_ERR_OPERATIONS_ERROR;
276         }
277
278         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
279
280         talloc_free(tmp_ctx);
281         return LDB_SUCCESS;
282 }
283
284 /*
285   find a GUID given a DN.
286  */
287 int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid,
288                            struct ldb_request *parent)
289 {
290         const char *attrs[] = { NULL };
291         struct ldb_result *res;
292         TALLOC_CTX *tmp_ctx = talloc_new(module);
293         int ret;
294         NTSTATUS status;
295
296         ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs,
297                                     DSDB_FLAG_NEXT_MODULE |
298                                     DSDB_SEARCH_SHOW_RECYCLED |
299                                     DSDB_SEARCH_SHOW_EXTENDED_DN,
300                                     parent);
301         if (ret != LDB_SUCCESS) {
302                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s",
303                                        ldb_dn_get_linearized(dn));
304                 talloc_free(tmp_ctx);
305                 return ret;
306         }
307
308         status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID");
309         if (!NT_STATUS_IS_OK(status)) {
310                 talloc_free(tmp_ctx);
311                 return ldb_operr(ldb_module_get_ctx(module));
312         }
313
314         talloc_free(tmp_ctx);
315         return LDB_SUCCESS;
316 }
317 /*
318   a ldb_extended request operating on modules below the
319   current module
320  */
321 int dsdb_module_extended(struct ldb_module *module,
322                        const char* oid, void* data,
323                        uint32_t dsdb_flags,
324                        struct ldb_request *parent)
325 {
326         struct ldb_request *req;
327         int ret;
328         struct ldb_context *ldb = ldb_module_get_ctx(module);
329         TALLOC_CTX *tmp_ctx = talloc_new(module);
330         struct ldb_result *res;
331
332         res = talloc_zero(tmp_ctx, struct ldb_result);
333         if (!res) {
334                 talloc_free(tmp_ctx);
335                 return ldb_oom(ldb_module_get_ctx(module));
336         }
337
338         ret = ldb_build_extended_req(&req, ldb,
339                         tmp_ctx,
340                         oid,
341                         data,
342                         NULL,
343                         res, ldb_extended_default_callback,
344                         parent);
345
346         LDB_REQ_SET_LOCATION(req);
347         if (ret != LDB_SUCCESS) {
348                 talloc_free(tmp_ctx);
349                 return ret;
350         }
351
352         ret = dsdb_request_add_controls(req, dsdb_flags);
353         if (ret != LDB_SUCCESS) {
354                 talloc_free(tmp_ctx);
355                 return ret;
356         }
357
358         if (dsdb_flags & DSDB_FLAG_TRUSTED) {
359                 ldb_req_mark_trusted(req);
360         }
361
362         /* Run the new request */
363         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
364                 ret = ldb_next_request(module, req);
365         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
366                 ret = ldb_request(ldb_module_get_ctx(module), req);
367         } else {
368                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
369                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
370                 ret = ops->extended(module, req);
371         }
372         if (ret == LDB_SUCCESS) {
373                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
374         }
375
376         talloc_free(tmp_ctx);
377         return ret;
378 }
379 /*
380   a ldb_modify request operating on modules below the
381   current module
382  */
383 int dsdb_module_modify(struct ldb_module *module,
384                        const struct ldb_message *message,
385                        uint32_t dsdb_flags,
386                        struct ldb_request *parent)
387 {
388         struct ldb_request *mod_req;
389         int ret;
390         struct ldb_context *ldb = ldb_module_get_ctx(module);
391         TALLOC_CTX *tmp_ctx = talloc_new(module);
392         struct ldb_result *res;
393
394         res = talloc_zero(tmp_ctx, struct ldb_result);
395         if (!res) {
396                 talloc_free(tmp_ctx);
397                 return ldb_oom(ldb_module_get_ctx(module));
398         }
399
400         ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx,
401                                 message,
402                                 NULL,
403                                 res,
404                                 ldb_modify_default_callback,
405                                 parent);
406         LDB_REQ_SET_LOCATION(mod_req);
407         if (ret != LDB_SUCCESS) {
408                 talloc_free(tmp_ctx);
409                 return ret;
410         }
411
412         ret = dsdb_request_add_controls(mod_req, dsdb_flags);
413         if (ret != LDB_SUCCESS) {
414                 talloc_free(tmp_ctx);
415                 return ret;
416         }
417
418         if (dsdb_flags & DSDB_FLAG_TRUSTED) {
419                 ldb_req_mark_trusted(mod_req);
420         }
421
422         /* Run the new request */
423         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
424                 ret = ldb_next_request(module, mod_req);
425         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
426                 ret = ldb_request(ldb_module_get_ctx(module), mod_req);
427         } else {
428                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
429                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
430                 ret = ops->modify(module, mod_req);
431         }
432         if (ret == LDB_SUCCESS) {
433                 ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL);
434         }
435
436         talloc_free(tmp_ctx);
437         return ret;
438 }
439
440
441
442 /*
443   a ldb_rename request operating on modules below the
444   current module
445  */
446 int dsdb_module_rename(struct ldb_module *module,
447                        struct ldb_dn *olddn, struct ldb_dn *newdn,
448                        uint32_t dsdb_flags,
449                        struct ldb_request *parent)
450 {
451         struct ldb_request *req;
452         int ret;
453         struct ldb_context *ldb = ldb_module_get_ctx(module);
454         TALLOC_CTX *tmp_ctx = talloc_new(module);
455         struct ldb_result *res;
456
457         res = talloc_zero(tmp_ctx, struct ldb_result);
458         if (!res) {
459                 talloc_free(tmp_ctx);
460                 return ldb_oom(ldb_module_get_ctx(module));
461         }
462
463         ret = ldb_build_rename_req(&req, ldb, tmp_ctx,
464                                    olddn,
465                                    newdn,
466                                    NULL,
467                                    res,
468                                    ldb_modify_default_callback,
469                                    parent);
470         LDB_REQ_SET_LOCATION(req);
471         if (ret != LDB_SUCCESS) {
472                 talloc_free(tmp_ctx);
473                 return ret;
474         }
475
476         ret = dsdb_request_add_controls(req, dsdb_flags);
477         if (ret != LDB_SUCCESS) {
478                 talloc_free(tmp_ctx);
479                 return ret;
480         }
481
482         if (dsdb_flags & DSDB_FLAG_TRUSTED) {
483                 ldb_req_mark_trusted(req);
484         }
485
486         /* Run the new request */
487         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
488                 ret = ldb_next_request(module, req);
489         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
490                 ret = ldb_request(ldb_module_get_ctx(module), req);
491         } else {
492                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
493                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
494                 ret = ops->rename(module, req);
495         }
496         if (ret == LDB_SUCCESS) {
497                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
498         }
499
500         talloc_free(tmp_ctx);
501         return ret;
502 }
503
504 /*
505   a ldb_add request operating on modules below the
506   current module
507  */
508 int dsdb_module_add(struct ldb_module *module,
509                     const struct ldb_message *message,
510                     uint32_t dsdb_flags,
511                     struct ldb_request *parent)
512 {
513         struct ldb_request *req;
514         int ret;
515         struct ldb_context *ldb = ldb_module_get_ctx(module);
516         TALLOC_CTX *tmp_ctx = talloc_new(module);
517         struct ldb_result *res;
518
519         res = talloc_zero(tmp_ctx, struct ldb_result);
520         if (!res) {
521                 talloc_free(tmp_ctx);
522                 return ldb_oom(ldb_module_get_ctx(module));
523         }
524
525         ret = ldb_build_add_req(&req, ldb, tmp_ctx,
526                                 message,
527                                 NULL,
528                                 res,
529                                 ldb_modify_default_callback,
530                                 parent);
531         LDB_REQ_SET_LOCATION(req);
532         if (ret != LDB_SUCCESS) {
533                 talloc_free(tmp_ctx);
534                 return ret;
535         }
536
537         ret = dsdb_request_add_controls(req, dsdb_flags);
538         if (ret != LDB_SUCCESS) {
539                 talloc_free(tmp_ctx);
540                 return ret;
541         }
542
543         if (dsdb_flags & DSDB_FLAG_TRUSTED) {
544                 ldb_req_mark_trusted(req);
545         }
546
547         /* Run the new request */
548         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
549                 ret = ldb_next_request(module, req);
550         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
551                 ret = ldb_request(ldb_module_get_ctx(module), req);
552         } else {
553                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
554                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
555                 ret = ops->add(module, req);
556         }
557         if (ret == LDB_SUCCESS) {
558                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
559         }
560
561         talloc_free(tmp_ctx);
562         return ret;
563 }
564
565 /*
566   a ldb_delete request operating on modules below the
567   current module
568  */
569 int dsdb_module_del(struct ldb_module *module,
570                     struct ldb_dn *dn,
571                     uint32_t dsdb_flags,
572                     struct ldb_request *parent)
573 {
574         struct ldb_request *req;
575         int ret;
576         struct ldb_context *ldb = ldb_module_get_ctx(module);
577         TALLOC_CTX *tmp_ctx = talloc_new(module);
578         struct ldb_result *res;
579
580         res = talloc_zero(tmp_ctx, struct ldb_result);
581         if (!res) {
582                 talloc_free(tmp_ctx);
583                 return ldb_oom(ldb);
584         }
585
586         ret = ldb_build_del_req(&req, ldb, tmp_ctx,
587                                 dn,
588                                 NULL,
589                                 res,
590                                 ldb_modify_default_callback,
591                                 parent);
592         LDB_REQ_SET_LOCATION(req);
593         if (ret != LDB_SUCCESS) {
594                 talloc_free(tmp_ctx);
595                 return ret;
596         }
597
598         ret = dsdb_request_add_controls(req, dsdb_flags);
599         if (ret != LDB_SUCCESS) {
600                 talloc_free(tmp_ctx);
601                 return ret;
602         }
603
604         if (dsdb_flags & DSDB_FLAG_TRUSTED) {
605                 ldb_req_mark_trusted(req);
606         }
607
608         /* Run the new request */
609         if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
610                 ret = ldb_next_request(module, req);
611         } else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
612                 ret = ldb_request(ldb_module_get_ctx(module), req);
613         } else {
614                 const struct ldb_module_ops *ops = ldb_module_get_ops(module);
615                 SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
616                 ret = ops->del(module, req);
617         }
618         if (ret == LDB_SUCCESS) {
619                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
620         }
621
622         talloc_free(tmp_ctx);
623         return ret;
624 }
625
626 /*
627   check if a single valued link has multiple non-deleted values
628
629   This is needed when we will be using the RELAX control to stop
630   ldb_tdb from checking single valued links
631  */
632 int dsdb_check_single_valued_link(const struct dsdb_attribute *attr,
633                                   const struct ldb_message_element *el)
634 {
635         bool found_active = false;
636         unsigned int i;
637
638         if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) ||
639             el->num_values < 2) {
640                 return LDB_SUCCESS;
641         }
642
643         for (i=0; i<el->num_values; i++) {
644                 if (!dsdb_dn_is_deleted_val(&el->values[i])) {
645                         if (found_active) {
646                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
647                         }
648                         found_active = true;
649                 }
650         }
651
652         return LDB_SUCCESS;
653 }
654
655 /*
656   check if an optional feature is enabled on our own NTDS DN
657
658   Note that features can be marked as enabled in more than one
659   place. For example, the recyclebin feature is marked as enabled both
660   on the CN=Partitions,CN=Configurration object and on the NTDS DN of
661   each DC in the forest. It seems likely that it is the job of the KCC
662   to propogate between the two
663  */
664 int dsdb_check_optional_feature(struct ldb_module *module, struct GUID op_feature_guid, bool *feature_enabled)
665 {
666         TALLOC_CTX *tmp_ctx;
667         struct ldb_context *ldb = ldb_module_get_ctx(module);
668         struct ldb_result *res;
669         struct ldb_dn *search_dn;
670         struct GUID search_guid;
671         const char *attrs[] = {"msDS-EnabledFeature", NULL};
672         int ret;
673         unsigned int i;
674         struct ldb_message_element *el;
675         struct ldb_dn *feature_dn;
676
677         feature_dn = samdb_ntds_settings_dn(ldb_module_get_ctx(module));
678         if (feature_dn == NULL) {
679                 return ldb_operr(ldb_module_get_ctx(module));
680         }
681
682         *feature_enabled = false;
683
684         tmp_ctx = talloc_new(ldb);
685
686         ret = dsdb_module_search_dn(module, tmp_ctx, &res, feature_dn, attrs, DSDB_FLAG_NEXT_MODULE, NULL);
687         if (ret != LDB_SUCCESS) {
688                 ldb_asprintf_errstring(ldb,
689                                 "Could not find the feature object - dn: %s\n",
690                                 ldb_dn_get_linearized(feature_dn));
691                 talloc_free(tmp_ctx);
692                 return LDB_ERR_OPERATIONS_ERROR;
693         }
694         if (res->msgs[0]->num_elements > 0) {
695                 const char *attrs2[] = {"msDS-OptionalFeatureGUID", NULL};
696
697                 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
698
699                 for (i=0; i<el->num_values; i++) {
700                         search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
701
702                         ret = dsdb_module_search_dn(module, tmp_ctx, &res,
703                                                     search_dn, attrs2, DSDB_FLAG_NEXT_MODULE, NULL);
704                         if (ret != LDB_SUCCESS) {
705                                 ldb_asprintf_errstring(ldb,
706                                                 "Could no find object dn: %s\n",
707                                                 ldb_dn_get_linearized(search_dn));
708                                 talloc_free(tmp_ctx);
709                                 return LDB_ERR_OPERATIONS_ERROR;
710                         }
711
712                         search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
713
714                         if (GUID_compare(&search_guid, &op_feature_guid) == 0) {
715                                 *feature_enabled = true;
716                                 break;
717                         }
718                 }
719         }
720         talloc_free(tmp_ctx);
721         return LDB_SUCCESS;
722 }
723
724 /*
725   find the NTDS GUID from a computers DN record
726  */
727 int dsdb_module_find_ntdsguid_for_computer(struct ldb_module *module,
728                                            TALLOC_CTX *mem_ctx,
729                                            struct ldb_dn *computer_dn,
730                                            struct GUID *ntds_guid,
731                                            struct ldb_request *parent)
732 {
733         int ret;
734         struct ldb_dn *dn;
735
736         *ntds_guid = GUID_zero();
737
738         ret = dsdb_module_reference_dn(module, mem_ctx, computer_dn,
739                                        "serverReferenceBL", &dn, parent);
740         if (ret != LDB_SUCCESS) {
741                 return ret;
742         }
743
744         if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
745                 talloc_free(dn);
746                 return LDB_ERR_OPERATIONS_ERROR;
747         }
748
749         ret = dsdb_module_guid_by_dn(module, dn, ntds_guid, parent);
750         talloc_free(dn);
751         return ret;
752 }
753
754 /*
755   find a 'reference' DN that points at another object
756   (eg. serverReference, rIDManagerReference etc)
757  */
758 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
759                              const char *attribute, struct ldb_dn **dn, struct ldb_request *parent)
760 {
761         const char *attrs[2];
762         struct ldb_result *res;
763         int ret;
764
765         attrs[0] = attribute;
766         attrs[1] = NULL;
767
768         ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs,
769                                     DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_EXTENDED_DN, parent);
770         if (ret != LDB_SUCCESS) {
771                 return ret;
772         }
773
774         *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
775                                       mem_ctx, res->msgs[0], attribute);
776         if (!*dn) {
777                 ldb_reset_err_string(ldb_module_get_ctx(module));
778                 talloc_free(res);
779                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
780         }
781
782         talloc_free(res);
783         return LDB_SUCCESS;
784 }
785
786 /*
787   find the RID Manager$ DN via the rIDManagerReference attribute in the
788   base DN
789  */
790 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn,
791                                struct ldb_request *parent)
792 {
793         return dsdb_module_reference_dn(module, mem_ctx,
794                                         ldb_get_default_basedn(ldb_module_get_ctx(module)),
795                                         "rIDManagerReference", dn, parent);
796 }
797
798 /*
799   used to chain to the callers callback
800  */
801 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
802 {
803         struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
804
805         talloc_steal(up_req, req);
806         return up_req->callback(up_req, ares);
807 }
808
809 /*
810   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
811   object for a partition
812  */
813 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
814                                    uint64_t *uSN, uint64_t *urgent_uSN, struct ldb_request *parent)
815 {
816         struct ldb_context *ldb = ldb_module_get_ctx(module);
817         struct ldb_request *req;
818         int ret;
819         TALLOC_CTX *tmp_ctx = talloc_new(module);
820         struct dsdb_control_current_partition *p_ctrl;
821         struct ldb_result *res;
822
823         res = talloc_zero(tmp_ctx, struct ldb_result);
824         if (!res) {
825                 talloc_free(tmp_ctx);
826                 return ldb_module_oom(module);
827         }
828
829         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
830                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
831                                    LDB_SCOPE_BASE,
832                                    NULL, NULL,
833                                    NULL,
834                                    res, ldb_search_default_callback,
835                                    parent);
836         LDB_REQ_SET_LOCATION(req);
837         if (ret != LDB_SUCCESS) {
838                 talloc_free(tmp_ctx);
839                 return ret;
840         }
841
842         p_ctrl = talloc(req, struct dsdb_control_current_partition);
843         if (p_ctrl == NULL) {
844                 talloc_free(tmp_ctx);
845                 return ldb_module_oom(module);
846         }
847         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
848         p_ctrl->dn = dn;
849
850
851         ret = ldb_request_add_control(req,
852                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
853                                       false, p_ctrl);
854         if (ret != LDB_SUCCESS) {
855                 talloc_free(tmp_ctx);
856                 return ret;
857         }
858
859         /* Run the new request */
860         ret = ldb_next_request(module, req);
861
862         if (ret == LDB_SUCCESS) {
863                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
864         }
865
866         if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
867                 /* it hasn't been created yet, which means
868                    an implicit value of zero */
869                 *uSN = 0;
870                 talloc_free(tmp_ctx);
871                 ldb_reset_err_string(ldb);
872                 return LDB_SUCCESS;
873         }
874
875         if (ret != LDB_SUCCESS) {
876                 talloc_free(tmp_ctx);
877                 return ret;
878         }
879
880         if (res->count != 1) {
881                 *uSN = 0;
882                 if (urgent_uSN) {
883                         *urgent_uSN = 0;
884                 }
885         } else {
886                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
887                 if (urgent_uSN) {
888                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
889                 }
890         }
891
892         talloc_free(tmp_ctx);
893
894         return LDB_SUCCESS;
895 }
896
897 /*
898   save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
899   partition
900  */
901 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
902                                    uint64_t uSN, uint64_t urgent_uSN,
903                                    struct ldb_request *parent)
904 {
905         struct ldb_context *ldb = ldb_module_get_ctx(module);
906         struct ldb_request *req;
907         struct ldb_message *msg;
908         struct dsdb_control_current_partition *p_ctrl;
909         int ret;
910         struct ldb_result *res;
911
912         msg = ldb_msg_new(module);
913         if (msg == NULL) {
914                 return ldb_module_oom(module);
915         }
916
917         msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
918         if (msg->dn == NULL) {
919                 talloc_free(msg);
920                 return ldb_operr(ldb_module_get_ctx(module));
921         }
922
923         res = talloc_zero(msg, struct ldb_result);
924         if (!res) {
925                 talloc_free(msg);
926                 return ldb_module_oom(module);
927         }
928
929         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNHighest", uSN);
930         if (ret != LDB_SUCCESS) {
931                 talloc_free(msg);
932                 return ret;
933         }
934         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
935
936         /* urgent_uSN is optional so may not be stored */
937         if (urgent_uSN) {
938                 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNUrgent",
939                                            urgent_uSN);
940                 if (ret != LDB_SUCCESS) {
941                         talloc_free(msg);
942                         return ret;
943                 }
944                 msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
945         }
946
947
948         p_ctrl = talloc(msg, struct dsdb_control_current_partition);
949         if (p_ctrl == NULL) {
950                 talloc_free(msg);
951                 return ldb_oom(ldb);
952         }
953         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
954         p_ctrl->dn = dn;
955         ret = ldb_build_mod_req(&req, ldb, msg,
956                                 msg,
957                                 NULL,
958                                 res,
959                                 ldb_modify_default_callback,
960                                 parent);
961         LDB_REQ_SET_LOCATION(req);
962 again:
963         if (ret != LDB_SUCCESS) {
964                 talloc_free(msg);
965                 return ret;
966         }
967
968         ret = ldb_request_add_control(req,
969                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
970                                       false, p_ctrl);
971         if (ret != LDB_SUCCESS) {
972                 talloc_free(msg);
973                 return ret;
974         }
975
976         /* Run the new request */
977         ret = ldb_next_request(module, req);
978
979         if (ret == LDB_SUCCESS) {
980                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
981         }
982         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
983                 ret = ldb_build_add_req(&req, ldb, msg,
984                                         msg,
985                                         NULL,
986                                         res,
987                                         ldb_modify_default_callback,
988                                         parent);
989                 LDB_REQ_SET_LOCATION(req);
990                 goto again;
991         }
992
993         talloc_free(msg);
994
995         return ret;
996 }
997
998 bool dsdb_module_am_system(struct ldb_module *module)
999 {
1000         struct ldb_context *ldb = ldb_module_get_ctx(module);
1001         struct auth_session_info *session_info
1002                 = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
1003         return security_session_user_level(session_info, NULL) == SECURITY_SYSTEM;
1004 }
1005
1006 bool dsdb_module_am_administrator(struct ldb_module *module)
1007 {
1008         struct ldb_context *ldb = ldb_module_get_ctx(module);
1009         struct auth_session_info *session_info
1010                 = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
1011         return security_session_user_level(session_info, NULL) == SECURITY_ADMINISTRATOR;
1012 }
1013
1014 /*
1015   check if the recyclebin is enabled
1016  */
1017 int dsdb_recyclebin_enabled(struct ldb_module *module, bool *enabled)
1018 {
1019         struct ldb_context *ldb = ldb_module_get_ctx(module);
1020         struct GUID recyclebin_guid;
1021         int ret;
1022
1023         GUID_from_string(DS_GUID_FEATURE_RECYCLE_BIN, &recyclebin_guid);
1024
1025         ret = dsdb_check_optional_feature(module, recyclebin_guid, enabled);
1026         if (ret != LDB_SUCCESS) {
1027                 ldb_asprintf_errstring(ldb, "Could not verify if Recycle Bin is enabled \n");
1028                 return LDB_ERR_UNWILLING_TO_PERFORM;
1029         }
1030
1031         return LDB_SUCCESS;
1032 }
1033
1034 int dsdb_msg_constrainted_update_int32(struct ldb_module *module,
1035                                        struct ldb_message *msg,
1036                                        const char *attr,
1037                                        const int32_t *old_val,
1038                                        const int32_t *new_val)
1039 {
1040         struct ldb_message_element *el;
1041         int ret;
1042         char *vstring;
1043
1044         if (old_val) {
1045                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
1046                 if (ret != LDB_SUCCESS) {
1047                         return ret;
1048                 }
1049                 el->num_values = 1;
1050                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1051                 if (!el->values) {
1052                         return ldb_module_oom(module);
1053                 }
1054                 vstring = talloc_asprintf(el->values, "%ld", (long)*old_val);
1055                 if (!vstring) {
1056                         return ldb_module_oom(module);
1057                 }
1058                 *el->values = data_blob_string_const(vstring);
1059         }
1060
1061         if (new_val) {
1062                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
1063                 if (ret != LDB_SUCCESS) {
1064                         return ret;
1065                 }
1066                 el->num_values = 1;
1067                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1068                 if (!el->values) {
1069                         return ldb_module_oom(module);
1070                 }
1071                 vstring = talloc_asprintf(el->values, "%ld", (long)*new_val);
1072                 if (!vstring) {
1073                         return ldb_module_oom(module);
1074                 }
1075                 *el->values = data_blob_string_const(vstring);
1076         }
1077
1078         return LDB_SUCCESS;
1079 }
1080
1081 int dsdb_msg_constrainted_update_uint32(struct ldb_module *module,
1082                                         struct ldb_message *msg,
1083                                         const char *attr,
1084                                         const uint32_t *old_val,
1085                                         const uint32_t *new_val)
1086 {
1087         return dsdb_msg_constrainted_update_int32(module, msg, attr,
1088                                                   (const int32_t *)old_val,
1089                                                   (const int32_t *)new_val);
1090 }
1091
1092 int dsdb_msg_constrainted_update_int64(struct ldb_module *module,
1093                                        struct ldb_message *msg,
1094                                        const char *attr,
1095                                        const int64_t *old_val,
1096                                        const int64_t *new_val)
1097 {
1098         struct ldb_message_element *el;
1099         int ret;
1100         char *vstring;
1101
1102         if (old_val) {
1103                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
1104                 if (ret != LDB_SUCCESS) {
1105                         return ret;
1106                 }
1107                 el->num_values = 1;
1108                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1109                 if (!el->values) {
1110                         return ldb_module_oom(module);
1111                 }
1112                 vstring = talloc_asprintf(el->values, "%lld", (long long)*old_val);
1113                 if (!vstring) {
1114                         return ldb_module_oom(module);
1115                 }
1116                 *el->values = data_blob_string_const(vstring);
1117         }
1118
1119         if (new_val) {
1120                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
1121                 if (ret != LDB_SUCCESS) {
1122                         return ret;
1123                 }
1124                 el->num_values = 1;
1125                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1126                 if (!el->values) {
1127                         return ldb_module_oom(module);
1128                 }
1129                 vstring = talloc_asprintf(el->values, "%lld", (long long)*new_val);
1130                 if (!vstring) {
1131                         return ldb_module_oom(module);
1132                 }
1133                 *el->values = data_blob_string_const(vstring);
1134         }
1135
1136         return LDB_SUCCESS;
1137 }
1138
1139 int dsdb_msg_constrainted_update_uint64(struct ldb_module *module,
1140                                         struct ldb_message *msg,
1141                                         const char *attr,
1142                                         const uint64_t *old_val,
1143                                         const uint64_t *new_val)
1144 {
1145         return dsdb_msg_constrainted_update_int64(module, msg, attr,
1146                                                   (const int64_t *)old_val,
1147                                                   (const int64_t *)new_val);
1148 }
1149
1150 /*
1151   update an int32 attribute safely via a constrained delete/add
1152  */
1153 int dsdb_module_constrainted_update_int32(struct ldb_module *module,
1154                                           struct ldb_dn *dn,
1155                                           const char *attr,
1156                                           const int32_t *old_val,
1157                                           const int32_t *new_val,
1158                                           struct ldb_request *parent)
1159 {
1160         struct ldb_message *msg;
1161         int ret;
1162
1163         msg = ldb_msg_new(module);
1164         msg->dn = dn;
1165
1166         ret = dsdb_msg_constrainted_update_int32(module,
1167                                                  msg, attr,
1168                                                  old_val,
1169                                                  new_val);
1170         if (ret != LDB_SUCCESS) {
1171                 talloc_free(msg);
1172                 return ret;
1173         }
1174
1175         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1176         talloc_free(msg);
1177         return ret;
1178 }
1179
1180 int dsdb_module_constrainted_update_uint32(struct ldb_module *module,
1181                                            struct ldb_dn *dn,
1182                                            const char *attr,
1183                                            const uint32_t *old_val,
1184                                            const uint32_t *new_val,
1185                                            struct ldb_request *parent)
1186 {
1187         return dsdb_module_constrainted_update_int32(module, dn, attr,
1188                                                      (const int32_t *)old_val,
1189                                                      (const int32_t *)new_val, parent);
1190 }
1191
1192 /*
1193   update an int64 attribute safely via a constrained delete/add
1194  */
1195 int dsdb_module_constrainted_update_int64(struct ldb_module *module,
1196                                           struct ldb_dn *dn,
1197                                           const char *attr,
1198                                           const int64_t *old_val,
1199                                           const int64_t *new_val,
1200                                           struct ldb_request *parent)
1201 {
1202         struct ldb_message *msg;
1203         int ret;
1204
1205         msg = ldb_msg_new(module);
1206         msg->dn = dn;
1207
1208         ret = dsdb_msg_constrainted_update_int64(module,
1209                                                  msg, attr,
1210                                                  old_val,
1211                                                  new_val);
1212         if (ret != LDB_SUCCESS) {
1213                 talloc_free(msg);
1214                 return ret;
1215         }
1216
1217         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1218         talloc_free(msg);
1219         return ret;
1220 }
1221
1222 int dsdb_module_constrainted_update_uint64(struct ldb_module *module,
1223                                            struct ldb_dn *dn,
1224                                            const char *attr,
1225                                            const uint64_t *old_val,
1226                                            const uint64_t *new_val,
1227                                            struct ldb_request *parent)
1228 {
1229         return dsdb_module_constrainted_update_int64(module, dn, attr,
1230                                                      (const int64_t *)old_val,
1231                                                      (const int64_t *)new_val,
1232                                                      parent);
1233 }
1234
1235
1236 const struct ldb_val *dsdb_module_find_dsheuristics(struct ldb_module *module,
1237                                                     TALLOC_CTX *mem_ctx, struct ldb_request *parent)
1238 {
1239         int ret;
1240         struct ldb_dn *new_dn;
1241         struct ldb_context *ldb = ldb_module_get_ctx(module);
1242         static const char *attrs[] = { "dSHeuristics", NULL };
1243         struct ldb_result *res;
1244
1245         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(ldb));
1246         if (!ldb_dn_add_child_fmt(new_dn,
1247                                    "CN=Directory Service,CN=Windows NT,CN=Services")) {
1248                 talloc_free(new_dn);
1249                 return NULL;
1250         }
1251         ret = dsdb_module_search_dn(module, mem_ctx, &res,
1252                                     new_dn,
1253                                     attrs,
1254                                     DSDB_FLAG_NEXT_MODULE,
1255                                     parent);
1256         if (ret == LDB_SUCCESS && res->count == 1) {
1257                 talloc_free(new_dn);
1258                 return ldb_msg_find_ldb_val(res->msgs[0],
1259                                             "dSHeuristics");
1260         }
1261         talloc_free(new_dn);
1262         return NULL;
1263 }
1264
1265 bool dsdb_block_anonymous_ops(struct ldb_module *module, struct ldb_request *parent)
1266 {
1267         TALLOC_CTX *tmp_ctx = talloc_new(module);
1268         bool result;
1269         const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module,
1270                                                                      tmp_ctx, parent);
1271         if (hr_val == NULL || hr_val->length < DS_HR_BLOCK_ANONYMOUS_OPS) {
1272                 result = true;
1273         } else if (hr_val->data[DS_HR_BLOCK_ANONYMOUS_OPS -1] == '2') {
1274                 result = false;
1275         } else {
1276                 result = true;
1277         }
1278
1279         talloc_free(tmp_ctx);
1280         return result;
1281 }
1282
1283 bool dsdb_user_password_support(struct ldb_module *module,
1284                                 TALLOC_CTX *mem_ctx,
1285                                 struct ldb_request *parent)
1286 {
1287         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1288         bool result;
1289         const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module,
1290                                                                      tmp_ctx,
1291                                                                      parent);
1292         if (hr_val == NULL || hr_val->length < DS_HR_USER_PASSWORD_SUPPORT) {
1293                 result = false;
1294         } else if ((hr_val->data[DS_HR_USER_PASSWORD_SUPPORT -1] == '2') ||
1295                    (hr_val->data[DS_HR_USER_PASSWORD_SUPPORT -1] == '0')) {
1296                 result = false;
1297         } else {
1298                 result = true;
1299         }
1300
1301         talloc_free(tmp_ctx);
1302         return result;
1303 }
1304
1305 /*
1306   show the chain of requests, useful for debugging async requests
1307  */
1308 void dsdb_req_chain_debug(struct ldb_request *req, int level)
1309 {
1310         char *s = ldb_module_call_chain(req, req);
1311         DEBUG(level, ("%s\n", s));
1312         talloc_free(s);
1313 }
1314
1315 /*
1316  * Gets back a single-valued attribute by the rules of the DSDB triggers when
1317  * performing a modify operation.
1318  *
1319  * In order that the constraint checking by the "objectclass_attrs" LDB module
1320  * does work properly, the change request should remain similar or only be
1321  * enhanced (no other modifications as deletions, variations).
1322  */
1323 struct ldb_message_element *dsdb_get_single_valued_attr(const struct ldb_message *msg,
1324                                                         const char *attr_name,
1325                                                         enum ldb_request_type operation)
1326 {
1327         struct ldb_message_element *el = NULL;
1328         unsigned int i;
1329
1330         /* We've to walk over all modification entries and consider the last
1331          * non-delete one which belongs to "attr_name".
1332          *
1333          * If "el" is NULL afterwards then that means there was no interesting
1334          * change entry. */
1335         for (i = 0; i < msg->num_elements; i++) {
1336                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
1337                         if ((operation == LDB_MODIFY) &&
1338                             (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
1339                                                 == LDB_FLAG_MOD_DELETE)) {
1340                                 continue;
1341                         }
1342                         el = &msg->elements[i];
1343                 }
1344         }
1345
1346         return el;
1347 }