1/*	$NetBSD: schema_prep.c,v 1.3 2021/08/14 16:14:58 christos Exp $	*/
2
3/* schema_prep.c - load builtin schema */
4/* $OpenLDAP$ */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1998-2021 The OpenLDAP Foundation.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted only as authorized by the OpenLDAP
12 * Public License.
13 *
14 * A copy of this license is available in the file LICENSE in the
15 * top-level directory of the distribution or, alternatively, at
16 * <http://www.OpenLDAP.org/license.html>.
17 */
18
19#include <sys/cdefs.h>
20__RCSID("$NetBSD: schema_prep.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
21
22#include "portable.h"
23
24#include <stdio.h>
25
26#include <ac/ctype.h>
27#include <ac/string.h>
28#include <ac/socket.h>
29
30#include "slap.h"
31
32#define OCDEBUG 0
33
34int schema_init_done = 0;
35
36struct slap_internal_schema slap_schema;
37
38static int
39oidValidate(
40	Syntax *syntax,
41	struct berval *in )
42{
43	struct berval val = *in;
44
45	if( val.bv_len == 0 ) {
46		/* disallow empty strings */
47		return LDAP_INVALID_SYNTAX;
48	}
49
50	if( DESC_LEADCHAR( val.bv_val[0] ) ) {
51		val.bv_val++;
52		val.bv_len--;
53		if ( val.bv_len == 0 ) return LDAP_SUCCESS;
54
55		while( DESC_CHAR( val.bv_val[0] ) ) {
56			val.bv_val++;
57			val.bv_len--;
58
59			if ( val.bv_len == 0 ) return LDAP_SUCCESS;
60		}
61
62	} else {
63		int sep = 0;
64		while( OID_LEADCHAR( val.bv_val[0] ) ) {
65			val.bv_val++;
66			val.bv_len--;
67
68			if ( val.bv_val[-1] != '0' ) {
69				while ( OID_LEADCHAR( val.bv_val[0] )) {
70					val.bv_val++;
71					val.bv_len--;
72				}
73			}
74
75			if( val.bv_len == 0 ) {
76				if( sep == 0 ) break;
77				return LDAP_SUCCESS;
78			}
79
80			if( !OID_SEPARATOR( val.bv_val[0] )) break;
81
82			sep++;
83			val.bv_val++;
84			val.bv_len--;
85		}
86	}
87
88	return LDAP_INVALID_SYNTAX;
89}
90
91
92static int objectClassPretty(
93	Syntax *syntax,
94	struct berval *in,
95	struct berval *out,
96	void *ctx )
97{
98	ObjectClass *oc;
99
100	if( oidValidate( NULL, in )) return LDAP_INVALID_SYNTAX;
101
102	oc = oc_bvfind( in );
103	if( oc == NULL ) return LDAP_INVALID_SYNTAX;
104
105	ber_dupbv_x( out, &oc->soc_cname, ctx );
106	return LDAP_SUCCESS;
107}
108
109static int
110attributeTypeMatch(
111	int *matchp,
112	slap_mask_t flags,
113	Syntax *syntax,
114	MatchingRule *mr,
115	struct berval *value,
116	void *assertedValue )
117{
118	struct berval *a = (struct berval *) assertedValue;
119	AttributeType *at = at_bvfind( value );
120	AttributeType *asserted = at_bvfind( a );
121
122	if( asserted == NULL ) {
123		if( OID_LEADCHAR( *a->bv_val ) ) {
124			/* OID form, return FALSE */
125			*matchp = 1;
126			return LDAP_SUCCESS;
127		}
128
129		/* desc form, return undefined */
130		return LDAP_INVALID_SYNTAX;
131	}
132
133	if ( at == NULL ) {
134		/* unrecognized stored value */
135		return LDAP_INVALID_SYNTAX;
136	}
137
138	*matchp = ( asserted != at );
139	return LDAP_SUCCESS;
140}
141
142static int
143matchingRuleMatch(
144	int *matchp,
145	slap_mask_t flags,
146	Syntax *syntax,
147	MatchingRule *mr,
148	struct berval *value,
149	void *assertedValue )
150{
151	struct berval *a = (struct berval *) assertedValue;
152	MatchingRule *mrv = mr_bvfind( value );
153	MatchingRule *asserted = mr_bvfind( a );
154
155	if( asserted == NULL ) {
156		if( OID_LEADCHAR( *a->bv_val ) ) {
157			/* OID form, return FALSE */
158			*matchp = 1;
159			return LDAP_SUCCESS;
160		}
161
162		/* desc form, return undefined */
163		return LDAP_INVALID_SYNTAX;
164	}
165
166	if ( mrv == NULL ) {
167		/* unrecognized stored value */
168		return LDAP_INVALID_SYNTAX;
169	}
170
171	*matchp = ( asserted != mrv );
172	return LDAP_SUCCESS;
173}
174
175static int
176objectClassMatch(
177	int *matchp,
178	slap_mask_t flags,
179	Syntax *syntax,
180	MatchingRule *mr,
181	struct berval *value,
182	void *assertedValue )
183{
184	struct berval *a = (struct berval *) assertedValue;
185	ObjectClass *oc = oc_bvfind( value );
186	ObjectClass *asserted = oc_bvfind( a );
187
188	if( asserted == NULL ) {
189		if( OID_LEADCHAR( *a->bv_val ) ) {
190			/* OID form, return FALSE */
191			*matchp = 1;
192			return LDAP_SUCCESS;
193		}
194
195		/* desc form, return undefined */
196		return LDAP_INVALID_SYNTAX;
197	}
198
199	if ( oc == NULL ) {
200		/* unrecognized stored value */
201		return LDAP_INVALID_SYNTAX;
202	}
203
204	*matchp = ( asserted != oc );
205	return LDAP_SUCCESS;
206}
207
208static int
209objectSubClassMatch(
210	int *matchp,
211	slap_mask_t flags,
212	Syntax *syntax,
213	MatchingRule *mr,
214	struct berval *value,
215	void *assertedValue )
216{
217	struct berval *a = (struct berval *) assertedValue;
218	ObjectClass *oc = oc_bvfind( value );
219	ObjectClass *asserted = oc_bvfind( a );
220
221	if( asserted == NULL ) {
222		if( OID_LEADCHAR( *a->bv_val ) ) {
223			/* OID form, return FALSE */
224			*matchp = 1;
225			return LDAP_SUCCESS;
226		}
227
228		/* desc form, return undefined */
229		return LDAP_INVALID_SYNTAX;
230	}
231
232	if ( oc == NULL ) {
233		/* unrecognized stored value */
234		return LDAP_INVALID_SYNTAX;
235	}
236
237	if( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX( flags ) ) {
238		*matchp = ( asserted != oc );
239	} else {
240		*matchp = !is_object_subclass( asserted, oc );
241	}
242
243	return LDAP_SUCCESS;
244}
245
246static int objectSubClassIndexer(
247	slap_mask_t use,
248	slap_mask_t mask,
249	Syntax *syntax,
250	MatchingRule *mr,
251	struct berval *prefix,
252	BerVarray values,
253	BerVarray *keysp,
254	void *ctx )
255{
256	int rc, noc, i;
257	BerVarray ocvalues;
258	ObjectClass **socs;
259
260	for( noc=0; values[noc].bv_val != NULL; noc++ ) {
261		/* just count em */;
262	}
263
264	/* over allocate */
265	socs = slap_sl_malloc( (noc+16) * sizeof( ObjectClass * ), ctx );
266
267	/* initialize */
268	for( i=0; i<noc; i++ ) {
269		socs[i] = oc_bvfind( &values[i] );
270	}
271
272	/* expand values */
273	for( i=0; i<noc; i++ ) {
274		int j;
275		ObjectClass *oc = socs[i];
276		if( oc == NULL || oc->soc_sups == NULL ) continue;
277
278		for( j=0; oc->soc_sups[j] != NULL; j++ ) {
279			int found = 0;
280			ObjectClass *sup = oc->soc_sups[j];
281			int k;
282
283			for( k=0; k<noc; k++ ) {
284				if( sup == socs[k] ) {
285					found++;
286					break;
287				}
288			}
289
290			if( !found ) {
291				socs = slap_sl_realloc( socs,
292					sizeof( ObjectClass * ) * (noc+2), ctx );
293
294				assert( k == noc );
295				socs[noc++] = sup;
296			}
297		}
298	}
299
300	ocvalues = slap_sl_malloc( sizeof( struct berval ) * (noc+1), ctx );
301	/* copy values */
302	for( i=0; i<noc; i++ ) {
303		if ( socs[i] )
304			ocvalues[i] = socs[i]->soc_cname;
305		else
306			ocvalues[i] = values[i];
307	}
308	BER_BVZERO( &ocvalues[i] );
309
310	rc = octetStringIndexer( use, mask, syntax, mr,
311		prefix, ocvalues, keysp, ctx );
312
313	slap_sl_free( ocvalues, ctx );
314	slap_sl_free( socs, ctx );
315	return rc;
316}
317
318#define objectSubClassFilter octetStringFilter
319
320static ObjectClassSchemaCheckFN rootDseObjectClass;
321static ObjectClassSchemaCheckFN aliasObjectClass;
322static ObjectClassSchemaCheckFN referralObjectClass;
323static ObjectClassSchemaCheckFN subentryObjectClass;
324#ifdef LDAP_DYNAMIC_OBJECTS
325static ObjectClassSchemaCheckFN dynamicObjectClass;
326#endif
327
328static struct slap_schema_oc_map {
329	char *ssom_name;
330	char *ssom_defn;
331	ObjectClassSchemaCheckFN *ssom_check;
332	slap_mask_t ssom_flags;
333	size_t ssom_offset;
334} oc_map[] = {
335	{ "top", "( 2.5.6.0 NAME 'top' "
336			"DESC 'top of the superclass chain' "
337			"ABSTRACT MUST objectClass )",
338		0, 0, offsetof(struct slap_internal_schema, si_oc_top) },
339	{ "extensibleObject", "( 1.3.6.1.4.1.1466.101.120.111 "
340			"NAME 'extensibleObject' "
341			"DESC 'RFC4512: extensible object' "
342			"SUP top AUXILIARY )",
343		0, SLAP_OC_OPERATIONAL,
344		offsetof(struct slap_internal_schema, si_oc_extensibleObject) },
345	{ "alias", "( 2.5.6.1 NAME 'alias' "
346			"DESC 'RFC4512: an alias' "
347			"SUP top STRUCTURAL "
348			"MUST aliasedObjectName )",
349		aliasObjectClass, SLAP_OC_ALIAS|SLAP_OC_OPERATIONAL,
350		offsetof(struct slap_internal_schema, si_oc_alias) },
351	{ "referral", "( 2.16.840.1.113730.3.2.6 NAME 'referral' "
352			"DESC 'namedref: named subordinate referral' "
353			"SUP top STRUCTURAL MUST ref )",
354		referralObjectClass, SLAP_OC_REFERRAL|SLAP_OC_OPERATIONAL,
355		offsetof(struct slap_internal_schema, si_oc_referral) },
356	{ "LDAProotDSE", "( 1.3.6.1.4.1.4203.1.4.1 "
357			"NAME ( 'OpenLDAProotDSE' 'LDAProotDSE' ) "
358			"DESC 'OpenLDAP Root DSE object' "
359			"SUP top STRUCTURAL MAY cn )",
360		rootDseObjectClass, SLAP_OC_OPERATIONAL,
361		offsetof(struct slap_internal_schema, si_oc_rootdse) },
362	{ "subentry", "( 2.5.17.0 NAME 'subentry' "
363			"DESC 'RFC3672: subentry' "
364			"SUP top STRUCTURAL "
365			"MUST ( cn $ subtreeSpecification ) )",
366		subentryObjectClass, SLAP_OC_SUBENTRY|SLAP_OC_OPERATIONAL,
367		offsetof(struct slap_internal_schema, si_oc_subentry) },
368	{ "subschema", "( 2.5.20.1 NAME 'subschema' "
369		"DESC 'RFC4512: controlling subschema (sub)entry' "
370		"AUXILIARY "
371		"MAY ( dITStructureRules $ nameForms $ dITContentRules $ "
372			"objectClasses $ attributeTypes $ matchingRules $ "
373			"matchingRuleUse ) )",
374		subentryObjectClass, SLAP_OC_OPERATIONAL,
375		offsetof(struct slap_internal_schema, si_oc_subschema) },
376#ifdef LDAP_COLLECTIVE_ATTRIBUTES
377	{ "collectiveAttributeSubentry", "( 2.5.17.2 "
378			"NAME 'collectiveAttributeSubentry' "
379			"DESC 'RFC3671: collective attribute subentry' "
380			"AUXILIARY )",
381		subentryObjectClass,
382		SLAP_OC_COLLECTIVEATTRIBUTESUBENTRY|SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
383		offsetof( struct slap_internal_schema,
384			si_oc_collectiveAttributeSubentry) },
385#endif
386#ifdef LDAP_DYNAMIC_OBJECTS
387	{ "dynamicObject", "( 1.3.6.1.4.1.1466.101.119.2 "
388			"NAME 'dynamicObject' "
389			"DESC 'RFC2589: Dynamic Object' "
390			"SUP top AUXILIARY )",
391		dynamicObjectClass, SLAP_OC_DYNAMICOBJECT,
392		offsetof(struct slap_internal_schema, si_oc_dynamicObject) },
393#endif
394	{ "glue", "( 1.3.6.1.4.1.4203.666.3.4 "
395			"NAME 'glue' "
396			"DESC 'Glue Entry' "
397			"SUP top STRUCTURAL )",
398		0, SLAP_OC_GLUE|SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
399		offsetof(struct slap_internal_schema, si_oc_glue) },
400	{ "syncConsumerSubentry", "( 1.3.6.1.4.1.4203.666.3.5 "
401			"NAME 'syncConsumerSubentry' "
402			"DESC 'Persistent Info for SyncRepl Consumer' "
403			"AUXILIARY "
404			"MAY syncreplCookie )",
405		0, SLAP_OC_SYNCCONSUMERSUBENTRY|SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
406		offsetof(struct slap_internal_schema, si_oc_syncConsumerSubentry) },
407	{ "syncProviderSubentry", "( 1.3.6.1.4.1.4203.666.3.6 "
408			"NAME 'syncProviderSubentry' "
409			"DESC 'Persistent Info for SyncRepl Producer' "
410			"AUXILIARY "
411			"MAY contextCSN )",
412		0, SLAP_OC_SYNCPROVIDERSUBENTRY|SLAP_OC_OPERATIONAL|SLAP_OC_HIDE,
413		offsetof(struct slap_internal_schema, si_oc_syncProviderSubentry) },
414
415	{ NULL, NULL, NULL, 0, 0 }
416};
417
418static AttributeTypeSchemaCheckFN rootDseAttribute;
419static AttributeTypeSchemaCheckFN aliasAttribute;
420static AttributeTypeSchemaCheckFN referralAttribute;
421static AttributeTypeSchemaCheckFN subentryAttribute;
422static AttributeTypeSchemaCheckFN administrativeRoleAttribute;
423#ifdef LDAP_DYNAMIC_OBJECTS
424static AttributeTypeSchemaCheckFN dynamicAttribute;
425#endif
426
427static struct slap_schema_ad_map {
428	char *ssam_name;
429	char *ssam_defn;
430	AttributeTypeSchemaCheckFN *ssam_check;
431	slap_mask_t ssam_flags;
432	slap_syntax_validate_func *ssam_syn_validate;
433	slap_syntax_transform_func *ssam_syn_pretty;
434	slap_mr_convert_func *ssam_mr_convert;
435	slap_mr_normalize_func *ssam_mr_normalize;
436	slap_mr_match_func *ssam_mr_match;
437	slap_mr_indexer_func *ssam_mr_indexer;
438	slap_mr_filter_func *ssam_mr_filter;
439	size_t ssam_offset;
440} ad_map[] = {
441	{ "objectClass", "( 2.5.4.0 NAME 'objectClass' "
442			"DESC 'RFC4512: object classes of the entity' "
443			"EQUALITY objectIdentifierMatch "
444			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
445		NULL, SLAP_AT_FINAL,
446		oidValidate, objectClassPretty,
447		NULL, NULL, objectSubClassMatch,
448			objectSubClassIndexer, objectSubClassFilter,
449		offsetof(struct slap_internal_schema, si_ad_objectClass) },
450
451	/* user entry operational attributes */
452	{ "structuralObjectClass", "( 2.5.21.9 NAME 'structuralObjectClass' "
453			"DESC 'RFC4512: structural object class of entry' "
454			"EQUALITY objectIdentifierMatch "
455			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
456			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
457		NULL, 0,
458		oidValidate, objectClassPretty,
459		NULL, NULL, objectSubClassMatch,
460			objectSubClassIndexer, objectSubClassFilter,
461		offsetof(struct slap_internal_schema, si_ad_structuralObjectClass) },
462	{ "createTimestamp", "( 2.5.18.1 NAME 'createTimestamp' "
463			"DESC 'RFC4512: time which object was created' "
464			"EQUALITY generalizedTimeMatch "
465			"ORDERING generalizedTimeOrderingMatch "
466			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
467			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
468		NULL, SLAP_AT_MANAGEABLE,
469		NULL, NULL,
470		NULL, NULL, NULL, NULL, NULL,
471		offsetof(struct slap_internal_schema, si_ad_createTimestamp) },
472	{ "modifyTimestamp", "( 2.5.18.2 NAME 'modifyTimestamp' "
473			"DESC 'RFC4512: time which object was last modified' "
474			"EQUALITY generalizedTimeMatch "
475			"ORDERING generalizedTimeOrderingMatch "
476			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
477			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
478		NULL, SLAP_AT_MANAGEABLE,
479		NULL, NULL,
480		NULL, NULL, NULL, NULL, NULL,
481		offsetof(struct slap_internal_schema, si_ad_modifyTimestamp) },
482	{ "creatorsName", "( 2.5.18.3 NAME 'creatorsName' "
483			"DESC 'RFC4512: name of creator' "
484			"EQUALITY distinguishedNameMatch "
485			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
486			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
487		NULL, SLAP_AT_MANAGEABLE,
488		NULL, NULL,
489		NULL, NULL, NULL, NULL, NULL,
490		offsetof(struct slap_internal_schema, si_ad_creatorsName) },
491	{ "modifiersName", "( 2.5.18.4 NAME 'modifiersName' "
492			"DESC 'RFC4512: name of last modifier' "
493			"EQUALITY distinguishedNameMatch "
494			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
495			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
496		NULL, SLAP_AT_MANAGEABLE,
497		NULL, NULL,
498		NULL, NULL, NULL, NULL, NULL,
499		offsetof(struct slap_internal_schema, si_ad_modifiersName) },
500	{ "hasSubordinates", "( 2.5.18.9 NAME 'hasSubordinates' "
501			"DESC 'X.501: entry has children' "
502			"EQUALITY booleanMatch "
503			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
504			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
505		NULL, SLAP_AT_DYNAMIC,
506		NULL, NULL,
507		NULL, NULL, NULL, NULL, NULL,
508		offsetof(struct slap_internal_schema, si_ad_hasSubordinates) },
509	{ "subschemaSubentry", "( 2.5.18.10 NAME 'subschemaSubentry' "
510			"DESC 'RFC4512: name of controlling subschema entry' "
511			"EQUALITY distinguishedNameMatch "
512			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE "
513			"NO-USER-MODIFICATION USAGE directoryOperation )",
514		NULL, SLAP_AT_DYNAMIC,
515		NULL, NULL,
516		NULL, NULL, NULL, NULL, NULL,
517		offsetof(struct slap_internal_schema, si_ad_subschemaSubentry) },
518#ifdef LDAP_COLLECTIVE_ATTRIBUTES
519	{ "collectiveAttributeSubentries", "( 2.5.18.12 "
520			"NAME 'collectiveAttributeSubentries' "
521			"DESC 'RFC3671: collective attribute subentries' "
522			"EQUALITY distinguishedNameMatch "
523			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
524			"NO-USER-MODIFICATION USAGE directoryOperation )",
525		NULL, SLAP_AT_HIDE,
526		NULL, NULL,
527		NULL, NULL, NULL, NULL, NULL,
528		offsetof(struct slap_internal_schema, si_ad_collectiveSubentries) },
529	{ "collectiveExclusions", "( 2.5.18.7 NAME 'collectiveExclusions' "
530			"DESC 'RFC3671: collective attribute exclusions' "
531			"EQUALITY objectIdentifierMatch "
532			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
533			"USAGE directoryOperation )",
534		NULL, SLAP_AT_HIDE,
535		NULL, NULL,
536		NULL, NULL, NULL, NULL, NULL,
537		offsetof(struct slap_internal_schema, si_ad_collectiveExclusions) },
538#endif
539
540	{ "entryDN", "( 1.3.6.1.1.20 NAME 'entryDN' "
541			"DESC 'DN of the entry' "
542			"EQUALITY distinguishedNameMatch "
543			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
544			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
545		NULL, SLAP_AT_DYNAMIC,
546		NULL, NULL,
547		NULL, NULL, NULL, NULL, NULL,
548		offsetof(struct slap_internal_schema, si_ad_entryDN) },
549	{ "entryUUID", "( 1.3.6.1.1.16.4 NAME 'entryUUID' "
550			"DESC 'UUID of the entry' "
551			"EQUALITY UUIDMatch "
552			"ORDERING UUIDOrderingMatch "
553			"SYNTAX 1.3.6.1.1.16.1 "
554			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
555		NULL, SLAP_AT_MANAGEABLE,
556		NULL, NULL,
557		NULL, NULL, NULL, NULL, NULL,
558		offsetof(struct slap_internal_schema, si_ad_entryUUID) },
559	{ "entryCSN", "( 1.3.6.1.4.1.4203.666.1.7 NAME 'entryCSN' "
560			"DESC 'change sequence number of the entry content' "
561			"EQUALITY CSNMatch "
562			"ORDERING CSNOrderingMatch "
563			"SYNTAX 1.3.6.1.4.1.4203.666.11.2.1{64} "
564			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
565		NULL, 0,
566		NULL, NULL,
567		NULL, NULL, NULL, NULL, NULL,
568		offsetof(struct slap_internal_schema, si_ad_entryCSN) },
569	{ "namingCSN", "( 1.3.6.1.4.1.4203.666.1.13 NAME 'namingCSN' "
570			"DESC 'change sequence number of the entry naming (RDN)' "
571			"EQUALITY CSNMatch "
572			"ORDERING CSNOrderingMatch "
573			"SYNTAX 1.3.6.1.4.1.4203.666.11.2.1{64} "
574			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
575		NULL, SLAP_AT_HIDE,
576		NULL, NULL,
577		NULL, NULL, NULL, NULL, NULL,
578		offsetof(struct slap_internal_schema, si_ad_namingCSN) },
579
580#ifdef LDAP_SUPERIOR_UUID
581	{ "superiorUUID", "( 1.3.6.1.4.1.4203.666.1.11 NAME 'superiorUUID' "
582			"DESC 'UUID of the superior entry' "
583			"EQUALITY UUIDMatch "
584			"ORDERING UUIDOrderingMatch "
585			"SYNTAX 1.3.6.1.1.16.1 "
586			"SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )",
587		NULL, SLAP_AT_HIDE,
588		NULL, NULL,
589		NULL, NULL, NULL, NULL, NULL,
590		offsetof(struct slap_internal_schema, si_ad_superiorUUID) },
591#endif
592
593	{ "syncreplCookie", "( 1.3.6.1.4.1.4203.666.1.23 "
594			"NAME 'syncreplCookie' "
595			"DESC 'syncrepl Cookie for shadow copy' "
596			"EQUALITY octetStringMatch "
597			"ORDERING octetStringOrderingMatch "
598			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
599			"SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )",
600		NULL, SLAP_AT_HIDE,
601		NULL, NULL,
602		NULL, NULL, NULL, NULL, NULL,
603		offsetof(struct slap_internal_schema, si_ad_syncreplCookie) },
604
605	{ "contextCSN", "( 1.3.6.1.4.1.4203.666.1.25 "
606			"NAME 'contextCSN' "
607			"DESC 'the largest committed CSN of a context' "
608			"EQUALITY CSNMatch "
609			"ORDERING CSNOrderingMatch "
610			"SYNTAX 1.3.6.1.4.1.4203.666.11.2.1{64} "
611			"NO-USER-MODIFICATION USAGE dSAOperation )",
612		NULL, 0,
613		NULL, NULL,
614		NULL, NULL, NULL, NULL, NULL,
615		offsetof(struct slap_internal_schema, si_ad_contextCSN) },
616
617#ifdef LDAP_SYNC_TIMESTAMP
618	{ "syncTimestamp", "( 1.3.6.1.4.1.4203.666.1.26 NAME 'syncTimestamp' "
619			"DESC 'Time which object was replicated' "
620			"EQUALITY generalizedTimeMatch "
621			"ORDERING generalizedTimeOrderingMatch "
622			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
623			"SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )",
624		NULL, 0,
625		NULL, NULL,
626		NULL, NULL, NULL, NULL, NULL,
627		offsetof(struct slap_internal_schema, si_ad_syncTimestamp) },
628#endif
629
630	/* root DSE attributes */
631	{ "altServer", "( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer' "
632			"DESC 'RFC4512: alternative servers' "
633			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 USAGE dSAOperation )",
634		rootDseAttribute, 0,
635		NULL, NULL,
636		NULL, NULL, NULL, NULL, NULL,
637		offsetof(struct slap_internal_schema, si_ad_altServer) },
638	{ "namingContexts", "( 1.3.6.1.4.1.1466.101.120.5 "
639			"NAME 'namingContexts' "
640			"DESC 'RFC4512: naming contexts' "
641			"EQUALITY distinguishedNameMatch "
642			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation )",
643		rootDseAttribute, 0,
644		NULL, NULL,
645		NULL, NULL, NULL, NULL, NULL,
646		offsetof(struct slap_internal_schema, si_ad_namingContexts) },
647	{ "supportedControl", "( 1.3.6.1.4.1.1466.101.120.13 "
648			"NAME 'supportedControl' "
649			"DESC 'RFC4512: supported controls' "
650			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )",
651		rootDseAttribute, 0,
652		NULL, NULL,
653		NULL, NULL, NULL, NULL, NULL,
654		offsetof(struct slap_internal_schema, si_ad_supportedControl) },
655	{ "supportedExtension", "( 1.3.6.1.4.1.1466.101.120.7 "
656			"NAME 'supportedExtension' "
657			"DESC 'RFC4512: supported extended operations' "
658			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )",
659		rootDseAttribute, 0,
660		NULL, NULL,
661		NULL, NULL, NULL, NULL, NULL,
662		offsetof(struct slap_internal_schema, si_ad_supportedExtension) },
663	{ "supportedLDAPVersion", "( 1.3.6.1.4.1.1466.101.120.15 "
664			"NAME 'supportedLDAPVersion' "
665			"DESC 'RFC4512: supported LDAP versions' "
666			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAGE dSAOperation )",
667		rootDseAttribute, 0,
668		NULL, NULL,
669		NULL, NULL, NULL, NULL, NULL,
670		offsetof(struct slap_internal_schema, si_ad_supportedLDAPVersion) },
671	{ "supportedSASLMechanisms", "( 1.3.6.1.4.1.1466.101.120.14 "
672			"NAME 'supportedSASLMechanisms' "
673			"DESC 'RFC4512: supported SASL mechanisms'"
674			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE dSAOperation )",
675		rootDseAttribute, 0,
676		NULL, NULL,
677		NULL, NULL, NULL, NULL, NULL,
678		offsetof(struct slap_internal_schema, si_ad_supportedSASLMechanisms) },
679	{ "supportedFeatures", "( 1.3.6.1.4.1.4203.1.3.5 "
680			"NAME 'supportedFeatures' "
681			"DESC 'RFC4512: features supported by the server' "
682			"EQUALITY objectIdentifierMatch "
683			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
684			"USAGE dSAOperation )",
685		rootDseAttribute, 0,
686		NULL, NULL,
687		NULL, NULL, NULL, NULL, NULL,
688		offsetof(struct slap_internal_schema, si_ad_supportedFeatures) },
689	{ "monitorContext", "( 1.3.6.1.4.1.4203.666.1.10 "
690			"NAME 'monitorContext' "
691			"DESC 'monitor context' "
692			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
693			"EQUALITY distinguishedNameMatch "
694			"SINGLE-VALUE NO-USER-MODIFICATION "
695			"USAGE dSAOperation )",
696		rootDseAttribute, SLAP_AT_HIDE,
697		NULL, NULL,
698		NULL, NULL, NULL, NULL, NULL,
699		offsetof(struct slap_internal_schema, si_ad_monitorContext) },
700	{ "configContext", "( 1.3.6.1.4.1.4203.1.12.2.1 "
701			"NAME 'configContext' "
702			"DESC 'config context' "
703			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
704			"EQUALITY distinguishedNameMatch "
705			"SINGLE-VALUE NO-USER-MODIFICATION "
706			"USAGE dSAOperation )",
707		rootDseAttribute, SLAP_AT_HIDE,
708		NULL, NULL,
709		NULL, NULL, NULL, NULL, NULL,
710		offsetof(struct slap_internal_schema, si_ad_configContext) },
711	{ "vendorName", "( 1.3.6.1.1.4 NAME 'vendorName' "
712			"DESC 'RFC3045: name of implementation vendor' "
713			"EQUALITY caseExactMatch "
714			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
715			"SINGLE-VALUE NO-USER-MODIFICATION "
716			"USAGE dSAOperation )",
717		rootDseAttribute, 0,
718		NULL, NULL,
719		NULL, NULL, NULL, NULL, NULL,
720		offsetof(struct slap_internal_schema, si_ad_vendorName) },
721	{ "vendorVersion", "( 1.3.6.1.1.5 NAME 'vendorVersion' "
722			"DESC 'RFC3045: version of implementation' "
723			"EQUALITY caseExactMatch "
724			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
725			"SINGLE-VALUE NO-USER-MODIFICATION "
726			"USAGE dSAOperation )",
727		rootDseAttribute, 0,
728		NULL, NULL,
729		NULL, NULL, NULL, NULL, NULL,
730		offsetof(struct slap_internal_schema, si_ad_vendorVersion) },
731
732	/* subentry attributes */
733	{ "administrativeRole", "( 2.5.18.5 NAME 'administrativeRole' "
734			"DESC 'RFC3672: administrative role' "
735			"EQUALITY objectIdentifierMatch "
736			"USAGE directoryOperation "
737			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
738		administrativeRoleAttribute, SLAP_AT_HIDE,
739		NULL, NULL,
740		NULL, NULL, NULL, NULL, NULL,
741		offsetof(struct slap_internal_schema, si_ad_administrativeRole) },
742	{ "subtreeSpecification", "( 2.5.18.6 NAME 'subtreeSpecification' "
743			"DESC 'RFC3672: subtree specification' "
744			"SINGLE-VALUE "
745			"USAGE directoryOperation "
746			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.45 )",
747		subentryAttribute, SLAP_AT_HIDE,
748		NULL, NULL,
749		NULL, NULL, NULL, NULL, NULL,
750		offsetof(struct slap_internal_schema, si_ad_subtreeSpecification) },
751
752	/* subschema subentry attributes */
753	{ "dITStructureRules", "( 2.5.21.1 NAME 'dITStructureRules' "
754			"DESC 'RFC4512: DIT structure rules' "
755			"EQUALITY integerFirstComponentMatch "
756			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 "
757			"USAGE directoryOperation ) ",
758		subentryAttribute, SLAP_AT_HIDE,
759		NULL, NULL,
760		NULL, NULL, NULL, NULL, NULL,
761		offsetof(struct slap_internal_schema, si_ad_ditStructureRules) },
762	{ "dITContentRules", "( 2.5.21.2 NAME 'dITContentRules' "
763			"DESC 'RFC4512: DIT content rules' "
764			"EQUALITY objectIdentifierFirstComponentMatch "
765			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 USAGE directoryOperation )",
766		subentryAttribute, SLAP_AT_HIDE,
767		oidValidate, NULL,
768		NULL, NULL, objectClassMatch, NULL, NULL,
769		offsetof(struct slap_internal_schema, si_ad_ditContentRules) },
770	{ "matchingRules", "( 2.5.21.4 NAME 'matchingRules' "
771			"DESC 'RFC4512: matching rules' "
772			"EQUALITY objectIdentifierFirstComponentMatch "
773			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.30 USAGE directoryOperation )",
774		subentryAttribute, 0,
775		oidValidate, NULL,
776		NULL, NULL, matchingRuleMatch, NULL, NULL,
777		offsetof(struct slap_internal_schema, si_ad_matchingRules) },
778	{ "attributeTypes", "( 2.5.21.5 NAME 'attributeTypes' "
779			"DESC 'RFC4512: attribute types' "
780			"EQUALITY objectIdentifierFirstComponentMatch "
781			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.3 USAGE directoryOperation )",
782		subentryAttribute, 0,
783		oidValidate, NULL,
784		NULL, NULL, attributeTypeMatch, NULL, NULL,
785		offsetof(struct slap_internal_schema, si_ad_attributeTypes) },
786	{ "objectClasses", "( 2.5.21.6 NAME 'objectClasses' "
787			"DESC 'RFC4512: object classes' "
788			"EQUALITY objectIdentifierFirstComponentMatch "
789			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.37 USAGE directoryOperation )",
790		subentryAttribute, 0,
791		oidValidate, NULL,
792		NULL, NULL, objectClassMatch, NULL, NULL,
793		offsetof(struct slap_internal_schema, si_ad_objectClasses) },
794	{ "nameForms", "( 2.5.21.7 NAME 'nameForms' "
795			"DESC 'RFC4512: name forms ' "
796			"EQUALITY objectIdentifierFirstComponentMatch "
797			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.35 USAGE directoryOperation )",
798		subentryAttribute, SLAP_AT_HIDE,
799		NULL, NULL,
800		NULL, NULL, NULL, NULL, NULL,
801		offsetof(struct slap_internal_schema, si_ad_nameForms) },
802	{ "matchingRuleUse", "( 2.5.21.8 NAME 'matchingRuleUse' "
803			"DESC 'RFC4512: matching rule uses' "
804			"EQUALITY objectIdentifierFirstComponentMatch "
805			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 USAGE directoryOperation )",
806		subentryAttribute, 0,
807		oidValidate, NULL,
808		NULL, NULL, matchingRuleMatch, NULL, NULL,
809		offsetof(struct slap_internal_schema, si_ad_matchingRuleUse) },
810
811	{ "ldapSyntaxes", "( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes' "
812			"DESC 'RFC4512: LDAP syntaxes' "
813			"EQUALITY objectIdentifierFirstComponentMatch "
814			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation )",
815		subentryAttribute, 0,
816		NULL, NULL,
817		NULL, NULL, NULL, NULL, NULL,
818		offsetof(struct slap_internal_schema, si_ad_ldapSyntaxes) },
819
820	/* knowledge information */
821	{ "aliasedObjectName", "( 2.5.4.1 "
822			"NAME ( 'aliasedObjectName' 'aliasedEntryName' ) "
823			"DESC 'RFC4512: name of aliased object' "
824			"EQUALITY distinguishedNameMatch "
825			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )",
826		aliasAttribute, SLAP_AT_FINAL,
827		NULL, NULL,
828		NULL, NULL, NULL, NULL, NULL,
829		offsetof(struct slap_internal_schema, si_ad_aliasedObjectName) },
830	{ "ref", "( 2.16.840.1.113730.3.1.34 NAME 'ref' "
831			"DESC 'RFC3296: subordinate referral URL' "
832			"EQUALITY caseExactMatch "
833			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
834			"USAGE distributedOperation )",
835		referralAttribute, 0,
836		NULL, NULL,
837		NULL, NULL, NULL, NULL, NULL,
838		offsetof(struct slap_internal_schema, si_ad_ref) },
839
840	/* access control internals */
841	{ "entry", "( 1.3.6.1.4.1.4203.1.3.1 "
842			"NAME 'entry' "
843			"DESC 'OpenLDAP ACL entry pseudo-attribute' "
844			"SYNTAX 1.3.6.1.4.1.4203.1.1.1 "
845			"SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )",
846		NULL, SLAP_AT_HIDE,
847		NULL, NULL,
848		NULL, NULL, NULL, NULL, NULL,
849		offsetof(struct slap_internal_schema, si_ad_entry) },
850	{ "children", "( 1.3.6.1.4.1.4203.1.3.2 "
851			"NAME 'children' "
852			"DESC 'OpenLDAP ACL children pseudo-attribute' "
853			"SYNTAX 1.3.6.1.4.1.4203.1.1.1 "
854			"SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )",
855		NULL, SLAP_AT_HIDE,
856		NULL, NULL,
857		NULL, NULL, NULL, NULL, NULL,
858		offsetof(struct slap_internal_schema, si_ad_children) },
859
860	/* access control externals */
861	{ "authzTo", "( 1.3.6.1.4.1.4203.666.1.8 "
862			"NAME ( 'authzTo' 'saslAuthzTo' ) "
863			"DESC 'proxy authorization targets' "
864			"EQUALITY authzMatch "
865			"SYNTAX 1.3.6.1.4.1.4203.666.2.7 "
866			"X-ORDERED 'VALUES' "
867			"USAGE distributedOperation )",
868		NULL, SLAP_AT_HIDE,
869		NULL, NULL,
870		NULL, NULL, NULL, NULL, NULL,
871		offsetof(struct slap_internal_schema, si_ad_saslAuthzTo) },
872	{ "authzFrom", "( 1.3.6.1.4.1.4203.666.1.9 "
873			"NAME ( 'authzFrom' 'saslAuthzFrom' ) "
874			"DESC 'proxy authorization sources' "
875			"EQUALITY authzMatch "
876			"SYNTAX 1.3.6.1.4.1.4203.666.2.7 "
877			"X-ORDERED 'VALUES' "
878			"USAGE distributedOperation )",
879		NULL, SLAP_AT_HIDE,
880		NULL, NULL,
881		NULL, NULL, NULL, NULL, NULL,
882		offsetof(struct slap_internal_schema, si_ad_saslAuthzFrom) },
883
884#ifdef LDAP_DYNAMIC_OBJECTS
885	{ "entryTtl", "( 1.3.6.1.4.1.1466.101.119.3 NAME 'entryTtl' "
886			"DESC 'RFC2589: entry time-to-live' "
887			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE "
888			"NO-USER-MODIFICATION USAGE dSAOperation )",
889		dynamicAttribute, SLAP_AT_MANAGEABLE,
890		NULL, NULL,
891		NULL, NULL, NULL, NULL, NULL,
892		offsetof(struct slap_internal_schema, si_ad_entryTtl) },
893	{ "dynamicSubtrees", "( 1.3.6.1.4.1.1466.101.119.4 "
894			"NAME 'dynamicSubtrees' "
895			"DESC 'RFC2589: dynamic subtrees' "
896			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION "
897			"USAGE dSAOperation )",
898		rootDseAttribute, 0,
899		NULL, NULL,
900		NULL, NULL, NULL, NULL, NULL,
901		offsetof(struct slap_internal_schema, si_ad_dynamicSubtrees) },
902#endif
903
904	/* userApplication attributes (which system schema depends upon) */
905	{ "distinguishedName", "( 2.5.4.49 NAME 'distinguishedName' "
906			"DESC 'RFC4519: common supertype of DN attributes' "
907			"EQUALITY distinguishedNameMatch "
908			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
909		NULL, SLAP_AT_ABSTRACT,
910		NULL, NULL,
911		NULL, NULL, NULL, NULL, NULL,
912		offsetof(struct slap_internal_schema, si_ad_distinguishedName) },
913	{ "name", "( 2.5.4.41 NAME 'name' "
914			"DESC 'RFC4519: common supertype of name attributes' "
915			"EQUALITY caseIgnoreMatch "
916			"SUBSTR caseIgnoreSubstringsMatch "
917			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )",
918		NULL, SLAP_AT_ABSTRACT,
919		NULL, NULL,
920		NULL, NULL, NULL, NULL, NULL,
921		offsetof(struct slap_internal_schema, si_ad_name) },
922	{ "cn", "( 2.5.4.3 NAME ( 'cn' 'commonName' ) "
923			"DESC 'RFC4519: common name(s) for which the entity is known by' "
924			"SUP name )",
925		NULL, 0,
926		NULL, NULL,
927		NULL, NULL, NULL, NULL, NULL,
928		offsetof(struct slap_internal_schema, si_ad_cn) },
929	{ "uid", "( 0.9.2342.19200300.100.1.1 NAME ( 'uid' 'userid' ) "
930			"DESC 'RFC4519: user identifier' "
931			"EQUALITY caseIgnoreMatch "
932			"SUBSTR caseIgnoreSubstringsMatch "
933			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )",
934		NULL, 0,
935		NULL, NULL,
936		NULL, NULL, NULL, NULL, NULL,
937		offsetof(struct slap_internal_schema, si_ad_uid) },
938	{ "uidNumber", /* for ldapi:// */
939		"( 1.3.6.1.1.1.1.0 NAME 'uidNumber' "
940    		"DESC 'RFC2307: An integer uniquely identifying a user "
941				"in an administrative domain' "
942    		"EQUALITY integerMatch "
943    		"ORDERING integerOrderingMatch "
944    		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )",
945		NULL, 0,
946		NULL, NULL,
947		NULL, NULL, NULL, NULL, NULL,
948		offsetof(struct slap_internal_schema, si_ad_uidNumber) },
949	{ "gidNumber", /* for ldapi:// */
950		"( 1.3.6.1.1.1.1.1 NAME 'gidNumber' "
951    		"DESC 'RFC2307: An integer uniquely identifying a group "
952				"in an administrative domain' "
953    		"EQUALITY integerMatch "
954    		"ORDERING integerOrderingMatch "
955    		"SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )",
956		NULL, 0,
957		NULL, NULL,
958		NULL, NULL, NULL, NULL, NULL,
959		offsetof(struct slap_internal_schema, si_ad_gidNumber) },
960	{ "userPassword", "( 2.5.4.35 NAME 'userPassword' "
961			"DESC 'RFC4519/2307: password of user' "
962			"EQUALITY octetStringMatch "
963			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )",
964		NULL, 0,
965		NULL, NULL,
966		NULL, NULL, NULL, NULL, NULL,
967		offsetof(struct slap_internal_schema, si_ad_userPassword) },
968
969	{ "labeledURI", "( 1.3.6.1.4.1.250.1.57 NAME 'labeledURI' "
970			"DESC 'RFC2079: Uniform Resource Identifier with optional label' "
971			"EQUALITY caseExactMatch "
972			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
973		NULL, 0,
974		NULL, NULL,
975		NULL, NULL, NULL, NULL, NULL,
976		offsetof(struct slap_internal_schema, si_ad_labeledURI) },
977
978#ifdef SLAPD_AUTHPASSWD
979	{ "authPassword", "( 1.3.6.1.4.1.4203.1.3.4 "
980			"NAME 'authPassword' "
981			"DESC 'RFC3112: authentication password attribute' "
982			"EQUALITY 1.3.6.1.4.1.4203.1.2.2 "
983			"SYNTAX 1.3.6.1.4.1.4203.1.1.2 )",
984		NULL, 0,
985		NULL, NULL,
986		NULL, NULL, NULL, NULL, NULL,
987		offsetof(struct slap_internal_schema, si_ad_authPassword) },
988	{ "supportedAuthPasswordSchemes", "( 1.3.6.1.4.1.4203.1.3.3 "
989			"NAME 'supportedAuthPasswordSchemes' "
990			"DESC 'RFC3112: supported authPassword schemes' "
991			"EQUALITY caseExactIA5Match "
992			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} "
993			"USAGE dSAOperation )",
994		subschemaAttribute, 0,
995		NULL, NULL,
996		NULL, NULL, NULL, NULL, NULL,
997		offsetof(struct slap_internal_schema, si_ad_authPasswordSchemes) },
998#endif
999
1000	{ "description", "( 2.5.4.13 NAME 'description' "
1001			"DESC 'RFC4519: descriptive information' "
1002			"EQUALITY caseIgnoreMatch "
1003			"SUBSTR caseIgnoreSubstringsMatch "
1004			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024} )",
1005		NULL, 0,
1006		NULL, NULL,
1007		NULL, NULL, NULL, NULL, NULL,
1008		offsetof(struct slap_internal_schema, si_ad_description) },
1009
1010	{ "seeAlso", "( 2.5.4.34 NAME 'seeAlso' "
1011			"DESC 'RFC4519: DN of related object' "
1012			"SUP distinguishedName )",
1013		NULL, 0,
1014		NULL, NULL,
1015		NULL, NULL, NULL, NULL, NULL,
1016		offsetof(struct slap_internal_schema, si_ad_seeAlso) },
1017
1018	{ "pKCS8PrivateKey", "( 1.3.6.1.4.1.4203.666.1.60 "
1019			"NAME 'pKCS8PrivateKey' "
1020			"DESC 'PKCS#8 PrivateKeyInfo, use ;binary' "
1021			"EQUALITY privateKeyMatch "
1022			"SYNTAX 1.2.840.113549.1.8.1.1 )",
1023		NULL, 0,
1024		NULL, NULL,
1025		NULL, NULL, NULL, NULL, NULL,
1026		offsetof(struct slap_internal_schema, si_ad_pKCS8PrivateKey) },
1027
1028	{ "pwdLastSuccess", "( 1.3.6.1.4.1.42.2.27.8.1.29 NAME 'pwdLastSuccess' "
1029			"DESC 'The timestamp of the last successful authentication' "
1030			"EQUALITY generalizedTimeMatch "
1031			"ORDERING generalizedTimeOrderingMatch "
1032			"SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 "
1033			"SINGLE-VALUE "
1034			"NO-USER-MODIFICATION "
1035			"USAGE directoryOperation )",
1036		NULL, 0,
1037		NULL, NULL,
1038		NULL, NULL, NULL, NULL, NULL,
1039		offsetof(struct slap_internal_schema, si_ad_pwdLastSuccess) },
1040
1041	{ NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0 }
1042};
1043
1044static AttributeType slap_at_undefined = {
1045	{ "1.1.1", NULL, "Catchall for undefined attribute types", 1, NULL,
1046		NULL, NULL, NULL, NULL,
1047		0, 0, 0, 1, LDAP_SCHEMA_DSA_OPERATION, NULL }, /* LDAPAttributeType */
1048	BER_BVC("UNDEFINED"), /* cname */
1049	NULL, /* sup */
1050	NULL, /* subtypes */
1051	NULL, NULL, NULL, NULL,	/* matching rules routines */
1052	NULL, /* syntax (will be set later to "octetString") */
1053	NULL, /* schema check function */
1054	NULL, /* oidmacro */
1055	NULL, /* soidmacro */
1056	SLAP_AT_ABSTRACT|SLAP_AT_FINAL,	/* mask */
1057	{ NULL }, /* next */
1058	NULL /* attribute description */
1059	/* mutex (don't know how to initialize it :) */
1060};
1061
1062static AttributeType slap_at_proxied = {
1063	{ "1.1.1", NULL, "Catchall for undefined proxied attribute types", 1, NULL,
1064		NULL, NULL, NULL, NULL,
1065		0, 0, 0, 0, LDAP_SCHEMA_USER_APPLICATIONS, NULL }, /* LDAPAttributeType */
1066	BER_BVC("PROXIED"), /* cname */
1067	NULL, /* sup */
1068	NULL, /* subtypes */
1069	NULL, NULL, NULL, NULL,	/* matching rules routines (will be set later) */
1070	NULL, /* syntax (will be set later to "octetString") */
1071	NULL, /* schema check function */
1072	NULL, /* oidmacro */
1073	NULL, /* soidmacro */
1074	SLAP_AT_ABSTRACT|SLAP_AT_FINAL,	/* mask */
1075	{ NULL }, /* next */
1076	NULL /* attribute description */
1077	/* mutex (don't know how to initialize it :) */
1078};
1079
1080static struct slap_schema_mr_map {
1081	char *ssmm_name;
1082	size_t ssmm_offset;
1083} mr_map[] = {
1084	{ "caseExactIA5Match",
1085		offsetof(struct slap_internal_schema, si_mr_caseExactIA5Match) },
1086	{ "caseExactMatch",
1087		offsetof(struct slap_internal_schema, si_mr_caseExactMatch) },
1088	{ "caseExactSubstringsMatch",
1089		offsetof(struct slap_internal_schema, si_mr_caseExactSubstringsMatch) },
1090	{ "distinguishedNameMatch",
1091		offsetof(struct slap_internal_schema, si_mr_distinguishedNameMatch) },
1092	{ "dnSubtreeMatch",
1093		offsetof(struct slap_internal_schema, si_mr_dnSubtreeMatch) },
1094	{ "dnOneLevelMatch",
1095		offsetof(struct slap_internal_schema, si_mr_dnOneLevelMatch) },
1096	{ "dnSubordinateMatch",
1097		offsetof(struct slap_internal_schema, si_mr_dnSubordinateMatch) },
1098	{ "dnSuperiorMatch",
1099		offsetof(struct slap_internal_schema, si_mr_dnSuperiorMatch) },
1100	{ "integerMatch",
1101		offsetof(struct slap_internal_schema, si_mr_integerMatch) },
1102	{ "integerFirstComponentMatch",
1103		offsetof(struct slap_internal_schema,
1104			si_mr_integerFirstComponentMatch) },
1105	{ "objectIdentifierFirstComponentMatch",
1106		offsetof(struct slap_internal_schema,
1107			si_mr_objectIdentifierFirstComponentMatch) },
1108	{ "caseIgnoreMatch",
1109		offsetof(struct slap_internal_schema, si_mr_caseIgnoreMatch) },
1110	{ "caseIgnoreListMatch",
1111		offsetof(struct slap_internal_schema, si_mr_caseIgnoreListMatch) },
1112	{ NULL, 0 }
1113};
1114
1115static struct slap_schema_syn_map {
1116	char *sssm_name;
1117	size_t sssm_offset;
1118} syn_map[] = {
1119	{ "1.3.6.1.4.1.1466.115.121.1.15",
1120		offsetof(struct slap_internal_schema, si_syn_directoryString) },
1121	{ "1.3.6.1.4.1.1466.115.121.1.12",
1122		offsetof(struct slap_internal_schema, si_syn_distinguishedName) },
1123	{ "1.3.6.1.4.1.1466.115.121.1.27",
1124		offsetof(struct slap_internal_schema, si_syn_integer) },
1125	{ "1.3.6.1.4.1.1466.115.121.1.40",
1126		offsetof(struct slap_internal_schema, si_syn_octetString) },
1127	{ "1.3.6.1.4.1.1466.115.121.1.3",
1128		offsetof(struct slap_internal_schema, si_syn_attributeTypeDesc) },
1129	{ "1.3.6.1.4.1.1466.115.121.1.16",
1130		offsetof(struct slap_internal_schema, si_syn_ditContentRuleDesc) },
1131	{ "1.3.6.1.4.1.1466.115.121.1.54",
1132		offsetof(struct slap_internal_schema, si_syn_ldapSyntaxDesc) },
1133	{ "1.3.6.1.4.1.1466.115.121.1.30",
1134		offsetof(struct slap_internal_schema, si_syn_matchingRuleDesc) },
1135	{ "1.3.6.1.4.1.1466.115.121.1.31",
1136		offsetof(struct slap_internal_schema, si_syn_matchingRuleUseDesc) },
1137	{ "1.3.6.1.4.1.1466.115.121.1.35",
1138		offsetof(struct slap_internal_schema, si_syn_nameFormDesc) },
1139	{ "1.3.6.1.4.1.1466.115.121.1.37",
1140		offsetof(struct slap_internal_schema, si_syn_objectClassDesc) },
1141	{ "1.3.6.1.4.1.1466.115.121.1.17",
1142		offsetof(struct slap_internal_schema, si_syn_ditStructureRuleDesc) },
1143	{ NULL, 0 }
1144};
1145
1146int
1147slap_schema_load( void )
1148{
1149	int i;
1150
1151	for( i=0; syn_map[i].sssm_name; i++ ) {
1152		Syntax ** synp = (Syntax **)
1153			&(((char *) &slap_schema)[syn_map[i].sssm_offset]);
1154
1155		assert( *synp == NULL );
1156
1157		*synp = syn_find( syn_map[i].sssm_name );
1158
1159		if( *synp == NULL ) {
1160			fprintf( stderr, "slap_schema_load: Syntax: "
1161				"No syntax \"%s\" defined in schema\n",
1162				syn_map[i].sssm_name );
1163			return LDAP_INVALID_SYNTAX;
1164		}
1165	}
1166
1167	for( i=0; mr_map[i].ssmm_name; i++ ) {
1168		MatchingRule ** mrp = (MatchingRule **)
1169			&(((char *) &slap_schema)[mr_map[i].ssmm_offset]);
1170
1171		assert( *mrp == NULL );
1172
1173		*mrp = mr_find( mr_map[i].ssmm_name );
1174
1175		if( *mrp == NULL ) {
1176			fprintf( stderr, "slap_schema_load: MatchingRule: "
1177				"No matching rule \"%s\" defined in schema\n",
1178				mr_map[i].ssmm_name );
1179			return LDAP_INAPPROPRIATE_MATCHING;
1180		}
1181	}
1182
1183	slap_at_undefined.sat_syntax = slap_schema.si_syn_octetString;
1184	slap_schema.si_at_undefined = &slap_at_undefined;
1185
1186	slap_at_proxied.sat_equality = mr_find( "octetStringMatch" );
1187	slap_at_proxied.sat_approx = mr_find( "octetStringMatch" );
1188	slap_at_proxied.sat_ordering = mr_find( "octetStringOrderingMatch" );
1189	slap_at_proxied.sat_substr = mr_find( "octetStringSubstringsMatch" );
1190	slap_at_proxied.sat_syntax = slap_schema.si_syn_octetString;
1191	slap_schema.si_at_proxied = &slap_at_proxied;
1192
1193	ldap_pvt_thread_mutex_init( &ad_index_mutex );
1194	ldap_pvt_thread_mutex_init( &ad_undef_mutex );
1195	ldap_pvt_thread_mutex_init( &oc_undef_mutex );
1196
1197	for( i=0; ad_map[i].ssam_name; i++ ) {
1198		assert( ad_map[i].ssam_defn != NULL );
1199		{
1200			LDAPAttributeType *at;
1201			int		code;
1202			const char	*err;
1203
1204			at = ldap_str2attributetype( ad_map[i].ssam_defn,
1205				&code, &err, LDAP_SCHEMA_ALLOW_ALL );
1206			if ( !at ) {
1207				fprintf( stderr,
1208					"slap_schema_load: AttributeType \"%s\": %s before %s\n",
1209					 ad_map[i].ssam_name, ldap_scherr2str(code), err );
1210				return code;
1211			}
1212
1213			if ( at->at_oid == NULL ) {
1214				fprintf( stderr, "slap_schema_load: "
1215					"AttributeType \"%s\": no OID\n",
1216					ad_map[i].ssam_name );
1217				ldap_attributetype_free( at );
1218				return LDAP_OTHER;
1219			}
1220
1221			code = at_add( at, 0, NULL, NULL, &err );
1222			if ( code ) {
1223				ldap_attributetype_free( at );
1224				fprintf( stderr, "slap_schema_load: AttributeType "
1225					"\"%s\": %s: \"%s\"\n",
1226					 ad_map[i].ssam_name, scherr2str(code), err );
1227				return code;
1228			}
1229			ldap_memfree( at );
1230		}
1231		{
1232			int rc;
1233			const char *text;
1234			Syntax *syntax = NULL;
1235
1236			AttributeDescription ** adp = (AttributeDescription **)
1237				&(((char *) &slap_schema)[ad_map[i].ssam_offset]);
1238
1239			assert( *adp == NULL );
1240
1241			rc = slap_str2ad( ad_map[i].ssam_name, adp, &text );
1242			if( rc != LDAP_SUCCESS ) {
1243				fprintf( stderr, "slap_schema_load: AttributeType \"%s\": "
1244					"not defined in schema\n",
1245					ad_map[i].ssam_name );
1246				return rc;
1247			}
1248
1249			if( ad_map[i].ssam_check ) {
1250				/* install check routine */
1251				(*adp)->ad_type->sat_check = ad_map[i].ssam_check;
1252			}
1253			/* install flags */
1254			(*adp)->ad_type->sat_flags |= ad_map[i].ssam_flags;
1255
1256			/* install custom syntax routines */
1257			if( ad_map[i].ssam_syn_validate ||
1258				ad_map[i].ssam_syn_pretty )
1259			{
1260				Syntax *syn;
1261
1262				syntax = (*adp)->ad_type->sat_syntax;
1263
1264				syn = ch_malloc( sizeof( Syntax ) );
1265				*syn = *syntax;
1266
1267				if( ad_map[i].ssam_syn_validate ) {
1268					syn->ssyn_validate = ad_map[i].ssam_syn_validate;
1269				}
1270				if( ad_map[i].ssam_syn_pretty ) {
1271					syn->ssyn_pretty = ad_map[i].ssam_syn_pretty;
1272				}
1273
1274				(*adp)->ad_type->sat_syntax = syn;
1275			}
1276
1277			/* install custom rule routines */
1278			if( syntax != NULL ||
1279				ad_map[i].ssam_mr_convert ||
1280				ad_map[i].ssam_mr_normalize ||
1281				ad_map[i].ssam_mr_match ||
1282				ad_map[i].ssam_mr_indexer ||
1283				ad_map[i].ssam_mr_filter )
1284			{
1285				MatchingRule *mr = ch_malloc( sizeof( MatchingRule ) );
1286				*mr = *(*adp)->ad_type->sat_equality;
1287
1288				if ( syntax != NULL ) {
1289					mr->smr_syntax = (*adp)->ad_type->sat_syntax;
1290				}
1291				if ( ad_map[i].ssam_mr_convert ) {
1292					mr->smr_convert = ad_map[i].ssam_mr_convert;
1293				}
1294				if ( ad_map[i].ssam_mr_normalize ) {
1295					mr->smr_normalize = ad_map[i].ssam_mr_normalize;
1296				}
1297				if ( ad_map[i].ssam_mr_match ) {
1298					mr->smr_match = ad_map[i].ssam_mr_match;
1299				}
1300				if ( ad_map[i].ssam_mr_indexer ) {
1301					mr->smr_indexer = ad_map[i].ssam_mr_indexer;
1302				}
1303				if ( ad_map[i].ssam_mr_filter ) {
1304					mr->smr_filter = ad_map[i].ssam_mr_filter;
1305				}
1306
1307				(*adp)->ad_type->sat_equality = mr;
1308			}
1309		}
1310	}
1311
1312	for( i=0; oc_map[i].ssom_name; i++ ) {
1313		assert( oc_map[i].ssom_defn != NULL );
1314		{
1315			LDAPObjectClass *oc;
1316			int		code;
1317			const char	*err;
1318
1319			oc = ldap_str2objectclass( oc_map[i].ssom_defn, &code, &err,
1320				LDAP_SCHEMA_ALLOW_ALL );
1321			if ( !oc ) {
1322				fprintf( stderr, "slap_schema_load: ObjectClass "
1323					"\"%s\": %s before %s\n",
1324				 	oc_map[i].ssom_name, ldap_scherr2str(code), err );
1325				return code;
1326			}
1327
1328			if ( oc->oc_oid == NULL ) {
1329				fprintf( stderr, "slap_schema_load: ObjectClass "
1330					"\"%s\": no OID\n",
1331					oc_map[i].ssom_name );
1332				ldap_objectclass_free( oc );
1333				return LDAP_OTHER;
1334			}
1335
1336			code = oc_add(oc,0,NULL,NULL,&err);
1337			if ( code ) {
1338				ldap_objectclass_free( oc );
1339				fprintf( stderr, "slap_schema_load: ObjectClass "
1340					"\"%s\": %s: \"%s\"\n",
1341				 	oc_map[i].ssom_name, scherr2str(code), err);
1342				return code;
1343			}
1344			ldap_memfree(oc);
1345
1346		}
1347		{
1348			ObjectClass ** ocp = (ObjectClass **)
1349				&(((char *) &slap_schema)[oc_map[i].ssom_offset]);
1350
1351			assert( *ocp == NULL );
1352
1353			*ocp = oc_find( oc_map[i].ssom_name );
1354			if( *ocp == NULL ) {
1355				fprintf( stderr, "slap_schema_load: "
1356					"ObjectClass \"%s\": not defined in schema\n",
1357					oc_map[i].ssom_name );
1358				return LDAP_OBJECT_CLASS_VIOLATION;
1359			}
1360
1361			if( oc_map[i].ssom_check ) {
1362				/* install check routine */
1363				(*ocp)->soc_check = oc_map[i].ssom_check;
1364			}
1365			/* install flags */
1366			(*ocp)->soc_flags |= oc_map[i].ssom_flags;
1367		}
1368	}
1369
1370	return LDAP_SUCCESS;
1371}
1372
1373int
1374slap_schema_check( void )
1375{
1376	/* we should only be called once after schema_init() was called */
1377	assert( schema_init_done == 1 );
1378
1379	/*
1380	 * cycle thru attributeTypes to build matchingRuleUse
1381	 */
1382	if ( matching_rule_use_init() ) {
1383		return LDAP_OTHER;
1384	}
1385
1386	++schema_init_done;
1387	return LDAP_SUCCESS;
1388}
1389
1390static int rootDseObjectClass (
1391	Backend *be,
1392	Entry *e,
1393	ObjectClass *oc,
1394	const char** text,
1395	char *textbuf, size_t textlen )
1396{
1397	*text = textbuf;
1398
1399	if( e->e_nname.bv_len ) {
1400		snprintf( textbuf, textlen,
1401			"objectClass \"%s\" only allowed in the root DSE",
1402			oc->soc_oid );
1403		return LDAP_OBJECT_CLASS_VIOLATION;
1404	}
1405
1406	/* we should not be called for the root DSE */
1407	assert( 0 );
1408	return LDAP_SUCCESS;
1409}
1410
1411static int aliasObjectClass (
1412	Backend *be,
1413	Entry *e,
1414	ObjectClass *oc,
1415	const char** text,
1416	char *textbuf, size_t textlen )
1417{
1418	*text = textbuf;
1419
1420	if( !SLAP_ALIASES(be) ) {
1421		snprintf( textbuf, textlen,
1422			"objectClass \"%s\" not supported in context",
1423			oc->soc_oid );
1424		return LDAP_OBJECT_CLASS_VIOLATION;
1425	}
1426
1427	return LDAP_SUCCESS;
1428}
1429
1430static int referralObjectClass (
1431	Backend *be,
1432	Entry *e,
1433	ObjectClass *oc,
1434	const char** text,
1435	char *textbuf, size_t textlen )
1436{
1437	*text = textbuf;
1438
1439	if( !SLAP_REFERRALS(be) ) {
1440		snprintf( textbuf, textlen,
1441			"objectClass \"%s\" not supported in context",
1442			oc->soc_oid );
1443		return LDAP_OBJECT_CLASS_VIOLATION;
1444	}
1445
1446	return LDAP_SUCCESS;
1447}
1448
1449static int subentryObjectClass (
1450	Backend *be,
1451	Entry *e,
1452	ObjectClass *oc,
1453	const char** text,
1454	char *textbuf, size_t textlen )
1455{
1456	*text = textbuf;
1457
1458	if( !SLAP_SUBENTRIES(be) ) {
1459		snprintf( textbuf, textlen,
1460			"objectClass \"%s\" not supported in context",
1461			oc->soc_oid );
1462		return LDAP_OBJECT_CLASS_VIOLATION;
1463	}
1464
1465	if( oc != slap_schema.si_oc_subentry && !is_entry_subentry( e ) ) {
1466		snprintf( textbuf, textlen,
1467			"objectClass \"%s\" only allowed in subentries",
1468			oc->soc_oid );
1469		return LDAP_OBJECT_CLASS_VIOLATION;
1470	}
1471
1472	return LDAP_SUCCESS;
1473}
1474
1475#ifdef LDAP_DYNAMIC_OBJECTS
1476static int dynamicObjectClass (
1477	Backend *be,
1478	Entry *e,
1479	ObjectClass *oc,
1480	const char** text,
1481	char *textbuf, size_t textlen )
1482{
1483	*text = textbuf;
1484
1485	if( !SLAP_DYNAMIC(be) ) {
1486		snprintf( textbuf, textlen,
1487			"objectClass \"%s\" not supported in context",
1488			oc->soc_oid );
1489		return LDAP_OBJECT_CLASS_VIOLATION;
1490	}
1491
1492	return LDAP_SUCCESS;
1493}
1494#endif /* LDAP_DYNAMIC_OBJECTS */
1495
1496static int rootDseAttribute (
1497	Backend *be,
1498	Entry *e,
1499	Attribute *attr,
1500	const char** text,
1501	char *textbuf, size_t textlen )
1502{
1503	*text = textbuf;
1504
1505	if( e->e_nname.bv_len ) {
1506		snprintf( textbuf, textlen,
1507			"attribute \"%s\" only allowed in the root DSE",
1508			attr->a_desc->ad_cname.bv_val );
1509		return LDAP_OBJECT_CLASS_VIOLATION;
1510	}
1511
1512	/* we should not be called for the root DSE */
1513	assert( 0 );
1514	return LDAP_SUCCESS;
1515}
1516
1517static int aliasAttribute (
1518	Backend *be,
1519	Entry *e,
1520	Attribute *attr,
1521	const char** text,
1522	char *textbuf, size_t textlen )
1523{
1524	*text = textbuf;
1525
1526	if( !SLAP_ALIASES(be) ) {
1527		snprintf( textbuf, textlen,
1528			"attribute \"%s\" not supported in context",
1529			attr->a_desc->ad_cname.bv_val );
1530		return LDAP_OBJECT_CLASS_VIOLATION;
1531	}
1532
1533	if( !is_entry_alias( e ) ) {
1534		snprintf( textbuf, textlen,
1535			"attribute \"%s\" only allowed in the alias",
1536			attr->a_desc->ad_cname.bv_val );
1537		return LDAP_OBJECT_CLASS_VIOLATION;
1538	}
1539
1540	return LDAP_SUCCESS;
1541}
1542
1543static int referralAttribute (
1544	Backend *be,
1545	Entry *e,
1546	Attribute *attr,
1547	const char** text,
1548	char *textbuf, size_t textlen )
1549{
1550	*text = textbuf;
1551
1552	if( !SLAP_REFERRALS(be) ) {
1553		snprintf( textbuf, textlen,
1554			"attribute \"%s\" not supported in context",
1555			attr->a_desc->ad_cname.bv_val );
1556		return LDAP_OBJECT_CLASS_VIOLATION;
1557	}
1558
1559	if( !is_entry_referral( e ) ) {
1560		snprintf( textbuf, textlen,
1561			"attribute \"%s\" only allowed in the referral",
1562			attr->a_desc->ad_cname.bv_val );
1563		return LDAP_OBJECT_CLASS_VIOLATION;
1564	}
1565
1566	return LDAP_SUCCESS;
1567}
1568
1569static int subentryAttribute (
1570	Backend *be,
1571	Entry *e,
1572	Attribute *attr,
1573	const char** text,
1574	char *textbuf, size_t textlen )
1575{
1576	*text = textbuf;
1577
1578	if( !SLAP_SUBENTRIES(be) ) {
1579		snprintf( textbuf, textlen,
1580			"attribute \"%s\" not supported in context",
1581			attr->a_desc->ad_cname.bv_val );
1582		return LDAP_OBJECT_CLASS_VIOLATION;
1583	}
1584
1585	if( !is_entry_subentry( e ) ) {
1586		snprintf( textbuf, textlen,
1587			"attribute \"%s\" only allowed in the subentry",
1588			attr->a_desc->ad_cname.bv_val );
1589		return LDAP_OBJECT_CLASS_VIOLATION;
1590	}
1591
1592	return LDAP_SUCCESS;
1593}
1594
1595static int administrativeRoleAttribute (
1596	Backend *be,
1597	Entry *e,
1598	Attribute *attr,
1599	const char** text,
1600	char *textbuf, size_t textlen )
1601{
1602	*text = textbuf;
1603
1604	if( !SLAP_SUBENTRIES(be) ) {
1605		snprintf( textbuf, textlen,
1606			"attribute \"%s\" not supported in context",
1607			attr->a_desc->ad_cname.bv_val );
1608		return LDAP_OBJECT_CLASS_VIOLATION;
1609	}
1610
1611	snprintf( textbuf, textlen,
1612		"attribute \"%s\" not supported!",
1613		attr->a_desc->ad_cname.bv_val );
1614	return LDAP_OBJECT_CLASS_VIOLATION;
1615}
1616
1617#ifdef LDAP_DYNAMIC_OBJECTS
1618static int dynamicAttribute (
1619	Backend *be,
1620	Entry *e,
1621	Attribute *attr,
1622	const char** text,
1623	char *textbuf, size_t textlen )
1624{
1625	*text = textbuf;
1626
1627	if( !SLAP_DYNAMIC(be) ) {
1628		snprintf( textbuf, textlen,
1629			"attribute \"%s\" not supported in context",
1630			attr->a_desc->ad_cname.bv_val );
1631		return LDAP_OBJECT_CLASS_VIOLATION;
1632	}
1633
1634	if( !is_entry_dynamicObject( e ) ) {
1635		snprintf( textbuf, textlen,
1636			"attribute \"%s\" only allowed in dynamic object",
1637			attr->a_desc->ad_cname.bv_val );
1638		return LDAP_OBJECT_CLASS_VIOLATION;
1639	}
1640
1641	return LDAP_SUCCESS;
1642}
1643#endif /* LDAP_DYNAMIC_OBJECTS */
1644