]> git.sur5r.net Git - openldap/blob - servers/slapd/syntax.c
Merge remote-tracking branch 'origin/mdb.master' into OPENLDAP_REL_ENG_2_5
[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-2014 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_validate == NULL && def->sd_pretty == NULL && syn->syn_extensions != NULL ) {
213                 LDAPSchemaExtensionItem **lsei;
214                 Syntax *subst = NULL;
215
216                 for ( lsei = syn->syn_extensions; *lsei != NULL; lsei++) {
217                         if ( strcmp( (*lsei)->lsei_name, "X-SUBST" ) != 0 ) {
218                                 continue;
219                         }
220
221                         assert( (*lsei)->lsei_values != NULL );
222                         if ( (*lsei)->lsei_values[0] == '\0'
223                                 || (*lsei)->lsei_values[1] != '\0' )
224                         {
225                                 Debug( LDAP_DEBUG_ANY, "syn_add(%s): exactly one substitute syntax must be present\n",
226                                         ssyn->ssyn_syn.syn_oid, 0, 0 );
227                                 return SLAP_SCHERR_SYN_SUBST_NOT_SPECIFIED;
228                         }
229
230                         subst = syn_find( (*lsei)->lsei_values[0] );
231                         if ( subst == NULL ) {
232                                 Debug( LDAP_DEBUG_ANY, "syn_add(%s): substitute syntax %s not found\n",
233                                         ssyn->ssyn_syn.syn_oid, (*lsei)->lsei_values[0], 0 );
234                                 return SLAP_SCHERR_SYN_SUBST_NOT_FOUND;
235                         }
236                         break;
237                 }
238
239                 if ( subst != NULL ) {
240                         ssyn->ssyn_flags = subst->ssyn_flags;
241                         ssyn->ssyn_validate = subst->ssyn_validate;
242                         ssyn->ssyn_pretty = subst->ssyn_pretty;
243
244                         ssyn->ssyn_sups = NULL;
245
246 #ifdef SLAPD_BINARY_CONVERSION
247                         ssyn->ssyn_ber2str = subst->ssyn_ber2str;
248                         ssyn->ssyn_str2ber = subst->ssyn_str2ber;
249 #endif
250                 }
251         }
252
253         if ( def->sd_sups != NULL ) {
254                 int     cnt;
255
256                 for ( cnt = 0; def->sd_sups[cnt] != NULL; cnt++ )
257                         ;
258                 
259                 ssyn->ssyn_sups = (Syntax **)SLAP_CALLOC( cnt + 1,
260                         sizeof( Syntax * ) );
261                 if ( ssyn->ssyn_sups == NULL ) {
262                         Debug( LDAP_DEBUG_ANY, "SLAP_CALLOC Error\n", 0, 0, 0 );
263                         code = SLAP_SCHERR_OUTOFMEM;
264
265                 } else {
266                         for ( cnt = 0; def->sd_sups[cnt] != NULL; cnt++ ) {
267                                 ssyn->ssyn_sups[cnt] = syn_find( def->sd_sups[cnt] );
268                                 if ( ssyn->ssyn_sups[cnt] == NULL ) {
269                                         *err = def->sd_sups[cnt];
270                                         code = SLAP_SCHERR_SYN_SUP_NOT_FOUND;
271                                 }
272                         }
273                 }
274         }
275
276         if ( !user )
277                 ssyn->ssyn_flags |= SLAP_SYNTAX_HARDCODE;
278
279         if ( code == 0 ) {
280                 code = syn_insert( ssyn, prev, err );
281         }
282
283         if ( code != 0 && ssyn != NULL ) {
284                 if ( ssyn->ssyn_sups != NULL ) {
285                         SLAP_FREE( ssyn->ssyn_sups );
286                 }
287                 SLAP_FREE( ssyn );
288                 ssyn = NULL;
289         }
290
291         if (ssynp ) {
292                 *ssynp = ssyn;
293         }
294
295         return code;
296 }
297
298 int
299 register_syntax(
300         slap_syntax_defs_rec *def )
301 {
302         LDAPSyntax      *syn;
303         int             code;
304         const char      *err;
305
306         syn = ldap_str2syntax( def->sd_desc, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
307         if ( !syn ) {
308                 Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s before %s in %s\n",
309                     ldap_scherr2str(code), err, def->sd_desc );
310
311                 return( -1 );
312         }
313
314         code = syn_add( syn, 0, def, NULL, NULL, &err );
315
316         if ( code ) {
317                 Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n",
318                     scherr2str(code), err, def->sd_desc );
319                 ldap_syntax_free( syn );
320
321                 return( -1 );
322         }
323
324         ldap_memfree( syn );
325
326         return( 0 );
327 }
328
329 int
330 syn_schema_info( Entry *e )
331 {
332         AttributeDescription *ad_ldapSyntaxes = slap_schema.si_ad_ldapSyntaxes;
333         Syntax          *syn;
334         struct berval   val;
335         struct berval   nval;
336
337         LDAP_STAILQ_FOREACH(syn, &syn_list, ssyn_next ) {
338                 if ( ! syn->ssyn_validate ) {
339                         /* skip syntaxes without validators */
340                         continue;
341                 }
342                 if ( syn->ssyn_flags & SLAP_SYNTAX_HIDE ) {
343                         /* hide syntaxes */
344                         continue;
345                 }
346
347                 if ( ldap_syntax2bv( &syn->ssyn_syn, &val ) == NULL ) {
348                         return -1;
349                 }
350 #if 0
351                 Debug( LDAP_DEBUG_TRACE, "Merging syn [%ld] %s\n",
352                (long) val.bv_len, val.bv_val, 0 );
353 #endif
354
355                 nval.bv_val = syn->ssyn_oid;
356                 nval.bv_len = strlen(syn->ssyn_oid);
357
358                 if( attr_merge_one( e, ad_ldapSyntaxes, &val, &nval ) )
359                 {
360                         return -1;
361                 }
362                 ldap_memfree( val.bv_val );
363         }
364         return 0;
365 }
366
367 void
368 syn_delete( Syntax *syn )
369 {
370         LDAP_STAILQ_REMOVE(&syn_list, syn, Syntax, ssyn_next);
371 }
372
373 int
374 syn_start( Syntax **syn )
375 {
376         assert( syn != NULL );
377
378         *syn = LDAP_STAILQ_FIRST(&syn_list);
379
380         return (*syn != NULL);
381 }
382
383 int
384 syn_next( Syntax **syn )
385 {
386         assert( syn != NULL );
387
388 #if 0   /* pedantic check: don't use this */
389         {
390                 Syntax *tmp = NULL;
391
392                 LDAP_STAILQ_FOREACH(tmp,&syn_list,ssyn_next) {
393                         if ( tmp == *syn ) {
394                                 break;
395                         }
396                 }
397
398                 assert( tmp != NULL );
399         }
400 #endif
401
402         *syn = LDAP_STAILQ_NEXT(*syn,ssyn_next);
403
404         return (*syn != NULL);
405 }
406
407 void
408 syn_unparse( BerVarray *res, Syntax *start, Syntax *end, int sys )
409 {
410         Syntax *syn;
411         int i, num;
412         struct berval bv, *bva = NULL, idx;
413         char ibuf[32];
414
415         if ( !start )
416                 start = LDAP_STAILQ_FIRST( &syn_list );
417
418         /* count the result size */
419         i = 0;
420         for ( syn = start; syn; syn = LDAP_STAILQ_NEXT( syn, ssyn_next ) ) {
421                 if ( sys && !( syn->ssyn_flags & SLAP_SYNTAX_HARDCODE ) ) break;
422                 i++;
423                 if ( syn == end ) break;
424         }
425         if ( !i ) return;
426
427         num = i;
428         bva = ch_malloc( (num+1) * sizeof(struct berval) );
429         BER_BVZERO( bva );
430         idx.bv_val = ibuf;
431         if ( sys ) {
432                 idx.bv_len = 0;
433                 ibuf[0] = '\0';
434         }
435         i = 0;
436         for ( syn = start; syn; syn = LDAP_STAILQ_NEXT( syn, ssyn_next ) ) {
437                 if ( sys && !( syn->ssyn_flags & SLAP_SYNTAX_HARDCODE ) ) break;
438                 if ( ldap_syntax2bv( &syn->ssyn_syn, &bv ) == NULL ) {
439                         ber_bvarray_free( bva );
440                 }
441                 if ( !sys ) {
442                         idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
443                 }
444                 bva[i].bv_len = idx.bv_len + bv.bv_len;
445                 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
446                 strcpy( bva[i].bv_val, ibuf );
447                 strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
448                 i++;
449                 bva[i].bv_val = NULL;
450                 ldap_memfree( bv.bv_val );
451                 if ( syn == end ) break;
452         }
453         *res = bva;
454 }
455