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