~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to servers/slapd/ad.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ad.c - routines for dealing with attribute descriptions */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/ad.c,v 1.95.2.4 2008/02/11 23:26:43 kurt Exp $ */
 
3
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 
4
 *
 
5
 * Copyright 1998-2008 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
#include "lutil.h"
 
29
 
 
30
static AttributeName anlist_no_attrs[] = {
 
31
        { BER_BVC( LDAP_NO_ATTRS ), NULL, 0, NULL },
 
32
        { BER_BVNULL, NULL, 0, NULL }
 
33
};
 
34
 
 
35
static AttributeName anlist_all_user_attributes[] = {
 
36
        { BER_BVC( LDAP_ALL_USER_ATTRIBUTES ), NULL, 0, NULL },
 
37
        { BER_BVNULL, NULL, 0, NULL }
 
38
};
 
39
 
 
40
static AttributeName anlist_all_operational_attributes[] = {
 
41
        { BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ), NULL, 0, NULL },
 
42
        { BER_BVNULL, NULL, 0, NULL }
 
43
};
 
44
 
 
45
static AttributeName anlist_all_attributes[] = {
 
46
        { BER_BVC( LDAP_ALL_USER_ATTRIBUTES ), NULL, 0, NULL },
 
47
        { BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ), NULL, 0, NULL },
 
48
        { BER_BVNULL, NULL, 0, NULL }
 
49
};
 
50
 
 
51
AttributeName *slap_anlist_no_attrs = anlist_no_attrs;
 
52
AttributeName *slap_anlist_all_user_attributes = anlist_all_user_attributes;
 
53
AttributeName *slap_anlist_all_operational_attributes = anlist_all_operational_attributes;
 
54
AttributeName *slap_anlist_all_attributes = anlist_all_attributes;
 
55
 
 
56
typedef struct Attr_option {
 
57
        struct berval name;     /* option name or prefix */
 
58
        int           prefix;   /* NAME is a tag and range prefix */
 
59
} Attr_option;
 
60
 
 
61
static Attr_option lang_option = { BER_BVC("lang-"), 1 };
 
62
 
 
63
/* Options sorted by name, and number of options */
 
64
static Attr_option *options = &lang_option;
 
65
static int option_count = 1;
 
66
 
 
67
static Attr_option *ad_find_option_definition( const char *opt, int optlen );
 
68
 
 
69
static int ad_keystring(
 
70
        struct berval *bv )
 
71
{
 
72
        ber_len_t i;
 
73
 
 
74
        if( !AD_LEADCHAR( bv->bv_val[0] ) ) {
 
75
                return 1;
 
76
        }
 
77
 
 
78
        for( i=1; i<bv->bv_len; i++ ) {
 
79
                if( !AD_CHAR( bv->bv_val[i] ) ) {
 
80
                        return 1;
 
81
                }
 
82
        }
 
83
        return 0;
 
84
}
 
85
 
 
86
void ad_destroy( AttributeDescription *ad )
 
87
{
 
88
        AttributeDescription *n;
 
89
 
 
90
        for (; ad != NULL; ad = n) {
 
91
                n = ad->ad_next;
 
92
                ldap_memfree( ad );
 
93
        }
 
94
}
 
95
 
 
96
/* Is there an AttributeDescription for this type that uses these tags? */
 
97
AttributeDescription * ad_find_tags(
 
98
        AttributeType *type,
 
99
        struct berval *tags )
 
100
{
 
101
        AttributeDescription *ad;
 
102
 
 
103
        ldap_pvt_thread_mutex_lock( &type->sat_ad_mutex );
 
104
        for (ad = type->sat_ad; ad; ad=ad->ad_next)
 
105
        {
 
106
                if (ad->ad_tags.bv_len == tags->bv_len &&
 
107
                        !strcasecmp(ad->ad_tags.bv_val, tags->bv_val))
 
108
                        break;
 
109
        }
 
110
        ldap_pvt_thread_mutex_unlock( &type->sat_ad_mutex );
 
111
        return ad;
 
112
}
 
113
 
 
114
int slap_str2ad(
 
115
        const char *str,
 
116
        AttributeDescription **ad,
 
117
        const char **text )
 
118
{
 
119
        struct berval bv;
 
120
        bv.bv_val = (char *) str;
 
121
        bv.bv_len = strlen( str );
 
122
 
 
123
        return slap_bv2ad( &bv, ad, text );
 
124
}
 
125
 
 
126
static char *strchrlen(
 
127
        const char *beg, 
 
128
        const char *end,
 
129
        const char ch, 
 
130
        int *len )
 
131
{
 
132
        const char *p;
 
133
 
 
134
        for( p=beg; *p && p < end; p++ ) {
 
135
                if( *p == ch ) {
 
136
                        *len = p - beg;
 
137
                        return (char *) p;
 
138
                }
 
139
        }
 
140
 
 
141
        *len = p - beg;
 
142
        return NULL;
 
143
}
 
144
 
 
145
int slap_bv2ad(
 
146
        struct berval *bv,
 
147
        AttributeDescription **ad,
 
148
        const char **text )
 
149
{
 
150
        int rtn = LDAP_UNDEFINED_TYPE;
 
151
        AttributeDescription desc, *d2;
 
152
        char *name, *options, *optn;
 
153
        char *opt, *next;
 
154
        int ntags;
 
155
        int tagslen;
 
156
 
 
157
        /* hardcoded limits for speed */
 
158
#define MAX_TAGGING_OPTIONS 128
 
159
        struct berval tags[MAX_TAGGING_OPTIONS+1];
 
160
#define MAX_TAGS_LEN 1024
 
161
        char tagbuf[MAX_TAGS_LEN];
 
162
 
 
163
        assert( ad != NULL );
 
164
        assert( *ad == NULL ); /* temporary */
 
165
 
 
166
        if( bv == NULL || BER_BVISNULL( bv ) || BER_BVISEMPTY( bv ) ) {
 
167
                *text = "empty AttributeDescription";
 
168
                return rtn;
 
169
        }
 
170
 
 
171
        /* make sure description is IA5 */
 
172
        if( ad_keystring( bv ) ) {
 
173
                *text = "AttributeDescription contains inappropriate characters";
 
174
                return rtn;
 
175
        }
 
176
 
 
177
        /* find valid base attribute type; parse in place */
 
178
        desc.ad_cname = *bv;
 
179
        desc.ad_flags = 0;
 
180
        BER_BVZERO( &desc.ad_tags );
 
181
        name = bv->bv_val;
 
182
        options = ber_bvchr( bv, ';' );
 
183
        if ( options != NULL && (unsigned) ( options - name ) < bv->bv_len ) {
 
184
                /* don't go past the end of the berval! */
 
185
                desc.ad_cname.bv_len = options - name;
 
186
        } else {
 
187
                options = NULL;
 
188
        }
 
189
        desc.ad_type = at_bvfind( &desc.ad_cname );
 
190
        if( desc.ad_type == NULL ) {
 
191
                *text = "attribute type undefined";
 
192
                return rtn;
 
193
        }
 
194
 
 
195
        if( is_at_operational( desc.ad_type ) && options != NULL ) {
 
196
                *text = "operational attribute with options undefined";
 
197
                return rtn;
 
198
        }
 
199
 
 
200
        /*
 
201
         * parse options in place
 
202
         */
 
203
        ntags = 0;
 
204
        tagslen = 0;
 
205
        optn = bv->bv_val + bv->bv_len;
 
206
 
 
207
        for( opt=options; opt != NULL; opt=next ) {
 
208
                int optlen;
 
209
                opt++; 
 
210
                next = strchrlen( opt, optn, ';', &optlen );
 
211
 
 
212
                if( optlen == 0 ) {
 
213
                        *text = "zero length option is invalid";
 
214
                        return rtn;
 
215
                
 
216
                } else if ( optlen == STRLENOF("binary") &&
 
217
                        strncasecmp( opt, "binary", STRLENOF("binary") ) == 0 )
 
218
                {
 
219
                        /* binary option */
 
220
                        if( slap_ad_is_binary( &desc ) ) {
 
221
                                *text = "option \"binary\" specified multiple times";
 
222
                                return rtn;
 
223
                        }
 
224
 
 
225
                        if( !slap_syntax_is_binary( desc.ad_type->sat_syntax )) {
 
226
                                /* not stored in binary, disallow option */
 
227
                                *text = "option \"binary\" not supported with type";
 
228
                                return rtn;
 
229
                        }
 
230
 
 
231
                        desc.ad_flags |= SLAP_DESC_BINARY;
 
232
                        continue;
 
233
 
 
234
                } else if ( ad_find_option_definition( opt, optlen ) ) {
 
235
                        int i;
 
236
 
 
237
                        if( opt[optlen-1] == '-' ) {
 
238
                                desc.ad_flags |= SLAP_DESC_TAG_RANGE;
 
239
                        }
 
240
 
 
241
                        if( ntags >= MAX_TAGGING_OPTIONS ) {
 
242
                                *text = "too many tagging options";
 
243
                                return rtn;
 
244
                        }
 
245
 
 
246
                        /*
 
247
                         * tags should be presented in sorted order,
 
248
                         * so run the array in reverse.
 
249
                         */
 
250
                        for( i=ntags-1; i>=0; i-- ) {
 
251
                                int rc;
 
252
 
 
253
                                rc = strncasecmp( opt, tags[i].bv_val,
 
254
                                        (unsigned) optlen < tags[i].bv_len
 
255
                                                ? (unsigned) optlen : tags[i].bv_len );
 
256
 
 
257
                                if( rc == 0 && (unsigned)optlen == tags[i].bv_len ) {
 
258
                                        /* duplicate (ignore) */
 
259
                                        goto done;
 
260
 
 
261
                                } else if ( rc > 0 ||
 
262
                                        ( rc == 0 && (unsigned)optlen > tags[i].bv_len ))
 
263
                                {
 
264
                                        AC_MEMCPY( &tags[i+2], &tags[i+1],
 
265
                                                (ntags-i-1)*sizeof(struct berval) );
 
266
                                        tags[i+1].bv_val = opt;
 
267
                                        tags[i+1].bv_len = optlen;
 
268
                                        goto done;
 
269
                                }
 
270
                        }
 
271
 
 
272
                        if( ntags ) {
 
273
                                AC_MEMCPY( &tags[1], &tags[0],
 
274
                                        ntags*sizeof(struct berval) );
 
275
                        }
 
276
                        tags[0].bv_val = opt;
 
277
                        tags[0].bv_len = optlen;
 
278
 
 
279
done:;
 
280
                        tagslen += optlen + 1;
 
281
                        ntags++;
 
282
 
 
283
                } else {
 
284
                        *text = "unrecognized option";
 
285
                        return rtn;
 
286
                }
 
287
        }
 
288
 
 
289
        if( ntags > 0 ) {
 
290
                int i;
 
291
 
 
292
                if( tagslen > MAX_TAGS_LEN ) {
 
293
                        *text = "tagging options too long";
 
294
                        return rtn;
 
295
                }
 
296
 
 
297
                desc.ad_tags.bv_val = tagbuf;
 
298
                tagslen = 0;
 
299
 
 
300
                for( i=0; i<ntags; i++ ) {
 
301
                        AC_MEMCPY( &desc.ad_tags.bv_val[tagslen],
 
302
                                tags[i].bv_val, tags[i].bv_len );
 
303
 
 
304
                        tagslen += tags[i].bv_len;
 
305
                        desc.ad_tags.bv_val[tagslen++] = ';';
 
306
                }
 
307
 
 
308
                desc.ad_tags.bv_val[--tagslen] = '\0';
 
309
                desc.ad_tags.bv_len = tagslen;
 
310
        }
 
311
 
 
312
        /* see if a matching description is already cached */
 
313
        for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
 
314
                if( d2->ad_flags != desc.ad_flags ) {
 
315
                        continue;
 
316
                }
 
317
                if( d2->ad_tags.bv_len != desc.ad_tags.bv_len ) {
 
318
                        continue;
 
319
                }
 
320
                if( d2->ad_tags.bv_len == 0 ) {
 
321
                        break;
 
322
                }
 
323
                if( strncasecmp( d2->ad_tags.bv_val, desc.ad_tags.bv_val,
 
324
                        desc.ad_tags.bv_len ) == 0 )
 
325
                {
 
326
                        break;
 
327
                }
 
328
        }
 
329
 
 
330
        /* Not found, add new one */
 
331
        while (d2 == NULL) {
 
332
                size_t dlen = 0;
 
333
                ldap_pvt_thread_mutex_lock( &desc.ad_type->sat_ad_mutex );
 
334
                /* check again now that we've locked */
 
335
                for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
 
336
                        if (d2->ad_flags != desc.ad_flags)
 
337
                                continue;
 
338
                        if (d2->ad_tags.bv_len != desc.ad_tags.bv_len)
 
339
                                continue;
 
340
                        if (d2->ad_tags.bv_len == 0)
 
341
                                break;
 
342
                        if (strncasecmp(d2->ad_tags.bv_val, desc.ad_tags.bv_val,
 
343
                                desc.ad_tags.bv_len) == 0)
 
344
                                break;
 
345
                }
 
346
                if (d2) {
 
347
                        ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex );
 
348
                        break;
 
349
                }
 
350
 
 
351
                /* Allocate a single contiguous block. If there are no
 
352
                 * options, we just need space for the AttrDesc structure.
 
353
                 * Otherwise, we need to tack on the full name length +
 
354
                 * options length, + maybe tagging options length again.
 
355
                 */
 
356
                if (desc.ad_tags.bv_len || desc.ad_flags != SLAP_DESC_NONE) {
 
357
                        dlen = desc.ad_type->sat_cname.bv_len + 1;
 
358
                        if (desc.ad_tags.bv_len) {
 
359
                                dlen += 1 + desc.ad_tags.bv_len;
 
360
                        }
 
361
                        if ( slap_ad_is_binary( &desc ) ) {
 
362
                                dlen += 1 + STRLENOF(";binary") + desc.ad_tags.bv_len;
 
363
                        }
 
364
                }
 
365
 
 
366
                d2 = ch_malloc(sizeof(AttributeDescription) + dlen);
 
367
                d2->ad_next = NULL;
 
368
                d2->ad_type = desc.ad_type;
 
369
                d2->ad_flags = desc.ad_flags;
 
370
                d2->ad_cname.bv_len = desc.ad_type->sat_cname.bv_len;
 
371
                d2->ad_tags.bv_len = desc.ad_tags.bv_len;
 
372
 
 
373
                if (dlen == 0) {
 
374
                        d2->ad_cname.bv_val = d2->ad_type->sat_cname.bv_val;
 
375
                        d2->ad_tags.bv_val = NULL;
 
376
                } else {
 
377
                        char *cp, *op, *lp;
 
378
                        int j;
 
379
                        d2->ad_cname.bv_val = (char *)(d2+1);
 
380
                        strcpy(d2->ad_cname.bv_val, d2->ad_type->sat_cname.bv_val);
 
381
                        cp = d2->ad_cname.bv_val + d2->ad_cname.bv_len;
 
382
                        if( slap_ad_is_binary( &desc ) ) {
 
383
                                op = cp;
 
384
                                lp = NULL;
 
385
                                if( desc.ad_tags.bv_len ) {
 
386
                                        lp = desc.ad_tags.bv_val;
 
387
                                        while( strncasecmp(lp, "binary", STRLENOF("binary")) < 0
 
388
                                               && (lp = strchr( lp, ';' )) != NULL )
 
389
                                                ++lp;
 
390
                                        if( lp != desc.ad_tags.bv_val ) {
 
391
                                                *cp++ = ';';
 
392
                                                j = (lp
 
393
                                                     ? (unsigned) (lp - desc.ad_tags.bv_val - 1)
 
394
                                                     : strlen( desc.ad_tags.bv_val ));
 
395
                                                cp = lutil_strncopy(cp, desc.ad_tags.bv_val, j);
 
396
                                        }
 
397
                                }
 
398
                                cp = lutil_strcopy(cp, ";binary");
 
399
                                if( lp != NULL ) {
 
400
                                        *cp++ = ';';
 
401
                                        cp = lutil_strcopy(cp, lp);
 
402
                                }
 
403
                                d2->ad_cname.bv_len = cp - d2->ad_cname.bv_val;
 
404
                                if( desc.ad_tags.bv_len )
 
405
                                        ldap_pvt_str2lower(op);
 
406
                                j = 1;
 
407
                        } else {
 
408
                                j = 0;
 
409
                        }
 
410
                        if( desc.ad_tags.bv_len ) {
 
411
                                lp = d2->ad_cname.bv_val + d2->ad_cname.bv_len + j;
 
412
                                if ( j == 0 )
 
413
                                        *lp++ = ';';
 
414
                                d2->ad_tags.bv_val = lp;
 
415
                                strcpy(lp, desc.ad_tags.bv_val);
 
416
                                ldap_pvt_str2lower(lp);
 
417
                                if( j == 0 )
 
418
                                        d2->ad_cname.bv_len += 1 + desc.ad_tags.bv_len;
 
419
                        }
 
420
                }
 
421
                /* Add new desc to list. We always want the bare Desc with
 
422
                 * no options to stay at the head of the list, assuming
 
423
                 * that one will be used most frequently.
 
424
                 */
 
425
                if (desc.ad_type->sat_ad == NULL || dlen == 0) {
 
426
                        d2->ad_next = desc.ad_type->sat_ad;
 
427
                        desc.ad_type->sat_ad = d2;
 
428
                } else {
 
429
                        d2->ad_next = desc.ad_type->sat_ad->ad_next;
 
430
                        desc.ad_type->sat_ad->ad_next = d2;
 
431
                }
 
432
                ldap_pvt_thread_mutex_unlock( &desc.ad_type->sat_ad_mutex );
 
433
        }
 
434
 
 
435
        if( *ad == NULL ) {
 
436
                *ad = d2;
 
437
        } else {
 
438
                **ad = *d2;
 
439
        }
 
440
 
 
441
        return LDAP_SUCCESS;
 
442
}
 
443
 
 
444
static int is_ad_subtags(
 
445
        struct berval *subtagsbv, 
 
446
        struct berval *suptagsbv )
 
447
{
 
448
        const char *suptags, *supp, *supdelimp, *supn;
 
449
        const char *subtags, *subp, *subdelimp, *subn;
 
450
        int  suplen, sublen;
 
451
 
 
452
        subtags =subtagsbv->bv_val;
 
453
        suptags =suptagsbv->bv_val;
 
454
        subn = subtags + subtagsbv->bv_len;
 
455
        supn = suptags + suptagsbv->bv_len;
 
456
 
 
457
        for( supp=suptags ; supp; supp=supdelimp ) {
 
458
                supdelimp = strchrlen( supp, supn, ';', &suplen );
 
459
                if( supdelimp ) supdelimp++;
 
460
 
 
461
                for( subp=subtags ; subp; subp=subdelimp ) {
 
462
                        subdelimp = strchrlen( subp, subn, ';', &sublen );
 
463
                        if( subdelimp ) subdelimp++;
 
464
 
 
465
                        if ( suplen > sublen
 
466
                                 ? ( suplen-1 == sublen && supp[suplen-1] == '-'
 
467
                                         && strncmp( supp, subp, sublen ) == 0 )
 
468
                                 : ( ( suplen == sublen || supp[suplen-1] == '-' )
 
469
                                         && strncmp( supp, subp, suplen ) == 0 ) )
 
470
                        {
 
471
                                goto match;
 
472
                        }
 
473
                }
 
474
 
 
475
                return 0;
 
476
match:;
 
477
        }
 
478
        return 1;
 
479
}
 
480
 
 
481
int is_ad_subtype(
 
482
        AttributeDescription *sub,
 
483
        AttributeDescription *super
 
484
)
 
485
{
 
486
        AttributeType *a;
 
487
        int lr;
 
488
 
 
489
        for ( a = sub->ad_type; a; a=a->sat_sup ) {
 
490
                if ( a == super->ad_type ) break;
 
491
        }
 
492
        if( !a ) {
 
493
                return 0;
 
494
        }
 
495
 
 
496
        /* ensure sub does support all flags of super */
 
497
        lr = sub->ad_tags.bv_len ? SLAP_DESC_TAG_RANGE : 0;
 
498
        if(( super->ad_flags & ( sub->ad_flags | lr )) != super->ad_flags ) {
 
499
                return 0;
 
500
        }
 
501
 
 
502
        /* check for tagging options */
 
503
        if ( super->ad_tags.bv_len == 0 )
 
504
                return 1;
 
505
        if ( sub->ad_tags.bv_len == 0 )
 
506
                return 0;
 
507
 
 
508
        return is_ad_subtags( &sub->ad_tags, &super->ad_tags );
 
509
}
 
510
 
 
511
int ad_inlist(
 
512
        AttributeDescription *desc,
 
513
        AttributeName *attrs )
 
514
{
 
515
        if (! attrs ) return 0;
 
516
 
 
517
        for( ; attrs->an_name.bv_val; attrs++ ) {
 
518
                AttributeType *a;
 
519
                ObjectClass *oc;
 
520
                
 
521
                if ( attrs->an_desc ) {
 
522
                        int lr;
 
523
 
 
524
                        if ( desc == attrs->an_desc ) {
 
525
                                return 1;
 
526
                        }
 
527
 
 
528
                        /*
 
529
                         * EXTENSION: if requested description is preceeded by
 
530
                         * a '-' character, do not match on subtypes.
 
531
                         */
 
532
                        if ( attrs->an_name.bv_val[0] == '-' ) {
 
533
                                continue;
 
534
                        }
 
535
                        
 
536
                        /* Is this a subtype of the requested attr? */
 
537
                        for (a = desc->ad_type; a; a=a->sat_sup) {
 
538
                                if ( a == attrs->an_desc->ad_type )
 
539
                                        break;
 
540
                        }
 
541
                        if ( !a ) {
 
542
                                continue;
 
543
                        }
 
544
                        /* Does desc support all the requested flags? */
 
545
                        lr = desc->ad_tags.bv_len ? SLAP_DESC_TAG_RANGE : 0;
 
546
                        if(( attrs->an_desc->ad_flags & (desc->ad_flags | lr))
 
547
                                != attrs->an_desc->ad_flags ) {
 
548
                                continue;
 
549
                        }
 
550
                        /* Do the descs have compatible tags? */
 
551
                        if ( attrs->an_desc->ad_tags.bv_len == 0 ) {
 
552
                                return 1;
 
553
                        }
 
554
                        if ( desc->ad_tags.bv_len == 0) {
 
555
                                continue;
 
556
                        }
 
557
                        if ( is_ad_subtags( &desc->ad_tags,
 
558
                                &attrs->an_desc->ad_tags ) ) {
 
559
                                return 1;
 
560
                        }
 
561
                        continue;
 
562
                }
 
563
 
 
564
                if ( ber_bvccmp( &attrs->an_name, '*' ) ) {
 
565
                        if ( !is_at_operational( desc->ad_type ) ) {
 
566
                                return 1;
 
567
                        }
 
568
                        continue;
 
569
                }
 
570
 
 
571
                if ( ber_bvccmp( &attrs->an_name, '+' ) ) {
 
572
                        if ( is_at_operational( desc->ad_type ) ) {
 
573
                                return 1;
 
574
                        }
 
575
                        continue;
 
576
                }
 
577
 
 
578
                /*
 
579
                 * EXTENSION: see if requested description is @objectClass
 
580
                 * if so, return attributes which the class requires/allows
 
581
                 * else if requested description is !objectClass, return
 
582
                 * attributes which the class does not require/allow
 
583
                 */
 
584
                oc = attrs->an_oc;
 
585
                if( oc == NULL && attrs->an_name.bv_val ) {
 
586
                        switch( attrs->an_name.bv_val[0] ) {
 
587
                        case '@': /* @objectClass */
 
588
                        case '+': /* +objectClass (deprecated) */
 
589
                        case '!': { /* exclude */
 
590
                                        struct berval ocname;
 
591
                                        ocname.bv_len = attrs->an_name.bv_len - 1;
 
592
                                        ocname.bv_val = &attrs->an_name.bv_val[1];
 
593
                                        oc = oc_bvfind( &ocname );
 
594
                                        attrs->an_oc_exclude = 0;
 
595
                                        if ( oc && attrs->an_name.bv_val[0] == '!' ) {
 
596
                                                attrs->an_oc_exclude = 1;
 
597
                                        }
 
598
                                } break;
 
599
 
 
600
                        default: /* old (deprecated) way */
 
601
                                oc = oc_bvfind( &attrs->an_name );
 
602
                        }
 
603
                        attrs->an_oc = oc;
 
604
                }
 
605
                if( oc != NULL ) {
 
606
                        if ( attrs->an_oc_exclude ) {
 
607
                                if ( oc == slap_schema.si_oc_extensibleObject ) {
 
608
                                        /* extensibleObject allows the return of anything */
 
609
                                        return 0;
 
610
                                }
 
611
 
 
612
                                if( oc->soc_required ) {
 
613
                                        /* allow return of required attributes */
 
614
                                        int i;
 
615
                                
 
616
                                        for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
 
617
                                                for (a = desc->ad_type; a; a=a->sat_sup) {
 
618
                                                        if ( a == oc->soc_required[i] ) {
 
619
                                                                return 0;
 
620
                                                        }
 
621
                                                }
 
622
                                        }
 
623
                                }
 
624
 
 
625
                                if( oc->soc_allowed ) {
 
626
                                        /* allow return of allowed attributes */
 
627
                                        int i;
 
628
                                        for ( i = 0; oc->soc_allowed[i] != NULL; i++ ) {
 
629
                                                for (a = desc->ad_type; a; a=a->sat_sup) {
 
630
                                                        if ( a == oc->soc_allowed[i] ) {
 
631
                                                                return 0;
 
632
                                                        }
 
633
                                                }
 
634
                                        }
 
635
                                }
 
636
 
 
637
                                return 1;
 
638
                        }
 
639
                        
 
640
                        if ( oc == slap_schema.si_oc_extensibleObject ) {
 
641
                                /* extensibleObject allows the return of anything */
 
642
                                return 1;
 
643
                        }
 
644
 
 
645
                        if( oc->soc_required ) {
 
646
                                /* allow return of required attributes */
 
647
                                int i;
 
648
                                
 
649
                                for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
 
650
                                        for (a = desc->ad_type; a; a=a->sat_sup) {
 
651
                                                if ( a == oc->soc_required[i] ) {
 
652
                                                        return 1;
 
653
                                                }
 
654
                                        }
 
655
                                }
 
656
                        }
 
657
 
 
658
                        if( oc->soc_allowed ) {
 
659
                                /* allow return of allowed attributes */
 
660
                                int i;
 
661
                                for ( i = 0; oc->soc_allowed[i] != NULL; i++ ) {
 
662
                                        for (a = desc->ad_type; a; a=a->sat_sup) {
 
663
                                                if ( a == oc->soc_allowed[i] ) {
 
664
                                                        return 1;
 
665
                                                }
 
666
                                        }
 
667
                                }
 
668
                        }
 
669
 
 
670
                } else {
 
671
                        const char      *text;
 
672
 
 
673
                        /* give it a chance of being retrieved by a proxy... */
 
674
                        (void)slap_bv2undef_ad( &attrs->an_name,
 
675
                                &attrs->an_desc, &text,
 
676
                                SLAP_AD_PROXIED|SLAP_AD_NOINSERT );
 
677
                }
 
678
        }
 
679
 
 
680
        return 0;
 
681
}
 
682
 
 
683
 
 
684
int slap_str2undef_ad(
 
685
        const char *str,
 
686
        AttributeDescription **ad,
 
687
        const char **text,
 
688
        unsigned flags )
 
689
{
 
690
        struct berval bv;
 
691
        bv.bv_val = (char *) str;
 
692
        bv.bv_len = strlen( str );
 
693
 
 
694
        return slap_bv2undef_ad( &bv, ad, text, flags );
 
695
}
 
696
 
 
697
int slap_bv2undef_ad(
 
698
        struct berval *bv,
 
699
        AttributeDescription **ad,
 
700
        const char **text,
 
701
        unsigned flags )
 
702
{
 
703
        AttributeDescription *desc;
 
704
        AttributeType *at;
 
705
 
 
706
        assert( ad != NULL );
 
707
 
 
708
        if( bv == NULL || bv->bv_len == 0 ) {
 
709
                *text = "empty AttributeDescription";
 
710
                return LDAP_UNDEFINED_TYPE;
 
711
        }
 
712
 
 
713
        /* make sure description is IA5 */
 
714
        if( ad_keystring( bv ) ) {
 
715
                *text = "AttributeDescription contains inappropriate characters";
 
716
                return LDAP_UNDEFINED_TYPE;
 
717
        }
 
718
 
 
719
        /* use the appropriate type */
 
720
        if ( flags & SLAP_AD_PROXIED ) {
 
721
                at = slap_schema.si_at_proxied;
 
722
 
 
723
        } else {
 
724
                at = slap_schema.si_at_undefined;
 
725
        }
 
726
 
 
727
        for( desc = at->sat_ad; desc; desc=desc->ad_next ) {
 
728
                if( desc->ad_cname.bv_len == bv->bv_len &&
 
729
                    !strcasecmp( desc->ad_cname.bv_val, bv->bv_val ) )
 
730
                {
 
731
                        break;
 
732
                }
 
733
        }
 
734
 
 
735
        if( !desc ) {
 
736
                if ( flags & SLAP_AD_NOINSERT ) {
 
737
                        *text = NULL;
 
738
                        return LDAP_UNDEFINED_TYPE;
 
739
                }
 
740
        
 
741
                desc = ch_malloc(sizeof(AttributeDescription) + 1 +
 
742
                        bv->bv_len);
 
743
                
 
744
                desc->ad_flags = SLAP_DESC_NONE;
 
745
                BER_BVZERO( &desc->ad_tags );
 
746
 
 
747
                desc->ad_cname.bv_len = bv->bv_len;
 
748
                desc->ad_cname.bv_val = (char *)(desc+1);
 
749
                strcpy(desc->ad_cname.bv_val, bv->bv_val);
 
750
 
 
751
                /* canonical to upper case */
 
752
                ldap_pvt_str2upper( desc->ad_cname.bv_val );
 
753
 
 
754
                /* shouldn't we protect this for concurrency? */
 
755
                desc->ad_type = at;
 
756
                ldap_pvt_thread_mutex_lock( &ad_undef_mutex );
 
757
                desc->ad_next = desc->ad_type->sat_ad;
 
758
                desc->ad_type->sat_ad = desc;
 
759
                ldap_pvt_thread_mutex_unlock( &ad_undef_mutex );
 
760
 
 
761
                Debug( LDAP_DEBUG_ANY,
 
762
                        "%s attributeDescription \"%s\" inserted.\n",
 
763
                        ( flags & SLAP_AD_PROXIED ) ? "PROXIED" : "UNKNOWN",
 
764
                        desc->ad_cname.bv_val, 0 );
 
765
        }
 
766
 
 
767
        if( !*ad ) {
 
768
                *ad = desc;
 
769
        } else {
 
770
                **ad = *desc;
 
771
        }
 
772
 
 
773
        return LDAP_SUCCESS;
 
774
}
 
775
 
 
776
AttributeDescription *
 
777
slap_bv2tmp_ad(
 
778
        struct berval *bv,
 
779
        void *memctx )
 
780
{
 
781
        AttributeDescription *ad =
 
782
                 slap_sl_mfuncs.bmf_malloc( sizeof(AttributeDescription) +
 
783
                        bv->bv_len + 1, memctx );
 
784
 
 
785
        ad->ad_cname.bv_val = (char *)(ad+1);
 
786
        strncpy( ad->ad_cname.bv_val, bv->bv_val, bv->bv_len+1 );
 
787
        ad->ad_cname.bv_len = bv->bv_len;
 
788
        ad->ad_flags = SLAP_DESC_TEMPORARY;
 
789
        ad->ad_type = slap_schema.si_at_undefined;
 
790
 
 
791
        return ad;
 
792
}
 
793
 
 
794
static int
 
795
undef_promote(
 
796
        AttributeType   *at,
 
797
        char            *name,
 
798
        AttributeType   *nat )
 
799
{
 
800
        AttributeDescription    **u_ad, **n_ad;
 
801
 
 
802
        /* Get to last ad on the new type */
 
803
        for ( n_ad = &nat->sat_ad; *n_ad; n_ad = &(*n_ad)->ad_next ) ;
 
804
 
 
805
        for ( u_ad = &at->sat_ad; *u_ad; ) {
 
806
                struct berval   bv;
 
807
 
 
808
                ber_str2bv( name, 0, 0, &bv );
 
809
 
 
810
                /* remove iff undef == name or undef == name;tag */
 
811
                if ( (*u_ad)->ad_cname.bv_len >= bv.bv_len
 
812
                        && strncasecmp( (*u_ad)->ad_cname.bv_val, bv.bv_val, bv.bv_len ) == 0
 
813
                        && ( (*u_ad)->ad_cname.bv_val[ bv.bv_len ] == '\0'
 
814
                                || (*u_ad)->ad_cname.bv_val[ bv.bv_len ] == ';' ) )
 
815
                {
 
816
                        AttributeDescription    *tmp = *u_ad;
 
817
 
 
818
                        *u_ad = (*u_ad)->ad_next;
 
819
 
 
820
                        tmp->ad_next = NULL;
 
821
                        *n_ad = tmp;
 
822
                        n_ad = &tmp->ad_next;
 
823
                } else {
 
824
                        u_ad = &(*u_ad)->ad_next;
 
825
                }
 
826
        }
 
827
 
 
828
        return 0;
 
829
}
 
830
 
 
831
int
 
832
slap_ad_undef_promote(
 
833
        char *name,
 
834
        AttributeType *at )
 
835
{
 
836
        int     rc;
 
837
 
 
838
        ldap_pvt_thread_mutex_lock( &ad_undef_mutex );
 
839
 
 
840
        rc = undef_promote( slap_schema.si_at_undefined, name, at );
 
841
        if ( rc == 0 ) {
 
842
                rc = undef_promote( slap_schema.si_at_proxied, name, at );
 
843
        }
 
844
 
 
845
        ldap_pvt_thread_mutex_unlock( &ad_undef_mutex );
 
846
 
 
847
        return rc;
 
848
}
 
849
 
 
850
int
 
851
an_find(
 
852
    AttributeName *a,
 
853
    struct berval *s
 
854
)
 
855
{
 
856
        if( a == NULL ) return 0;
 
857
 
 
858
        for ( ; a->an_name.bv_val; a++ ) {
 
859
                if ( a->an_name.bv_len != s->bv_len) continue;
 
860
                if ( strcasecmp( s->bv_val, a->an_name.bv_val ) == 0 ) {
 
861
                        return( 1 );
 
862
                }
 
863
        }
 
864
 
 
865
        return( 0 );
 
866
}
 
867
 
 
868
/*
 
869
 * Convert a delimited string into a list of AttributeNames; add
 
870
 * on to an existing list if it was given.  If the string is not
 
871
 * a valid attribute name, if a '-' is prepended it is skipped
 
872
 * and the remaining name is tried again; if a '@' (or '+') is
 
873
 * prepended, an objectclass name is searched instead; if a '!'
 
874
 * is prepended, the objectclass name is negated.
 
875
 * 
 
876
 * NOTE: currently, if a valid attribute name is not found, the
 
877
 * same string is also checked as valid objectclass name; however,
 
878
 * this behavior is deprecated.
 
879
 */
 
880
AttributeName *
 
881
str2anlist( AttributeName *an, char *in, const char *brkstr )
 
882
{
 
883
        char    *str;
 
884
        char    *s;
 
885
        char    *lasts;
 
886
        int     i, j;
 
887
        const char *text;
 
888
        AttributeName *anew;
 
889
 
 
890
        /* find last element in list */
 
891
        i = 0;
 
892
        if ( an != NULL ) {
 
893
                for ( i = 0; !BER_BVISNULL( &an[ i ].an_name ) ; i++)
 
894
                        ;
 
895
        }
 
896
        
 
897
        /* protect the input string from strtok */
 
898
        str = ch_strdup( in );
 
899
 
 
900
        /* Count words in string */
 
901
        j = 1;
 
902
        for ( s = str; *s; s++ ) {
 
903
                if ( strchr( brkstr, *s ) != NULL ) {
 
904
                        j++;
 
905
                }
 
906
        }
 
907
 
 
908
        an = ch_realloc( an, ( i + j + 1 ) * sizeof( AttributeName ) );
 
909
        anew = an + i;
 
910
        for ( s = ldap_pvt_strtok( str, brkstr, &lasts );
 
911
                s != NULL;
 
912
                s = ldap_pvt_strtok( NULL, brkstr, &lasts ) )
 
913
        {
 
914
                /* put a stop mark */
 
915
                BER_BVZERO( &anew[1].an_name );
 
916
 
 
917
                anew->an_desc = NULL;
 
918
                anew->an_oc = NULL;
 
919
                anew->an_oc_exclude = 0;
 
920
                ber_str2bv(s, 0, 1, &anew->an_name);
 
921
                slap_bv2ad(&anew->an_name, &anew->an_desc, &text);
 
922
                if ( !anew->an_desc ) {
 
923
                        switch( anew->an_name.bv_val[0] ) {
 
924
                        case '-': {
 
925
                                        struct berval adname;
 
926
                                        adname.bv_len = anew->an_name.bv_len - 1;
 
927
                                        adname.bv_val = &anew->an_name.bv_val[1];
 
928
                                        slap_bv2ad(&adname, &anew->an_desc, &text);
 
929
                                        if ( !anew->an_desc ) {
 
930
                                                goto reterr;
 
931
                                        }
 
932
                                } break;
 
933
 
 
934
                        case '@':
 
935
                        case '+': /* (deprecated) */
 
936
                        case '!': {
 
937
                                        struct berval ocname;
 
938
                                        ocname.bv_len = anew->an_name.bv_len - 1;
 
939
                                        ocname.bv_val = &anew->an_name.bv_val[1];
 
940
                                        anew->an_oc = oc_bvfind( &ocname );
 
941
                                        if ( !anew->an_oc ) {
 
942
                                                goto reterr;
 
943
                                        }
 
944
 
 
945
                                        if ( anew->an_name.bv_val[0] == '!' ) {
 
946
                                                anew->an_oc_exclude = 1;
 
947
                                        }
 
948
                                } break;
 
949
 
 
950
                        default:
 
951
                                /* old (deprecated) way */
 
952
                                anew->an_oc = oc_bvfind( &anew->an_name );
 
953
                                if ( !anew->an_oc ) {
 
954
                                        goto reterr;
 
955
                                }
 
956
                        }
 
957
                }
 
958
                anew++;
 
959
        }
 
960
 
 
961
        BER_BVZERO( &anew->an_name );
 
962
        free( str );
 
963
        return( an );
 
964
 
 
965
reterr:
 
966
        anlist_free( an, 1, NULL );
 
967
 
 
968
        /*
 
969
         * overwrites input string
 
970
         * on error!
 
971
         */
 
972
        strcpy( in, s );
 
973
        free( str );
 
974
        return NULL;
 
975
}
 
976
 
 
977
void
 
978
anlist_free( AttributeName *an, int freename, void *ctx )
 
979
{
 
980
        if ( an == NULL ) {
 
981
                return;
 
982
        }
 
983
 
 
984
        if ( freename ) {
 
985
                int     i;
 
986
 
 
987
                for ( i = 0; an[i].an_name.bv_val; i++ ) {
 
988
                        ber_memfree_x( an[i].an_name.bv_val, ctx );
 
989
                }
 
990
        }
 
991
 
 
992
        ber_memfree_x( an, ctx );
 
993
}
 
994
 
 
995
char **anlist2charray_x( AttributeName *an, int dup, void *ctx )
 
996
{
 
997
    char **attrs;
 
998
    int i;
 
999
                                                                                
 
1000
    if ( an != NULL ) {
 
1001
        for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ )
 
1002
            ;
 
1003
                attrs = (char **) slap_sl_malloc( (i + 1) * sizeof(char *), ctx );
 
1004
        for ( i = 0; !BER_BVISNULL( &an[i].an_name ); i++ ) {
 
1005
                        if ( dup )
 
1006
                    attrs[i] = ch_strdup( an[i].an_name.bv_val );
 
1007
                        else
 
1008
                    attrs[i] = an[i].an_name.bv_val;
 
1009
        }
 
1010
        attrs[i] = NULL;
 
1011
    } else {
 
1012
        attrs = NULL;
 
1013
    }
 
1014
                                                                                
 
1015
    return attrs;
 
1016
}
 
1017
 
 
1018
char **anlist2charray( AttributeName *an, int dup )
 
1019
{
 
1020
        return anlist2charray_x( an, dup, NULL );
 
1021
}
 
1022
 
 
1023
char**
 
1024
anlist2attrs( AttributeName * anlist )
 
1025
{
 
1026
        int i, j, k = 0;
 
1027
        int n;
 
1028
        char **attrs;
 
1029
        ObjectClass *oc;
 
1030
 
 
1031
        if ( anlist == NULL )
 
1032
                return NULL;
 
1033
 
 
1034
        for ( i = 0; anlist[i].an_name.bv_val; i++ ) {
 
1035
                if ( ( oc = anlist[i].an_oc ) ) {
 
1036
                        for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ ) ;
 
1037
                        k += j;
 
1038
                        for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ ) ;
 
1039
                        k += j;
 
1040
                }
 
1041
        }
 
1042
 
 
1043
        if ( i == 0 )
 
1044
                return NULL;
 
1045
                                                                                
 
1046
        attrs = anlist2charray( anlist, 1 );
 
1047
                                                                                
 
1048
        n = i;
 
1049
                                                                                
 
1050
        if ( k )
 
1051
                attrs = (char **) ch_realloc( attrs, (i + k + 1) * sizeof( char * ));
 
1052
 
 
1053
        for ( i = 0; anlist[i].an_name.bv_val; i++ ) {
 
1054
                if ( ( oc = anlist[i].an_oc ) ) {
 
1055
                        for ( j = 0; oc->soc_required && oc->soc_required[j]; j++ ) {
 
1056
                                attrs[n++] = ch_strdup(
 
1057
                                                                oc->soc_required[j]->sat_cname.bv_val );
 
1058
                        }
 
1059
                        for ( j = 0; oc->soc_allowed && oc->soc_allowed[j]; j++ ) {
 
1060
                                attrs[n++] = ch_strdup(
 
1061
                                                                oc->soc_allowed[j]->sat_cname.bv_val );
 
1062
                        }
 
1063
                }
 
1064
        }
 
1065
        
 
1066
        if ( attrs )
 
1067
                attrs[n] = NULL;
 
1068
 
 
1069
        i = 0;
 
1070
        while ( attrs && attrs[i] ) {
 
1071
                if ( *attrs[i] == '@' ) {
 
1072
                        ch_free( attrs[i] );
 
1073
                        for ( j = i; attrs[j]; j++ ) {
 
1074
                                attrs[j] = attrs[j+1];
 
1075
                        }
 
1076
                } else {
 
1077
                        i++;
 
1078
                }
 
1079
        }
 
1080
 
 
1081
        for ( i = 0; attrs && attrs[i]; i++ ) {
 
1082
                j = i + 1;
 
1083
                while ( attrs && attrs[j] ) {
 
1084
                        if ( !strcmp( attrs[i], attrs[j] )) {
 
1085
                                ch_free( attrs[j] );
 
1086
                                for ( k = j; attrs && attrs[k]; k++ ) {
 
1087
                                        attrs[k] = attrs[k+1];
 
1088
                                }
 
1089
                        } else {
 
1090
                                j++;
 
1091
                        }
 
1092
                }
 
1093
        }
 
1094
 
 
1095
        if ( i != n )
 
1096
                attrs = (char **) ch_realloc( attrs, (i+1) * sizeof( char * ));
 
1097
 
 
1098
        return attrs;
 
1099
}
 
1100
 
 
1101
#define LBUFSIZ 80
 
1102
AttributeName*
 
1103
file2anlist( AttributeName *an, const char *fname, const char *brkstr )
 
1104
{
 
1105
        FILE    *fp;
 
1106
        char    *line = NULL;
 
1107
        char    *lcur = NULL;
 
1108
        char    *c;
 
1109
        size_t  lmax = LBUFSIZ;
 
1110
 
 
1111
        fp = fopen( fname, "r" );
 
1112
        if ( fp == NULL ) {
 
1113
                Debug( LDAP_DEBUG_ANY,
 
1114
                        "get_attrs_from_file: failed to open attribute list file "
 
1115
                        "\"%s\": %s\n", fname, strerror(errno), 0 );
 
1116
                return NULL;
 
1117
        }
 
1118
 
 
1119
        lcur = line = (char *) ch_malloc( lmax );
 
1120
        if ( !line ) {
 
1121
                Debug( LDAP_DEBUG_ANY,
 
1122
                        "get_attrs_from_file: could not allocate memory\n",
 
1123
                        0, 0, 0 );
 
1124
                fclose(fp);
 
1125
                return NULL;
 
1126
        }
 
1127
 
 
1128
        while ( fgets( lcur, LBUFSIZ, fp ) != NULL ) {
 
1129
                if ( ( c = strchr( lcur, '\n' ) ) ) {
 
1130
                        if ( c == line ) {
 
1131
                                *c = '\0';
 
1132
                        } else if ( *(c-1) == '\r' ) {
 
1133
                                *(c-1) = '\0';
 
1134
                        } else {
 
1135
                                *c = '\0';
 
1136
                        }
 
1137
                } else {
 
1138
                        lmax += LBUFSIZ;
 
1139
                        line = (char *) ch_realloc( line, lmax );
 
1140
                        if ( !line ) {
 
1141
                                Debug( LDAP_DEBUG_ANY,
 
1142
                                        "get_attrs_from_file: could not allocate memory\n",
 
1143
                                        0, 0, 0 );
 
1144
                                fclose(fp);
 
1145
                                return NULL;
 
1146
                        }
 
1147
                        lcur = line + strlen( line );
 
1148
                        continue;
 
1149
                }
 
1150
                an = str2anlist( an, line, brkstr );
 
1151
                if ( an == NULL )
 
1152
                        break;
 
1153
                lcur = line;
 
1154
        }
 
1155
        ch_free( line );
 
1156
        fclose(fp);
 
1157
        return an;
 
1158
}
 
1159
#undef LBUFSIZ
 
1160
 
 
1161
/* Define an attribute option. */
 
1162
int
 
1163
ad_define_option( const char *name, const char *fname, int lineno )
 
1164
{
 
1165
        int i;
 
1166
        unsigned int optlen;
 
1167
 
 
1168
        if ( options == &lang_option ) {
 
1169
                options = NULL;
 
1170
                option_count = 0;
 
1171
        }
 
1172
        if ( name == NULL )
 
1173
                return 0;
 
1174
 
 
1175
        optlen = 0;
 
1176
        do {
 
1177
                if ( !DESC_CHAR( name[optlen] ) ) {
 
1178
                        Debug( LDAP_DEBUG_ANY,
 
1179
                               "%s: line %d: illegal option name \"%s\"\n",
 
1180
                                    fname, lineno, name );
 
1181
                        return 1;
 
1182
                }
 
1183
        } while ( name[++optlen] );
 
1184
 
 
1185
        options = ch_realloc( options,
 
1186
                (option_count+1) * sizeof(Attr_option) );
 
1187
 
 
1188
        if ( strcasecmp( name, "binary" ) == 0
 
1189
             || ad_find_option_definition( name, optlen ) ) {
 
1190
                Debug( LDAP_DEBUG_ANY,
 
1191
                       "%s: line %d: option \"%s\" is already defined\n",
 
1192
                       fname, lineno, name );
 
1193
                return 1;
 
1194
        }
 
1195
 
 
1196
        for ( i = option_count; i; --i ) {
 
1197
                if ( strcasecmp( name, options[i-1].name.bv_val ) >= 0 )
 
1198
                        break;
 
1199
                options[i] = options[i-1];
 
1200
        }
 
1201
 
 
1202
        options[i].name.bv_val = ch_strdup( name );
 
1203
        options[i].name.bv_len = optlen;
 
1204
        options[i].prefix = (name[optlen-1] == '-');
 
1205
 
 
1206
        if ( i != option_count &&
 
1207
             options[i].prefix &&
 
1208
             optlen < options[i+1].name.bv_len &&
 
1209
             strncasecmp( name, options[i+1].name.bv_val, optlen ) == 0 ) {
 
1210
                        Debug( LDAP_DEBUG_ANY,
 
1211
                               "%s: line %d: option \"%s\" overrides previous option\n",
 
1212
                                    fname, lineno, name );
 
1213
                        return 1;
 
1214
        }
 
1215
 
 
1216
        option_count++;
 
1217
        return 0;
 
1218
}
 
1219
 
 
1220
void
 
1221
ad_unparse_options( BerVarray *res )
 
1222
{
 
1223
        int i;
 
1224
        for ( i = 0; i < option_count; i++ ) {
 
1225
                value_add_one( res, &options[i].name );
 
1226
        }
 
1227
}
 
1228
 
 
1229
/* Find the definition of the option name or prefix matching the arguments */
 
1230
static Attr_option *
 
1231
ad_find_option_definition( const char *opt, int optlen )
 
1232
{
 
1233
        int top = 0, bot = option_count;
 
1234
        while ( top < bot ) {
 
1235
                int mid = (top + bot) / 2;
 
1236
                int mlen = options[mid].name.bv_len;
 
1237
                char *mname = options[mid].name.bv_val;
 
1238
                int j;
 
1239
                if ( optlen < mlen ) {
 
1240
                        j = strncasecmp( opt, mname, optlen ) - 1;
 
1241
                } else {
 
1242
                        j = strncasecmp( opt, mname, mlen );
 
1243
                        if ( j==0 && (optlen==mlen || options[mid].prefix) )
 
1244
                                return &options[mid];
 
1245
                }
 
1246
                if ( j < 0 )
 
1247
                        bot = mid;
 
1248
                else
 
1249
                        top = mid + 1;
 
1250
        }
 
1251
        return NULL;
 
1252
}
 
1253
 
 
1254
MatchingRule *ad_mr(
 
1255
        AttributeDescription *ad,
 
1256
        unsigned usage )
 
1257
{
 
1258
        switch( usage & SLAP_MR_TYPE_MASK ) {
 
1259
        case SLAP_MR_NONE:
 
1260
        case SLAP_MR_EQUALITY:
 
1261
                return ad->ad_type->sat_equality;
 
1262
                break;
 
1263
        case SLAP_MR_ORDERING:
 
1264
                return ad->ad_type->sat_ordering;
 
1265
                break;
 
1266
        case SLAP_MR_SUBSTR:
 
1267
                return ad->ad_type->sat_substr;
 
1268
                break;
 
1269
        case SLAP_MR_EXT:
 
1270
        default:
 
1271
                assert( 0 /* ad_mr: bad usage */);
 
1272
        }
 
1273
        return NULL;
 
1274
}