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) {