]> git.sur5r.net Git - openldap/blob - servers/slapd/syntax.c
ITS#5663
[openldap] / servers / slapd / syntax.c
1 /* syntax.c - routines to manage syntax definitions */
2 /* $OpenLDAP$ */
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/string.h>
23 #include <ac/socket.h>
24
25 #include "slap.h"
26
27 struct sindexrec {
28         char            *sir_name;
29         Syntax          *sir_syn;
30 };
31
32 static Avlnode  *syn_index = NULL;
33 static LDAP_STAILQ_HEAD(SyntaxList, Syntax) syn_list
34         = LDAP_STAILQ_HEAD_INITIALIZER(syn_list);
35
36 /* Last hardcoded attribute registered */
37 Syntax *syn_sys_tail;
38
39 static int
40 syn_index_cmp(
41         const void *v_sir1,
42         const void *v_sir2
43 )
44 {
45         const struct sindexrec *sir1 = v_sir1, *sir2 = v_sir2;
46         return (strcmp( sir1->sir_name, sir2->sir_name ));
47 }
48
49 static int
50 syn_index_name_cmp(
51         const void *name,
52         const void *sir
53 )
54 {
55         return (strcmp( name, ((const struct sindexrec *)sir)->sir_name ));
56 }
57
58 Syntax *
59 syn_find( const char *synname )
60 {
61         struct sindexrec        *sir = NULL;
62
63         if ( (sir = avl_find( syn_index, synname, syn_index_name_cmp )) != NULL ) {
64                 return( sir->sir_syn );
65         }
66         return( NULL );
67 }
68
69 Syntax *
70 syn_find_desc( const char *syndesc, int *len )
71 {
72         Syntax          *synp;
73
74         LDAP_STAILQ_FOREACH(synp, &syn_list, ssyn_next) {
75                 if ((*len = dscompare( synp->ssyn_syn.syn_desc, syndesc, '{' /*'}'*/ ))) {
76                         return synp;
77                 }
78         }
79         return( NULL );
80 }
81
82 int
83 syn_is_sup( Syntax *syn, Syntax *sup )
84 {
85         int     i;
86
87         assert( syn != NULL );
88         assert( sup != NULL );
89
90         if ( syn == sup ) {
91                 return 1;
92         }
93
94         if ( syn->ssyn_sups == NULL ) {
95                 return 0;
96         }
97
98         for ( i = 0; syn->ssyn_sups[i]; i++ ) {
99                 if ( syn->ssyn_sups[i] == sup ) {
100                         return 1;
101                 }
102
103                 if ( syn_is_sup( syn->ssyn_sups[i], sup ) ) {
104                         return 1;
105                 }
106         }
107
108         return 0;
109 }
110
111 void
112 syn_destroy( void )
113 {
114         Syntax  *s;
115
116         avl_free( syn_index, ldap_memfree );
117         while( !LDAP_STAILQ_EMPTY( &syn_list ) ) {
118                 s = LDAP_STAILQ_FIRST( &syn_list );
119                 LDAP_STAILQ_REMOVE_HEAD( &syn_list, ssyn_next );
120                 if ( s->ssyn_sups ) {
121                         SLAP_FREE( s->ssyn_sups );
122                 }
123                 ldap_syntax_free( (LDAPSyntax *)s );
124         }
125 }
126
127 static int
128 syn_insert(
129         Syntax          *ssyn,
130         Syntax          *prev,
131         const char      **err )
132 {
133         struct sindexrec        *sir;
134
135         LDAP_STAILQ_NEXT( ssyn, ssyn_next ) = NULL;
136  
137         if ( ssyn->ssyn_oid ) {
138                 sir = (struct sindexrec *)
139                         SLAP_CALLOC( 1, sizeof(struct sindexrec) );
140                 if( sir == NULL ) {
141                         Debug( LDAP_DEBUG_ANY, "SLAP_CALLOC Error\n", 0, 0, 0 );
142                         return LDAP_OTHER;
143                 }
144                 sir->sir_name = ssyn->ssyn_oid;
145                 sir->sir_syn = ssyn;
146                 if ( avl_insert( &syn_index, (caddr_t) sir,
147                                  syn_index_cmp, avl_dup_error ) ) {
148                         *err = ssyn->ssyn_oid;
149                         ldap_memfree(sir);
150                         return SLAP_SCHERR_SYN_DUP;
151                 }
152                 /* FIX: temporal consistency check */
153                 syn_find(sir->sir_name);
154         }
155
156         if ( ssyn->ssyn_flags & SLAP_AT_HARDCODE ) {
157                 prev = syn_sys_tail;
158                 syn_sys_tail = ssyn;
159         }
160
161         if ( prev ) {
162                 LDAP_STAILQ_INSERT_AFTER( &syn_list, prev, ssyn, ssyn_next );
163         } else {
164                 LDAP_STAILQ_INSERT_TAIL( &syn_list, ssyn, ssyn_next );
165         }
166         return 0;
167 }
168
169 int
170 syn_add(
171         LDAPSyntax              *syn,
172         int                     user,
173         slap_syntax_defs_rec    *def,
174         Syntax                  **ssynp,
175         Syntax                  *prev,
176         const char              **err )
177 {
178         Syntax          *ssyn;
179         int             code = 0;
180
181         if ( ssynp != NULL ) {
182                 *ssynp = NULL;
183         }
184
185         ssyn = (Syntax *) SLAP_CALLOC( 1, sizeof(Syntax) );
186         if ( ssyn == NULL ) {
187                 Debug( LDAP_DEBUG_ANY, "SLAP_CALLOC Error\n", 0, 0, 0 );
188                 return SLAP_SCHERR_OUTOFMEM;
189         }
190
191         AC_MEMCPY( &ssyn->ssyn_syn, syn, sizeof(LDAPSyntax) );
192
193         LDAP_STAILQ_NEXT(ssyn,ssyn_next) = NULL;
194
195         /*
196          * note: ssyn_bvoid uses the same memory of ssyn_syn.syn_oid;
197          * ssyn_oidlen is #defined as ssyn_bvoid.bv_len
198          */
199         ssyn->ssyn_bvoid.bv_val = ssyn->ssyn_syn.syn_oid;
200         ssyn->ssyn_oidlen = strlen(syn->syn_oid);
201         ssyn->ssyn_flags = def->sd_flags;
202         ssyn->ssyn_validate = def->sd_validate;
203         ssyn->ssyn_pretty = def->sd_pretty;
204
205         ssyn->ssyn_sups = NULL;
206
207 #ifdef SLAPD_BINARY_CONVERSION
208         ssyn->ssyn_ber2str = def->sd_ber2str;
209         ssyn->ssyn_str2ber = def->sd_str2ber;
210 #endif
211
212         if ( def->sd_sups != NULL ) {
213                 int     cnt;
214
215                 for ( cnt = 0; def->sd_sups[cnt] != NULL; cnt++ )
216                         ;
217                 
218                 ssyn->ssyn_sups = (Syntax **)SLAP_CALLOC( cnt + 1,
219                         sizeof( Syntax * ) );
220                 if ( ssyn->ssyn_sups == NULL ) {
221                         Debug( LDAP_DEBUG_ANY, "SLAP_CALLOC Error\n", 0, 0, 0 );
222                         code = SLAP_SCHERR_OUTOFMEM;
223
224                 } else {
225                         for ( cnt = 0; def->sd_sups[cnt] != NULL; cnt++ ) {
226                                 ssyn->ssyn_sups[cnt] = syn_find( def->sd_sups[cnt] );
227                                 if ( ssyn->ssyn_sups[cnt] == NULL ) {
228                                         *err = def->sd_sups[cnt];
229                                         code = SLAP_SCHERR_SYN_SUP_NOT_FOUND;
230                                 }
231                         }
232                 }
233         }
234
235         if ( !user )
236                 ssyn->ssyn_flags |= SLAP_SYNTAX_HARDCODE;
237
238         if ( code == 0 ) {
239                 code = syn_insert( ssyn, prev, err );
240         }
241
242         if ( code != 0 && ssyn != NULL ) {
243                 if ( ssyn->ssyn_sups != NULL ) {
244                         SLAP_FREE( ssyn->ssyn_sups );
245                 }
246                 SLAP_FREE( ssyn );
247                 ssyn = NULL;
248         }
249
250         if (ssynp ) {
251                 *ssynp = ssyn;
252         }
253
254         return code;
255 }
256
257 int
258 register_syntax(
259         slap_syntax_defs_rec *def )
260 {
261         LDAPSyntax      *syn;
262         int             code;
263         const char      *err;
264
265         syn = ldap_str2syntax( def->sd_desc, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
266         if ( !syn ) {
267                 Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s before %s in %s\n",
268                     ldap_scherr2str(code), err, def->sd_desc );
269
270                 return( -1 );
271         }
272
273         code = syn_add( syn, 0, def, NULL, NULL, &err );
274
275         if ( code ) {
276                 Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n",
277                     scherr2str(code), err, def->sd_desc );
278                 ldap_syntax_free( syn );
279
280                 return( -1 );
281         }
282
283         ldap_memfree( syn );
284
285         return( 0 );
286 }
287
288 int
289 syn_schema_info( Entry *e )
290 {
291         AttributeDescription *ad_ldapSyntaxes = slap_schema.si_ad_ldapSyntaxes;
292         Syntax          *syn;
293         struct berval   val;
294         struct berval   nval;
295
296         LDAP_STAILQ_FOREACH(syn, &syn_list, ssyn_next ) {
297                 if ( ! syn->ssyn_validate ) {
298                         /* skip syntaxes without validators */
299                         continue;
300                 }
301                 if ( syn->ssyn_flags & SLAP_SYNTAX_HIDE ) {
302                         /* hide syntaxes */
303                         continue;
304                 }
305
306                 if ( ldap_syntax2bv( &syn->ssyn_syn, &val ) == NULL ) {
307                         return -1;
308                 }
309 #if 0
310                 Debug( LDAP_DEBUG_TRACE, "Merging syn [%ld] %s\n",
311                (long) val.bv_len, val.bv_val, 0 );
312 #endif
313
314                 nval.bv_val = syn->ssyn_oid;
315                 nval.bv_len = strlen(syn->ssyn_oid);
316
317                 if( attr_merge_one( e, ad_ldapSyntaxes, &val, &nval ) )
318                 {
319                         return -1;
320                 }
321                 ldap_memfree( val.bv_val );
322         }
323         return 0;
324 }
325
326 void
327 syn_delete( Syntax *syn )
328 {
329         LDAP_STAILQ_REMOVE(&syn_list, syn, Syntax, ssyn_next);
330 }
331
332 int
333 syn_start( Syntax **syn )
334 {
335         assert( syn != NULL );
336
337         *syn = LDAP_STAILQ_FIRST(&syn_list);
338
339         return (*syn != NULL);
340 }
341
342 int
343 syn_next( Syntax **syn )
344 {
345         assert( syn != NULL );
346
347 #if 0   /* pedantic check: don't use this */
348         {
349                 Syntax *tmp = NULL;
350
351                 LDAP_STAILQ_FOREACH(tmp,&syn_list,ssyn_next) {
352                         if ( tmp == *syn ) {
353                                 break;
354                         }
355                 }
356
357                 assert( tmp != NULL );
358         }
359 #endif
360
361         *syn = LDAP_STAILQ_NEXT(*syn,ssyn_next);
362
363         return (*syn != NULL);
364 }
365
366 void
367 syn_unparse( BerVarray *res, Syntax *start, Syntax *end, int sys )
368 {
369         Syntax *syn;
370         int i, num;
371         struct berval bv, *bva = NULL, idx;
372         char ibuf[32];
373
374         if ( !start )
375                 start = LDAP_STAILQ_FIRST( &syn_list );
376
377         /* count the result size */
378         i = 0;
379         for ( syn = start; syn; syn = LDAP_STAILQ_NEXT( syn, ssyn_next ) ) {
380                 if ( sys && !( syn->ssyn_flags & SLAP_SYNTAX_HARDCODE ) ) break;
381                 i++;
382                 if ( syn == end ) break;
383         }
384         if ( !i ) return;
385
386         num = i;
387         bva = ch_malloc( (num+1) * sizeof(struct berval) );
388         BER_BVZERO( bva );
389         idx.bv_val = ibuf;
390         if ( sys ) {
391                 idx.bv_len = 0;
392                 ibuf[0] = '\0';
393         }
394         i = 0;
395         for ( syn = start; syn; syn = LDAP_STAILQ_NEXT( syn, ssyn_next ) ) {
396                 if ( sys && !( syn->ssyn_flags & SLAP_SYNTAX_HARDCODE ) ) break;
397                 if ( ldap_syntax2bv( &syn->ssyn_syn, &bv ) == NULL ) {
398                         ber_bvarray_free( bva );
399                 }
400                 if ( !sys ) {
401                         idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
402                 }
403                 bva[i].bv_len = idx.bv_len + bv.bv_len;
404                 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
405                 strcpy( bva[i].bv_val, ibuf );
406                 strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
407                 i++;
408                 bva[i].bv_val = NULL;
409                 ldap_memfree( bv.bv_val );
410                 if ( syn == end ) break;
411         }
412         *res = bva;
413 }
414