2 ldb database library - ldif handlers for Samba
4 Copyright (C) Andrew Tridgell 2005
5 Copyright (C) Andrew Bartlett 2006-2007
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
10 This library is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Lesser General Public
12 License as published by the Free Software Foundation; either
13 version 3 of the License, or (at your option) any later version.
15 This library is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 #include "lib/ldb/include/ldb_includes.h"
26 #include "dsdb/samdb/samdb.h"
27 #include "librpc/gen_ndr/ndr_security.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_drsblobs.h"
30 #include "libcli/security/security.h"
31 #include "param/param.h"
34 convert a ldif formatted objectSid to a NDR formatted blob
36 static int ldif_read_objectSid(struct ldb_context
*ldb
, void *mem_ctx
,
37 const struct ldb_val
*in
, struct ldb_val
*out
)
39 enum ndr_err_code ndr_err
;
41 sid
= dom_sid_parse_length(mem_ctx
, in
);
45 ndr_err
= ndr_push_struct_blob(out
, mem_ctx
, NULL
, sid
,
46 (ndr_push_flags_fn_t
)ndr_push_dom_sid
);
48 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
55 convert a NDR formatted blob to a ldif formatted objectSid
57 static int ldif_write_objectSid(struct ldb_context
*ldb
, void *mem_ctx
,
58 const struct ldb_val
*in
, struct ldb_val
*out
)
61 enum ndr_err_code ndr_err
;
63 sid
= talloc(mem_ctx
, struct dom_sid
);
67 ndr_err
= ndr_pull_struct_blob(in
, sid
, NULL
, sid
,
68 (ndr_pull_flags_fn_t
)ndr_pull_dom_sid
);
69 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
73 *out
= data_blob_string_const(dom_sid_string(mem_ctx
, sid
));
75 if (out
->data
== NULL
) {
81 static bool ldb_comparision_objectSid_isString(const struct ldb_val
*v
)
87 if (strncmp("S-", (const char *)v
->data
, 2) != 0) return false;
93 compare two objectSids
95 static int ldb_comparison_objectSid(struct ldb_context
*ldb
, void *mem_ctx
,
96 const struct ldb_val
*v1
, const struct ldb_val
*v2
)
98 if (ldb_comparision_objectSid_isString(v1
) && ldb_comparision_objectSid_isString(v2
)) {
99 return ldb_comparison_binary(ldb
, mem_ctx
, v1
, v2
);
100 } else if (ldb_comparision_objectSid_isString(v1
)
101 && !ldb_comparision_objectSid_isString(v2
)) {
104 if (ldif_read_objectSid(ldb
, mem_ctx
, v1
, &v
) != 0) {
105 /* Perhaps not a string after all */
106 return ldb_comparison_binary(ldb
, mem_ctx
, v1
, v2
);
108 ret
= ldb_comparison_binary(ldb
, mem_ctx
, &v
, v2
);
111 } else if (!ldb_comparision_objectSid_isString(v1
)
112 && ldb_comparision_objectSid_isString(v2
)) {
115 if (ldif_read_objectSid(ldb
, mem_ctx
, v2
, &v
) != 0) {
116 /* Perhaps not a string after all */
117 return ldb_comparison_binary(ldb
, mem_ctx
, v1
, v2
);
119 ret
= ldb_comparison_binary(ldb
, mem_ctx
, v1
, &v
);
123 return ldb_comparison_binary(ldb
, mem_ctx
, v1
, v2
);
127 canonicalise a objectSid
129 static int ldb_canonicalise_objectSid(struct ldb_context
*ldb
, void *mem_ctx
,
130 const struct ldb_val
*in
, struct ldb_val
*out
)
132 if (ldb_comparision_objectSid_isString(in
)) {
133 if (ldif_read_objectSid(ldb
, mem_ctx
, in
, out
) != 0) {
134 /* Perhaps not a string after all */
135 return ldb_handler_copy(ldb
, mem_ctx
, in
, out
);
139 return ldb_handler_copy(ldb
, mem_ctx
, in
, out
);
143 convert a ldif formatted objectGUID to a NDR formatted blob
145 static int ldif_read_objectGUID(struct ldb_context
*ldb
, void *mem_ctx
,
146 const struct ldb_val
*in
, struct ldb_val
*out
)
151 enum ndr_err_code ndr_err
;
152 guid_string
= talloc_strndup(mem_ctx
, (const char *)in
->data
, in
->length
);
157 status
= GUID_from_string(guid_string
, &guid
);
158 talloc_free(guid_string
);
159 if (!NT_STATUS_IS_OK(status
)) {
163 ndr_err
= ndr_push_struct_blob(out
, mem_ctx
, NULL
, &guid
,
164 (ndr_push_flags_fn_t
)ndr_push_GUID
);
165 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
172 convert a NDR formatted blob to a ldif formatted objectGUID
174 static int ldif_write_objectGUID(struct ldb_context
*ldb
, void *mem_ctx
,
175 const struct ldb_val
*in
, struct ldb_val
*out
)
178 enum ndr_err_code ndr_err
;
179 ndr_err
= ndr_pull_struct_blob(in
, mem_ctx
, NULL
, &guid
,
180 (ndr_pull_flags_fn_t
)ndr_pull_GUID
);
181 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
184 out
->data
= (uint8_t *)GUID_string(mem_ctx
, &guid
);
185 if (out
->data
== NULL
) {
188 out
->length
= strlen((const char *)out
->data
);
192 static bool ldb_comparision_objectGUID_isString(const struct ldb_val
*v
)
197 if (v
->length
< 33) return false;
199 /* see if the input if null-terninated (safety check for the below) */
200 if (v
->data
[v
->length
] != '\0') return false;
202 status
= GUID_from_string((const char *)v
->data
, &guid
);
203 if (!NT_STATUS_IS_OK(status
)) {
211 compare two objectGUIDs
213 static int ldb_comparison_objectGUID(struct ldb_context
*ldb
, void *mem_ctx
,
214 const struct ldb_val
*v1
, const struct ldb_val
*v2
)
216 if (ldb_comparision_objectGUID_isString(v1
) && ldb_comparision_objectGUID_isString(v2
)) {
217 return ldb_comparison_binary(ldb
, mem_ctx
, v1
, v2
);
218 } else if (ldb_comparision_objectGUID_isString(v1
)
219 && !ldb_comparision_objectGUID_isString(v2
)) {
222 if (ldif_read_objectGUID(ldb
, mem_ctx
, v1
, &v
) != 0) {
223 /* Perhaps it wasn't a valid string after all */
224 return ldb_comparison_binary(ldb
, mem_ctx
, v1
, v2
);
226 ret
= ldb_comparison_binary(ldb
, mem_ctx
, &v
, v2
);
229 } else if (!ldb_comparision_objectGUID_isString(v1
)
230 && ldb_comparision_objectGUID_isString(v2
)) {
233 if (ldif_read_objectGUID(ldb
, mem_ctx
, v2
, &v
) != 0) {
234 /* Perhaps it wasn't a valid string after all */
235 return ldb_comparison_binary(ldb
, mem_ctx
, v1
, v2
);
237 ret
= ldb_comparison_binary(ldb
, mem_ctx
, v1
, &v
);
241 return ldb_comparison_binary(ldb
, mem_ctx
, v1
, v2
);
245 canonicalise a objectGUID
247 static int ldb_canonicalise_objectGUID(struct ldb_context
*ldb
, void *mem_ctx
,
248 const struct ldb_val
*in
, struct ldb_val
*out
)
250 if (ldb_comparision_objectGUID_isString(in
)) {
251 if (ldif_read_objectGUID(ldb
, mem_ctx
, in
, out
) != 0) {
252 /* Perhaps it wasn't a valid string after all */
253 return ldb_handler_copy(ldb
, mem_ctx
, in
, out
);
257 return ldb_handler_copy(ldb
, mem_ctx
, in
, out
);
262 convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
264 static int ldif_read_ntSecurityDescriptor(struct ldb_context
*ldb
, void *mem_ctx
,
265 const struct ldb_val
*in
, struct ldb_val
*out
)
267 struct security_descriptor
*sd
;
268 enum ndr_err_code ndr_err
;
270 sd
= sddl_decode(mem_ctx
, (const char *)in
->data
, NULL
);
274 ndr_err
= ndr_push_struct_blob(out
, mem_ctx
, NULL
, sd
,
275 (ndr_push_flags_fn_t
)ndr_push_security_descriptor
);
277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
284 convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
286 static int ldif_write_ntSecurityDescriptor(struct ldb_context
*ldb
, void *mem_ctx
,
287 const struct ldb_val
*in
, struct ldb_val
*out
)
289 struct security_descriptor
*sd
;
290 enum ndr_err_code ndr_err
;
292 sd
= talloc(mem_ctx
, struct security_descriptor
);
296 ndr_err
= ndr_pull_struct_blob(in
, sd
, NULL
, sd
,
297 (ndr_pull_flags_fn_t
)ndr_pull_security_descriptor
);
298 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
302 out
->data
= (uint8_t *)sddl_encode(mem_ctx
, sd
, NULL
);
304 if (out
->data
== NULL
) {
307 out
->length
= strlen((const char *)out
->data
);
312 canonicalise an objectCategory. We use the short form as the cannoical form:
313 cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
316 static int ldif_canonicalise_objectCategory(struct ldb_context
*ldb
, void *mem_ctx
,
317 const struct ldb_val
*in
, struct ldb_val
*out
)
319 struct ldb_dn
*dn1
= NULL
;
320 const struct dsdb_schema
*schema
= dsdb_get_schema(ldb
);
321 const struct dsdb_class
*class;
322 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
324 return LDB_ERR_OPERATIONS_ERROR
;
328 *out
= data_blob_talloc(mem_ctx
, in
->data
, in
->length
);
329 if (in
->data
&& !out
->data
) {
330 return LDB_ERR_OPERATIONS_ERROR
;
334 dn1
= ldb_dn_from_ldb_val(tmp_ctx
, ldb
, in
);
335 if ( ! ldb_dn_validate(dn1
)) {
336 const char *lDAPDisplayName
= talloc_strndup(tmp_ctx
, (char *)in
->data
, in
->length
);
337 class = dsdb_class_by_lDAPDisplayName(schema
, lDAPDisplayName
);
339 struct ldb_dn
*dn
= ldb_dn_new(mem_ctx
, ldb
,
340 class->defaultObjectCategory
);
341 *out
= data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx
, dn
));
342 talloc_free(tmp_ctx
);
345 return LDB_ERR_OPERATIONS_ERROR
;
349 *out
= data_blob_talloc(mem_ctx
, in
->data
, in
->length
);
350 talloc_free(tmp_ctx
);
352 if (in
->data
&& !out
->data
) {
353 return LDB_ERR_OPERATIONS_ERROR
;
358 *out
= data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx
, dn1
));
359 talloc_free(tmp_ctx
);
362 return LDB_ERR_OPERATIONS_ERROR
;
367 static int ldif_comparison_objectCategory(struct ldb_context
*ldb
, void *mem_ctx
,
368 const struct ldb_val
*v1
,
369 const struct ldb_val
*v2
)
373 struct ldb_val v1_canon
, v2_canon
;
374 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
376 /* I could try and bail if tmp_ctx was NULL, but what return
379 * It seems easier to continue on the NULL context
381 ret1
= ldif_canonicalise_objectCategory(ldb
, tmp_ctx
, v1
, &v1_canon
);
382 ret2
= ldif_canonicalise_objectCategory(ldb
, tmp_ctx
, v2
, &v2_canon
);
384 if (ret1
== LDB_SUCCESS
&& ret2
== LDB_SUCCESS
) {
385 ret
= data_blob_cmp(&v1_canon
, &v2_canon
);
387 ret
= data_blob_cmp(v1
, v2
);
389 talloc_free(tmp_ctx
);
394 convert a ldif formatted prefixMap to a NDR formatted blob
396 static int ldif_read_prefixMap(struct ldb_context
*ldb
, void *mem_ctx
,
397 const struct ldb_val
*in
, struct ldb_val
*out
)
399 struct prefixMapBlob
*blob
;
400 enum ndr_err_code ndr_err
;
401 char *string
, *line
, *p
, *oid
;
403 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
405 if (tmp_ctx
== NULL
) {
409 blob
= talloc_zero(tmp_ctx
, struct prefixMapBlob
);
415 blob
->version
= PREFIX_MAP_VERSION_DSDB
;
417 string
= talloc_strndup(mem_ctx
, (const char *)in
->data
, in
->length
);
418 if (string
== NULL
) {
424 while (line
&& line
[0]) {
429 p
=strchr(line
, '\n');
434 /* allow a traling seperator */
439 blob
->ctr
.dsdb
.mappings
= talloc_realloc(blob
,
440 blob
->ctr
.dsdb
.mappings
,
441 struct drsuapi_DsReplicaOIDMapping
,
442 blob
->ctr
.dsdb
.num_mappings
+1);
443 if (!blob
->ctr
.dsdb
.mappings
) {
444 talloc_free(tmp_ctx
);
448 blob
->ctr
.dsdb
.mappings
[blob
->ctr
.dsdb
.num_mappings
].id_prefix
= strtoul(line
, &oid
, 10);
451 talloc_free(tmp_ctx
);
455 /* we know there must be at least ":" */
458 blob
->ctr
.dsdb
.mappings
[blob
->ctr
.dsdb
.num_mappings
].oid
.oid
459 = talloc_strdup(blob
->ctr
.dsdb
.mappings
, oid
);
461 blob
->ctr
.dsdb
.num_mappings
++;
463 /* Now look past the terminator we added above */
471 ndr_err
= ndr_push_struct_blob(out
, mem_ctx
,
472 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
474 (ndr_push_flags_fn_t
)ndr_push_prefixMapBlob
);
475 talloc_free(tmp_ctx
);
476 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
483 convert a NDR formatted blob to a ldif formatted prefixMap
485 static int ldif_write_prefixMap(struct ldb_context
*ldb
, void *mem_ctx
,
486 const struct ldb_val
*in
, struct ldb_val
*out
)
488 struct prefixMapBlob
*blob
;
489 enum ndr_err_code ndr_err
;
493 blob
= talloc(mem_ctx
, struct prefixMapBlob
);
497 ndr_err
= ndr_pull_struct_blob(in
, blob
,
498 lp_iconv_convenience(ldb_get_opaque(ldb
, "loadparm")),
500 (ndr_pull_flags_fn_t
)ndr_pull_prefixMapBlob
);
501 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
505 if (blob
->version
!= PREFIX_MAP_VERSION_DSDB
) {
508 string
= talloc_strdup(mem_ctx
, "");
509 if (string
== NULL
) {
513 for (i
=0; i
< blob
->ctr
.dsdb
.num_mappings
; i
++) {
515 string
= talloc_asprintf_append(string
, ";");
517 string
= talloc_asprintf_append(string
, "%u:%s",
518 blob
->ctr
.dsdb
.mappings
[i
].id_prefix
,
519 blob
->ctr
.dsdb
.mappings
[i
].oid
.oid
);
520 if (string
== NULL
) {
526 *out
= data_blob_string_const(string
);
530 static bool ldif_comparision_prefixMap_isString(const struct ldb_val
*v
)
536 if (IVAL(v
->data
, 0) == PREFIX_MAP_VERSION_DSDB
) {
544 canonicalise a prefixMap
546 static int ldif_canonicalise_prefixMap(struct ldb_context
*ldb
, void *mem_ctx
,
547 const struct ldb_val
*in
, struct ldb_val
*out
)
549 if (ldif_comparision_prefixMap_isString(in
)) {
550 return ldif_read_prefixMap(ldb
, mem_ctx
, in
, out
);
552 return ldb_handler_copy(ldb
, mem_ctx
, in
, out
);
555 static int ldif_comparison_prefixMap(struct ldb_context
*ldb
, void *mem_ctx
,
556 const struct ldb_val
*v1
,
557 const struct ldb_val
*v2
)
561 struct ldb_val v1_canon
, v2_canon
;
562 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
564 /* I could try and bail if tmp_ctx was NULL, but what return
567 * It seems easier to continue on the NULL context
569 ret1
= ldif_canonicalise_prefixMap(ldb
, tmp_ctx
, v1
, &v1_canon
);
570 ret2
= ldif_canonicalise_prefixMap(ldb
, tmp_ctx
, v2
, &v2_canon
);
572 if (ret1
== LDB_SUCCESS
&& ret2
== LDB_SUCCESS
) {
573 ret
= data_blob_cmp(&v1_canon
, &v2_canon
);
575 ret
= data_blob_cmp(v1
, v2
);
577 talloc_free(tmp_ctx
);
581 #define LDB_SYNTAX_SAMBA_GUID "LDB_SYNTAX_SAMBA_GUID"
582 #define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
583 #define LDB_SYNTAX_SAMBA_PREFIX_MAP "LDB_SYNTAX_SAMBA_PREFIX_MAP"
585 static const struct ldb_schema_syntax samba_syntaxes
[] = {
587 .name
= LDB_SYNTAX_SAMBA_SID
,
588 .ldif_read_fn
= ldif_read_objectSid
,
589 .ldif_write_fn
= ldif_write_objectSid
,
590 .canonicalise_fn
= ldb_canonicalise_objectSid
,
591 .comparison_fn
= ldb_comparison_objectSid
593 .name
= LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR
,
594 .ldif_read_fn
= ldif_read_ntSecurityDescriptor
,
595 .ldif_write_fn
= ldif_write_ntSecurityDescriptor
,
596 .canonicalise_fn
= ldb_handler_copy
,
597 .comparison_fn
= ldb_comparison_binary
599 .name
= LDB_SYNTAX_SAMBA_GUID
,
600 .ldif_read_fn
= ldif_read_objectGUID
,
601 .ldif_write_fn
= ldif_write_objectGUID
,
602 .canonicalise_fn
= ldb_canonicalise_objectGUID
,
603 .comparison_fn
= ldb_comparison_objectGUID
605 .name
= LDB_SYNTAX_SAMBA_OBJECT_CATEGORY
,
606 .ldif_read_fn
= ldb_handler_copy
,
607 .ldif_write_fn
= ldb_handler_copy
,
608 .canonicalise_fn
= ldif_canonicalise_objectCategory
,
609 .comparison_fn
= ldif_comparison_objectCategory
611 .name
= LDB_SYNTAX_SAMBA_PREFIX_MAP
,
612 .ldif_read_fn
= ldif_read_prefixMap
,
613 .ldif_write_fn
= ldif_write_prefixMap
,
614 .canonicalise_fn
= ldif_canonicalise_prefixMap
,
615 .comparison_fn
= ldif_comparison_prefixMap
619 static const struct {
622 } samba_attributes
[] = {
623 { "objectSid", LDB_SYNTAX_SAMBA_SID
},
624 { "securityIdentifier", LDB_SYNTAX_SAMBA_SID
},
625 { "ntSecurityDescriptor", LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR
},
626 { "objectGUID", LDB_SYNTAX_SAMBA_GUID
},
627 { "invocationId", LDB_SYNTAX_SAMBA_GUID
},
628 { "schemaIDGUID", LDB_SYNTAX_SAMBA_GUID
},
629 { "attributeSecurityGUID", LDB_SYNTAX_SAMBA_GUID
},
630 { "parentGUID", LDB_SYNTAX_SAMBA_GUID
},
631 { "siteGUID", LDB_SYNTAX_SAMBA_GUID
},
632 { "pKTGUID", LDB_SYNTAX_SAMBA_GUID
},
633 { "fRSVersionGUID", LDB_SYNTAX_SAMBA_GUID
},
634 { "fRSReplicaSetGUID", LDB_SYNTAX_SAMBA_GUID
},
635 { "netbootGUID", LDB_SYNTAX_SAMBA_GUID
},
636 { "objectCategory", LDB_SYNTAX_SAMBA_OBJECT_CATEGORY
},
637 { "prefixMap", LDB_SYNTAX_SAMBA_PREFIX_MAP
}
640 const struct ldb_schema_syntax
*ldb_samba_syntax_by_name(struct ldb_context
*ldb
, const char *name
)
643 const struct ldb_schema_syntax
*s
= NULL
;
645 for (j
=0; j
< ARRAY_SIZE(samba_syntaxes
); j
++) {
646 if (strcmp(name
, samba_syntaxes
[j
].name
) == 0) {
647 s
= &samba_syntaxes
[j
];
656 register the samba ldif handlers
658 int ldb_register_samba_handlers(struct ldb_context
*ldb
)
662 for (i
=0; i
< ARRAY_SIZE(samba_attributes
); i
++) {
664 const struct ldb_schema_syntax
*s
= NULL
;
666 s
= ldb_samba_syntax_by_name(ldb
, samba_attributes
[i
].syntax
);
669 s
= ldb_standard_syntax_by_name(ldb
, samba_attributes
[i
].syntax
);
676 ret
= ldb_schema_attribute_add_with_syntax(ldb
, samba_attributes
[i
].name
, LDB_ATTR_FLAG_FIXED
, s
);
677 if (ret
!= LDB_SUCCESS
) {