]> git.sur5r.net Git - openldap/blob - servers/slapd/ad.c
Remove lint
[openldap] / servers / slapd / ad.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /* ad.c - routines for dealing with attribute descriptions */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/ctype.h>
13 #include <ac/errno.h>
14 #include <ac/socket.h>
15 #include <ac/string.h>
16 #include <ac/time.h>
17
18 #include "ldap_pvt.h"
19 #include "slap.h"
20
21 extern ldap_pvt_thread_mutex_t  ad_mutex;       /* init.c */
22
23 static int ad_keystring(
24         struct berval *bv )
25 {
26         ber_len_t i;
27
28         if( !AD_CHAR( bv->bv_val[0] ) ) {
29                 return 1;
30         }
31
32         for( i=1; i<bv->bv_len; i++ ) {
33                 if( !AD_CHAR( bv->bv_val[i] ) ) {
34                         return 1;
35                 }
36         }
37         return 0;
38 }
39
40 void ad_destroy( void *in )
41 {
42         AttributeDescription *ad = in, *n;
43
44         for (;ad;ad = n) {
45                 n = ad->ad_next;
46                 ldap_memfree(ad);
47         }
48 }
49
50 int slap_str2ad(
51         const char *str,
52         AttributeDescription **ad,
53         const char **text )
54 {
55         struct berval bv;
56         bv.bv_val = (char *) str;
57         bv.bv_len = strlen( str );
58
59         return slap_bv2ad( &bv, ad, text );
60 }
61
62 int slap_bv2ad(
63         struct berval *bv,
64         AttributeDescription **ad,
65         const char **text )
66 {
67         int rtn = LDAP_UNDEFINED_TYPE;
68         int i;
69         AttributeDescription desc, *d2;
70         char *name, *options;
71
72         assert( ad != NULL );
73         assert( *ad == NULL ); /* temporary */
74
75         if( bv == NULL || bv->bv_len == 0 ) {
76                 *text = "empty attribute description";
77                 return rtn;
78         }
79
80         /* make sure description is IA5 */
81         if( ad_keystring( bv ) ) {
82                 *text = "attribute description contains inappropriate characters";
83                 return rtn;
84         }
85
86         /* find valid base attribute type; parse in place */
87         name = bv->bv_val;
88         options = strchr(name, ';');
89         if (options != NULL) *options = '\0';
90         desc.ad_type = at_find( name );
91         if (options != NULL) *options = ';';
92         if( desc.ad_type == NULL ) {
93                 *text = "attribute type undefined";
94
95                 return rtn;
96         }
97
98         if (options != NULL)
99                 desc.ad_cname.bv_len = options - name;
100         else
101                 desc.ad_cname.bv_len = strlen(name);
102
103         desc.ad_flags = SLAP_DESC_NONE;
104         desc.ad_lang.bv_len = 0;
105         desc.ad_lang.bv_val = NULL;
106
107         /* parse options in place */
108         for( ; options != NULL; ) {
109                 name = options+1;
110                 options = strchr( name, ';' );
111                 if ( options != NULL )
112                         i = options - name;
113                 else
114                         i = strlen(name);
115
116                 if( i == sizeof("binary")-1 && strncasecmp( name, "binary", i) == 0 ) {
117                         if( slap_ad_is_binary( &desc ) ) {
118                                 *text = "option \"binary\" specified multiple times";
119                                 goto done;
120                         }
121
122                         if( !slap_syntax_is_binary( desc.ad_type->sat_syntax )) {
123                                 /* not stored in binary, disallow option */
124                                 *text = "option \"binary\" with type not supported";
125                                 goto done;
126                         }
127
128                         desc.ad_flags |= SLAP_DESC_BINARY;
129
130                 } else if ( i >= sizeof("lang-") && strncasecmp( name, "lang-",
131                         sizeof("lang-")-1 ) == 0)
132                 {
133                         if( desc.ad_lang.bv_len != 0 ) {
134                                 *text = "multiple language tag options specified";
135                                 goto done;
136                         }
137
138                         desc.ad_lang.bv_val = name;
139                         desc.ad_lang.bv_len = i;
140                 } else {
141                         *text = "unrecognized option";
142                         goto done;
143                 }
144         }
145
146         /* see if a matching description is already cached */
147         for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
148                 if (d2->ad_flags != desc.ad_flags)
149                         continue;
150                 if (d2->ad_lang.bv_len != desc.ad_lang.bv_len)
151                         continue;
152                 if (d2->ad_lang.bv_len == 0)
153                         break;
154                 if (strncasecmp(d2->ad_lang.bv_val, desc.ad_lang.bv_val,
155                         desc.ad_lang.bv_len) == 0)
156                         break;
157         }
158
159         /* Not found, add new one */
160         while (d2 == NULL) {
161                 int dlen = 0;
162                 /* uses a single mutex instead of one per attributetype.
163                  * I don't believe this is a significant bottleneck. If
164                  * necessary, could change to a per-AttrType rwlock.
165                  */
166                 ldap_pvt_thread_mutex_lock( &ad_mutex );
167                 /* Check again just in case another thread added it */
168                 for (d2 = desc.ad_type->sat_ad; d2; d2=d2->ad_next) {
169                         if (d2->ad_flags != desc.ad_flags)
170                                 continue;
171                         if (d2->ad_lang.bv_len != desc.ad_lang.bv_len)
172                                 continue;
173                         if (d2->ad_lang.bv_len == 0)
174                                 break;
175                         if (strncasecmp(d2->ad_lang.bv_val,desc.ad_lang.bv_val,
176                                 desc.ad_lang.bv_len) == 0)
177                                 break;
178                 }
179                 /* Some other thread added it before we got the lock. */
180                 if (d2 != NULL) {
181                         ldap_pvt_thread_mutex_unlock( &ad_mutex );
182                         break;
183                 }
184
185                 /* Allocate a single contiguous block. If there are no
186                  * options, we just need space for the AttrDesc structure.
187                  * Otherwise, we need to tack on the full name length +
188                  * options length.
189                  */
190                 i = sizeof(AttributeDescription);
191                 if (desc.ad_lang.bv_len || desc.ad_flags != SLAP_DESC_NONE) {
192                         if (desc.ad_lang.bv_len)
193                                 dlen = desc.ad_lang.bv_len+1;
194                         dlen += strlen(desc.ad_type->sat_cname)+1;
195                         if( slap_ad_is_binary( &desc ) ) {
196                                 dlen += sizeof("binary");
197                         }
198                 }
199
200                 d2 = ch_malloc(i + dlen);
201                 d2->ad_type = desc.ad_type;
202                 d2->ad_flags = desc.ad_flags;
203                 d2->ad_cname.bv_len = desc.ad_cname.bv_len;
204                 d2->ad_lang.bv_len = desc.ad_lang.bv_len;
205                 if (dlen == 0) {
206                         d2->ad_cname.bv_val = d2->ad_type->sat_cname;
207                         d2->ad_lang.bv_val = NULL;
208                 } else {
209                         d2->ad_cname.bv_val = (char *)(d2+1);
210                         strcpy(d2->ad_cname.bv_val, d2->ad_type->sat_cname);
211                         if( slap_ad_is_binary( &desc ) ) {
212                                 strcpy(d2->ad_cname.bv_val+d2->ad_cname.bv_len,
213                                         ";binary");
214                                 d2->ad_cname.bv_len += sizeof("binary");
215                         }
216                         if( d2->ad_lang.bv_len ) {
217                                 d2->ad_cname.bv_val[d2->ad_cname.bv_len++]=';';
218                                 d2->ad_lang.bv_val = d2->ad_cname.bv_val+
219                                         d2->ad_cname.bv_len;
220                                 strncpy(d2->ad_lang.bv_val,desc.ad_lang.bv_val,
221                                         d2->ad_lang.bv_len);
222                                 d2->ad_lang.bv_val[d2->ad_lang.bv_len] = '\0';
223                                 ldap_pvt_str2lower(d2->ad_lang.bv_val);
224                                 d2->ad_cname.bv_len += d2->ad_lang.bv_len;
225                         }
226                 }
227                 /* Add new desc to list. We always want the bare Desc with
228                  * no options to stay at the head of the list, assuming
229                  * that one will be used most frequently.
230                  */
231                 if (desc.ad_type->sat_ad == NULL || dlen == 0) {
232                         d2->ad_next = desc.ad_type->sat_ad;
233                         desc.ad_type->sat_ad = d2;
234                 } else {
235                         d2->ad_next = desc.ad_type->sat_ad->ad_next;
236                         desc.ad_type->sat_ad->ad_next = d2;
237                 }
238                 ldap_pvt_thread_mutex_unlock( &ad_mutex );
239         }
240
241         if( *ad == NULL ) {
242                 *ad = d2;
243         } else {
244                 **ad = *d2;
245         }
246
247         rtn = LDAP_SUCCESS;
248
249 done:
250         return rtn;
251 }
252
253 int is_ad_subtype(
254         AttributeDescription *sub,
255         AttributeDescription *super
256 )
257 {
258         if( !is_at_subtype( sub->ad_type, super->ad_type ) ) {
259                 return 0;
260         }
261
262         if( super->ad_flags && ( super->ad_flags != sub->ad_flags )) {
263                 return 0;
264         }
265
266         if( super->ad_lang.bv_len && (sub->ad_lang.bv_len !=
267                 super->ad_lang.bv_len || strcmp( super->ad_lang.bv_val,
268                 sub->ad_lang.bv_val)))
269         {
270                 return 0;
271         }
272
273         return 1;
274 }
275
276
277 int ad_inlist(
278         AttributeDescription *desc,
279         char **attrs )
280 {
281         int i;
282         for( i=0; attrs[i] != NULL; i++ ) {
283                 AttributeDescription *ad = NULL;
284                 const char *text;
285                 int rc;
286                 
287                 rc = slap_str2ad( attrs[i], &ad, &text );
288
289                 if( rc != LDAP_SUCCESS ) continue;
290
291                 rc = is_ad_subtype( desc, ad );
292
293                 if( rc ) return 1;
294         }
295
296         return 0;
297 }
298
299
300 int slap_str2undef_ad(
301         const char *str,
302         AttributeDescription **ad,
303         const char **text )
304 {
305         struct berval bv;
306         bv.bv_val = (char *) str;
307         bv.bv_len = strlen( str );
308
309         return slap_bv2undef_ad( &bv, ad, text );
310 }
311
312 int slap_bv2undef_ad(
313         struct berval *bv,
314         AttributeDescription **ad,
315         const char **text )
316 {
317         AttributeDescription *desc;
318
319         assert( ad != NULL );
320
321         if( bv == NULL || bv->bv_len == 0 ) {
322                 *text = "empty attribute description";
323                 return LDAP_UNDEFINED_TYPE;
324         }
325
326         /* make sure description is IA5 */
327         if( ad_keystring( bv ) ) {
328                 *text = "attribute description contains inappropriate characters";
329                 return LDAP_UNDEFINED_TYPE;
330         }
331
332         for (desc = slap_schema.si_at_undefined->sat_ad; desc;
333                 desc=desc->ad_next)
334                 if (desc->ad_cname.bv_len == bv->bv_len &&
335                     !strcasecmp(desc->ad_cname.bv_val, bv->bv_val))
336                         break;
337         
338         if (!desc) {
339                 desc = ch_malloc(sizeof(AttributeDescription) +
340                         bv->bv_len + 1);
341                 
342                 desc->ad_flags = SLAP_DESC_NONE;
343                 desc->ad_lang.bv_val = NULL;
344                 desc->ad_lang.bv_len = 0;
345
346                 desc->ad_cname.bv_len = bv->bv_len;
347                 desc->ad_cname.bv_val = (char *)(desc+1);
348                 strcpy(desc->ad_cname.bv_val, bv->bv_val);
349
350                 /* canonical to upper case */
351                 ldap_pvt_str2upper( desc->ad_cname.bv_val );
352
353                 desc->ad_type = slap_schema.si_at_undefined;
354                 desc->ad_next = desc->ad_type->sat_ad;
355                 desc->ad_type->sat_ad = desc;
356         }
357
358         if (!*ad)
359                 *ad = desc;
360         else
361                 **ad = *desc;
362
363         return LDAP_SUCCESS;
364 }