• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt/router/samba-3.5.8/source4/lib/ldb-samba/
1/*
2   ldb database library - ldif handlers for Samba
3
4   Copyright (C) Andrew Tridgell 2005
5   Copyright (C) Andrew Bartlett 2006-2007
6   Copyright (C) Matthias Dieter Walln��fer 2009
7     ** NOTE! The following LGPL license applies to the ldb
8     ** library. This does NOT imply that all of Samba is released
9     ** under the LGPL
10
11   This library is free software; you can redistribute it and/or
12   modify it under the terms of the GNU Lesser General Public
13   License as published by the Free Software Foundation; either
14   version 3 of the License, or (at your option) any later version.
15
16   This library is distributed in the hope that it will be useful,
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19   Lesser General Public License for more details.
20
21   You should have received a copy of the GNU Lesser General Public
22   License along with this library; if not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "includes.h"
26#include "lib/ldb/include/ldb.h"
27#include "lib/ldb/include/ldb_module.h"
28#include "ldb_handlers.h"
29#include "dsdb/samdb/samdb.h"
30#include "librpc/gen_ndr/ndr_security.h"
31#include "librpc/gen_ndr/ndr_misc.h"
32#include "librpc/gen_ndr/ndr_drsblobs.h"
33#include "librpc/ndr/libndr.h"
34#include "libcli/security/security.h"
35#include "param/param.h"
36
37/*
38  use ndr_print_* to convert a NDR formatted blob to a ldif formatted blob
39*/
40static int ldif_write_NDR(struct ldb_context *ldb, void *mem_ctx,
41			  const struct ldb_val *in, struct ldb_val *out,
42			  size_t struct_size,
43			  ndr_pull_flags_fn_t pull_fn,
44			  ndr_print_fn_t print_fn)
45{
46	uint8_t *p;
47	enum ndr_err_code err;
48	if (!(ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY)) {
49		return ldb_handler_copy(ldb, mem_ctx, in, out);
50	}
51	p = talloc_size(mem_ctx, struct_size);
52	err = ndr_pull_struct_blob(in, mem_ctx,
53				   lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
54				   p, pull_fn);
55	if (err != NDR_ERR_SUCCESS) {
56		talloc_free(p);
57		out->data = (uint8_t *)talloc_strdup(mem_ctx, "<Unable to decode binary data>");
58		out->length = strlen((const char *)out->data);
59		return 0;
60	}
61	out->data = (uint8_t *)ndr_print_struct_string(mem_ctx, print_fn, "NDR", p);
62	talloc_free(p);
63	if (out->data == NULL) {
64		return ldb_handler_copy(ldb, mem_ctx, in, out);
65	}
66	out->length = strlen((char *)out->data);
67	return 0;
68}
69
70/*
71  convert a ldif formatted objectSid to a NDR formatted blob
72*/
73static int ldif_read_objectSid(struct ldb_context *ldb, void *mem_ctx,
74			       const struct ldb_val *in, struct ldb_val *out)
75{
76	enum ndr_err_code ndr_err;
77	struct dom_sid *sid;
78	sid = dom_sid_parse_length(mem_ctx, in);
79	if (sid == NULL) {
80		return -1;
81	}
82	ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sid,
83				       (ndr_push_flags_fn_t)ndr_push_dom_sid);
84	talloc_free(sid);
85	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
86		return -1;
87	}
88	return 0;
89}
90
91/*
92  convert a NDR formatted blob to a ldif formatted objectSid
93*/
94static int ldif_write_objectSid(struct ldb_context *ldb, void *mem_ctx,
95				const struct ldb_val *in, struct ldb_val *out)
96{
97	struct dom_sid *sid;
98	enum ndr_err_code ndr_err;
99
100	sid = talloc(mem_ctx, struct dom_sid);
101	if (sid == NULL) {
102		return -1;
103	}
104	ndr_err = ndr_pull_struct_blob_all(in, sid, NULL, sid,
105					   (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
106	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
107		talloc_free(sid);
108		return -1;
109	}
110	*out = data_blob_string_const(dom_sid_string(mem_ctx, sid));
111	talloc_free(sid);
112	if (out->data == NULL) {
113		return -1;
114	}
115	return 0;
116}
117
118static bool ldif_comparision_objectSid_isString(const struct ldb_val *v)
119{
120	if (v->length < 3) {
121		return false;
122	}
123
124	if (strncmp("S-", (const char *)v->data, 2) != 0) return false;
125
126	return true;
127}
128
129/*
130  compare two objectSids
131*/
132static int ldif_comparison_objectSid(struct ldb_context *ldb, void *mem_ctx,
133				    const struct ldb_val *v1, const struct ldb_val *v2)
134{
135	if (ldif_comparision_objectSid_isString(v1) && ldif_comparision_objectSid_isString(v2)) {
136		return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
137	} else if (ldif_comparision_objectSid_isString(v1)
138		   && !ldif_comparision_objectSid_isString(v2)) {
139		struct ldb_val v;
140		int ret;
141		if (ldif_read_objectSid(ldb, mem_ctx, v1, &v) != 0) {
142			/* Perhaps not a string after all */
143			return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
144		}
145		ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
146		talloc_free(v.data);
147		return ret;
148	} else if (!ldif_comparision_objectSid_isString(v1)
149		   && ldif_comparision_objectSid_isString(v2)) {
150		struct ldb_val v;
151		int ret;
152		if (ldif_read_objectSid(ldb, mem_ctx, v2, &v) != 0) {
153			/* Perhaps not a string after all */
154			return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
155		}
156		ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
157		talloc_free(v.data);
158		return ret;
159	}
160	return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
161}
162
163/*
164  canonicalise a objectSid
165*/
166static int ldif_canonicalise_objectSid(struct ldb_context *ldb, void *mem_ctx,
167				      const struct ldb_val *in, struct ldb_val *out)
168{
169	if (ldif_comparision_objectSid_isString(in)) {
170		if (ldif_read_objectSid(ldb, mem_ctx, in, out) != 0) {
171			/* Perhaps not a string after all */
172			return ldb_handler_copy(ldb, mem_ctx, in, out);
173		}
174		return 0;
175	}
176	return ldb_handler_copy(ldb, mem_ctx, in, out);
177}
178
179static int extended_dn_read_SID(struct ldb_context *ldb, void *mem_ctx,
180			      const struct ldb_val *in, struct ldb_val *out)
181{
182	struct dom_sid sid;
183	enum ndr_err_code ndr_err;
184	if (ldif_comparision_objectSid_isString(in)) {
185		if (ldif_read_objectSid(ldb, mem_ctx, in, out) == 0) {
186			return 0;
187		}
188	}
189
190	/* Perhaps not a string after all */
191	*out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
192
193	if (!out->data) {
194		return -1;
195	}
196
197	(*out).length = strhex_to_str((char *)out->data, out->length,
198				     (const char *)in->data, in->length);
199
200	/* Check it looks like a SID */
201	ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &sid,
202					   (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
203	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
204		return -1;
205	}
206	return 0;
207}
208
209/*
210  convert a ldif formatted objectGUID to a NDR formatted blob
211*/
212static int ldif_read_objectGUID(struct ldb_context *ldb, void *mem_ctx,
213			        const struct ldb_val *in, struct ldb_val *out)
214{
215	struct GUID guid;
216	NTSTATUS status;
217	enum ndr_err_code ndr_err;
218
219	status = GUID_from_data_blob(in, &guid);
220	if (!NT_STATUS_IS_OK(status)) {
221		return -1;
222	}
223
224	ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, &guid,
225				       (ndr_push_flags_fn_t)ndr_push_GUID);
226	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
227		return -1;
228	}
229	return 0;
230}
231
232/*
233  convert a NDR formatted blob to a ldif formatted objectGUID
234*/
235static int ldif_write_objectGUID(struct ldb_context *ldb, void *mem_ctx,
236				 const struct ldb_val *in, struct ldb_val *out)
237{
238	struct GUID guid;
239	enum ndr_err_code ndr_err;
240	ndr_err = ndr_pull_struct_blob_all(in, mem_ctx, NULL, &guid,
241					   (ndr_pull_flags_fn_t)ndr_pull_GUID);
242	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
243		return -1;
244	}
245	out->data = (uint8_t *)GUID_string(mem_ctx, &guid);
246	if (out->data == NULL) {
247		return -1;
248	}
249	out->length = strlen((const char *)out->data);
250	return 0;
251}
252
253static bool ldif_comparision_objectGUID_isString(const struct ldb_val *v)
254{
255	if (v->length != 36 && v->length != 38) return false;
256
257	/* Might be a GUID string, can't be a binary GUID (fixed 16 bytes) */
258	return true;
259}
260
261static int extended_dn_read_GUID(struct ldb_context *ldb, void *mem_ctx,
262			      const struct ldb_val *in, struct ldb_val *out)
263{
264	struct GUID guid;
265	enum ndr_err_code ndr_err;
266	if (in->length == 36 && ldif_read_objectGUID(ldb, mem_ctx, in, out) == 0) {
267		return 0;
268	}
269
270	/* Try as 'hex' form */
271	if (in->length != 32) {
272		return -1;
273	}
274
275	*out = data_blob_talloc(mem_ctx, NULL, in->length/2+1);
276
277	if (!out->data) {
278		return -1;
279	}
280
281	(*out).length = strhex_to_str((char *)out->data, out->length,
282				      (const char *)in->data, in->length);
283
284	/* Check it looks like a GUID */
285	ndr_err = ndr_pull_struct_blob_all(out, mem_ctx, NULL, &guid,
286					   (ndr_pull_flags_fn_t)ndr_pull_GUID);
287	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
288		return -1;
289	}
290	return 0;
291}
292
293/*
294  compare two objectGUIDs
295*/
296static int ldif_comparison_objectGUID(struct ldb_context *ldb, void *mem_ctx,
297				     const struct ldb_val *v1, const struct ldb_val *v2)
298{
299	if (ldif_comparision_objectGUID_isString(v1) && ldif_comparision_objectGUID_isString(v2)) {
300		return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
301	} else if (ldif_comparision_objectGUID_isString(v1)
302		   && !ldif_comparision_objectGUID_isString(v2)) {
303		struct ldb_val v;
304		int ret;
305		if (ldif_read_objectGUID(ldb, mem_ctx, v1, &v) != 0) {
306			/* Perhaps it wasn't a valid string after all */
307			return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
308		}
309		ret = ldb_comparison_binary(ldb, mem_ctx, &v, v2);
310		talloc_free(v.data);
311		return ret;
312	} else if (!ldif_comparision_objectGUID_isString(v1)
313		   && ldif_comparision_objectGUID_isString(v2)) {
314		struct ldb_val v;
315		int ret;
316		if (ldif_read_objectGUID(ldb, mem_ctx, v2, &v) != 0) {
317			/* Perhaps it wasn't a valid string after all */
318			return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
319		}
320		ret = ldb_comparison_binary(ldb, mem_ctx, v1, &v);
321		talloc_free(v.data);
322		return ret;
323	}
324	return ldb_comparison_binary(ldb, mem_ctx, v1, v2);
325}
326
327/*
328  canonicalise a objectGUID
329*/
330static int ldif_canonicalise_objectGUID(struct ldb_context *ldb, void *mem_ctx,
331				       const struct ldb_val *in, struct ldb_val *out)
332{
333	if (ldif_comparision_objectGUID_isString(in)) {
334		if (ldif_read_objectGUID(ldb, mem_ctx, in, out) != 0) {
335			/* Perhaps it wasn't a valid string after all */
336			return ldb_handler_copy(ldb, mem_ctx, in, out);
337		}
338		return 0;
339	}
340	return ldb_handler_copy(ldb, mem_ctx, in, out);
341}
342
343
344/*
345  convert a ldif (SDDL) formatted ntSecurityDescriptor to a NDR formatted blob
346*/
347static int ldif_read_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
348					  const struct ldb_val *in, struct ldb_val *out)
349{
350	struct security_descriptor *sd;
351	enum ndr_err_code ndr_err;
352
353	sd = talloc(mem_ctx, struct security_descriptor);
354	if (sd == NULL) {
355		return -1;
356	}
357
358	ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
359				       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
360	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
361		/* If this does not parse, then it is probably SDDL, and we should try it that way */
362
363		const struct dom_sid *sid = samdb_domain_sid(ldb);
364		talloc_free(sd);
365		sd = sddl_decode(mem_ctx, (const char *)in->data, sid);
366		if (sd == NULL) {
367			return -1;
368		}
369	}
370
371	ndr_err = ndr_push_struct_blob(out, mem_ctx, NULL, sd,
372				       (ndr_push_flags_fn_t)ndr_push_security_descriptor);
373	talloc_free(sd);
374	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
375		return -1;
376	}
377
378	return 0;
379}
380
381/*
382  convert a NDR formatted blob to a ldif formatted ntSecurityDescriptor (SDDL format)
383*/
384static int ldif_write_ntSecurityDescriptor(struct ldb_context *ldb, void *mem_ctx,
385					   const struct ldb_val *in, struct ldb_val *out)
386{
387	struct security_descriptor *sd;
388	enum ndr_err_code ndr_err;
389
390	if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
391		return ldif_write_NDR(ldb, mem_ctx, in, out,
392				      sizeof(struct security_descriptor),
393				      (ndr_pull_flags_fn_t)ndr_pull_security_descriptor,
394				      (ndr_print_fn_t)ndr_print_security_descriptor);
395
396	}
397
398	sd = talloc(mem_ctx, struct security_descriptor);
399	if (sd == NULL) {
400		return -1;
401	}
402	/* We can't use ndr_pull_struct_blob_all because this contains relative pointers */
403	ndr_err = ndr_pull_struct_blob(in, sd, NULL, sd,
404					   (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
405	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
406		talloc_free(sd);
407		return -1;
408	}
409	out->data = (uint8_t *)sddl_encode(mem_ctx, sd, NULL);
410	talloc_free(sd);
411	if (out->data == NULL) {
412		return -1;
413	}
414	out->length = strlen((const char *)out->data);
415	return 0;
416}
417
418/*
419   canonicalise an objectCategory.  We use the short form as the cannoical form:
420   cn=Person,cn=Schema,cn=Configuration,<basedn> becomes 'person'
421*/
422
423static int ldif_canonicalise_objectCategory(struct ldb_context *ldb, void *mem_ctx,
424					    const struct ldb_val *in, struct ldb_val *out)
425{
426	struct ldb_dn *dn1 = NULL;
427	const struct dsdb_schema *schema = dsdb_get_schema(ldb);
428	const struct dsdb_class *sclass;
429	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
430	if (!tmp_ctx) {
431		return LDB_ERR_OPERATIONS_ERROR;
432	}
433
434	if (!schema) {
435		talloc_free(tmp_ctx);
436		*out = data_blob_talloc(mem_ctx, in->data, in->length);
437		if (in->data && !out->data) {
438			return LDB_ERR_OPERATIONS_ERROR;
439		}
440		return LDB_SUCCESS;
441	}
442	dn1 = ldb_dn_from_ldb_val(tmp_ctx, ldb, in);
443	if ( ! ldb_dn_validate(dn1)) {
444		const char *lDAPDisplayName = talloc_strndup(tmp_ctx, (char *)in->data, in->length);
445		sclass = dsdb_class_by_lDAPDisplayName(schema, lDAPDisplayName);
446		if (sclass) {
447			struct ldb_dn *dn = ldb_dn_new(mem_ctx, ldb,
448						       sclass->defaultObjectCategory);
449			*out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn));
450			talloc_free(tmp_ctx);
451
452			if (!out->data) {
453				return LDB_ERR_OPERATIONS_ERROR;
454			}
455			return LDB_SUCCESS;
456		} else {
457			*out = data_blob_talloc(mem_ctx, in->data, in->length);
458			talloc_free(tmp_ctx);
459
460			if (in->data && !out->data) {
461				return LDB_ERR_OPERATIONS_ERROR;
462			}
463			return LDB_SUCCESS;
464		}
465	}
466	*out = data_blob_string_const(ldb_dn_alloc_casefold(mem_ctx, dn1));
467	talloc_free(tmp_ctx);
468
469	if (!out->data) {
470		return LDB_ERR_OPERATIONS_ERROR;
471	}
472	return LDB_SUCCESS;
473}
474
475static int ldif_comparison_objectCategory(struct ldb_context *ldb, void *mem_ctx,
476					  const struct ldb_val *v1,
477					  const struct ldb_val *v2)
478{
479
480	int ret, ret1, ret2;
481	struct ldb_val v1_canon, v2_canon;
482	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
483
484	/* I could try and bail if tmp_ctx was NULL, but what return
485	 * value would I use?
486	 *
487	 * It seems easier to continue on the NULL context
488	 */
489	ret1 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v1, &v1_canon);
490	ret2 = ldif_canonicalise_objectCategory(ldb, tmp_ctx, v2, &v2_canon);
491
492	if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
493		ret = data_blob_cmp(&v1_canon, &v2_canon);
494	} else {
495		ret = data_blob_cmp(v1, v2);
496	}
497	talloc_free(tmp_ctx);
498	return ret;
499}
500
501/*
502  convert a ldif formatted prefixMap to a NDR formatted blob
503*/
504static int ldif_read_prefixMap(struct ldb_context *ldb, void *mem_ctx,
505			       const struct ldb_val *in, struct ldb_val *out)
506{
507	struct prefixMapBlob *blob;
508	enum ndr_err_code ndr_err;
509	char *string, *line, *p, *oid;
510
511	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
512
513	if (tmp_ctx == NULL) {
514		return -1;
515	}
516
517	blob = talloc_zero(tmp_ctx, struct prefixMapBlob);
518	if (blob == NULL) {
519		talloc_free(blob);
520		return -1;
521	}
522
523	blob->version = PREFIX_MAP_VERSION_DSDB;
524
525	string = talloc_strndup(mem_ctx, (const char *)in->data, in->length);
526	if (string == NULL) {
527		talloc_free(blob);
528		return -1;
529	}
530
531	line = string;
532	while (line && line[0]) {
533		p=strchr(line, ';');
534		if (p) {
535			p[0] = '\0';
536		} else {
537			p=strchr(line, '\n');
538			if (p) {
539				p[0] = '\0';
540			}
541		}
542		/* allow a traling seperator */
543		if (line == p) {
544			break;
545		}
546
547		blob->ctr.dsdb.mappings = talloc_realloc(blob,
548							 blob->ctr.dsdb.mappings,
549							 struct drsuapi_DsReplicaOIDMapping,
550							 blob->ctr.dsdb.num_mappings+1);
551		if (!blob->ctr.dsdb.mappings) {
552			talloc_free(tmp_ctx);
553			return -1;
554		}
555
556		blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].id_prefix = strtoul(line, &oid, 10);
557
558		if (oid[0] != ':') {
559			talloc_free(tmp_ctx);
560			return -1;
561		}
562
563		/* we know there must be at least ":" */
564		oid++;
565
566		blob->ctr.dsdb.mappings[blob->ctr.dsdb.num_mappings].oid.oid
567			= talloc_strdup(blob->ctr.dsdb.mappings, oid);
568
569		blob->ctr.dsdb.num_mappings++;
570
571		/* Now look past the terminator we added above */
572		if (p) {
573			line = p + 1;
574		} else {
575			line = NULL;
576		}
577	}
578
579	ndr_err = ndr_push_struct_blob(out, mem_ctx,
580				       lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
581				       blob,
582				       (ndr_push_flags_fn_t)ndr_push_prefixMapBlob);
583	talloc_free(tmp_ctx);
584	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
585		return -1;
586	}
587	return 0;
588}
589
590/*
591  convert a NDR formatted blob to a ldif formatted prefixMap
592*/
593static int ldif_write_prefixMap(struct ldb_context *ldb, void *mem_ctx,
594				const struct ldb_val *in, struct ldb_val *out)
595{
596	struct prefixMapBlob *blob;
597	enum ndr_err_code ndr_err;
598	char *string;
599	uint32_t i;
600
601	if (ldb_get_flags(ldb) & LDB_FLG_SHOW_BINARY) {
602		return ldif_write_NDR(ldb, mem_ctx, in, out,
603				      sizeof(struct prefixMapBlob),
604				      (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob,
605				      (ndr_print_fn_t)ndr_print_prefixMapBlob);
606
607	}
608
609	blob = talloc(mem_ctx, struct prefixMapBlob);
610	if (blob == NULL) {
611		return -1;
612	}
613	ndr_err = ndr_pull_struct_blob_all(in, blob,
614					   lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
615					   blob,
616					   (ndr_pull_flags_fn_t)ndr_pull_prefixMapBlob);
617	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
618		talloc_free(blob);
619		return -1;
620	}
621	if (blob->version != PREFIX_MAP_VERSION_DSDB) {
622		return -1;
623	}
624	string = talloc_strdup(mem_ctx, "");
625	if (string == NULL) {
626		return -1;
627	}
628
629	for (i=0; i < blob->ctr.dsdb.num_mappings; i++) {
630		if (i > 0) {
631			string = talloc_asprintf_append(string, ";");
632		}
633		string = talloc_asprintf_append(string, "%u:%s",
634						   blob->ctr.dsdb.mappings[i].id_prefix,
635						   blob->ctr.dsdb.mappings[i].oid.oid);
636		if (string == NULL) {
637			return -1;
638		}
639	}
640
641	talloc_free(blob);
642	*out = data_blob_string_const(string);
643	return 0;
644}
645
646static bool ldif_comparision_prefixMap_isString(const struct ldb_val *v)
647{
648	if (v->length < 4) {
649		return true;
650	}
651
652	if (IVAL(v->data, 0) == PREFIX_MAP_VERSION_DSDB) {
653		return false;
654	}
655
656	return true;
657}
658
659/*
660  canonicalise a prefixMap
661*/
662static int ldif_canonicalise_prefixMap(struct ldb_context *ldb, void *mem_ctx,
663				       const struct ldb_val *in, struct ldb_val *out)
664{
665	if (ldif_comparision_prefixMap_isString(in)) {
666		return ldif_read_prefixMap(ldb, mem_ctx, in, out);
667	}
668	return ldb_handler_copy(ldb, mem_ctx, in, out);
669}
670
671static int ldif_comparison_prefixMap(struct ldb_context *ldb, void *mem_ctx,
672				     const struct ldb_val *v1,
673				     const struct ldb_val *v2)
674{
675
676	int ret, ret1, ret2;
677	struct ldb_val v1_canon, v2_canon;
678	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
679
680	/* I could try and bail if tmp_ctx was NULL, but what return
681	 * value would I use?
682	 *
683	 * It seems easier to continue on the NULL context
684	 */
685	ret1 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v1, &v1_canon);
686	ret2 = ldif_canonicalise_prefixMap(ldb, tmp_ctx, v2, &v2_canon);
687
688	if (ret1 == LDB_SUCCESS && ret2 == LDB_SUCCESS) {
689		ret = data_blob_cmp(&v1_canon, &v2_canon);
690	} else {
691		ret = data_blob_cmp(v1, v2);
692	}
693	talloc_free(tmp_ctx);
694	return ret;
695}
696
697/* Canonicalisation of two 32-bit integers */
698static int ldif_canonicalise_int32(struct ldb_context *ldb, void *mem_ctx,
699			const struct ldb_val *in, struct ldb_val *out)
700{
701	char *end;
702	/* We've to use "strtoll" here to have the intended overflows.
703	 * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
704	int32_t i = (int32_t) strtoll((char *)in->data, &end, 0);
705	if (*end != 0) {
706		return -1;
707	}
708	out->data = (uint8_t *) talloc_asprintf(mem_ctx, "%d", i);
709	if (out->data == NULL) {
710		return -1;
711	}
712	out->length = strlen((char *)out->data);
713	return 0;
714}
715
716/* Comparison of two 32-bit integers */
717static int ldif_comparison_int32(struct ldb_context *ldb, void *mem_ctx,
718			const struct ldb_val *v1, const struct ldb_val *v2)
719{
720	/* We've to use "strtoll" here to have the intended overflows.
721	 * Otherwise we may get "LONG_MAX" and the conversion is wrong. */
722	return (int32_t) strtoll((char *)v1->data, NULL, 0)
723	 - (int32_t) strtoll((char *)v2->data, NULL, 0);
724}
725
726/*
727  convert a NDR formatted blob to a ldif formatted repsFromTo
728*/
729static int ldif_write_repsFromTo(struct ldb_context *ldb, void *mem_ctx,
730				 const struct ldb_val *in, struct ldb_val *out)
731{
732	return ldif_write_NDR(ldb, mem_ctx, in, out,
733			      sizeof(struct repsFromToBlob),
734			      (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob,
735			      (ndr_print_fn_t)ndr_print_repsFromToBlob);
736}
737
738/*
739  convert a NDR formatted blob to a ldif formatted replPropertyMetaData
740*/
741static int ldif_write_replPropertyMetaData(struct ldb_context *ldb, void *mem_ctx,
742					   const struct ldb_val *in, struct ldb_val *out)
743{
744	return ldif_write_NDR(ldb, mem_ctx, in, out,
745			      sizeof(struct replPropertyMetaDataBlob),
746			      (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob,
747			      (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob);
748}
749
750/*
751  convert a NDR formatted blob to a ldif formatted replUpToDateVector
752*/
753static int ldif_write_replUpToDateVector(struct ldb_context *ldb, void *mem_ctx,
754					 const struct ldb_val *in, struct ldb_val *out)
755{
756	return ldif_write_NDR(ldb, mem_ctx, in, out,
757			      sizeof(struct replUpToDateVectorBlob),
758			      (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob,
759			      (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob);
760}
761
762
763static int extended_dn_write_hex(struct ldb_context *ldb, void *mem_ctx,
764				 const struct ldb_val *in, struct ldb_val *out)
765{
766	*out = data_blob_string_const(data_blob_hex_string(mem_ctx, in));
767	if (!out->data) {
768		return -1;
769	}
770	return 0;
771}
772
773static const struct ldb_schema_syntax samba_syntaxes[] = {
774	{
775		.name		  = LDB_SYNTAX_SAMBA_SID,
776		.ldif_read_fn	  = ldif_read_objectSid,
777		.ldif_write_fn	  = ldif_write_objectSid,
778		.canonicalise_fn  = ldif_canonicalise_objectSid,
779		.comparison_fn	  = ldif_comparison_objectSid
780	},{
781		.name		  = LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR,
782		.ldif_read_fn	  = ldif_read_ntSecurityDescriptor,
783		.ldif_write_fn	  = ldif_write_ntSecurityDescriptor,
784		.canonicalise_fn  = ldb_handler_copy,
785		.comparison_fn	  = ldb_comparison_binary
786	},{
787		.name		  = LDB_SYNTAX_SAMBA_GUID,
788		.ldif_read_fn	  = ldif_read_objectGUID,
789		.ldif_write_fn	  = ldif_write_objectGUID,
790		.canonicalise_fn  = ldif_canonicalise_objectGUID,
791		.comparison_fn	  = ldif_comparison_objectGUID
792	},{
793		.name		  = LDB_SYNTAX_SAMBA_OBJECT_CATEGORY,
794		.ldif_read_fn	  = ldb_handler_copy,
795		.ldif_write_fn	  = ldb_handler_copy,
796		.canonicalise_fn  = ldif_canonicalise_objectCategory,
797		.comparison_fn	  = ldif_comparison_objectCategory
798	},{
799		.name		  = LDB_SYNTAX_SAMBA_PREFIX_MAP,
800		.ldif_read_fn	  = ldif_read_prefixMap,
801		.ldif_write_fn	  = ldif_write_prefixMap,
802		.canonicalise_fn  = ldif_canonicalise_prefixMap,
803		.comparison_fn	  = ldif_comparison_prefixMap
804	},{
805		.name		  = LDB_SYNTAX_SAMBA_INT32,
806		.ldif_read_fn	  = ldb_handler_copy,
807		.ldif_write_fn	  = ldb_handler_copy,
808		.canonicalise_fn  = ldif_canonicalise_int32,
809		.comparison_fn	  = ldif_comparison_int32
810	},{
811		.name		  = LDB_SYNTAX_SAMBA_REPSFROMTO,
812		.ldif_read_fn	  = ldb_handler_copy,
813		.ldif_write_fn	  = ldif_write_repsFromTo,
814		.canonicalise_fn  = ldb_handler_copy,
815		.comparison_fn	  = ldb_comparison_binary
816	},{
817		.name		  = LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA,
818		.ldif_read_fn	  = ldb_handler_copy,
819		.ldif_write_fn	  = ldif_write_replPropertyMetaData,
820		.canonicalise_fn  = ldb_handler_copy,
821		.comparison_fn	  = ldb_comparison_binary
822	},{
823		.name		  = LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR,
824		.ldif_read_fn	  = ldb_handler_copy,
825		.ldif_write_fn	  = ldif_write_replUpToDateVector,
826		.canonicalise_fn  = ldb_handler_copy,
827		.comparison_fn	  = ldb_comparison_binary
828	},
829};
830
831static const struct ldb_dn_extended_syntax samba_dn_syntax[] = {
832	{
833		.name		  = "SID",
834		.read_fn          = extended_dn_read_SID,
835		.write_clear_fn   = ldif_write_objectSid,
836		.write_hex_fn     = extended_dn_write_hex
837	},{
838		.name		  = "GUID",
839		.read_fn          = extended_dn_read_GUID,
840		.write_clear_fn   = ldif_write_objectGUID,
841		.write_hex_fn     = extended_dn_write_hex
842	},{
843		.name		  = "WKGUID",
844		.read_fn          = ldb_handler_copy,
845		.write_clear_fn   = ldb_handler_copy,
846		.write_hex_fn     = ldb_handler_copy
847	}
848};
849
850/* TODO: Should be dynamic at some point */
851static const struct {
852	const char *name;
853	const char *syntax;
854} samba_attributes[] = {
855	{ "objectSid",			LDB_SYNTAX_SAMBA_SID },
856	{ "securityIdentifier", 	LDB_SYNTAX_SAMBA_SID },
857	{ "ntSecurityDescriptor",	LDB_SYNTAX_SAMBA_SECURITY_DESCRIPTOR },
858	{ "objectGUID",			LDB_SYNTAX_SAMBA_GUID },
859	{ "invocationId",		LDB_SYNTAX_SAMBA_GUID },
860	{ "schemaIDGUID",		LDB_SYNTAX_SAMBA_GUID },
861	{ "attributeSecurityGUID",	LDB_SYNTAX_SAMBA_GUID },
862	{ "parentGUID",			LDB_SYNTAX_SAMBA_GUID },
863	{ "siteGUID",			LDB_SYNTAX_SAMBA_GUID },
864	{ "pKTGUID",			LDB_SYNTAX_SAMBA_GUID },
865	{ "fRSVersionGUID",		LDB_SYNTAX_SAMBA_GUID },
866	{ "fRSReplicaSetGUID",		LDB_SYNTAX_SAMBA_GUID },
867	{ "netbootGUID",		LDB_SYNTAX_SAMBA_GUID },
868	{ "objectCategory",		LDB_SYNTAX_SAMBA_OBJECT_CATEGORY },
869	{ "prefixMap",                  LDB_SYNTAX_SAMBA_PREFIX_MAP },
870	{ "repsFrom",                   LDB_SYNTAX_SAMBA_REPSFROMTO },
871	{ "repsTo",                     LDB_SYNTAX_SAMBA_REPSFROMTO },
872	{ "replPropertyMetaData",       LDB_SYNTAX_SAMBA_REPLPROPERTYMETADATA },
873	{ "replUpToDateVector",         LDB_SYNTAX_SAMBA_REPLUPTODATEVECTOR },
874};
875
876const struct ldb_schema_syntax *ldb_samba_syntax_by_name(struct ldb_context *ldb, const char *name)
877{
878	uint32_t j;
879	const struct ldb_schema_syntax *s = NULL;
880
881	for (j=0; j < ARRAY_SIZE(samba_syntaxes); j++) {
882		if (strcmp(name, samba_syntaxes[j].name) == 0) {
883			s = &samba_syntaxes[j];
884			break;
885		}
886	}
887	return s;
888}
889
890const struct ldb_schema_syntax *ldb_samba_syntax_by_lDAPDisplayName(struct ldb_context *ldb, const char *name)
891{
892	uint32_t j;
893	const struct ldb_schema_syntax *s = NULL;
894
895	for (j=0; j < ARRAY_SIZE(samba_attributes); j++) {
896		if (strcmp(samba_attributes[j].name, name) == 0) {
897			s = ldb_samba_syntax_by_name(ldb, samba_attributes[j].syntax);
898			break;
899		}
900	}
901
902	return s;
903}
904
905/*
906  register the samba ldif handlers
907*/
908int ldb_register_samba_handlers(struct ldb_context *ldb)
909{
910	uint32_t i;
911
912	for (i=0; i < ARRAY_SIZE(samba_attributes); i++) {
913		int ret;
914		const struct ldb_schema_syntax *s = NULL;
915
916		s = ldb_samba_syntax_by_name(ldb, samba_attributes[i].syntax);
917
918		if (!s) {
919			s = ldb_standard_syntax_by_name(ldb, samba_attributes[i].syntax);
920		}
921
922		if (!s) {
923			return -1;
924		}
925
926		ret = ldb_schema_attribute_add_with_syntax(ldb, samba_attributes[i].name, LDB_ATTR_FLAG_FIXED, s);
927		if (ret != LDB_SUCCESS) {
928			return ret;
929		}
930	}
931
932	for (i=0; i < ARRAY_SIZE(samba_dn_syntax); i++) {
933		int ret;
934		ret = ldb_dn_extended_add_syntax(ldb, LDB_ATTR_FLAG_FIXED, &samba_dn_syntax[i]);
935		if (ret != LDB_SUCCESS) {
936			return ret;
937		}
938
939
940	}
941
942	return LDB_SUCCESS;
943}
944