ad.c 19.1 KB
Newer Older
1
2
/* $OpenLDAP$ */
/*
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
 * Copyright 1998-2003 The OpenLDAP Foundation, All Rights Reserved.
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
 */
/* ad.c - routines for dealing with attribute descriptions */

#include "portable.h"

#include <stdio.h>

#include <ac/ctype.h>
#include <ac/errno.h>
#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>

#include "ldap_pvt.h"
#include "slap.h"
Howard Chu's avatar
Howard Chu committed
20
#include "lutil.h"
21

22
23
24
25
26
27
28
29
30
31
32
33
34
typedef struct Attr_option {
	struct berval name;	/* option name or prefix */
	int           prefix;	/* NAME is a tag and range prefix */
} Attr_option;

static Attr_option lang_option = { { sizeof("lang-")-1, "lang-" }, 1 };

/* Options sorted by name, and number of options */
static Attr_option *options = &lang_option;
static int option_count = 1;

static Attr_option *ad_find_option_definition( const char *opt, int optlen );

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
static int ad_keystring(
	struct berval *bv )
{
	ber_len_t i;

	if( !AD_CHAR( bv->bv_val[0] ) ) {
		return 1;
	}

	for( i=1; i<bv->bv_len; i++ ) {
		if( !AD_CHAR( bv->bv_val[i] ) ) {
			return 1;
		}
	}
	return 0;
}

52
void ad_destroy( AttributeDescription *ad )
53
{
54
	AttributeDescription *n;
55

56
	for (; ad != NULL; ad = n) {
57
		n = ad->ad_next;
58
		ldap_memfree( ad );
59
60
61
	}
}

62
63
/* Is there an AttributeDescription for this type that uses these tags? */
AttributeDescription * ad_find_tags(
64
	AttributeType *type,
65
	struct berval *tags )
66
67
68
69
70
71
{
	AttributeDescription *ad;

	ldap_pvt_thread_mutex_lock( &type->sat_ad_mutex );
	for (ad = type->sat_ad; ad; ad=ad->ad_next)
	{
72
73
		if (ad->ad_tags.bv_len == tags->bv_len &&
			!strcasecmp(ad->ad_tags.bv_val, tags->bv_val))
74
75
76
77
78
79
			break;
	}
	ldap_pvt_thread_mutex_unlock( &type->sat_ad_mutex );
	return ad;
}

80
81
82
int slap_str2ad(
	const char *str,
	AttributeDescription **ad,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
83
	const char **text )
84
85
86
87
88
89
90
91
{
	struct berval bv;
	bv.bv_val = (char *) str;
	bv.bv_len = strlen( str );

	return slap_bv2ad( &bv, ad, text );
}

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
static char *strchrlen(
	const char *p, 
	const char ch, 
	int *len )
{
	int i;

	for( i=0; p[i]; i++ ) {
		if( p[i] == ch ) {
			*len = i;
			return (char *) &p[i];
		}
	}

	*len = i;
	return NULL;
}

110
111
112
int slap_bv2ad(
	struct berval *bv,
	AttributeDescription **ad,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
113
	const char **text )
114
115
{
	int rtn = LDAP_UNDEFINED_TYPE;
116
117
	AttributeDescription desc, *d2;
	char *name, *options;
118
	char *opt, *next;
119
120
	int ntags;
	int tagslen;
121
122

	/* hardcoded limits for speed */
123
124
125
126
#define MAX_TAGGING_OPTIONS 128
	struct berval tags[MAX_TAGGING_OPTIONS+1];
#define MAX_TAGS_LEN 1024
	char tagbuf[MAX_TAGS_LEN];
127

128
	assert( ad != NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
129
	assert( *ad == NULL ); /* temporary */
130
131
132

	if( bv == NULL || bv->bv_len == 0 ) {
		*text = "empty attribute description";
133
		return rtn;
134
135
136
	}

	/* make sure description is IA5 */
137
138
	if( ad_keystring( bv ) ) {
		*text = "attribute description contains inappropriate characters";
139
		return rtn;
140
141
	}

142
	/* find valid base attribute type; parse in place */
143
	memset( &desc, 0, sizeof( desc ));
144
	desc.ad_cname = *bv;
145
146
	name = bv->bv_val;
	options = strchr(name, ';');
147
	if( options != NULL ) {
148
		desc.ad_cname.bv_len = options - name;
149
	}
150
	desc.ad_type = at_bvfind( &desc.ad_cname );
151
152
	if( desc.ad_type == NULL ) {
		*text = "attribute type undefined";
153
		return rtn;
154
155
	}

156
157
158
159
160
	if( is_at_operational( desc.ad_type ) && options != NULL ) {
		*text = "operational attribute with options undefined";
		return rtn;
	}

161
162
163
	/*
	 * parse options in place
	 */
164
165
166
	ntags = 0;
	memset( tags, 0, sizeof( tags ));
	tagslen = 0;
167
168
169
170
171
172
173
174
175
176
177
178
179
180

	for( opt=options; opt != NULL; opt=next ) {
		int optlen;
		opt++; 
		next = strchrlen( opt, ';', &optlen );

		if( optlen == 0 ) {
			*text = "zero length option is invalid";
			return rtn;
		
		} else if ( optlen == sizeof("binary")-1 &&
			strncasecmp( opt, "binary", sizeof("binary")-1 ) == 0 )
		{
			/* binary option */
181
			if( slap_ad_is_binary( &desc ) ) {
182
				*text = "option \"binary\" specified multiple times";
183
				return rtn;
184
185
			}

186
			if( !slap_syntax_is_binary( desc.ad_type->sat_syntax )) {
187
				/* not stored in binary, disallow option */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
188
				*text = "option \"binary\" not supported with type";
189
				return rtn;
190
191
192
			}

			desc.ad_flags |= SLAP_DESC_BINARY;
193
			continue;
194

Kurt Zeilenga's avatar
Kurt Zeilenga committed
195
		} else if ( ad_find_option_definition( opt, optlen ) ) {
196
197
198
			int i;

			if( opt[optlen-1] == '-' ) {
199
				desc.ad_flags |= SLAP_DESC_TAG_RANGE;
200
			}
201

202
			if( ntags >= MAX_TAGGING_OPTIONS ) {
203
				*text = "too many tagging options";
204
205
206
207
208
209
210
				return rtn;
			}

			/*
			 * tags should be presented in sorted order,
			 * so run the array in reverse.
			 */
211
			for( i=ntags-1; i>=0; i-- ) {
212
213
				int rc;

214
215
216
				rc = strncasecmp( opt, tags[i].bv_val,
					(unsigned) optlen < tags[i].bv_len
						? optlen : tags[i].bv_len );
217

218
				if( rc == 0 && (unsigned)optlen == tags[i].bv_len ) {
219
220
221
222
					/* duplicate (ignore) */
					goto done;

				} else if ( rc > 0 ||
223
					( rc == 0 && (unsigned)optlen > tags[i].bv_len ))
224
				{
225
226
227
228
					AC_MEMCPY( &tags[i+1], &tags[i],
						(ntags-i)*sizeof(struct berval) );
					tags[i].bv_val = opt;
					tags[i].bv_len = optlen;
229
230
231
232
					goto done;
				}
			}

233
234
235
			if( ntags ) {
				AC_MEMCPY( &tags[1], &tags[0],
					ntags*sizeof(struct berval) );
236
			}
237
238
			tags[0].bv_val = opt;
			tags[0].bv_len = optlen;
239
240

done:;
241
242
			tagslen += optlen + 1;
			ntags++;
243

244
245
		} else {
			*text = "unrecognized option";
246
247
248
249
			return rtn;
		}
	}

250
	if( ntags > 0 ) {
251
252
		int i;

253
		if( tagslen > MAX_TAGS_LEN ) {
254
			*text = "tagging options too long";
255
256
257
			return rtn;
		}

258
259
		desc.ad_tags.bv_val = tagbuf;
		tagslen = 0;
260

261
262
263
		for( i=0; i<ntags; i++ ) {
			AC_MEMCPY( &desc.ad_tags.bv_val[tagslen],
				tags[i].bv_val, tags[i].bv_len );
264

265
266
			tagslen += tags[i].bv_len;
			desc.ad_tags.bv_val[tagslen++] = ';';
267
		}
268

269
270
		desc.ad_tags.bv_val[--tagslen] = '\0';
		desc.ad_tags.bv_len = tagslen;
271
272
	}

273
274
	/* see if a matching description is already cached */
	for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
275
		if( d2->ad_flags != desc.ad_flags ) {
276
			continue;
277
		}
278
		if( d2->ad_tags.bv_len != desc.ad_tags.bv_len ) {
279
			continue;
280
		}
281
		if( d2->ad_tags.bv_len == 0 ) {
282
			break;
283
		}
284
285
		if( strncasecmp( d2->ad_tags.bv_val, desc.ad_tags.bv_val,
			desc.ad_tags.bv_len ) == 0 )
286
		{
287
			break;
288
		}
289
290
	}

291
292
	/* Not found, add new one */
	while (d2 == NULL) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
293
		size_t dlen = 0;
Howard Chu's avatar
Howard Chu committed
294
295
296
297
298
		ldap_pvt_thread_mutex_lock( &desc.ad_type->sat_ad_mutex );
		/* check again now that we've locked */
		for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
			if (d2->ad_flags != desc.ad_flags)
				continue;
299
			if (d2->ad_tags.bv_len != desc.ad_tags.bv_len)
Howard Chu's avatar
Howard Chu committed
300
				continue;
301
			if (d2->ad_tags.bv_len == 0)
Howard Chu's avatar
Howard Chu committed
302
				break;
303
304
			if (strncasecmp(d2->ad_tags.bv_val, desc.ad_tags.bv_val,
				desc.ad_tags.bv_len) == 0)
Howard Chu's avatar
Howard Chu committed
305
306
307
308
309
310
				break;
		}
		if (d2) {
			ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex );
			break;
		}
311

312
313
314
		/* Allocate a single contiguous block. If there are no
		 * options, we just need space for the AttrDesc structure.
		 * Otherwise, we need to tack on the full name length +
315
		 * options length, + maybe tagging options length again.
316
		 */
317
		if (desc.ad_tags.bv_len || desc.ad_flags != SLAP_DESC_NONE) {
318
			dlen = desc.ad_type->sat_cname.bv_len + 1;
319
320
			if (desc.ad_tags.bv_len) {
				dlen += 1+desc.ad_tags.bv_len;
321
			}
322
			if( slap_ad_is_binary( &desc ) ) {
323
				dlen += sizeof(";binary")+desc.ad_tags.bv_len;
324
325
			}
		}
326

327
		d2 = ch_malloc(sizeof(AttributeDescription) + dlen);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
328
		d2->ad_next = NULL;
329
330
		d2->ad_type = desc.ad_type;
		d2->ad_flags = desc.ad_flags;
331
		d2->ad_cname.bv_len = desc.ad_type->sat_cname.bv_len;
332
		d2->ad_tags.bv_len = desc.ad_tags.bv_len;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
333

334
		if (dlen == 0) {
335
			d2->ad_cname.bv_val = d2->ad_type->sat_cname.bv_val;
336
			d2->ad_tags.bv_val = NULL;
337
		} else {
338
339
			char *cp, *op, *lp;
			int j;
340
			d2->ad_cname.bv_val = (char *)(d2+1);
341
			strcpy(d2->ad_cname.bv_val, d2->ad_type->sat_cname.bv_val);
342
			cp = d2->ad_cname.bv_val + d2->ad_cname.bv_len;
343
			if( slap_ad_is_binary( &desc ) ) {
344
345
				op = cp;
				lp = NULL;
346
347
				if( desc.ad_tags.bv_len ) {
					lp = desc.ad_tags.bv_val;
348
349
350
					while( strncasecmp(lp, "binary", sizeof("binary")-1) < 0
					       && (lp = strchr( lp, ';' )) != NULL )
						++lp;
351
					if( lp != desc.ad_tags.bv_val ) {
352
353
						*cp++ = ';';
						j = (lp
354
355
						     ? lp - desc.ad_tags.bv_val - 1
						     : strlen( desc.ad_tags.bv_val ));
Howard Chu's avatar
Howard Chu committed
356
						cp = lutil_strncopy(cp, desc.ad_tags.bv_val, j);
357
358
					}
				}
Howard Chu's avatar
Howard Chu committed
359
				cp = lutil_strcopy(cp, ";binary");
360
361
				if( lp != NULL ) {
					*cp++ = ';';
Howard Chu's avatar
Howard Chu committed
362
					cp = lutil_strcopy(cp, lp);
363
364
				}
				d2->ad_cname.bv_len = cp - d2->ad_cname.bv_val;
365
				if( desc.ad_tags.bv_len )
366
367
368
369
					ldap_pvt_str2lower(op);
				j = 1;
			} else {
				j = 0;
370
			}
371
			if( desc.ad_tags.bv_len ) {
372
373
374
				lp = d2->ad_cname.bv_val + d2->ad_cname.bv_len + j;
				if ( j == 0 )
					*lp++ = ';';
375
376
				d2->ad_tags.bv_val = lp;
				strcpy(lp, desc.ad_tags.bv_val);
377
378
				ldap_pvt_str2lower(lp);
				if( j == 0 )
379
					d2->ad_cname.bv_len += 1 + desc.ad_tags.bv_len;
380
381
382
383
384
385
386
387
388
389
390
391
392
			}
		}
		/* Add new desc to list. We always want the bare Desc with
		 * no options to stay at the head of the list, assuming
		 * that one will be used most frequently.
		 */
		if (desc.ad_type->sat_ad == NULL || dlen == 0) {
			d2->ad_next = desc.ad_type->sat_ad;
			desc.ad_type->sat_ad = d2;
		} else {
			d2->ad_next = desc.ad_type->sat_ad->ad_next;
			desc.ad_type->sat_ad->ad_next = d2;
		}
Howard Chu's avatar
Howard Chu committed
393
		ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex );
394
395
	}

396
	if( *ad == NULL ) {
397
398
399
		*ad = d2;
	} else {
		**ad = *d2;
400
401
	}

402
403
404
	return LDAP_SUCCESS;
}

405
406
407
static int is_ad_subtags(
	struct berval *subtagsbv, 
	struct berval *suptagsbv )
408
{
409
410
	const char *suptags, *supp, *supdelimp;
	const char *subtags, *subp, *subdelimp;
411
412
	int  suplen, sublen;

413
414
	if( suptagsbv->bv_len == 0 ) return 1;
	if( subtagsbv->bv_len == 0 ) return 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
415

416
417
	subtags =subtagsbv->bv_val;
	suptags =suptagsbv->bv_val;
418

419
	for( supp=suptags ; supp; supp=supdelimp ) {
420
421
422
		supdelimp = strchrlen( supp, ';', &suplen );
		if( supdelimp ) supdelimp++;

423
		for( subp=subtags ; subp; subp=subdelimp ) {
424
425
426
			subdelimp = strchrlen( subp, ';', &sublen );
			if( subdelimp ) subdelimp++;

427
428
429
430
431
			if ( suplen > sublen
				 ? ( suplen-1 == sublen && supp[suplen-1] == '-'
					 && strncmp( supp, subp, sublen ) == 0 )
				 : ( ( suplen == sublen || supp[suplen-1] == '-' )
					 && strncmp( supp, subp, suplen ) == 0 ) )
432
433
434
435
			{
				goto match;
			}
		}
436

437
438
439
440
		return 0;
match:;
	}
	return 1;
441
442
}

443
444
445
446
447
int is_ad_subtype(
	AttributeDescription *sub,
	AttributeDescription *super
)
{
448
449
	int lr;

450
451
452
453
	if( !is_at_subtype( sub->ad_type, super->ad_type ) ) {
		return 0;
	}

454
	/* ensure sub does support all flags of super */
455
	lr = sub->ad_tags.bv_len ? SLAP_DESC_TAG_RANGE : 0;
456
	if(( super->ad_flags & ( sub->ad_flags | lr )) != super->ad_flags ) {
457
458
459
		return 0;
	}

460
461
	/* check for tagging options */
	if ( !is_ad_subtags( &sub->ad_tags, &super->ad_tags )) {
462
463
464
465
466
467
		return 0;
	}

	return 1;
}

468
469
int ad_inlist(
	AttributeDescription *desc,
470
	AttributeName *attrs )
471
{
472
473
474
	if (! attrs ) return 0;

	for( ; attrs->an_name.bv_val; attrs++ ) {
475
		ObjectClass *oc;
476
477
		int rc;
		
478
		if ( attrs->an_desc ) {
479
			if ( desc == attrs->an_desc ) {
480
				return 1;
481
482
483
484
485
486
487
488
489
490
491
492
			}

			/*
			 * EXTENSION: if requested description is preceeded by an
			 * a '-' character, do not match on subtypes.
			 */
			if ( attrs->an_name.bv_val[0] != '-' &&
				is_ad_subtype( desc, attrs->an_desc ))
			{
				return 1;
			}

493
494
			continue;
		}
495

496
		/*
497
		 * EXTENSION: see if requested description is +objectClass
498
499
		 * if so, return attributes which the class requires/allows
		 */
500
		oc = attrs->an_oc;
501
502
		if( oc == NULL && attrs->an_name.bv_val ) {
			switch( attrs->an_name.bv_val[0] ) {
503
			case '+': { /* new way */
504
505
506
507
508
					struct berval ocname;
					ocname.bv_len = attrs->an_name.bv_len - 1;
					ocname.bv_val = &attrs->an_name.bv_val[1];
					oc = oc_bvfind( &ocname );
				} break;
509
510
			default: /* old (deprecated) way */
				oc = oc_bvfind( &attrs->an_name );
511
			}
512
513
			attrs->an_oc = oc;
		}
514
515
516
517
518
		if( oc != NULL ) {
			if ( oc == slap_schema.si_oc_extensibleObject ) {
				/* extensibleObject allows the return of anything */
				return 1;
			}
519

520
521
522
523
524
			if( oc->soc_required ) {
				/* allow return of required attributes */
				int i;
   				for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
					rc = is_at_subtype( desc->ad_type,
525
						oc->soc_required[i] );
526
527
528
					if( rc ) return 1;
				}
			}
529

530
531
532
533
534
535
536
537
538
			if( oc->soc_allowed ) {
				/* allow return of allowed attributes */
				int i;
   				for ( i = 0; oc->soc_allowed[i] != NULL; i++ ) {
					rc = is_at_subtype( desc->ad_type,
						oc->soc_allowed[i] );
					if( rc ) return 1;
				}
			}
539

Howard Chu's avatar
Howard Chu committed
540
541
542
543
544
545
546
547
548
549
		} else {
			/* short-circuit this search next time around */
			if (!slap_schema.si_at_undefined->sat_ad) {
				const char *text;
				slap_bv2undef_ad(&attrs->an_name,
					&attrs->an_desc, &text);
			} else {
				attrs->an_desc =
					slap_schema.si_at_undefined->sat_ad;
			}
550
		}
551
552
553
	}

	return 0;
554
555
556
}


557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
int slap_str2undef_ad(
	const char *str,
	AttributeDescription **ad,
	const char **text )
{
	struct berval bv;
	bv.bv_val = (char *) str;
	bv.bv_len = strlen( str );

	return slap_bv2undef_ad( &bv, ad, text );
}

int slap_bv2undef_ad(
	struct berval *bv,
	AttributeDescription **ad,
	const char **text )
{
574
	AttributeDescription *desc;
575
576
577
578
579
580
581
582
583
584
585
586
587
588

	assert( ad != NULL );

	if( bv == NULL || bv->bv_len == 0 ) {
		*text = "empty attribute description";
		return LDAP_UNDEFINED_TYPE;
	}

	/* make sure description is IA5 */
	if( ad_keystring( bv ) ) {
		*text = "attribute description contains inappropriate characters";
		return LDAP_UNDEFINED_TYPE;
	}

589
590
591
592
593
594
	for( desc = slap_schema.si_at_undefined->sat_ad; desc;
		desc=desc->ad_next ) 
	{
		if( desc->ad_cname.bv_len == bv->bv_len &&
		    !strcasecmp( desc->ad_cname.bv_val, bv->bv_val ))
		{
595
		    	break;
596
597
		}
	}
598
	
599
	if( !desc ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
600
601
		desc = ch_malloc(sizeof(AttributeDescription) + 1 +
			bv->bv_len);
602
603
		
		desc->ad_flags = SLAP_DESC_NONE;
604
605
		desc->ad_tags.bv_val = NULL;
		desc->ad_tags.bv_len = 0;
606

607
608
609
		desc->ad_cname.bv_len = bv->bv_len;
		desc->ad_cname.bv_val = (char *)(desc+1);
		strcpy(desc->ad_cname.bv_val, bv->bv_val);
610

611
612
		/* canonical to upper case */
		ldap_pvt_str2upper( desc->ad_cname.bv_val );
613

614
615
616
		desc->ad_type = slap_schema.si_at_undefined;
		desc->ad_next = desc->ad_type->sat_ad;
		desc->ad_type->sat_ad = desc;
617
618
	}

619
	if( !*ad ) {
620
		*ad = desc;
621
	} else {
622
		**ad = *desc;
623
	}
624
625
626

	return LDAP_SUCCESS;
}
627
628
629
630
631
632
633
634
635

int
an_find(
    AttributeName *a,
    struct berval *s
)
{
	if( a == NULL ) return 0;

636
	for ( ; a->an_name.bv_val; a++ ) {
637
638
639
640
641
642
643
644
645
		if ( a->an_name.bv_len != s->bv_len) continue;
		if ( strcasecmp( s->bv_val, a->an_name.bv_val ) == 0 ) {
			return( 1 );
		}
	}

	return( 0 );
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
646
647
648
649
650
651
652
653
654
655
/*
 * Convert a delimited string into a list of AttributeNames; 
 * add on to an existing list if it was given.  If the string
 * is not a valid attribute name, if a '-' is prepended it is 
 * skipped and the remaining name is tried again; if a '+' is
 * prepended, an objectclass name is searched instead.
 * 
 * NOTE: currently, if a valid attribute name is not found,
 * the same string is also checked as valid objectclass name;
 * however, this behavior is deprecated.
656
657
 */
AttributeName *
658
str2anlist( AttributeName *an, char *in, const char *brkstr )
659
660
661
662
{
	char	*str;
	char	*s;
	char	*lasts;
663
	int	i, j;
664
	const char *text;
665
	AttributeName *anew;
666

667
668
669
	/* find last element in list */
	for (i = 0; an && an[i].an_name.bv_val; i++);
	
670
671
672
	/* protect the input string from strtok */
	str = ch_strdup( in );

673
674
675
676
677
678
679
680
681
682
	/* Count words in string */
	j=1;
	for ( s = str; *s; s++ ) {
		if ( strchr( brkstr, *s ) != NULL ) {
			j++;
		}
	}

	an = ch_realloc( an, ( i + j + 1 ) * sizeof( AttributeName ) );
	anew = an + i;
683
684
685
686
687
	for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
		s != NULL;
		s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
	{
		anew->an_desc = NULL;
688
		anew->an_oc = NULL;
689
690
		ber_str2bv(s, 0, 1, &anew->an_name);
		slap_bv2ad(&anew->an_name, &anew->an_desc, &text);
691
		if ( !anew->an_desc ) {
692
693
694
695
696
697
698
699
			switch( anew->an_name.bv_val[0] ) {
			case '-': {
					struct berval adname;
					adname.bv_len = anew->an_name.bv_len - 1;
					adname.bv_val = &anew->an_name.bv_val[1];
					slap_bv2ad(&adname, &anew->an_desc, &text);
					if ( !anew->an_desc ) {
						free( an );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
700
701
702
703
						/*
						 * overwrites input string
						 * on error!
						 */
704
705
706
707
						strcpy( in, s );
						return NULL;
					}
				} break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
708

709
710
711
712
713
714
715
			case '+': {
					struct berval ocname;
					ocname.bv_len = anew->an_name.bv_len - 1;
					ocname.bv_val = &anew->an_name.bv_val[1];
					anew->an_oc = oc_bvfind( &ocname );
					if ( !anew->an_oc ) {
						free( an );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
716
717
718
719
						/*
						 * overwrites input string
						 * on error!
						 */
720
721
722
723
						strcpy( in, s );
						return NULL;
					}
				} break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
724

725
726
727
728
729
730
731
732
733
			default:
				/* old (deprecated) way */
				anew->an_oc = oc_bvfind( &anew->an_name );
				if ( !anew->an_oc ) {
					free( an );
					/* overwrites input string on error! */
					strcpy( in, s );
					return NULL;
				}
734
735
			}
		}
736
		anew++;
737
738
	}

739
	anew->an_name.bv_val = NULL;
740
741
742
	free( str );
	return( an );
}
743

744
745
746
747
748

/* Define an attribute option. */
int
ad_define_option( const char *name, const char *fname, int lineno )
{
749
750
	int i;
	unsigned int optlen;
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775

	if ( options == &lang_option ) {
		options = NULL;
		option_count = 0;
	}
	if ( name == NULL )
		return 0;

	optlen = 0;
	do {
		if ( !DESC_CHAR( name[optlen] ) ) {
#ifdef NEW_LOGGING
			LDAP_LOG( CONFIG, CRIT,
			          "%s: line %d: illegal option name \"%s\"\n",
			          fname, lineno, name );
#else
			Debug( LDAP_DEBUG_ANY,
			       "%s: line %d: illegal option name \"%s\"\n",
				    fname, lineno, name );
#endif
			return 1;
		}
	} while ( name[++optlen] );

	options = ch_realloc( options,
776
		(option_count+1) * sizeof(Attr_option) );
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845

	if ( strcasecmp( name, "binary" ) == 0
	     || ad_find_option_definition( name, optlen ) ) {
#ifdef NEW_LOGGING
		LDAP_LOG( CONFIG, CRIT,
		          "%s: line %d: option \"%s\" is already defined\n",
		          fname, lineno, name );
#else
		Debug( LDAP_DEBUG_ANY,
		       "%s: line %d: option \"%s\" is already defined\n",
		       fname, lineno, name );
#endif
		return 1;
	}

	for ( i = option_count; i; --i ) {
		if ( strcasecmp( name, options[i-1].name.bv_val ) >= 0 )
			break;
		options[i] = options[i-1];
	}

	options[i].name.bv_val = ch_strdup( name );
	options[i].name.bv_len = optlen;
	options[i].prefix = (name[optlen-1] == '-');

	if ( i != option_count &&
	     options[i].prefix &&
	     optlen < options[i+1].name.bv_len &&
	     strncasecmp( name, options[i+1].name.bv_val, optlen ) == 0 ) {
#ifdef NEW_LOGGING
			LDAP_LOG( CONFIG, CRIT,
			          "%s: line %d: option \"%s\" overrides previous option\n",
			          fname, lineno, name );
#else
			Debug( LDAP_DEBUG_ANY,
			       "%s: line %d: option \"%s\" overrides previous option\n",
				    fname, lineno, name );
#endif
			return 1;
	}

	option_count++;
	return 0;
}

/* Find the definition of the option name or prefix matching the arguments */
static Attr_option *
ad_find_option_definition( const char *opt, int optlen )
{
	int top = 0, bot = option_count;
	while ( top < bot ) {
		int mid = (top + bot) / 2;
		int mlen = options[mid].name.bv_len;
		char *mname = options[mid].name.bv_val;
		int j;
		if ( optlen < mlen ) {
			j = strncasecmp( opt, mname, optlen ) - 1;
		} else {
			j = strncasecmp( opt, mname, mlen );
			if ( j==0 && (optlen==mlen || options[mid].prefix) )
				return &options[mid];
		}
		if ( j < 0 )
			bot = mid;
		else
			top = mid + 1;
	}
	return NULL;
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867

MatchingRule *ad_mr(
	AttributeDescription *ad,
	unsigned usage )
{
	switch( usage & SLAP_MR_TYPE_MASK ) {
	case SLAP_MR_NONE:
	case SLAP_MR_EQUALITY:
		return ad->ad_type->sat_equality;
		break;
	case SLAP_MR_ORDERING:
		return ad->ad_type->sat_ordering;
		break;
	case SLAP_MR_SUBSTR:
		return ad->ad_type->sat_substr;
		break;
	case SLAP_MR_EXT:
	default:
		assert( 0 /* ad_mr: bad usage */);
	}
	return NULL;
}