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 "ldb_private.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_all(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);
142 static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx,
143 const struct ldb_val *in, struct ldb_val *out)
146 enum ndr_err_code ndr_err;
147 if (ldb_comparision_objectSid_isString(in)) {
148 if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) {
153 /* Perhaps not a string after all */
154 *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
160 (*out).length = strhex_to_str((char *)out->data, out->length,
161 (const char *)in->data, in->length);
163 /* Check it looks like a SID */
164 ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &sid,
165 (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
166 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
173 convert a ldif formatted objectGUID to a NDR formatted blob
175 static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
176 const struct ldb_val *in, struct ldb_val *out)
180 enum ndr_err_code ndr_err;
182 status = GUID_from_data_blob(in, &guid);
183 if (!NT_STATUS_IS_OK(status)) {
187 ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, &guid,
188 (ndr_push_flags_fn_t)ndr_push_GUID);
189 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
196 convert a NDR formatted blob to a ldif formatted objectGUID
198 static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
199 const struct ldb_val *in, struct ldb_val *out)
202 enum ndr_err_code ndr_err;
203 ndr_err = ndr_pull_struct_blob_all(in, mem_ctx, NULL, &guid,
204 (ndr_pull_flags_fn_t)ndr_pull_GUID);
205 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
208 out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
209 if (out->data == NULL) {
212 out->length = strlen((const char *)out->data);
216 static bool ldb_comparision_objectGUID_isString(const struct ldb_val *v)
218 if (v->length != 36 && v->length != 38) return false;
220 /* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */
224 static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
225 const struct ldb_val *in, struct ldb_val *out)
228 enum ndr_err_code ndr_err;
229 if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) {
233 /* Try as 'hex' form */
234 if (in->length != 32) {
238 *out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
244 (*out).length = strhex_to_str((char *)out->data, out->length,
245 (const char *)in->data, in->length);
247 /* Check it looks like a GUID */
248 ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &guid,
249 (ndr_pull_flags_fn_t)ndr_pull_GUID);
250 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
257 compare two objectGUIDs
259 static int ldb_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
260 const struct ldb_val *v1, const struct ldb_val *v2)
262 if (ldb_comparision_objectGUID_isString(v1) && ldb_comparision_objectGUID_isString(v2)) {
263 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
264 } else if (ldb_comparision_objectGUID_isString(v1)
265 && !ldb_comparision_objectGUID_isString(v2)) {
268 if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
269 /* Perhaps it wasn't a valid string after all */
270 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
272 ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
275 } else if (!ldb_comparision_objectGUID_isString(v1)
276 && ldb_comparision_objectGUID_isString(v2)) {
279 if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
280 /* Perhaps it wasn't a valid string after all */
281 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
283 ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
287 return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
291 canonicalise a objectGUID
293 static int ldb_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
294 const struct ldb_val *in, struct ldb_val *out)
296 if (ldb_comparision_objectGUID_isString(in)) {
297 if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) {
298 /* Perhaps it wasn't a valid string after all */
299 return ldb_handler_copy(ldb, mem_ctx, in, out);
303 return ldb_handler_copy(ldb, mem_ctx, in, out);
308 convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
310 static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
311 const struct ldb_val *in, struct ldb_val *out)
313 struct security_descriptor *sd;
314 enum ndr_err_code ndr_err;
316 sd = sddl_decode(mem_ctx, (const char *)in->data, NULL);
320 ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sd,
321 (ndr_push_flags_fn_t)ndr_push_security_descriptor);
323 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
330 convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
332 static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
333 const struct ldb_val *in, struct ldb_val *out)
335 struct security_descriptor *sd;
336 enum ndr_err_code ndr_err;
338 sd = talloc(mem_ctx, struct security_descriptor);
342 /* We can't use ndr_pull_struct_blob_all because this contains relative pointers */
343 ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
344 (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
345 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
349 out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
351 if (out->data == NULL) {
354 out->length = strlen((const char *)out->data);
359 canonicalise an objectCategory. We use the short form as the cannoical form:
360 cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
363 static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
364 const struct ldb_val *in, struct ldb_val *out)
366 struct ldb_dn *dn1 = NULL;
367 const struct dsdb_schema *schema = dsdb_get_schema(ldb);
368 const struct dsdb_class *class;
369 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
371 return LDB_ERR_OPERATIONS_ERROR;
375 *out = data_blob_talloc(mem_ctx, in->data, in->length);
376 if (in->data && !out->data) {
377 return LDB_ERR_OPERATIONS_ERROR;
381 dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
382 if ( ! ldb_dn_validate(dn1)) {
383 const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
384 class = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
386 struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,
387 class->defaultObjectCategory);
388 *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
389 talloc_free(tmp_ctx);
392 return LDB_ERR_OPERATIONS_ERROR;
396 *out = data_blob_talloc(mem_ctx, in->data, in->length);
397 talloc_free(tmp_ctx);
399 if (in->data && !out->data) {
400 return LDB_ERR_OPERATIONS_ERROR;
405 *out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
406 talloc_free(tmp_ctx);
409 return LDB_ERR_OPERATIONS_ERROR;
414 static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
415 const struct ldb_val *v1,
416 const struct ldb_val *v2)
420 struct ldb_val v1_canon, v2_canon;
421 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
423 /* I could try and bail if tmp_ctx was NULL, but what return
426 * It seems easier to continue on the NULL context
428 ret1 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v1, &v1_canon);
429 ret2 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v2, &v2_canon);
431 if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
432 ret = data_blob_cmp(&v1_canon, &v2_canon);
434 ret = data_blob_cmp(v1, v2);
436 talloc_free(tmp_ctx);
441 convert a ldif formatted prefixMap to a NDR formatted blob
443 static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
444 const struct ldb_val *in, struct ldb_val *out)
446 struct prefixMapBlob *blob;
447 enum ndr_err_code ndr_err;
448 char *string, *line, *p, *oid;
450 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
452 if (tmp_ctx == NULL) {
456 blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
462 blob->version = PREFIX_MAP_VERSION_DSDB;
464 string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
465 if (string == NULL) {
471 while (line && line[0]) {
476 p=strchr(line, '\n');
481 /* allow a traling seperator */
486 blob->ctr.dsdb.mappings = talloc_realloc(blob,
487 blob->ctr.dsdb.mappings,
488 struct drsuapi_DsReplicaOIDMapping,
489 blob->ctr.dsdb.num_mappings+1);
490 if (!blob->ctr.dsdb.mappings) {
491 talloc_free(tmp_ctx);
495 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
498 talloc_free(tmp_ctx);
502 /* we know there must be at least ":" */
505 blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.oid
506 = talloc_strdup(blob->ctr.dsdb.mappings, oid);
508 blob->ctr.dsdb.num_mappings++;
510 /* Now look past the terminator we added above */
518 ndr_err = ndr_push_struct_blob(out, mem_ctx,
519 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
521 (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
522 talloc_free(tmp_ctx);
523 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
530 convert a NDR formatted blob to a ldif formatted prefixMap
532 static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
533 const struct ldb_val *in, struct ldb_val *out)
535 struct prefixMapBlob *blob;
536 enum ndr_err_code ndr_err;
540 blob = talloc(mem_ctx, struct prefixMapBlob);
544 ndr_err = ndr_pull_struct_blob_all(in, blob,
545 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
547 (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
548 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
552 if (blob->version != PREFIX_MAP_VERSION_DSDB) {
555 string = talloc_strdup(mem_ctx, "");
556 if (string == NULL) {
560 for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
562 string = talloc_asprintf_append(string, ";");
564 string = talloc_asprintf_append(string, "%u:%s",
565 blob->ctr.dsdb.mappings[i].id_prefix,
566 blob->ctr.dsdb.mappings[i].oid.oid);
567 if (string == NULL) {
573 *out = data_blob_string_const(string);
577 static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
583 if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
591 canonicalise a prefixMap
593 static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
594 const struct ldb_val *in, struct ldb_val *out)
596 if (ldif_comparision_prefixMap_isString(in)) {
597 return ldif_read_prefixMap(ldb, mem_ctx, in, out);
599 return ldb_handler_copy(ldb, mem_ctx, in, out);
602 static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
603 const struct ldb_val *v1,
604 const struct ldb_val *v2)
608 struct ldb_val v1_canon, v2_canon;
609 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
611 /* I could try and bail if tmp_ctx was NULL, but what return
614 * It seems easier to continue on the NULL context
616 ret1 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v1, &v1_canon);
617 ret2 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v2, &v2_canon);
619 if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
620 ret = data_blob_cmp(&v1_canon, &v2_canon);
622 ret = data_blob_cmp(v1, v2);
624 talloc_free(tmp_ctx);
628 static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
629 const struct ldb_val *in, struct ldb_val *out)
631 *out = data_blob_string_const(data_blob_hex_string(mem_ctx, in));
639 #define LDB_SYNTAX_SAMBA_GUID "LDB_SYNTAX_SAMBA_GUID"
640 #define LDB_SYNTAX_SAMBA_OBJECT_CATEGORY "LDB_SYNTAX_SAMBA_OBJECT_CATEGORY"
641 #define LDB_SYNTAX_SAMBA_PREFIX_MAP "LDB_SYNTAX_SAMBA_PREFIX_MAP"
643 static const struct ldb_schema_syntax samba_syntaxes[] = {
645 .name = LDB_SYNTAX_SAMBA_SID,
646 .ldif_read_fn = ldif_read_objectSid,
647 .ldif_write_fn = ldif_write_objectSid,
648 .canonicalise_fn = ldb_canonicalise_objectSid,
649 .comparison_fn = ldb_comparison_objectSid
651 .name = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
652 .ldif_read_fn = ldif_read_ntSecurityDescriptor,
653 .ldif_write_fn = ldif_write_ntSecurityDescriptor,
654 .canonicalise_fn = ldb_handler_copy,
655 .comparison_fn = ldb_comparison_binary
657 .name = LDB_SYNTAX_SAMBA_GUID,
658 .ldif_read_fn = ldif_read_objectGUID,
659 .ldif_write_fn = ldif_write_objectGUID,
660 .canonicalise_fn = ldb_canonicalise_objectGUID,
661 .comparison_fn = ldb_comparison_objectGUID
663 .name = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
664 .ldif_read_fn = ldb_handler_copy,
665 .ldif_write_fn = ldb_handler_copy,
666 .canonicalise_fn = ldif_canonicalise_objectCategory,
667 .comparison_fn = ldif_comparison_objectCategory
669 .name = LDB_SYNTAX_SAMBA_PREFIX_MAP,
670 .ldif_read_fn = ldif_read_prefixMap,
671 .ldif_write_fn = ldif_write_prefixMap,
672 .canonicalise_fn = ldif_canonicalise_prefixMap,
673 .comparison_fn = ldif_comparison_prefixMap
677 static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
680 .read_fn = extended_dn_read_SID,
681 .write_clear_fn = ldif_write_objectSid,
682 .write_hex_fn = extended_dn_write_hex
685 .read_fn = extended_dn_read_GUID,
686 .write_clear_fn = ldif_write_objectGUID,
687 .write_hex_fn = extended_dn_write_hex
690 .read_fn = ldb_handler_copy,
691 .write_clear_fn = ldb_handler_copy,
692 .write_hex_fn = ldb_handler_copy
696 static const struct {
699 } samba_attributes[] = {
700 { "objectSid", LDB_SYNTAX_SAMBA_SID },
701 { "securityIdentifier", LDB_SYNTAX_SAMBA_SID },
702 { "ntSecurityDescriptor", LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
703 { "objectGUID", LDB_SYNTAX_SAMBA_GUID },
704 { "invocationId", LDB_SYNTAX_SAMBA_GUID },
705 { "schemaIDGUID", LDB_SYNTAX_SAMBA_GUID },
706 { "attributeSecurityGUID", LDB_SYNTAX_SAMBA_GUID },
707 { "parentGUID", LDB_SYNTAX_SAMBA_GUID },
708 { "siteGUID", LDB_SYNTAX_SAMBA_GUID },
709 { "pKTGUID", LDB_SYNTAX_SAMBA_GUID },
710 { "fRSVersionGUID", LDB_SYNTAX_SAMBA_GUID },
711 { "fRSReplicaSetGUID", LDB_SYNTAX_SAMBA_GUID },
712 { "netbootGUID", LDB_SYNTAX_SAMBA_GUID },
713 { "objectCategory", LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
714 { "prefixMap", LDB_SYNTAX_SAMBA_PREFIX_MAP }
717 const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
720 const struct ldb_schema_syntax *s = NULL;
722 for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
723 if (strcmp(name, samba_syntaxes[j].name) == 0) {
724 s = &samba_syntaxes[j];
733 register the samba ldif handlers
735 int ldb_register_samba_handlers(struct ldb_context *ldb)
739 for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
741 const struct ldb_schema_syntax *s = NULL;
743 s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
746 s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
753 ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
754 if (ret != LDB_SUCCESS) {
759 for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
761 ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
762 if (ret != LDB_SUCCESS) {