1/* at.c - routines for dealing with attribute types */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 1998-2011 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16
17#include "portable.h"
18
19#include <stdio.h>
20
21#include <ac/ctype.h>
22#include <ac/errno.h>
23#include <ac/socket.h>
24#include <ac/string.h>
25#include <ac/time.h>
26
27#include "slap.h"
28
29
30const char *
31at_syntax(
32	AttributeType	*at )
33{
34	for ( ; at != NULL; at = at->sat_sup ) {
35		if ( at->sat_syntax_oid ) {
36			return at->sat_syntax_oid;
37		}
38	}
39
40	assert( 0 );
41
42	return NULL;
43}
44
45int
46is_at_syntax(
47	AttributeType	*at,
48	const char	*oid )
49{
50	const char *syn_oid = at_syntax( at );
51
52	if ( syn_oid ) {
53		return strcmp( syn_oid, oid ) == 0;
54	}
55
56	return 0;
57}
58
59int is_at_subtype(
60	AttributeType *sub,
61	AttributeType *sup )
62{
63	for( ; sub != NULL; sub = sub->sat_sup ) {
64		if( sub == sup ) return 1;
65	}
66
67	return 0;
68}
69
70struct aindexrec {
71	struct berval	air_name;
72	AttributeType	*air_at;
73};
74
75static Avlnode	*attr_index = NULL;
76static Avlnode	*attr_cache = NULL;
77static LDAP_STAILQ_HEAD(ATList, AttributeType) attr_list
78	= LDAP_STAILQ_HEAD_INITIALIZER(attr_list);
79
80/* Last hardcoded attribute registered */
81AttributeType *at_sys_tail;
82
83int at_oc_cache;
84
85static int
86attr_index_cmp(
87    const void	*v_air1,
88    const void	*v_air2 )
89{
90	const struct aindexrec	*air1 = v_air1;
91	const struct aindexrec	*air2 = v_air2;
92	int i = air1->air_name.bv_len - air2->air_name.bv_len;
93	if (i) return i;
94	return (strcasecmp( air1->air_name.bv_val, air2->air_name.bv_val ));
95}
96
97static int
98attr_index_name_cmp(
99    const void	*v_type,
100    const void	*v_air )
101{
102    const struct berval    *type = v_type;
103    const struct aindexrec *air  = v_air;
104	int i = type->bv_len - air->air_name.bv_len;
105	if (i) return i;
106	return (strncasecmp( type->bv_val, air->air_name.bv_val, type->bv_len ));
107}
108
109AttributeType *
110at_find( const char *name )
111{
112	struct berval bv;
113
114	bv.bv_val = (char *)name;
115	bv.bv_len = strlen( name );
116
117	return at_bvfind( &bv );
118}
119
120AttributeType *
121at_bvfind( struct berval *name )
122{
123	struct aindexrec *air;
124
125	if ( attr_cache ) {
126		air = avl_find( attr_cache, name, attr_index_name_cmp );
127		if ( air ) return air->air_at;
128	}
129
130	air = avl_find( attr_index, name, attr_index_name_cmp );
131
132	if ( air ) {
133		if ( air->air_at->sat_flags & SLAP_AT_DELETED ) {
134			air = NULL;
135		} else if (( slapMode & SLAP_TOOL_MODE ) && at_oc_cache ) {
136			avl_insert( &attr_cache, (caddr_t) air,
137				attr_index_cmp, avl_dup_error );
138		}
139	}
140
141	return air != NULL ? air->air_at : NULL;
142}
143
144int
145at_append_to_list(
146    AttributeType	*sat,
147    AttributeType	***listp )
148{
149	AttributeType	**list;
150	AttributeType	**list1;
151	int		size;
152
153	list = *listp;
154	if ( !list ) {
155		size = 2;
156		list = ch_calloc(size, sizeof(AttributeType *));
157		if ( !list ) {
158			return -1;
159		}
160	} else {
161		size = 0;
162		list1 = *listp;
163		while ( *list1 ) {
164			size++;
165			list1++;
166		}
167		size += 2;
168		list1 = ch_realloc(list, size*sizeof(AttributeType *));
169		if ( !list1 ) {
170			return -1;
171		}
172		list = list1;
173	}
174	list[size-2] = sat;
175	list[size-1] = NULL;
176	*listp = list;
177	return 0;
178}
179
180int
181at_delete_from_list(
182    int			pos,
183    AttributeType	***listp )
184{
185	AttributeType	**list;
186	AttributeType	**list1;
187	int		i;
188	int		j;
189
190	if ( pos < 0 ) {
191		return -2;
192	}
193	list = *listp;
194	for ( i=0; list[i]; i++ )
195		;
196	if ( pos >= i ) {
197		return -2;
198	}
199	for ( i=pos, j=pos+1; list[j]; i++, j++ ) {
200		list[i] = list[j];
201	}
202	list[i] = NULL;
203	/* Tell the runtime this can be shrinked */
204	list1 = ch_realloc(list, (i+1)*sizeof(AttributeType **));
205	if ( !list1 ) {
206		return -1;
207	}
208	*listp = list1;
209	return 0;
210}
211
212int
213at_find_in_list(
214    AttributeType	*sat,
215    AttributeType	**list )
216{
217	int	i;
218
219	if ( !list ) {
220		return -1;
221	}
222	for ( i=0; list[i]; i++ ) {
223		if ( sat == list[i] ) {
224			return i;
225		}
226	}
227	return -1;
228}
229
230static void
231at_delete_names( AttributeType *at )
232{
233	char			**names = at->sat_names;
234
235	while (*names) {
236		struct aindexrec	tmpair, *air;
237
238		ber_str2bv( *names, 0, 0, &tmpair.air_name );
239		tmpair.air_at = at;
240		air = (struct aindexrec *)avl_delete( &attr_index,
241			(caddr_t)&tmpair, attr_index_cmp );
242		assert( air != NULL );
243		ldap_memfree( air );
244		names++;
245	}
246}
247
248/* Mark the attribute as deleted, remove from list, and remove all its
249 * names from the AVL tree. Leave the OID in the tree.
250 */
251void
252at_delete( AttributeType *at )
253{
254	at->sat_flags |= SLAP_AT_DELETED;
255
256	LDAP_STAILQ_REMOVE(&attr_list, at, AttributeType, sat_next);
257
258	at_delete_names( at );
259}
260
261static void
262at_clean( AttributeType *a )
263{
264	if ( a->sat_equality ) {
265		MatchingRule	*mr;
266
267		mr = mr_find( a->sat_equality->smr_oid );
268		assert( mr != NULL );
269		if ( mr != a->sat_equality ) {
270			ch_free( a->sat_equality );
271			a->sat_equality = NULL;
272		}
273	}
274
275	assert( a->sat_syntax != NULL );
276	if ( a->sat_syntax != NULL ) {
277		Syntax		*syn;
278
279		syn = syn_find( a->sat_syntax->ssyn_oid );
280		assert( syn != NULL );
281		if ( syn != a->sat_syntax ) {
282			ch_free( a->sat_syntax );
283			a->sat_syntax = NULL;
284		}
285	}
286
287	if ( a->sat_oidmacro ) {
288		ldap_memfree( a->sat_oidmacro );
289		a->sat_oidmacro = NULL;
290	}
291	if ( a->sat_soidmacro ) {
292		ldap_memfree( a->sat_soidmacro );
293		a->sat_soidmacro = NULL;
294	}
295	if ( a->sat_subtypes ) {
296		ldap_memfree( a->sat_subtypes );
297		a->sat_subtypes = NULL;
298	}
299}
300
301static void
302at_destroy_one( void *v )
303{
304	struct aindexrec *air = v;
305	AttributeType *a = air->air_at;
306
307	at_clean( a );
308	ad_destroy(a->sat_ad);
309	ldap_pvt_thread_mutex_destroy(&a->sat_ad_mutex);
310	ldap_attributetype_free((LDAPAttributeType *)a);
311	ldap_memfree(air);
312}
313
314void
315at_destroy( void )
316{
317	AttributeType *a;
318
319	while( !LDAP_STAILQ_EMPTY(&attr_list) ) {
320		a = LDAP_STAILQ_FIRST(&attr_list);
321		LDAP_STAILQ_REMOVE_HEAD(&attr_list, sat_next);
322
323		at_delete_names( a );
324	}
325
326	avl_free(attr_index, at_destroy_one);
327
328	if ( slap_schema.si_at_undefined ) {
329		ad_destroy(slap_schema.si_at_undefined->sat_ad);
330	}
331
332	if ( slap_schema.si_at_proxied ) {
333		ad_destroy(slap_schema.si_at_proxied->sat_ad);
334	}
335}
336
337int
338at_start( AttributeType **at )
339{
340	assert( at != NULL );
341
342	*at = LDAP_STAILQ_FIRST(&attr_list);
343
344	return (*at != NULL);
345}
346
347int
348at_next( AttributeType **at )
349{
350	assert( at != NULL );
351
352#if 0	/* pedantic check: don't use this */
353	{
354		AttributeType *tmp = NULL;
355
356		LDAP_STAILQ_FOREACH(tmp,&attr_list,sat_next) {
357			if ( tmp == *at ) {
358				break;
359			}
360		}
361
362		assert( tmp != NULL );
363	}
364#endif
365
366	*at = LDAP_STAILQ_NEXT(*at,sat_next);
367
368	return (*at != NULL);
369}
370
371/*
372 * check whether the two attributeTypes actually __are__ identical,
373 * or rather inconsistent
374 */
375static int
376at_check_dup(
377	AttributeType		*sat,
378	AttributeType		*new_sat )
379{
380	if ( new_sat->sat_oid != NULL ) {
381		if ( sat->sat_oid == NULL ) {
382			return SLAP_SCHERR_ATTR_INCONSISTENT;
383		}
384
385		if ( strcmp( sat->sat_oid, new_sat->sat_oid ) != 0 ) {
386			return SLAP_SCHERR_ATTR_INCONSISTENT;
387		}
388
389	} else {
390		if ( sat->sat_oid != NULL ) {
391			return SLAP_SCHERR_ATTR_INCONSISTENT;
392		}
393	}
394
395	if ( new_sat->sat_names ) {
396		int	i;
397
398		if ( sat->sat_names == NULL ) {
399			return SLAP_SCHERR_ATTR_INCONSISTENT;
400		}
401
402		for ( i = 0; new_sat->sat_names[ i ]; i++ ) {
403			if ( sat->sat_names[ i ] == NULL ) {
404				return SLAP_SCHERR_ATTR_INCONSISTENT;
405			}
406
407			if ( strcasecmp( sat->sat_names[ i ],
408					new_sat->sat_names[ i ] ) != 0 )
409			{
410				return SLAP_SCHERR_ATTR_INCONSISTENT;
411			}
412		}
413	} else {
414		if ( sat->sat_names != NULL ) {
415			return SLAP_SCHERR_ATTR_INCONSISTENT;
416		}
417	}
418
419	return SLAP_SCHERR_ATTR_DUP;
420}
421
422static struct aindexrec *air_old;
423
424static int
425at_dup_error( void *left, void *right )
426{
427	air_old = left;
428	return -1;
429}
430
431static int
432at_insert(
433    AttributeType	**rat,
434	AttributeType	*prev,
435    const char		**err )
436{
437	struct aindexrec	*air;
438	char			**names = NULL;
439	AttributeType	*sat = *rat;
440
441	if ( sat->sat_oid ) {
442		air = (struct aindexrec *)
443			ch_calloc( 1, sizeof(struct aindexrec) );
444		ber_str2bv( sat->sat_oid, 0, 0, &air->air_name );
445		air->air_at = sat;
446		air_old = NULL;
447
448		if ( avl_insert( &attr_index, (caddr_t) air,
449		                 attr_index_cmp, at_dup_error ) )
450		{
451			AttributeType	*old_sat;
452			int		rc;
453
454			*err = sat->sat_oid;
455
456			assert( air_old != NULL );
457			old_sat = air_old->air_at;
458
459			/* replacing a deleted definition? */
460			if ( old_sat->sat_flags & SLAP_AT_DELETED ) {
461				AttributeType tmp;
462				AttributeDescription *ad;
463
464				/* Keep old oid, free new oid;
465				 * Keep old ads, free new ads;
466				 * Keep old ad_mutex, free new ad_mutex;
467				 * Keep new everything else, free old
468				 */
469				tmp = *old_sat;
470				*old_sat = *sat;
471				old_sat->sat_oid = tmp.sat_oid;
472				tmp.sat_oid = sat->sat_oid;
473				old_sat->sat_ad = tmp.sat_ad;
474				tmp.sat_ad = sat->sat_ad;
475				old_sat->sat_ad_mutex = tmp.sat_ad_mutex;
476				tmp.sat_ad_mutex = sat->sat_ad_mutex;
477				*sat = tmp;
478
479				/* Check for basic ad pointing at old cname */
480				for ( ad = old_sat->sat_ad; ad; ad=ad->ad_next ) {
481					if ( ad->ad_cname.bv_val == sat->sat_cname.bv_val ) {
482						ad->ad_cname = old_sat->sat_cname;
483						break;
484					}
485				}
486
487				at_clean( sat );
488				at_destroy_one( air );
489
490				air = air_old;
491				sat = old_sat;
492				*rat = sat;
493			} else {
494				ldap_memfree( air );
495
496				rc = at_check_dup( old_sat, sat );
497
498				return rc;
499			}
500		}
501		/* FIX: temporal consistency check */
502		at_bvfind( &air->air_name );
503	}
504
505	names = sat->sat_names;
506	if ( names ) {
507		while ( *names ) {
508			air = (struct aindexrec *)
509				ch_calloc( 1, sizeof(struct aindexrec) );
510			ber_str2bv( *names, 0, 0, &air->air_name );
511			air->air_at = sat;
512			if ( avl_insert( &attr_index, (caddr_t) air,
513			                 attr_index_cmp, avl_dup_error ) )
514			{
515				AttributeType	*old_sat;
516				int		rc;
517
518				*err = *names;
519
520				old_sat = at_bvfind( &air->air_name );
521				assert( old_sat != NULL );
522				rc = at_check_dup( old_sat, sat );
523
524				ldap_memfree(air);
525
526				while ( names > sat->sat_names ) {
527					struct aindexrec	tmpair;
528
529					names--;
530					ber_str2bv( *names, 0, 0, &tmpair.air_name );
531					tmpair.air_at = sat;
532					air = (struct aindexrec *)avl_delete( &attr_index,
533						(caddr_t)&tmpair, attr_index_cmp );
534					assert( air != NULL );
535					ldap_memfree( air );
536				}
537
538				if ( sat->sat_oid ) {
539					struct aindexrec	tmpair;
540
541					ber_str2bv( sat->sat_oid, 0, 0, &tmpair.air_name );
542					tmpair.air_at = sat;
543					air = (struct aindexrec *)avl_delete( &attr_index,
544						(caddr_t)&tmpair, attr_index_cmp );
545					assert( air != NULL );
546					ldap_memfree( air );
547				}
548
549				return rc;
550			}
551			/* FIX: temporal consistency check */
552			at_bvfind(&air->air_name);
553			names++;
554		}
555	}
556
557	if ( sat->sat_oid ) {
558		slap_ad_undef_promote( sat->sat_oid, sat );
559	}
560
561	names = sat->sat_names;
562	if ( names ) {
563		while ( *names ) {
564			slap_ad_undef_promote( *names, sat );
565			names++;
566		}
567	}
568
569	if ( sat->sat_flags & SLAP_AT_HARDCODE ) {
570		prev = at_sys_tail;
571		at_sys_tail = sat;
572	}
573	if ( prev ) {
574		LDAP_STAILQ_INSERT_AFTER( &attr_list, prev, sat, sat_next );
575	} else {
576		LDAP_STAILQ_INSERT_TAIL( &attr_list, sat, sat_next );
577	}
578
579	return 0;
580}
581
582int
583at_add(
584	LDAPAttributeType	*at,
585	int			user,
586	AttributeType		**rsat,
587	AttributeType	*prev,
588	const char		**err )
589{
590	AttributeType	*sat = NULL;
591	MatchingRule	*mr = NULL;
592	Syntax		*syn = NULL;
593	int		i;
594	int		code = LDAP_SUCCESS;
595	char		*cname = NULL;
596	char		*oidm = NULL;
597	char		*soidm = NULL;
598
599	if ( !at->at_oid ) {
600		*err = "";
601		return SLAP_SCHERR_ATTR_INCOMPLETE;
602	}
603
604	if ( !OID_LEADCHAR( at->at_oid[0] )) {
605		char	*oid;
606
607		/* Expand OID macros */
608		oid = oidm_find( at->at_oid );
609		if ( !oid ) {
610			*err = at->at_oid;
611			return SLAP_SCHERR_OIDM;
612		}
613		if ( oid != at->at_oid ) {
614			oidm = at->at_oid;
615			at->at_oid = oid;
616		}
617	}
618
619	if ( at->at_syntax_oid && !OID_LEADCHAR( at->at_syntax_oid[0] )) {
620		char	*oid;
621
622		/* Expand OID macros */
623		oid = oidm_find( at->at_syntax_oid );
624		if ( !oid ) {
625			*err = at->at_syntax_oid;
626			code = SLAP_SCHERR_OIDM;
627			goto error_return;
628		}
629		if ( oid != at->at_syntax_oid ) {
630			soidm = at->at_syntax_oid;
631			at->at_syntax_oid = oid;
632		}
633	}
634
635	if ( at->at_names && at->at_names[0] ) {
636		int i;
637
638		for( i=0; at->at_names[i]; i++ ) {
639			if( !slap_valid_descr( at->at_names[i] ) ) {
640				*err = at->at_names[i];
641				code = SLAP_SCHERR_BAD_DESCR;
642				goto error_return;
643			}
644		}
645
646		cname = at->at_names[0];
647
648	} else {
649		cname = at->at_oid;
650
651	}
652
653	*err = cname;
654
655	if ( !at->at_usage && at->at_no_user_mod ) {
656		/* user attribute must be modifable */
657		code = SLAP_SCHERR_ATTR_BAD_USAGE;
658		goto error_return;
659	}
660
661	if ( at->at_collective ) {
662		if( at->at_usage ) {
663			/* collective attributes cannot be operational */
664			code = SLAP_SCHERR_ATTR_BAD_USAGE;
665			goto error_return;
666		}
667
668		if( at->at_single_value ) {
669			/* collective attributes cannot be single-valued */
670			code = SLAP_SCHERR_ATTR_BAD_USAGE;
671			goto error_return;
672		}
673	}
674
675	sat = (AttributeType *) ch_calloc( 1, sizeof(AttributeType) );
676	AC_MEMCPY( &sat->sat_atype, at, sizeof(LDAPAttributeType));
677
678	sat->sat_cname.bv_val = cname;
679	sat->sat_cname.bv_len = strlen( cname );
680	sat->sat_oidmacro = oidm;
681	sat->sat_soidmacro = soidm;
682	ldap_pvt_thread_mutex_init(&sat->sat_ad_mutex);
683
684	if ( at->at_sup_oid ) {
685		AttributeType *supsat = at_find(at->at_sup_oid);
686
687		if ( supsat == NULL ) {
688			*err = at->at_sup_oid;
689			code = SLAP_SCHERR_ATTR_NOT_FOUND;
690			goto error_return;
691		}
692
693		sat->sat_sup = supsat;
694
695		if ( at_append_to_list(sat, &supsat->sat_subtypes) ) {
696			code = SLAP_SCHERR_OUTOFMEM;
697			goto error_return;
698		}
699
700		if ( sat->sat_usage != supsat->sat_usage ) {
701			/* subtypes must have same usage as their SUP */
702			code = SLAP_SCHERR_ATTR_BAD_USAGE;
703			goto error_return;
704		}
705
706		if ( supsat->sat_obsolete && !sat->sat_obsolete ) {
707			/* subtypes must be obsolete if super is */
708			code = SLAP_SCHERR_ATTR_BAD_SUP;
709			goto error_return;
710		}
711
712		if ( sat->sat_flags & SLAP_AT_FINAL ) {
713			/* cannot subtype a "final" attribute type */
714			code = SLAP_SCHERR_ATTR_BAD_SUP;
715			goto error_return;
716		}
717	}
718
719	/*
720	 * Inherit definitions from superiors.  We only check the
721	 * direct superior since that one has already inherited from
722	 * its own superiorss
723	 */
724	if ( sat->sat_sup ) {
725		Syntax *syn = syn_find(sat->sat_sup->sat_syntax->ssyn_oid);
726		if ( syn != sat->sat_sup->sat_syntax ) {
727			sat->sat_syntax = ch_malloc( sizeof( Syntax ));
728			*sat->sat_syntax = *sat->sat_sup->sat_syntax;
729		} else {
730			sat->sat_syntax = sat->sat_sup->sat_syntax;
731		}
732		if ( sat->sat_sup->sat_equality ) {
733			MatchingRule *mr = mr_find( sat->sat_sup->sat_equality->smr_oid );
734			if ( mr != sat->sat_sup->sat_equality ) {
735				sat->sat_equality = ch_malloc( sizeof( MatchingRule ));
736				*sat->sat_equality = *sat->sat_sup->sat_equality;
737			} else {
738				sat->sat_equality = sat->sat_sup->sat_equality;
739			}
740		}
741		sat->sat_approx = sat->sat_sup->sat_approx;
742		sat->sat_ordering = sat->sat_sup->sat_ordering;
743		sat->sat_substr = sat->sat_sup->sat_substr;
744	}
745
746	/*
747	 * check for X-ORDERED attributes
748	 */
749	if ( sat->sat_extensions ) {
750		for (i=0; sat->sat_extensions[i]; i++) {
751			if (!strcasecmp( sat->sat_extensions[i]->lsei_name,
752				"X-ORDERED" ) && sat->sat_extensions[i]->lsei_values ) {
753				if ( !strcasecmp( sat->sat_extensions[i]->lsei_values[0],
754					"VALUES" )) {
755					sat->sat_flags |= SLAP_AT_ORDERED_VAL;
756					break;
757				} else if ( !strcasecmp( sat->sat_extensions[i]->lsei_values[0],
758					"SIBLINGS" )) {
759					sat->sat_flags |= SLAP_AT_ORDERED_SIB;
760					break;
761				}
762			}
763		}
764	}
765
766	if ( !user )
767		sat->sat_flags |= SLAP_AT_HARDCODE;
768
769	if ( at->at_syntax_oid ) {
770		syn = syn_find(sat->sat_syntax_oid);
771		if ( syn == NULL ) {
772			*err = sat->sat_syntax_oid;
773			code = SLAP_SCHERR_SYN_NOT_FOUND;
774			goto error_return;
775		}
776
777		if ( sat->sat_syntax != NULL && sat->sat_syntax != syn ) {
778			/* BEWARE: no loop detection! */
779			if ( syn_is_sup( sat->sat_syntax, syn ) ) {
780				code = SLAP_SCHERR_ATTR_BAD_SUP;
781				goto error_return;
782			}
783		}
784
785		sat->sat_syntax = syn;
786
787	} else if ( sat->sat_syntax == NULL ) {
788		code = SLAP_SCHERR_ATTR_INCOMPLETE;
789		goto error_return;
790	}
791
792	if ( sat->sat_equality_oid ) {
793		mr = mr_find(sat->sat_equality_oid);
794
795		if( mr == NULL ) {
796			*err = sat->sat_equality_oid;
797			code = SLAP_SCHERR_MR_NOT_FOUND;
798			goto error_return;
799		}
800
801		if(( mr->smr_usage & SLAP_MR_EQUALITY ) != SLAP_MR_EQUALITY ) {
802			*err = sat->sat_equality_oid;
803			code = SLAP_SCHERR_ATTR_BAD_MR;
804			goto error_return;
805		}
806
807		if( sat->sat_syntax != mr->smr_syntax ) {
808			if( mr->smr_compat_syntaxes == NULL ) {
809				*err = sat->sat_equality_oid;
810				code = SLAP_SCHERR_ATTR_BAD_MR;
811				goto error_return;
812			}
813
814			for(i=0; mr->smr_compat_syntaxes[i]; i++) {
815				if( sat->sat_syntax == mr->smr_compat_syntaxes[i] ) {
816					i = -1;
817					break;
818				}
819			}
820
821			if( i >= 0 ) {
822				*err = sat->sat_equality_oid;
823				code = SLAP_SCHERR_ATTR_BAD_MR;
824				goto error_return;
825			}
826		}
827
828		sat->sat_equality = mr;
829		sat->sat_approx = mr->smr_associated;
830	}
831
832	if ( sat->sat_ordering_oid ) {
833		if( !sat->sat_equality ) {
834			*err = sat->sat_ordering_oid;
835			code = SLAP_SCHERR_ATTR_BAD_MR;
836			goto error_return;
837		}
838
839		mr = mr_find(sat->sat_ordering_oid);
840
841		if( mr == NULL ) {
842			*err = sat->sat_ordering_oid;
843			code = SLAP_SCHERR_MR_NOT_FOUND;
844			goto error_return;
845		}
846
847		if(( mr->smr_usage & SLAP_MR_ORDERING ) != SLAP_MR_ORDERING ) {
848			*err = sat->sat_ordering_oid;
849			code = SLAP_SCHERR_ATTR_BAD_MR;
850			goto error_return;
851		}
852
853		if( sat->sat_syntax != mr->smr_syntax ) {
854			if( mr->smr_compat_syntaxes == NULL ) {
855				*err = sat->sat_ordering_oid;
856				code = SLAP_SCHERR_ATTR_BAD_MR;
857				goto error_return;
858			}
859
860			for(i=0; mr->smr_compat_syntaxes[i]; i++) {
861				if( sat->sat_syntax == mr->smr_compat_syntaxes[i] ) {
862					i = -1;
863					break;
864				}
865			}
866
867			if( i >= 0 ) {
868				*err = sat->sat_ordering_oid;
869				code = SLAP_SCHERR_ATTR_BAD_MR;
870				goto error_return;
871			}
872		}
873
874		sat->sat_ordering = mr;
875	}
876
877	if ( sat->sat_substr_oid ) {
878		if( !sat->sat_equality ) {
879			*err = sat->sat_substr_oid;
880			code = SLAP_SCHERR_ATTR_BAD_MR;
881			goto error_return;
882		}
883
884		mr = mr_find(sat->sat_substr_oid);
885
886		if( mr == NULL ) {
887			*err = sat->sat_substr_oid;
888			code = SLAP_SCHERR_MR_NOT_FOUND;
889			goto error_return;
890		}
891
892		if(( mr->smr_usage & SLAP_MR_SUBSTR ) != SLAP_MR_SUBSTR ) {
893			*err = sat->sat_substr_oid;
894			code = SLAP_SCHERR_ATTR_BAD_MR;
895			goto error_return;
896		}
897
898		/* due to funky LDAP builtin substring rules,
899		 * we check against the equality rule assertion
900		 * syntax and compat syntaxes instead of those
901		 * associated with the substrings rule.
902		 */
903		if( sat->sat_syntax != sat->sat_equality->smr_syntax ) {
904			if( sat->sat_equality->smr_compat_syntaxes == NULL ) {
905				*err = sat->sat_substr_oid;
906				code = SLAP_SCHERR_ATTR_BAD_MR;
907				goto error_return;
908			}
909
910			for(i=0; sat->sat_equality->smr_compat_syntaxes[i]; i++) {
911				if( sat->sat_syntax ==
912					sat->sat_equality->smr_compat_syntaxes[i] )
913				{
914					i = -1;
915					break;
916				}
917			}
918
919			if( i >= 0 ) {
920				*err = sat->sat_substr_oid;
921				code = SLAP_SCHERR_ATTR_BAD_MR;
922				goto error_return;
923			}
924		}
925
926		sat->sat_substr = mr;
927	}
928
929	code = at_insert( &sat, prev, err );
930	if ( code != 0 ) {
931error_return:;
932		if ( sat ) {
933			ldap_pvt_thread_mutex_destroy( &sat->sat_ad_mutex );
934			ch_free( sat );
935		}
936
937		if ( oidm ) {
938			SLAP_FREE( at->at_oid );
939			at->at_oid = oidm;
940		}
941
942		if ( soidm ) {
943			SLAP_FREE( at->at_syntax_oid );
944			at->at_syntax_oid = soidm;
945		}
946
947	} else if ( rsat ) {
948		*rsat = sat;
949	}
950
951	return code;
952}
953
954#ifdef LDAP_DEBUG
955#ifdef SLAPD_UNUSED
956static int
957at_index_printnode( void *v_air, void *ignore )
958{
959	struct aindexrec *air = v_air;
960	printf("%s = %s\n",
961		air->air_name.bv_val,
962		ldap_attributetype2str(&air->air_at->sat_atype) );
963	return( 0 );
964}
965
966static void
967at_index_print( void )
968{
969	printf("Printing attribute type index:\n");
970	(void) avl_apply( attr_index, at_index_printnode, 0, -1, AVL_INORDER );
971}
972#endif
973#endif
974
975void
976at_unparse( BerVarray *res, AttributeType *start, AttributeType *end, int sys )
977{
978	AttributeType *at;
979	int i, num;
980	struct berval bv, *bva = NULL, idx;
981	char ibuf[32];
982
983	if ( !start )
984		start = LDAP_STAILQ_FIRST( &attr_list );
985
986	/* count the result size */
987	i = 0;
988	for ( at=start; at; at=LDAP_STAILQ_NEXT(at, sat_next)) {
989		if ( sys && !(at->sat_flags & SLAP_AT_HARDCODE)) break;
990		i++;
991		if ( at == end ) break;
992	}
993	if (!i) return;
994
995	num = i;
996	bva = ch_malloc( (num+1) * sizeof(struct berval) );
997	BER_BVZERO( bva );
998	idx.bv_val = ibuf;
999	if ( sys ) {
1000		idx.bv_len = 0;
1001		ibuf[0] = '\0';
1002	}
1003	i = 0;
1004	for ( at=start; at; at=LDAP_STAILQ_NEXT(at, sat_next)) {
1005		LDAPAttributeType lat, *latp;
1006		if ( sys && !(at->sat_flags & SLAP_AT_HARDCODE)) break;
1007		if ( at->sat_oidmacro || at->sat_soidmacro ) {
1008			lat = at->sat_atype;
1009			if ( at->sat_oidmacro )
1010				lat.at_oid = at->sat_oidmacro;
1011			if ( at->sat_soidmacro )
1012				lat.at_syntax_oid = at->sat_soidmacro;
1013			latp = &lat;
1014		} else {
1015			latp = &at->sat_atype;
1016		}
1017		if ( ldap_attributetype2bv( latp, &bv ) == NULL ) {
1018			ber_bvarray_free( bva );
1019		}
1020		if ( !sys ) {
1021			idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
1022		}
1023		bva[i].bv_len = idx.bv_len + bv.bv_len;
1024		bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
1025		strcpy( bva[i].bv_val, ibuf );
1026		strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
1027		i++;
1028		bva[i].bv_val = NULL;
1029		ldap_memfree( bv.bv_val );
1030		if ( at == end ) break;
1031	}
1032	*res = bva;
1033}
1034
1035int
1036at_schema_info( Entry *e )
1037{
1038	AttributeDescription *ad_attributeTypes = slap_schema.si_ad_attributeTypes;
1039	AttributeType	*at;
1040	struct berval	val;
1041	struct berval	nval;
1042
1043	LDAP_STAILQ_FOREACH(at,&attr_list,sat_next) {
1044		if( at->sat_flags & SLAP_AT_HIDE ) continue;
1045
1046		if ( ldap_attributetype2bv( &at->sat_atype, &val ) == NULL ) {
1047			return -1;
1048		}
1049
1050		ber_str2bv( at->sat_oid, 0, 0, &nval );
1051
1052		if( attr_merge_one( e, ad_attributeTypes, &val, &nval ) )
1053		{
1054			return -1;
1055		}
1056		ldap_memfree( val.bv_val );
1057	}
1058	return 0;
1059}
1060
1061int
1062register_at( const char *def, AttributeDescription **rad, int dupok )
1063{
1064	LDAPAttributeType *at;
1065	int code, freeit = 0;
1066	const char *err;
1067	AttributeDescription *ad = NULL;
1068
1069	at = ldap_str2attributetype( def, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
1070	if ( !at ) {
1071		Debug( LDAP_DEBUG_ANY,
1072			"register_at: AttributeType \"%s\": %s, %s\n",
1073				def, ldap_scherr2str(code), err );
1074		return code;
1075	}
1076
1077	code = at_add( at, 0, NULL, NULL, &err );
1078	if ( code ) {
1079		if ( code == SLAP_SCHERR_ATTR_DUP && dupok ) {
1080			freeit = 1;
1081
1082		} else {
1083			Debug( LDAP_DEBUG_ANY,
1084				"register_at: AttributeType \"%s\": %s, %s\n",
1085				def, scherr2str(code), err );
1086			ldap_attributetype_free( at );
1087			return code;
1088		}
1089	}
1090	code = slap_str2ad( at->at_names[0], &ad, &err );
1091	if ( freeit || code ) {
1092		ldap_attributetype_free( at );
1093	} else {
1094		ldap_memfree( at );
1095	}
1096	if ( code ) {
1097		Debug( LDAP_DEBUG_ANY, "register_at: AttributeType \"%s\": %s\n",
1098			def, err, 0 );
1099	}
1100	if ( rad ) *rad = ad;
1101	return code;
1102}
1103