]> git.sur5r.net Git - openldap/blob - servers/slapd/schema_init.c
Split out schema initialization of builtin syntax/matching rule
[openldap] / servers / slapd / schema_init.c
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/ctype.h>
13 #include <ac/string.h>
14 #include <ac/socket.h>
15
16 #include "slap.h"
17 #include "ldap_pvt.h"
18
19 static int
20 octetStringValidate(
21         Syntax *syntax,
22         struct berval *in )
23 {
24         /* any value allowed */
25         return 0;
26 }
27
28 static int
29 UTF8StringValidate(
30         Syntax *syntax,
31         struct berval *in )
32 {
33         ber_len_t count;
34         int len;
35         unsigned char *u = in->bv_val;
36
37         for( count = in->bv_len; count > 0; count+=len, u+=len ) {
38                 /* get the length indicated by the first byte */
39                 len = LDAP_UTF8_CHARLEN( u );
40
41                 /* should not be zero */
42                 if( len == 0 ) return -1;
43
44                 /* make sure len corresponds with the offset
45                         to the next character */
46                 if( LDAP_UTF8_OFFSET( u ) != len ) return -1;
47         }
48
49         if( count != 0 ) return -1;
50
51         return 0;
52 }
53
54 static int
55 UTF8StringNormalize(
56         Syntax *syntax,
57         MatchingRule *mr,
58         struct berval *val,
59         struct berval **normalized )
60 {
61         struct berval *newval;
62         char *p, *q, *s;
63
64         newval = ch_malloc( sizeof( struct berval ) );
65
66         p = val->bv_val;
67
68         /* Ignore initial whitespace */
69         while ( ldap_utf8_isspace( p ) ) {
70                 LDAP_UTF8_INCR( p );
71         }
72
73         if( *p ) {
74                 ch_free( newval );
75                 return 1;
76         }
77
78         newval->bv_val = ch_strdup( p );
79         p = q = newval->bv_val;
80         s = NULL;
81
82         while ( *p ) {
83                 int len;
84
85                 if ( ldap_utf8_isspace( p ) ) {
86                         len = LDAP_UTF8_COPY(q,p);
87                         s=q;
88                         p+=len;
89                         q+=len;
90
91                         /* Ignore the extra whitespace */
92                         while ( ldap_utf8_isspace( p ) ) {
93                                 LDAP_UTF8_INCR( p );
94                         }
95                 } else {
96                         len = LDAP_UTF8_COPY(q,p);
97                         s=NULL;
98                         p+=len;
99                         q+=len;
100                 }
101         }
102
103         assert( *newval->bv_val );
104         assert( newval->bv_val < p );
105         assert( p <= q );
106
107         /* cannot start with a space */
108         assert( !ldap_utf8_isspace(newval->bv_val) );
109
110         /*
111          * If the string ended in space, backup the pointer one
112          * position.  One is enough because the above loop collapsed
113          * all whitespace to a single space.
114          */
115
116         if ( s != NULL ) {
117                 q = s;
118         }
119
120         /* cannot end with a space */
121         assert( !ldap_utf8_isspace( LDAP_UTF8_PREV(q) ) );
122
123         /* null terminate */
124         *q = '\0';
125
126         newval->bv_len = q - newval->bv_val;
127         normalized = &newval;
128
129         return 0;
130 }
131
132 static int
133 IA5StringValidate(
134         Syntax *syntax,
135         struct berval *val )
136 {
137         ber_len_t i;
138
139         for(i=0; i < val->bv_len; i++) {
140                 if( !isascii(val->bv_val[i]) ) return -1;
141         }
142
143         return 0;
144 }
145
146 static int
147 IA5StringConvert(
148         Syntax *syntax,
149         struct berval *in,
150         struct berval **out )
151 {
152         ber_len_t i;
153         struct berval *bv = ch_malloc( sizeof(struct berval) );
154         bv->bv_len = (in->bv_len+1) * sizeof( ldap_unicode_t );
155         bv->bv_val = ch_malloc( bv->bv_len );
156
157         for(i=0; i < in->bv_len; i++ ) {
158                 /*
159                  * IA5StringValidate should have been called to ensure
160                  * input is limited to IA5.
161                  */
162                 bv->bv_val[i] = in->bv_val[i];
163         }
164
165         *out = bv;
166         return 0;
167 }
168
169 static int
170 IA5StringNormalize(
171         Syntax *syntax,
172         MatchingRule *mr,
173         struct berval *val,
174         struct berval **normalized )
175 {
176         struct berval *newval;
177         char *p, *q;
178
179         newval = ch_malloc( sizeof( struct berval ) );
180
181         p = val->bv_val;
182
183         /* Ignore initial whitespace */
184         while ( isspace( *p++ ) ) {
185                 /* EMPTY */  ;
186         }
187
188         if( *p ) {
189                 ch_free( newval );
190                 return 1;
191         }
192
193         newval->bv_val = ch_strdup( p );
194         p = q = newval->bv_val;
195
196         while ( *p ) {
197                 if ( isspace( *p ) ) {
198                         *q++ = *p++;
199
200                         /* Ignore the extra whitespace */
201                         while ( isspace( *p++ ) ) {
202                                 /* EMPTY */  ;
203                         }
204                 } else {
205                         *q++ = *p++;
206                 }
207         }
208
209         assert( *newval->bv_val );
210         assert( newval->bv_val < p );
211         assert( p <= q );
212
213         /* cannot start with a space */
214         assert( !isspace(*newval->bv_val) );
215
216         /*
217          * If the string ended in space, backup the pointer one
218          * position.  One is enough because the above loop collapsed
219          * all whitespace to a single space.
220          */
221
222         if ( isspace( q[-1] ) ) {
223                 --q;
224         }
225
226         /* cannot end with a space */
227         assert( !isspace( q[-1] ) );
228
229         /* null terminate */
230         *q = '\0';
231
232         newval->bv_len = q - newval->bv_val;
233         normalized = &newval;
234
235         return 0;
236 }
237
238 static int
239 caseExactIA5Match(
240         Syntax *syntax,
241         MatchingRule *mr,
242         struct berval *value,
243         struct berval *assertedValue )
244 {
245         return strcmp( value->bv_val, assertedValue->bv_val );
246 }
247
248 static int
249 caseIgnoreIA5Match(
250         Syntax *syntax,
251         MatchingRule *mr,
252         struct berval *value,
253         struct berval *assertedValue )
254 {
255         return strcasecmp( value->bv_val, assertedValue->bv_val );
256 }
257
258 struct syntax_defs_rec {
259         char *sd_desc;
260         slap_syntax_validate_func *sd_validate;
261         slap_syntax_transform_func *sd_ber2str;
262         slap_syntax_transform_func *sd_str2ber;
263 };
264
265 struct syntax_defs_rec syntax_defs[] = {
266         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'AttributeTypeDescription' )",
267                 NULL, NULL, NULL},
268         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' )",
269                 NULL, NULL, NULL},
270         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' )",
271                 NULL, NULL, NULL},
272         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'BitString' )",
273                 NULL, NULL, NULL},
274         {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
275                 NULL, NULL, NULL},
276         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' )",
277                 NULL, NULL, NULL},
278         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'CertificateList' )",
279                 NULL, NULL, NULL},
280         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'CertificatePair' )",
281                 NULL, NULL, NULL},
282         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'DN' )",
283                 NULL, NULL, NULL},
284         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'DeliveryMethod' )",
285                 NULL, NULL, NULL},
286         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'DirectoryString' )",
287                 UTF8StringValidate, NULL, NULL},
288         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DITContentRuleDescription' )",
289                 NULL, NULL, NULL},
290         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DITStructureRuleDescription' )",
291                 NULL, NULL, NULL},
292         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'EnhancedGuide' )",
293                 NULL, NULL, NULL},
294         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'FacsimileTelephoneNumber' )",
295                 NULL, NULL, NULL},
296         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'GeneralizedTime' )",
297                 NULL, NULL, NULL},
298         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
299                 NULL, NULL, NULL},
300         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5String' )",
301                 IA5StringValidate, NULL, NULL},
302         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
303                 NULL, NULL, NULL},
304         {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' )",
305                 NULL, NULL, NULL},
306         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'MatchingRuleDescription' )",
307                 NULL, NULL, NULL},
308         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'MatchingRuleUseDescription' )",
309                 NULL, NULL, NULL},
310         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'MailPreference' )",
311                 NULL, NULL, NULL},
312         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'NameAndOptionalUID' )",
313                 NULL, NULL, NULL},
314         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'NameFormDescription' )",
315                 NULL, NULL, NULL},
316         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'NumericString' )",
317                 NULL, NULL, NULL},
318         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'ObjectClassDescription' )",
319                 NULL, NULL, NULL},
320         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
321                 NULL, NULL, NULL},
322         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'OtherMailbox' )",
323                 NULL, NULL, NULL},
324         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'OctetString' )",
325                 octetStringValidate, NULL, NULL},
326         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'PostalAddress' )",
327                 NULL, NULL, NULL},
328         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'ProtocolInformation' )",
329                 NULL, NULL, NULL},
330         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'PresentationAddress' )",
331                 NULL, NULL, NULL},
332         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'PrintableString' )",
333                 NULL, NULL, NULL},
334         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'SupportedAlgorithm' )",
335                 NULL, NULL, NULL},
336         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'TelephoneNumber' )",
337                 NULL, NULL, NULL},
338         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'TeletexTerminalIdentifier' )",
339                 NULL, NULL, NULL},
340         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'TelexNumber' )",
341                 NULL, NULL, NULL},
342         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTCTime' )",
343                 NULL, NULL, NULL},
344         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAPSyntaxDescription' )",
345                 NULL, NULL, NULL},
346         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'SubstringAssertion' )",
347                 NULL, NULL, NULL},
348
349         {NULL, NULL, NULL}
350 };
351
352 struct mrule_defs_rec {
353         char *mrd_desc;
354         slap_mr_convert_func *mrd_convert;
355         slap_mr_normalize_func *mrd_normalize;
356         slap_mr_match_func *mrd_match;
357 };
358
359 /*
360  * Other matching rules in X.520 that we do not use:
361  *
362  * 2.5.13.9             numericStringOrderingMatch
363  * 2.5.13.12    caseIgnoreListSubstringsMatch
364  * 2.5.13.13    booleanMatch
365  * 2.5.13.15    integerOrderingMatch
366  * 2.5.13.18    octetStringOrderingMatch
367  * 2.5.13.19    octetStringSubstringsMatch
368  * 2.5.13.25    uTCTimeMatch
369  * 2.5.13.26    uTCTimeOrderingMatch
370  * 2.5.13.31    directoryStringFirstComponentMatch
371  * 2.5.13.32    wordMatch
372  * 2.5.13.33    keywordMatch
373  * 2.5.13.34    certificateExactMatch
374  * 2.5.13.35    certificateMatch
375  * 2.5.13.36    certificatePairExactMatch
376  * 2.5.13.37    certificatePairMatch
377  * 2.5.13.38    certificateListExactMatch
378  * 2.5.13.39    certificateListMatch
379  * 2.5.13.40    algorithmIdentifierMatch
380  * 2.5.13.41    storedPrefixMatch
381  * 2.5.13.42    attributeCertificateMatch
382  * 2.5.13.43    readerAndKeyIDMatch
383  * 2.5.13.44    attributeIntegrityMatch
384  */
385
386 /* recycled matching functions */
387 #define caseIgnoreMatch caseIgnoreIA5Match
388 #define caseExactMatch caseExactIA5Match
389
390 /* unimplemented matching functions */
391 #define objectIdentifierMatch NULL
392 #define distinguishedNameMatch NULL
393 #define caseIgnoreOrderingMatch NULL
394 #define caseIgnoreSubstringsMatch NULL
395 #define caseExactOrderingMatch NULL
396 #define caseExactSubstringsMatch NULL
397 #define numericStringMatch NULL
398 #define numericStringSubstringsMatch NULL
399 #define caseIgnoreListMatch NULL
400 #define integerMatch NULL
401 #define bitStringMatch NULL
402 #define octetStringMatch NULL
403 #define telephoneNumberMatch NULL
404 #define telephoneNumberSubstringsMatch NULL
405 #define presentationAddressMatch NULL
406 #define uniqueMemberMatch NULL
407 #define protocolInformationMatch NULL
408 #define generalizedTimeMatch NULL
409 #define generalizedTimeOrderingMatch NULL
410 #define integerFirstComponentMatch NULL
411 #define objectIdentifierFirstComponentMatch NULL
412 #define caseIgnoreIA5SubstringsMatch NULL
413
414 struct mrule_defs_rec mrule_defs[] = {
415         {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
416                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
417                 NULL, NULL, objectIdentifierMatch},
418
419         {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
420                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
421                 NULL, NULL, distinguishedNameMatch},
422
423         {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
424                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
425                 NULL, UTF8StringNormalize, caseIgnoreMatch},
426
427         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
428                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
429                 NULL, UTF8StringNormalize, caseIgnoreOrderingMatch},
430
431         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
432                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
433                 NULL, UTF8StringNormalize, caseIgnoreSubstringsMatch},
434
435         /* Next three are not in the RFC's, but are needed for compatibility */
436         {"( 2.5.13.5 NAME 'caseExactMatch' "
437                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
438                 NULL, UTF8StringNormalize, caseExactMatch},
439
440         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
441                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
442                 NULL, UTF8StringNormalize, caseExactOrderingMatch},
443
444         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
445                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
446                 NULL, UTF8StringNormalize, caseExactSubstringsMatch},
447
448         {"( 2.5.13.8 NAME 'numericStringMatch' "
449                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
450                 NULL, NULL, numericStringMatch},
451
452         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
453                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
454                 NULL, NULL, numericStringSubstringsMatch},
455
456         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
457                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
458                 NULL, NULL, caseIgnoreListMatch},
459
460         {"( 2.5.13.14 NAME 'integerMatch' "
461                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
462                 NULL, NULL, integerMatch},
463
464         {"( 2.5.13.16 NAME 'bitStringMatch' "
465                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
466                 NULL, NULL, bitStringMatch},
467
468         {"( 2.5.13.17 NAME 'octetStringMatch' "
469                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
470                 NULL, NULL, octetStringMatch},
471
472         {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
473                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
474                 NULL, NULL, telephoneNumberMatch},
475
476         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
477                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
478                 NULL, NULL, telephoneNumberSubstringsMatch},
479
480         {"( 2.5.13.22 NAME 'presentationAddressMatch' "
481                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
482                 NULL, NULL, presentationAddressMatch},
483
484         {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
485                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
486                 NULL, NULL, uniqueMemberMatch},
487
488         {"( 2.5.13.24 NAME 'protocolInformationMatch' "
489                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
490                 NULL, NULL, protocolInformationMatch},
491
492         {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
493                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
494                 NULL, NULL, generalizedTimeMatch},
495
496         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
497                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
498                 NULL, NULL, generalizedTimeOrderingMatch},
499
500         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
501                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
502                 NULL, NULL, integerFirstComponentMatch},
503
504         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
505                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
506                 NULL, NULL, objectIdentifierFirstComponentMatch},
507
508         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
509                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
510                 NULL, IA5StringNormalize, caseExactIA5Match},
511
512         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
513                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
514                 NULL, IA5StringNormalize, caseIgnoreIA5Match},
515
516         {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
517                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
518                 NULL, IA5StringNormalize, caseIgnoreIA5SubstringsMatch},
519
520         {NULL, NULL, NULL, NULL}
521 };
522
523 int
524 schema_init( void )
525 {
526         int             res;
527         int             i;
528         static int      schema_init_done = 0;
529
530         /* We are called from read_config that is recursive */
531         if ( schema_init_done )
532                 return( 0 );
533
534         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
535                 res = register_syntax( syntax_defs[i].sd_desc,
536                     syntax_defs[i].sd_validate,
537                     syntax_defs[i].sd_ber2str,
538                         syntax_defs[i].sd_str2ber );
539
540                 if ( res ) {
541                         fprintf( stderr, "schema_init: Error registering syntax %s\n",
542                                  syntax_defs[i].sd_desc );
543                         exit( EXIT_FAILURE );
544                 }
545         }
546
547         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
548                 res = register_matching_rule(
549                         mrule_defs[i].mrd_desc,
550                         mrule_defs[i].mrd_convert,
551                         mrule_defs[i].mrd_normalize,
552                     mrule_defs[i].mrd_match );
553
554                 if ( res ) {
555                         fprintf( stderr,
556                                 "schema_init: Error registering matching rule %s\n",
557                                  mrule_defs[i].mrd_desc );
558                         exit( EXIT_FAILURE );
559                 }
560         }
561         schema_init_done = 1;
562         return( 0 );
563 }