2 Unix SMB/CIFS implementation.
3 Samba utility functions
5 Copyright (C) Andrew Tridgell 2009
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "ldb_module.h"
25 #include "librpc/ndr/libndr.h"
26 #include "dsdb/samdb/ldb_modules/util.h"
27 #include "dsdb/samdb/samdb.h"
29 #include "libcli/security/security.h"
32 search for attrs on one DN, in the modules below
34 int dsdb_module_search_dn(struct ldb_module
*module
,
36 struct ldb_result
**_res
,
37 struct ldb_dn
*basedn
,
38 const char * const *attrs
,
42 struct ldb_request
*req
;
44 struct ldb_result
*res
;
46 tmp_ctx
= talloc_new(mem_ctx
);
48 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
50 return LDB_ERR_OPERATIONS_ERROR
;
53 ret
= ldb_build_search_req(&req
, ldb_module_get_ctx(module
), tmp_ctx
,
60 ldb_search_default_callback
,
62 if (ret
!= LDB_SUCCESS
) {
67 ret
= dsdb_request_add_controls(req
, dsdb_flags
);
68 if (ret
!= LDB_SUCCESS
) {
73 ret
= ldb_next_request(module
, req
);
74 if (ret
== LDB_SUCCESS
) {
75 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
78 if (ret
!= LDB_SUCCESS
) {
83 if (res
->count
!= 1) {
84 /* we may be reading a DB that does not have the 'check base on search' option... */
85 ret
= LDB_ERR_NO_SUCH_OBJECT
;
86 ldb_asprintf_errstring(ldb_module_get_ctx(module
),
87 "dsdb_module_search_dn: did not find base dn %s (%d results)",
88 ldb_dn_get_linearized(basedn
), res
->count
);
90 *_res
= talloc_steal(mem_ctx
, res
);
97 search for attrs in the modules below
99 int dsdb_module_search(struct ldb_module
*module
,
101 struct ldb_result
**_res
,
102 struct ldb_dn
*basedn
, enum ldb_scope scope
,
103 const char * const *attrs
,
105 const char *format
, ...) _PRINTF_ATTRIBUTE(8, 9)
108 struct ldb_request
*req
;
110 struct ldb_result
*res
;
114 tmp_ctx
= talloc_new(mem_ctx
);
116 va_start(ap
, format
);
117 expression
= talloc_vasprintf(tmp_ctx
, format
, ap
);
120 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
122 return LDB_ERR_OPERATIONS_ERROR
;
125 ret
= ldb_build_search_req(&req
, ldb_module_get_ctx(module
), tmp_ctx
,
132 ldb_search_default_callback
,
134 if (ret
!= LDB_SUCCESS
) {
135 talloc_free(tmp_ctx
);
139 ret
= dsdb_request_add_controls(req
, dsdb_flags
);
140 if (ret
!= LDB_SUCCESS
) {
141 talloc_free(tmp_ctx
);
145 if (dsdb_flags
& DSDB_FLAG_OWN_MODULE
) {
146 const struct ldb_module_ops
*ops
= ldb_module_get_ops(module
);
147 ret
= ops
->search(module
, req
);
148 } else if (dsdb_flags
& DSDB_FLAG_TOP_MODULE
) {
149 ret
= ldb_request(ldb_module_get_ctx(module
), req
);
151 ret
= ldb_next_request(module
, req
);
153 if (ret
== LDB_SUCCESS
) {
154 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
158 if (ret
== LDB_SUCCESS
) {
159 *_res
= talloc_steal(mem_ctx
, res
);
161 talloc_free(tmp_ctx
);
166 find a DN given a GUID. This searches across all partitions
168 int dsdb_module_dn_by_guid(struct ldb_module
*module
, TALLOC_CTX
*mem_ctx
,
169 const struct GUID
*guid
, struct ldb_dn
**dn
)
171 struct ldb_result
*res
;
172 const char *attrs
[] = { NULL
};
173 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
176 ret
= dsdb_module_search(module
, tmp_ctx
, &res
, NULL
, LDB_SCOPE_SUBTREE
,
178 DSDB_SEARCH_SHOW_DELETED
|
179 DSDB_SEARCH_SEARCH_ALL_PARTITIONS
|
180 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
,
181 "objectGUID=%s", GUID_string(tmp_ctx
, guid
));
182 if (ret
!= LDB_SUCCESS
) {
183 talloc_free(tmp_ctx
);
186 if (res
->count
== 0) {
187 talloc_free(tmp_ctx
);
188 return LDB_ERR_NO_SUCH_OBJECT
;
190 if (res
->count
!= 1) {
191 ldb_asprintf_errstring(ldb_module_get_ctx(module
), "More than one object found matching objectGUID %s\n",
192 GUID_string(tmp_ctx
, guid
));
193 talloc_free(tmp_ctx
);
194 return LDB_ERR_OPERATIONS_ERROR
;
197 *dn
= talloc_steal(mem_ctx
, res
->msgs
[0]->dn
);
199 talloc_free(tmp_ctx
);
204 find a GUID given a DN.
206 int dsdb_module_guid_by_dn(struct ldb_module
*module
, struct ldb_dn
*dn
, struct GUID
*guid
)
208 const char *attrs
[] = { NULL
};
209 struct ldb_result
*res
;
210 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
214 ret
= dsdb_module_search_dn(module
, tmp_ctx
, &res
, dn
, attrs
,
215 DSDB_SEARCH_SHOW_DELETED
|
216 DSDB_SEARCH_SHOW_EXTENDED_DN
);
217 if (ret
!= LDB_SUCCESS
) {
218 ldb_asprintf_errstring(ldb_module_get_ctx(module
), "Failed to find GUID for %s",
219 ldb_dn_get_linearized(dn
));
220 talloc_free(tmp_ctx
);
224 status
= dsdb_get_extended_dn_guid(res
->msgs
[0]->dn
, guid
, "GUID");
225 if (!NT_STATUS_IS_OK(status
)) {
226 talloc_free(tmp_ctx
);
227 return LDB_ERR_OPERATIONS_ERROR
;
230 talloc_free(tmp_ctx
);
235 a ldb_modify request operating on modules below the
238 int dsdb_module_modify(struct ldb_module
*module
,
239 const struct ldb_message
*message
,
242 struct ldb_request
*mod_req
;
244 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
245 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
247 ret
= ldb_build_mod_req(&mod_req
, ldb
, tmp_ctx
,
251 ldb_op_default_callback
,
253 if (ret
!= LDB_SUCCESS
) {
254 talloc_free(tmp_ctx
);
258 ret
= dsdb_request_add_controls(mod_req
, dsdb_flags
);
259 if (ret
!= LDB_SUCCESS
) {
260 talloc_free(tmp_ctx
);
264 /* Run the new request */
265 if (dsdb_flags
& DSDB_FLAG_OWN_MODULE
) {
266 const struct ldb_module_ops
*ops
= ldb_module_get_ops(module
);
267 ret
= ops
->modify(module
, mod_req
);
268 } else if (dsdb_flags
& DSDB_FLAG_TOP_MODULE
) {
269 ret
= ldb_request(ldb_module_get_ctx(module
), mod_req
);
271 ret
= ldb_next_request(module
, mod_req
);
273 if (ret
== LDB_SUCCESS
) {
274 ret
= ldb_wait(mod_req
->handle
, LDB_WAIT_ALL
);
277 talloc_free(tmp_ctx
);
284 a ldb_rename request operating on modules below the
287 int dsdb_module_rename(struct ldb_module
*module
,
288 struct ldb_dn
*olddn
, struct ldb_dn
*newdn
,
291 struct ldb_request
*req
;
293 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
294 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
296 ret
= ldb_build_rename_req(&req
, ldb
, tmp_ctx
,
301 ldb_op_default_callback
,
303 if (ret
!= LDB_SUCCESS
) {
304 talloc_free(tmp_ctx
);
308 ret
= dsdb_request_add_controls(req
, dsdb_flags
);
309 if (ret
!= LDB_SUCCESS
) {
310 talloc_free(tmp_ctx
);
314 /* Run the new request */
315 if (dsdb_flags
& DSDB_FLAG_OWN_MODULE
) {
316 const struct ldb_module_ops
*ops
= ldb_module_get_ops(module
);
317 ret
= ops
->rename(module
, req
);
318 } else if (dsdb_flags
& DSDB_FLAG_TOP_MODULE
) {
319 ret
= ldb_request(ldb_module_get_ctx(module
), req
);
321 ret
= ldb_next_request(module
, req
);
323 if (ret
== LDB_SUCCESS
) {
324 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
327 talloc_free(tmp_ctx
);
332 a ldb_add request operating on modules below the
335 int dsdb_module_add(struct ldb_module
*module
,
336 const struct ldb_message
*message
,
339 struct ldb_request
*req
;
341 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
342 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
344 ret
= ldb_build_add_req(&req
, ldb
, tmp_ctx
,
348 ldb_op_default_callback
,
350 if (ret
!= LDB_SUCCESS
) {
351 talloc_free(tmp_ctx
);
355 ret
= dsdb_request_add_controls(req
, dsdb_flags
);
356 if (ret
!= LDB_SUCCESS
) {
357 talloc_free(tmp_ctx
);
361 /* Run the new request */
362 if (dsdb_flags
& DSDB_FLAG_OWN_MODULE
) {
363 const struct ldb_module_ops
*ops
= ldb_module_get_ops(module
);
364 ret
= ops
->add(module
, req
);
365 } else if (dsdb_flags
& DSDB_FLAG_TOP_MODULE
) {
366 ret
= ldb_request(ldb_module_get_ctx(module
), req
);
368 ret
= ldb_next_request(module
, req
);
370 if (ret
== LDB_SUCCESS
) {
371 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
374 talloc_free(tmp_ctx
);
379 const struct dsdb_class
* get_last_structural_class(const struct dsdb_schema
*schema
,const struct ldb_message_element
*element
)
381 const struct dsdb_class
*last_class
= NULL
;
384 for (i
= 0; i
< element
->num_values
; i
++){
385 const struct dsdb_class
*tmp_class
= dsdb_class_by_lDAPDisplayName_ldb_val(schema
, &element
->values
[i
]);
387 if(tmp_class
== NULL
) {
391 if(tmp_class
->objectClassCategory
== 3) {
396 last_class
= tmp_class
;
398 if (tmp_class
->subClass_order
> last_class
->subClass_order
)
399 last_class
= tmp_class
;
407 check if a single valued link has multiple non-deleted values
409 This is needed when we will be using the RELAX control to stop
410 ldb_tdb from checking single valued links
412 int dsdb_check_single_valued_link(const struct dsdb_attribute
*attr
,
413 const struct ldb_message_element
*el
)
415 bool found_active
= false;
418 if (!(attr
->ldb_schema_attribute
->flags
& LDB_ATTR_FLAG_SINGLE_VALUE
) ||
419 el
->num_values
< 2) {
423 for (i
=0; i
<el
->num_values
; i
++) {
424 if (!dsdb_dn_is_deleted_val(&el
->values
[i
])) {
426 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS
;
435 int dsdb_check_optional_feature(struct ldb_module
*module
, struct ldb_dn
*scope
,
436 struct GUID op_feature_guid
, bool *feature_enabled
)
439 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
440 struct ldb_result
*res
;
441 struct ldb_dn
*search_dn
;
442 struct GUID search_guid
;
443 const char *attrs
[] = {"msDS-EnabledFeature", NULL
};
446 struct ldb_message_element
*el
;
448 *feature_enabled
= false;
450 tmp_ctx
= talloc_new(ldb
);
452 ret
= ldb_search(ldb
, tmp_ctx
, &res
,
453 scope
, LDB_SCOPE_BASE
, attrs
,
455 if (ret
!= LDB_SUCCESS
) {
456 ldb_asprintf_errstring(ldb
,
457 "Could no find the scope object - dn: %s\n",
458 ldb_dn_get_linearized(scope
));
459 talloc_free(tmp_ctx
);
460 return LDB_ERR_OPERATIONS_ERROR
;
462 if (res
->msgs
[0]->num_elements
> 0) {
464 el
= ldb_msg_find_element(res
->msgs
[0],"msDS-EnabledFeature");
466 attrs
[0] = "msDS-OptionalFeatureGUID";
468 for (i
=0; i
<el
->num_values
; i
++) {
469 search_dn
= ldb_dn_from_ldb_val(tmp_ctx
, ldb
, &el
->values
[i
]);
471 ret
= ldb_search(ldb
, tmp_ctx
, &res
,
472 search_dn
, LDB_SCOPE_BASE
, attrs
,
474 if (ret
!= LDB_SUCCESS
) {
475 ldb_asprintf_errstring(ldb
,
476 "Could no find object dn: %s\n",
477 ldb_dn_get_linearized(search_dn
));
478 talloc_free(tmp_ctx
);
479 return LDB_ERR_OPERATIONS_ERROR
;
482 search_guid
= samdb_result_guid(res
->msgs
[0], "msDS-OptionalFeatureGUID");
484 if (GUID_compare(&search_guid
, &op_feature_guid
) == 0){
485 *feature_enabled
= true;
490 talloc_free(tmp_ctx
);
495 find a 'reference' DN that points at another object
496 (eg. serverReference, rIDManagerReference etc)
498 int dsdb_module_reference_dn(struct ldb_module
*module
, TALLOC_CTX
*mem_ctx
, struct ldb_dn
*base
,
499 const char *attribute
, struct ldb_dn
**dn
)
501 const char *attrs
[2];
502 struct ldb_result
*res
;
505 attrs
[0] = attribute
;
508 ret
= dsdb_module_search_dn(module
, mem_ctx
, &res
, base
, attrs
, 0);
509 if (ret
!= LDB_SUCCESS
) {
513 *dn
= ldb_msg_find_attr_as_dn(ldb_module_get_ctx(module
),
514 mem_ctx
, res
->msgs
[0], attribute
);
517 return LDB_ERR_NO_SUCH_ATTRIBUTE
;
525 find the RID Manager$ DN via the rIDManagerReference attribute in the
528 int dsdb_module_rid_manager_dn(struct ldb_module
*module
, TALLOC_CTX
*mem_ctx
, struct ldb_dn
**dn
)
530 return dsdb_module_reference_dn(module
, mem_ctx
,
531 ldb_get_default_basedn(ldb_module_get_ctx(module
)),
532 "rIDManagerReference", dn
);
537 update an integer attribute safely via a constrained delete/add
539 int dsdb_module_constrainted_update_integer(struct ldb_module
*module
, struct ldb_dn
*dn
,
540 const char *attr
, uint64_t old_val
, uint64_t new_val
)
542 struct ldb_message
*msg
;
543 struct ldb_message_element
*el
;
544 struct ldb_val v1
, v2
;
548 msg
= ldb_msg_new(module
);
551 ret
= ldb_msg_add_empty(msg
, attr
, LDB_FLAG_MOD_DELETE
, &el
);
552 if (ret
!= LDB_SUCCESS
) {
558 vstring
= talloc_asprintf(msg
, "%llu", (unsigned long long)old_val
);
560 ldb_module_oom(module
);
562 return LDB_ERR_OPERATIONS_ERROR
;
564 v1
= data_blob_string_const(vstring
);
566 ret
= ldb_msg_add_empty(msg
, attr
, LDB_FLAG_MOD_ADD
, &el
);
567 if (ret
!= LDB_SUCCESS
) {
573 vstring
= talloc_asprintf(msg
, "%llu", (unsigned long long)new_val
);
575 ldb_module_oom(module
);
577 return LDB_ERR_OPERATIONS_ERROR
;
579 v2
= data_blob_string_const(vstring
);
581 ret
= dsdb_module_modify(module
, msg
, 0);
587 used to chain to the callers callback
589 int dsdb_next_callback(struct ldb_request
*req
, struct ldb_reply
*ares
)
591 struct ldb_request
*up_req
= talloc_get_type(req
->context
, struct ldb_request
);
593 talloc_steal(up_req
, req
);
594 return up_req
->callback(up_req
, ares
);
599 set an integer attribute
601 int dsdb_module_set_integer(struct ldb_module
*module
, struct ldb_dn
*dn
,
602 const char *attr
, uint64_t new_val
)
604 struct ldb_message
*msg
;
607 msg
= ldb_msg_new(module
);
610 ret
= ldb_msg_add_fmt(msg
, attr
, "%llu", (unsigned long long)new_val
);
611 if (ret
!= LDB_SUCCESS
) {
615 msg
->elements
[0].flags
= LDB_FLAG_MOD_REPLACE
;
617 ret
= dsdb_module_modify(module
, msg
, 0);
623 load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
624 object for a partition
626 int dsdb_module_load_partition_usn(struct ldb_module
*module
, struct ldb_dn
*dn
,
627 uint64_t *uSN
, uint64_t *urgent_uSN
)
629 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
630 struct ldb_request
*req
;
632 TALLOC_CTX
*tmp_ctx
= talloc_new(module
);
633 struct dsdb_control_current_partition
*p_ctrl
;
634 struct ldb_result
*res
;
636 res
= talloc_zero(tmp_ctx
, struct ldb_result
);
638 talloc_free(tmp_ctx
);
639 return LDB_ERR_OPERATIONS_ERROR
;
642 ret
= ldb_build_search_req(&req
, ldb
, tmp_ctx
,
643 ldb_dn_new(tmp_ctx
, ldb
, "@REPLCHANGED"),
647 res
, ldb_search_default_callback
,
649 if (ret
!= LDB_SUCCESS
) {
650 talloc_free(tmp_ctx
);
654 p_ctrl
= talloc(req
, struct dsdb_control_current_partition
);
655 if (p_ctrl
== NULL
) {
657 return LDB_ERR_OPERATIONS_ERROR
;
659 p_ctrl
->version
= DSDB_CONTROL_CURRENT_PARTITION_VERSION
;
663 ret
= ldb_request_add_control(req
,
664 DSDB_CONTROL_CURRENT_PARTITION_OID
,
666 if (ret
!= LDB_SUCCESS
) {
667 talloc_free(tmp_ctx
);
671 /* Run the new request */
672 ret
= ldb_next_request(module
, req
);
674 if (ret
== LDB_SUCCESS
) {
675 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
678 if (ret
== LDB_ERR_NO_SUCH_OBJECT
|| ret
== LDB_ERR_INVALID_DN_SYNTAX
) {
679 /* it hasn't been created yet, which means
680 an implicit value of zero */
682 talloc_free(tmp_ctx
);
686 if (ret
!= LDB_SUCCESS
) {
687 talloc_free(tmp_ctx
);
691 if (res
->count
< 1) {
697 *uSN
= ldb_msg_find_attr_as_uint64(res
->msgs
[0], "uSNHighest", 0);
699 *urgent_uSN
= ldb_msg_find_attr_as_uint64(res
->msgs
[0], "uSNUrgent", 0);
703 talloc_free(tmp_ctx
);
709 save uSNHighest and uSNUrgent attributes in the @REPLCHANGED object for a
712 int dsdb_module_save_partition_usn(struct ldb_module
*module
, struct ldb_dn
*dn
,
713 uint64_t uSN
, uint64_t urgent_uSN
)
715 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
716 struct ldb_request
*req
;
717 struct ldb_message
*msg
;
718 struct dsdb_control_current_partition
*p_ctrl
;
721 msg
= ldb_msg_new(module
);
723 return LDB_ERR_OPERATIONS_ERROR
;
726 msg
->dn
= ldb_dn_new(msg
, ldb
, "@REPLCHANGED");
727 if (msg
->dn
== NULL
) {
729 return LDB_ERR_OPERATIONS_ERROR
;
732 ret
= ldb_msg_add_fmt(msg
, "uSNHighest", "%llu", (unsigned long long)uSN
);
733 if (ret
!= LDB_SUCCESS
) {
737 msg
->elements
[0].flags
= LDB_FLAG_MOD_REPLACE
;
739 /* urgent_uSN is optional so may not be stored */
741 ret
= ldb_msg_add_fmt(msg
, "uSNUrgent", "%llu", (unsigned long long)urgent_uSN
);
742 if (ret
!= LDB_SUCCESS
) {
746 msg
->elements
[1].flags
= LDB_FLAG_MOD_REPLACE
;
750 p_ctrl
= talloc(msg
, struct dsdb_control_current_partition
);
751 if (p_ctrl
== NULL
) {
753 return LDB_ERR_OPERATIONS_ERROR
;
755 p_ctrl
->version
= DSDB_CONTROL_CURRENT_PARTITION_VERSION
;
758 ret
= ldb_build_mod_req(&req
, ldb
, msg
,
761 NULL
, ldb_op_default_callback
,
764 if (ret
!= LDB_SUCCESS
) {
769 ret
= ldb_request_add_control(req
,
770 DSDB_CONTROL_CURRENT_PARTITION_OID
,
772 if (ret
!= LDB_SUCCESS
) {
777 /* Run the new request */
778 ret
= ldb_next_request(module
, req
);
780 if (ret
== LDB_SUCCESS
) {
781 ret
= ldb_wait(req
->handle
, LDB_WAIT_ALL
);
783 if (ret
== LDB_ERR_NO_SUCH_OBJECT
) {
784 ret
= ldb_build_add_req(&req
, ldb
, msg
,
787 NULL
, ldb_op_default_callback
,
797 bool dsdb_module_am_system(struct ldb_module
*module
)
799 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
800 struct auth_session_info
*session_info
801 = (struct auth_session_info
*)ldb_get_opaque(ldb
, "sessionInfo");
802 return security_session_user_level(session_info
) == SECURITY_SYSTEM
;
806 check if the recyclebin is enabled
808 int dsdb_recyclebin_enabled(struct ldb_module
*module
, bool *enabled
)
810 struct ldb_context
*ldb
= ldb_module_get_ctx(module
);
811 struct ldb_dn
*partitions_dn
;
812 struct GUID recyclebin_guid
;
815 partitions_dn
= samdb_partitions_dn(ldb
, module
);
817 GUID_from_string(DS_GUID_FEATURE_RECYCLE_BIN
, &recyclebin_guid
);
819 ret
= dsdb_check_optional_feature(module
, partitions_dn
, recyclebin_guid
, enabled
);
820 if (ret
!= LDB_SUCCESS
) {
821 ldb_asprintf_errstring(ldb
, "Could not verify if Recycle Bin is enabled \n");
822 talloc_free(partitions_dn
);
823 return LDB_ERR_UNWILLING_TO_PERFORM
;
826 talloc_free(partitions_dn
);