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