build: avoid util.h as a public header name due to conflict with MacOS
[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 int dsdb_check_optional_feature(struct ldb_module *module, struct ldb_dn *scope,
656                                         struct GUID op_feature_guid, bool *feature_enabled)
657 {
658         TALLOC_CTX *tmp_ctx;
659         struct ldb_context *ldb = ldb_module_get_ctx(module);
660         struct ldb_result *res;
661         struct ldb_dn *search_dn;
662         struct GUID search_guid;
663         const char *attrs[] = {"msDS-EnabledFeature", NULL};
664         int ret;
665         unsigned int i;
666         struct ldb_message_element *el;
667
668         *feature_enabled = false;
669
670         tmp_ctx = talloc_new(ldb);
671
672         ret = ldb_search(ldb, tmp_ctx, &res,
673                                         scope, LDB_SCOPE_BASE, attrs,
674                                         NULL);
675         if (ret != LDB_SUCCESS) {
676                 ldb_asprintf_errstring(ldb,
677                                 "Could no find the scope object - dn: %s\n",
678                                 ldb_dn_get_linearized(scope));
679                 talloc_free(tmp_ctx);
680                 return LDB_ERR_OPERATIONS_ERROR;
681         }
682         if (res->msgs[0]->num_elements > 0) {
683
684                 el = ldb_msg_find_element(res->msgs[0],"msDS-EnabledFeature");
685
686                 attrs[0] = "msDS-OptionalFeatureGUID";
687
688                 for (i=0; i<el->num_values; i++) {
689                         search_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb, &el->values[i]);
690
691                         ret = ldb_search(ldb, tmp_ctx, &res,
692                                                         search_dn, LDB_SCOPE_BASE, attrs,
693                                                         NULL);
694                         if (ret != LDB_SUCCESS) {
695                                 ldb_asprintf_errstring(ldb,
696                                                 "Could no find object dn: %s\n",
697                                                 ldb_dn_get_linearized(search_dn));
698                                 talloc_free(tmp_ctx);
699                                 return LDB_ERR_OPERATIONS_ERROR;
700                         }
701
702                         search_guid = samdb_result_guid(res->msgs[0], "msDS-OptionalFeatureGUID");
703
704                         if (GUID_compare(&search_guid, &op_feature_guid) == 0){
705                                 *feature_enabled = true;
706                                 break;
707                         }
708                 }
709         }
710         talloc_free(tmp_ctx);
711         return LDB_SUCCESS;
712 }
713
714 /*
715   find the NTDS GUID from a computers DN record
716  */
717 int dsdb_module_find_ntdsguid_for_computer(struct ldb_module *module,
718                                            TALLOC_CTX *mem_ctx,
719                                            struct ldb_dn *computer_dn,
720                                            struct GUID *ntds_guid,
721                                            struct ldb_request *parent)
722 {
723         int ret;
724         struct ldb_dn *dn;
725
726         *ntds_guid = GUID_zero();
727
728         ret = dsdb_module_reference_dn(module, mem_ctx, computer_dn,
729                                        "serverReferenceBL", &dn, parent);
730         if (ret != LDB_SUCCESS) {
731                 return ret;
732         }
733
734         if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
735                 talloc_free(dn);
736                 return LDB_ERR_OPERATIONS_ERROR;
737         }
738
739         ret = dsdb_module_guid_by_dn(module, dn, ntds_guid, parent);
740         talloc_free(dn);
741         return ret;
742 }
743
744 /*
745   find a 'reference' DN that points at another object
746   (eg. serverReference, rIDManagerReference etc)
747  */
748 int dsdb_module_reference_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
749                              const char *attribute, struct ldb_dn **dn, struct ldb_request *parent)
750 {
751         const char *attrs[2];
752         struct ldb_result *res;
753         int ret;
754
755         attrs[0] = attribute;
756         attrs[1] = NULL;
757
758         ret = dsdb_module_search_dn(module, mem_ctx, &res, base, attrs,
759                                     DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_EXTENDED_DN, parent);
760         if (ret != LDB_SUCCESS) {
761                 return ret;
762         }
763
764         *dn = ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module),
765                                       mem_ctx, res->msgs[0], attribute);
766         if (!*dn) {
767                 ldb_reset_err_string(ldb_module_get_ctx(module));
768                 talloc_free(res);
769                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
770         }
771
772         talloc_free(res);
773         return LDB_SUCCESS;
774 }
775
776 /*
777   find the RID Manager$ DN via the rIDManagerReference attribute in the
778   base DN
779  */
780 int dsdb_module_rid_manager_dn(struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_dn **dn,
781                                struct ldb_request *parent)
782 {
783         return dsdb_module_reference_dn(module, mem_ctx,
784                                         ldb_get_default_basedn(ldb_module_get_ctx(module)),
785                                         "rIDManagerReference", dn, parent);
786 }
787
788 /*
789   used to chain to the callers callback
790  */
791 int dsdb_next_callback(struct ldb_request *req, struct ldb_reply *ares)
792 {
793         struct ldb_request *up_req = talloc_get_type(req->context, struct ldb_request);
794
795         talloc_steal(up_req, req);
796         return up_req->callback(up_req, ares);
797 }
798
799 /*
800   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
801   object for a partition
802  */
803 int dsdb_module_load_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
804                                    uint64_t *uSN, uint64_t *urgent_uSN, struct ldb_request *parent)
805 {
806         struct ldb_context *ldb = ldb_module_get_ctx(module);
807         struct ldb_request *req;
808         int ret;
809         TALLOC_CTX *tmp_ctx = talloc_new(module);
810         struct dsdb_control_current_partition *p_ctrl;
811         struct ldb_result *res;
812
813         res = talloc_zero(tmp_ctx, struct ldb_result);
814         if (!res) {
815                 talloc_free(tmp_ctx);
816                 return ldb_module_oom(module);
817         }
818
819         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
820                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
821                                    LDB_SCOPE_BASE,
822                                    NULL, NULL,
823                                    NULL,
824                                    res, ldb_search_default_callback,
825                                    parent);
826         LDB_REQ_SET_LOCATION(req);
827         if (ret != LDB_SUCCESS) {
828                 talloc_free(tmp_ctx);
829                 return ret;
830         }
831
832         p_ctrl = talloc(req, struct dsdb_control_current_partition);
833         if (p_ctrl == NULL) {
834                 talloc_free(tmp_ctx);
835                 return ldb_module_oom(module);
836         }
837         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
838         p_ctrl->dn = dn;
839
840
841         ret = ldb_request_add_control(req,
842                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
843                                       false, p_ctrl);
844         if (ret != LDB_SUCCESS) {
845                 talloc_free(tmp_ctx);
846                 return ret;
847         }
848
849         /* Run the new request */
850         ret = ldb_next_request(module, req);
851
852         if (ret == LDB_SUCCESS) {
853                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
854         }
855
856         if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
857                 /* it hasn't been created yet, which means
858                    an implicit value of zero */
859                 *uSN = 0;
860                 talloc_free(tmp_ctx);
861                 ldb_reset_err_string(ldb);
862                 return LDB_SUCCESS;
863         }
864
865         if (ret != LDB_SUCCESS) {
866                 talloc_free(tmp_ctx);
867                 return ret;
868         }
869
870         if (res->count != 1) {
871                 *uSN = 0;
872                 if (urgent_uSN) {
873                         *urgent_uSN = 0;
874                 }
875         } else {
876                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
877                 if (urgent_uSN) {
878                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
879                 }
880         }
881
882         talloc_free(tmp_ctx);
883
884         return LDB_SUCCESS;
885 }
886
887 /*
888   save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
889   partition
890  */
891 int dsdb_module_save_partition_usn(struct ldb_module *module, struct ldb_dn *dn,
892                                    uint64_t uSN, uint64_t urgent_uSN,
893                                    struct ldb_request *parent)
894 {
895         struct ldb_context *ldb = ldb_module_get_ctx(module);
896         struct ldb_request *req;
897         struct ldb_message *msg;
898         struct dsdb_control_current_partition *p_ctrl;
899         int ret;
900         struct ldb_result *res;
901
902         msg = ldb_msg_new(module);
903         if (msg == NULL) {
904                 return ldb_module_oom(module);
905         }
906
907         msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
908         if (msg->dn == NULL) {
909                 talloc_free(msg);
910                 return ldb_operr(ldb_module_get_ctx(module));
911         }
912
913         res = talloc_zero(msg, struct ldb_result);
914         if (!res) {
915                 talloc_free(msg);
916                 return ldb_module_oom(module);
917         }
918
919         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNHighest", uSN);
920         if (ret != LDB_SUCCESS) {
921                 talloc_free(msg);
922                 return ret;
923         }
924         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
925
926         /* urgent_uSN is optional so may not be stored */
927         if (urgent_uSN) {
928                 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNUrgent",
929                                            urgent_uSN);
930                 if (ret != LDB_SUCCESS) {
931                         talloc_free(msg);
932                         return ret;
933                 }
934                 msg->elements[1].flags = LDB_FLAG_MOD_REPLACE;
935         }
936
937
938         p_ctrl = talloc(msg, struct dsdb_control_current_partition);
939         if (p_ctrl == NULL) {
940                 talloc_free(msg);
941                 return ldb_oom(ldb);
942         }
943         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
944         p_ctrl->dn = dn;
945         ret = ldb_build_mod_req(&req, ldb, msg,
946                                 msg,
947                                 NULL,
948                                 res,
949                                 ldb_modify_default_callback,
950                                 parent);
951         LDB_REQ_SET_LOCATION(req);
952 again:
953         if (ret != LDB_SUCCESS) {
954                 talloc_free(msg);
955                 return ret;
956         }
957
958         ret = ldb_request_add_control(req,
959                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
960                                       false, p_ctrl);
961         if (ret != LDB_SUCCESS) {
962                 talloc_free(msg);
963                 return ret;
964         }
965
966         /* Run the new request */
967         ret = ldb_next_request(module, req);
968
969         if (ret == LDB_SUCCESS) {
970                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
971         }
972         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
973                 ret = ldb_build_add_req(&req, ldb, msg,
974                                         msg,
975                                         NULL,
976                                         res,
977                                         ldb_modify_default_callback,
978                                         parent);
979                 LDB_REQ_SET_LOCATION(req);
980                 goto again;
981         }
982
983         talloc_free(msg);
984
985         return ret;
986 }
987
988 bool dsdb_module_am_system(struct ldb_module *module)
989 {
990         struct ldb_context *ldb = ldb_module_get_ctx(module);
991         struct auth_session_info *session_info
992                 = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
993         return security_session_user_level(session_info, NULL) == SECURITY_SYSTEM;
994 }
995
996 bool dsdb_module_am_administrator(struct ldb_module *module)
997 {
998         struct ldb_context *ldb = ldb_module_get_ctx(module);
999         struct auth_session_info *session_info
1000                 = talloc_get_type(ldb_get_opaque(ldb, "sessionInfo"), struct auth_session_info);
1001         return security_session_user_level(session_info, NULL) == SECURITY_ADMINISTRATOR;
1002 }
1003
1004 /*
1005   check if the recyclebin is enabled
1006  */
1007 int dsdb_recyclebin_enabled(struct ldb_module *module, bool *enabled)
1008 {
1009         struct ldb_context *ldb = ldb_module_get_ctx(module);
1010         struct ldb_dn *partitions_dn;
1011         struct GUID recyclebin_guid;
1012         int ret;
1013
1014         partitions_dn = samdb_partitions_dn(ldb, module);
1015
1016         GUID_from_string(DS_GUID_FEATURE_RECYCLE_BIN, &recyclebin_guid);
1017
1018         ret = dsdb_check_optional_feature(module, partitions_dn, recyclebin_guid, enabled);
1019         if (ret != LDB_SUCCESS) {
1020                 ldb_asprintf_errstring(ldb, "Could not verify if Recycle Bin is enabled \n");
1021                 talloc_free(partitions_dn);
1022                 return LDB_ERR_UNWILLING_TO_PERFORM;
1023         }
1024
1025         talloc_free(partitions_dn);
1026         return LDB_SUCCESS;
1027 }
1028
1029 int dsdb_msg_constrainted_update_int32(struct ldb_module *module,
1030                                        struct ldb_message *msg,
1031                                        const char *attr,
1032                                        const int32_t *old_val,
1033                                        const int32_t *new_val)
1034 {
1035         struct ldb_message_element *el;
1036         int ret;
1037         char *vstring;
1038
1039         if (old_val) {
1040                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
1041                 if (ret != LDB_SUCCESS) {
1042                         return ret;
1043                 }
1044                 el->num_values = 1;
1045                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1046                 if (!el->values) {
1047                         return ldb_module_oom(module);
1048                 }
1049                 vstring = talloc_asprintf(el->values, "%ld", (long)*old_val);
1050                 if (!vstring) {
1051                         return ldb_module_oom(module);
1052                 }
1053                 *el->values = data_blob_string_const(vstring);
1054         }
1055
1056         if (new_val) {
1057                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
1058                 if (ret != LDB_SUCCESS) {
1059                         return ret;
1060                 }
1061                 el->num_values = 1;
1062                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1063                 if (!el->values) {
1064                         return ldb_module_oom(module);
1065                 }
1066                 vstring = talloc_asprintf(el->values, "%ld", (long)*new_val);
1067                 if (!vstring) {
1068                         return ldb_module_oom(module);
1069                 }
1070                 *el->values = data_blob_string_const(vstring);
1071         }
1072
1073         return LDB_SUCCESS;
1074 }
1075
1076 int dsdb_msg_constrainted_update_uint32(struct ldb_module *module,
1077                                         struct ldb_message *msg,
1078                                         const char *attr,
1079                                         const uint32_t *old_val,
1080                                         const uint32_t *new_val)
1081 {
1082         return dsdb_msg_constrainted_update_int32(module, msg, attr,
1083                                                   (const int32_t *)old_val,
1084                                                   (const int32_t *)new_val);
1085 }
1086
1087 int dsdb_msg_constrainted_update_int64(struct ldb_module *module,
1088                                        struct ldb_message *msg,
1089                                        const char *attr,
1090                                        const int64_t *old_val,
1091                                        const int64_t *new_val)
1092 {
1093         struct ldb_message_element *el;
1094         int ret;
1095         char *vstring;
1096
1097         if (old_val) {
1098                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_DELETE, &el);
1099                 if (ret != LDB_SUCCESS) {
1100                         return ret;
1101                 }
1102                 el->num_values = 1;
1103                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1104                 if (!el->values) {
1105                         return ldb_module_oom(module);
1106                 }
1107                 vstring = talloc_asprintf(el->values, "%lld", (long long)*old_val);
1108                 if (!vstring) {
1109                         return ldb_module_oom(module);
1110                 }
1111                 *el->values = data_blob_string_const(vstring);
1112         }
1113
1114         if (new_val) {
1115                 ret = ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_ADD, &el);
1116                 if (ret != LDB_SUCCESS) {
1117                         return ret;
1118                 }
1119                 el->num_values = 1;
1120                 el->values = talloc_array(msg, struct ldb_val, el->num_values);
1121                 if (!el->values) {
1122                         return ldb_module_oom(module);
1123                 }
1124                 vstring = talloc_asprintf(el->values, "%lld", (long long)*new_val);
1125                 if (!vstring) {
1126                         return ldb_module_oom(module);
1127                 }
1128                 *el->values = data_blob_string_const(vstring);
1129         }
1130
1131         return LDB_SUCCESS;
1132 }
1133
1134 int dsdb_msg_constrainted_update_uint64(struct ldb_module *module,
1135                                         struct ldb_message *msg,
1136                                         const char *attr,
1137                                         const uint64_t *old_val,
1138                                         const uint64_t *new_val)
1139 {
1140         return dsdb_msg_constrainted_update_int64(module, msg, attr,
1141                                                   (const int64_t *)old_val,
1142                                                   (const int64_t *)new_val);
1143 }
1144
1145 /*
1146   update an int32 attribute safely via a constrained delete/add
1147  */
1148 int dsdb_module_constrainted_update_int32(struct ldb_module *module,
1149                                           struct ldb_dn *dn,
1150                                           const char *attr,
1151                                           const int32_t *old_val,
1152                                           const int32_t *new_val,
1153                                           struct ldb_request *parent)
1154 {
1155         struct ldb_message *msg;
1156         int ret;
1157
1158         msg = ldb_msg_new(module);
1159         msg->dn = dn;
1160
1161         ret = dsdb_msg_constrainted_update_int32(module,
1162                                                  msg, attr,
1163                                                  old_val,
1164                                                  new_val);
1165         if (ret != LDB_SUCCESS) {
1166                 talloc_free(msg);
1167                 return ret;
1168         }
1169
1170         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1171         talloc_free(msg);
1172         return ret;
1173 }
1174
1175 int dsdb_module_constrainted_update_uint32(struct ldb_module *module,
1176                                            struct ldb_dn *dn,
1177                                            const char *attr,
1178                                            const uint32_t *old_val,
1179                                            const uint32_t *new_val,
1180                                            struct ldb_request *parent)
1181 {
1182         return dsdb_module_constrainted_update_int32(module, dn, attr,
1183                                                      (const int32_t *)old_val,
1184                                                      (const int32_t *)new_val, parent);
1185 }
1186
1187 /*
1188   update an int64 attribute safely via a constrained delete/add
1189  */
1190 int dsdb_module_constrainted_update_int64(struct ldb_module *module,
1191                                           struct ldb_dn *dn,
1192                                           const char *attr,
1193                                           const int64_t *old_val,
1194                                           const int64_t *new_val,
1195                                           struct ldb_request *parent)
1196 {
1197         struct ldb_message *msg;
1198         int ret;
1199
1200         msg = ldb_msg_new(module);
1201         msg->dn = dn;
1202
1203         ret = dsdb_msg_constrainted_update_int64(module,
1204                                                  msg, attr,
1205                                                  old_val,
1206                                                  new_val);
1207         if (ret != LDB_SUCCESS) {
1208                 talloc_free(msg);
1209                 return ret;
1210         }
1211
1212         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
1213         talloc_free(msg);
1214         return ret;
1215 }
1216
1217 int dsdb_module_constrainted_update_uint64(struct ldb_module *module,
1218                                            struct ldb_dn *dn,
1219                                            const char *attr,
1220                                            const uint64_t *old_val,
1221                                            const uint64_t *new_val,
1222                                            struct ldb_request *parent)
1223 {
1224         return dsdb_module_constrainted_update_int64(module, dn, attr,
1225                                                      (const int64_t *)old_val,
1226                                                      (const int64_t *)new_val,
1227                                                      parent);
1228 }
1229
1230
1231 const struct ldb_val *dsdb_module_find_dsheuristics(struct ldb_module *module,
1232                                                     TALLOC_CTX *mem_ctx, struct ldb_request *parent)
1233 {
1234         int ret;
1235         struct ldb_dn *new_dn;
1236         struct ldb_context *ldb = ldb_module_get_ctx(module);
1237         static const char *attrs[] = { "dSHeuristics", NULL };
1238         struct ldb_result *res;
1239
1240         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(ldb));
1241         if (!ldb_dn_add_child_fmt(new_dn,
1242                                    "CN=Directory Service,CN=Windows NT,CN=Services")) {
1243                 talloc_free(new_dn);
1244                 return NULL;
1245         }
1246         ret = dsdb_module_search_dn(module, mem_ctx, &res,
1247                                     new_dn,
1248                                     attrs,
1249                                     DSDB_FLAG_NEXT_MODULE,
1250                                     parent);
1251         if (ret == LDB_SUCCESS && res->count == 1) {
1252                 talloc_free(new_dn);
1253                 return ldb_msg_find_ldb_val(res->msgs[0],
1254                                             "dSHeuristics");
1255         }
1256         talloc_free(new_dn);
1257         return NULL;
1258 }
1259
1260 bool dsdb_block_anonymous_ops(struct ldb_module *module, struct ldb_request *parent)
1261 {
1262         TALLOC_CTX *tmp_ctx = talloc_new(module);
1263         bool result;
1264         const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module,
1265                                                                      tmp_ctx, parent);
1266         if (hr_val == NULL || hr_val->length < DS_HR_BLOCK_ANONYMOUS_OPS) {
1267                 result = true;
1268         } else if (hr_val->data[DS_HR_BLOCK_ANONYMOUS_OPS -1] == '2') {
1269                 result = false;
1270         } else {
1271                 result = true;
1272         }
1273
1274         talloc_free(tmp_ctx);
1275         return result;
1276 }
1277
1278 bool dsdb_user_password_support(struct ldb_module *module,
1279                                 TALLOC_CTX *mem_ctx,
1280                                 struct ldb_request *parent)
1281 {
1282         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1283         bool result;
1284         const struct ldb_val *hr_val = dsdb_module_find_dsheuristics(module,
1285                                                                      tmp_ctx,
1286                                                                      parent);
1287         if (hr_val == NULL || hr_val->length < DS_HR_USER_PASSWORD_SUPPORT) {
1288                 result = false;
1289         } else if ((hr_val->data[DS_HR_USER_PASSWORD_SUPPORT -1] == '2') ||
1290                    (hr_val->data[DS_HR_USER_PASSWORD_SUPPORT -1] == '0')) {
1291                 result = false;
1292         } else {
1293                 result = true;
1294         }
1295
1296         talloc_free(tmp_ctx);
1297         return result;
1298 }
1299
1300 /*
1301   show the chain of requests, useful for debugging async requests
1302  */
1303 void dsdb_req_chain_debug(struct ldb_request *req, int level)
1304 {
1305         char *s = ldb_module_call_chain(req, req);
1306         DEBUG(level, ("%s\n", s));
1307         talloc_free(s);
1308 }
1309
1310 /*
1311  * Gets back a single-valued attribute by the rules of the DSDB triggers when
1312  * performing a modify operation.
1313  *
1314  * In order that the constraint checking by the "objectclass_attrs" LDB module
1315  * does work properly, the change request should remain similar or only be
1316  * enhanced (no other modifications as deletions, variations).
1317  */
1318 struct ldb_message_element *dsdb_get_single_valued_attr(const struct ldb_message *msg,
1319                                                         const char *attr_name,
1320                                                         enum ldb_request_type operation)
1321 {
1322         struct ldb_message_element *el = NULL;
1323         unsigned int i;
1324
1325         /* We've to walk over all modification entries and consider the last
1326          * non-delete one which belongs to "attr_name".
1327          *
1328          * If "el" is NULL afterwards then that means there was no interesting
1329          * change entry. */
1330         for (i = 0; i < msg->num_elements; i++) {
1331                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
1332                         if ((operation == LDB_MODIFY) &&
1333                             (LDB_FLAG_MOD_TYPE(msg->elements[i].flags)
1334                                                 == LDB_FLAG_MOD_DELETE)) {
1335                                 continue;
1336                         }
1337                         el = &msg->elements[i];
1338                 }
1339         }
1340
1341         return el;
1342 }