Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / openldap / dist / servers / slapd / schema_init.c
blob807ec9468c9b828758a98f523dccffcfb210ad9f
1 /* schema_init.c - init builtin schema */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/schema_init.c,v 1.386.2.22 2008/07/10 00:02:48 quanah Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2008 The OpenLDAP Foundation.
6 * All rights reserved.
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.
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>.
17 #include "portable.h"
19 #include <stdio.h>
20 #ifdef HAVE_LIMITS_H
21 #include <limits.h>
22 #endif
24 #include <ac/ctype.h>
25 #include <ac/errno.h>
26 #include <ac/string.h>
27 #include <ac/socket.h>
29 #include "slap.h"
30 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
32 #include "ldap_utf8.h"
34 #include "lutil.h"
35 #include "lutil_hash.h"
36 #define HASH_BYTES LUTIL_HASH_BYTES
37 #define HASH_CONTEXT lutil_HASH_CTX
38 #define HASH_Init(c) lutil_HASHInit(c)
39 #define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
40 #define HASH_Final(d,c) lutil_HASHFinal(d,c)
42 /* approx matching rules */
43 #define directoryStringApproxMatchOID "1.3.6.1.4.1.4203.666.4.4"
44 #define directoryStringApproxMatch approxMatch
45 #define directoryStringApproxIndexer approxIndexer
46 #define directoryStringApproxFilter approxFilter
47 #define IA5StringApproxMatchOID "1.3.6.1.4.1.4203.666.4.5"
48 #define IA5StringApproxMatch approxMatch
49 #define IA5StringApproxIndexer approxIndexer
50 #define IA5StringApproxFilter approxFilter
52 /* Change Sequence Number (CSN) - much of this will change */
53 #define csnMatch octetStringMatch
54 #define csnOrderingMatch octetStringOrderingMatch
55 #define csnIndexer generalizedTimeIndexer
56 #define csnFilter generalizedTimeFilter
58 #define authzMatch octetStringMatch
60 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
61 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
62 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
63 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
65 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
66 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
67 SLAP_INDEX_INTLEN_DEFAULT );
69 ldap_pvt_thread_mutex_t ad_undef_mutex;
70 ldap_pvt_thread_mutex_t oc_undef_mutex;
72 static int
73 generalizedTimeValidate(
74 Syntax *syntax,
75 struct berval *in );
77 static int
78 inValidate(
79 Syntax *syntax,
80 struct berval *in )
82 /* no value allowed */
83 return LDAP_INVALID_SYNTAX;
86 static int
87 blobValidate(
88 Syntax *syntax,
89 struct berval *in )
91 /* any value allowed */
92 return LDAP_SUCCESS;
95 #define berValidate blobValidate
97 static int
98 sequenceValidate(
99 Syntax *syntax,
100 struct berval *in )
102 if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
103 if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
105 return LDAP_SUCCESS;
108 /* X.509 related stuff */
110 enum {
111 SLAP_X509_V1 = 0,
112 SLAP_X509_V2 = 1,
113 SLAP_X509_V3 = 2
116 #define SLAP_X509_OPTION (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
118 enum {
119 SLAP_X509_OPT_C_VERSION = SLAP_X509_OPTION + 0,
120 SLAP_X509_OPT_C_ISSUERUNIQUEID = SLAP_X509_OPTION + 1,
121 SLAP_X509_OPT_C_SUBJECTUNIQUEID = SLAP_X509_OPTION + 2,
122 SLAP_X509_OPT_C_EXTENSIONS = SLAP_X509_OPTION + 3
125 enum {
126 SLAP_X509_OPT_CL_CRLEXTENSIONS = SLAP_X509_OPTION + 0
129 /* X.509 certificate validation */
130 static int certificateValidate( Syntax *syntax, struct berval *in )
132 BerElementBuffer berbuf;
133 BerElement *ber = (BerElement *)&berbuf;
134 ber_tag_t tag;
135 ber_len_t len;
136 ber_int_t version = SLAP_X509_V1;
138 ber_init2( ber, in, LBER_USE_DER );
139 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
140 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
141 tag = ber_skip_tag( ber, &len ); /* Sequence */
142 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
143 tag = ber_peek_tag( ber, &len );
144 /* Optional version */
145 if ( tag == SLAP_X509_OPT_C_VERSION ) {
146 tag = ber_skip_tag( ber, &len );
147 tag = ber_get_int( ber, &version );
148 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
150 /* NOTE: don't try to parse Serial, because it might be longer
151 * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
152 tag = ber_skip_tag( ber, &len ); /* Serial */
153 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
154 ber_skip_data( ber, len );
155 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
156 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
157 ber_skip_data( ber, len );
158 tag = ber_skip_tag( ber, &len ); /* Issuer DN */
159 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
160 ber_skip_data( ber, len );
161 tag = ber_skip_tag( ber, &len ); /* Validity */
162 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
163 ber_skip_data( ber, len );
164 tag = ber_skip_tag( ber, &len ); /* Subject DN */
165 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
166 ber_skip_data( ber, len );
167 tag = ber_skip_tag( ber, &len ); /* Subject PublicKeyInfo */
168 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
169 ber_skip_data( ber, len );
170 tag = ber_skip_tag( ber, &len );
171 if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) { /* issuerUniqueID */
172 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
173 ber_skip_data( ber, len );
174 tag = ber_skip_tag( ber, &len );
176 if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
177 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
178 ber_skip_data( ber, len );
179 tag = ber_skip_tag( ber, &len );
181 if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) { /* Extensions */
182 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
183 tag = ber_skip_tag( ber, &len );
184 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
185 ber_skip_data( ber, len );
186 tag = ber_skip_tag( ber, &len );
188 /* signatureAlgorithm */
189 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
190 ber_skip_data( ber, len );
191 tag = ber_skip_tag( ber, &len );
192 /* Signature */
193 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
194 ber_skip_data( ber, len );
195 tag = ber_skip_tag( ber, &len );
196 /* Must be at end now */
197 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
198 return LDAP_SUCCESS;
201 /* X.509 certificate list validation */
202 static int certificateListValidate( Syntax *syntax, struct berval *in )
204 BerElementBuffer berbuf;
205 BerElement *ber = (BerElement *)&berbuf;
206 ber_tag_t tag;
207 ber_len_t len;
208 ber_int_t version = SLAP_X509_V1;
210 ber_init2( ber, in, LBER_USE_DER );
211 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
212 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
213 tag = ber_skip_tag( ber, &len ); /* Sequence */
214 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
215 tag = ber_peek_tag( ber, &len );
216 /* Optional version */
217 if ( tag == LBER_INTEGER ) {
218 tag = ber_get_int( ber, &version );
219 assert( tag == LBER_INTEGER );
220 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
222 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
223 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
224 ber_skip_data( ber, len );
225 tag = ber_skip_tag( ber, &len ); /* Issuer DN */
226 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
227 ber_skip_data( ber, len );
228 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
229 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
230 if ( tag != 0x17U && tag != 0x18U ) return LDAP_INVALID_SYNTAX;
231 ber_skip_data( ber, len );
232 /* Optional nextUpdate */
233 tag = ber_skip_tag( ber, &len );
234 if ( tag == 0x17U || tag == 0x18U ) {
235 ber_skip_data( ber, len );
236 tag = ber_skip_tag( ber, &len );
238 /* revokedCertificates - Sequence of Sequence, Optional */
239 if ( tag == LBER_SEQUENCE ) {
240 ber_len_t seqlen;
241 if ( ber_peek_tag( ber, &seqlen ) == LBER_SEQUENCE ) {
242 /* Should NOT be empty */
243 ber_skip_data( ber, len );
244 tag = ber_skip_tag( ber, &len );
247 /* Optional Extensions */
248 if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
249 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
250 tag = ber_skip_tag( ber, &len );
251 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
252 ber_skip_data( ber, len );
253 tag = ber_skip_tag( ber, &len );
255 /* signatureAlgorithm */
256 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
257 ber_skip_data( ber, len );
258 tag = ber_skip_tag( ber, &len );
259 /* Signature */
260 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
261 ber_skip_data( ber, len );
262 tag = ber_skip_tag( ber, &len );
263 /* Must be at end now */
264 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
265 return LDAP_SUCCESS;
269 octetStringMatch(
270 int *matchp,
271 slap_mask_t flags,
272 Syntax *syntax,
273 MatchingRule *mr,
274 struct berval *value,
275 void *assertedValue )
277 struct berval *asserted = (struct berval *) assertedValue;
278 int match = value->bv_len - asserted->bv_len;
280 if( match == 0 ) {
281 match = memcmp( value->bv_val, asserted->bv_val, value->bv_len );
284 *matchp = match;
285 return LDAP_SUCCESS;
289 octetStringOrderingMatch(
290 int *matchp,
291 slap_mask_t flags,
292 Syntax *syntax,
293 MatchingRule *mr,
294 struct berval *value,
295 void *assertedValue )
297 struct berval *asserted = (struct berval *) assertedValue;
298 ber_len_t v_len = value->bv_len;
299 ber_len_t av_len = asserted->bv_len;
301 int match = memcmp( value->bv_val, asserted->bv_val,
302 (v_len < av_len ? v_len : av_len) );
304 if( match == 0 ) match = v_len - av_len;
306 *matchp = match;
307 return LDAP_SUCCESS;
310 static void
311 hashPreset(
312 HASH_CONTEXT *HASHcontext,
313 struct berval *prefix,
314 char pre,
315 Syntax *syntax,
316 MatchingRule *mr)
318 HASH_Init(HASHcontext);
319 if(prefix && prefix->bv_len > 0) {
320 HASH_Update(HASHcontext,
321 (unsigned char *)prefix->bv_val, prefix->bv_len);
323 if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
324 HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
325 HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
326 return;
329 static void
330 hashIter(
331 HASH_CONTEXT *HASHcontext,
332 unsigned char *HASHdigest,
333 unsigned char *value,
334 int len)
336 HASH_CONTEXT ctx = *HASHcontext;
337 HASH_Update( &ctx, value, len );
338 HASH_Final( HASHdigest, &ctx );
341 /* Index generation function */
342 int octetStringIndexer(
343 slap_mask_t use,
344 slap_mask_t flags,
345 Syntax *syntax,
346 MatchingRule *mr,
347 struct berval *prefix,
348 BerVarray values,
349 BerVarray *keysp,
350 void *ctx )
352 int i;
353 size_t slen, mlen;
354 BerVarray keys;
355 HASH_CONTEXT HASHcontext;
356 unsigned char HASHdigest[HASH_BYTES];
357 struct berval digest;
358 digest.bv_val = (char *)HASHdigest;
359 digest.bv_len = sizeof(HASHdigest);
361 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
362 /* just count them */
365 /* we should have at least one value at this point */
366 assert( i > 0 );
368 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
370 slen = syntax->ssyn_oidlen;
371 mlen = mr->smr_oidlen;
373 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
374 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
375 hashIter( &HASHcontext, HASHdigest,
376 (unsigned char *)values[i].bv_val, values[i].bv_len );
377 ber_dupbv_x( &keys[i], &digest, ctx );
380 BER_BVZERO( &keys[i] );
382 *keysp = keys;
384 return LDAP_SUCCESS;
387 /* Index generation function */
388 int octetStringFilter(
389 slap_mask_t use,
390 slap_mask_t flags,
391 Syntax *syntax,
392 MatchingRule *mr,
393 struct berval *prefix,
394 void * assertedValue,
395 BerVarray *keysp,
396 void *ctx )
398 size_t slen, mlen;
399 BerVarray keys;
400 HASH_CONTEXT HASHcontext;
401 unsigned char HASHdigest[HASH_BYTES];
402 struct berval *value = (struct berval *) assertedValue;
403 struct berval digest;
404 digest.bv_val = (char *)HASHdigest;
405 digest.bv_len = sizeof(HASHdigest);
407 slen = syntax->ssyn_oidlen;
408 mlen = mr->smr_oidlen;
410 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
412 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
413 hashIter( &HASHcontext, HASHdigest,
414 (unsigned char *)value->bv_val, value->bv_len );
416 ber_dupbv_x( keys, &digest, ctx );
417 BER_BVZERO( &keys[1] );
419 *keysp = keys;
421 return LDAP_SUCCESS;
424 static int
425 octetStringSubstringsMatch(
426 int *matchp,
427 slap_mask_t flags,
428 Syntax *syntax,
429 MatchingRule *mr,
430 struct berval *value,
431 void *assertedValue )
433 int match = 0;
434 SubstringsAssertion *sub = assertedValue;
435 struct berval left = *value;
436 int i;
437 ber_len_t inlen = 0;
439 /* Add up asserted input length */
440 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
441 inlen += sub->sa_initial.bv_len;
443 if ( sub->sa_any ) {
444 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
445 inlen += sub->sa_any[i].bv_len;
448 if ( !BER_BVISNULL( &sub->sa_final ) ) {
449 inlen += sub->sa_final.bv_len;
452 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
453 if ( inlen > left.bv_len ) {
454 match = 1;
455 goto done;
458 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
459 sub->sa_initial.bv_len );
461 if ( match != 0 ) {
462 goto done;
465 left.bv_val += sub->sa_initial.bv_len;
466 left.bv_len -= sub->sa_initial.bv_len;
467 inlen -= sub->sa_initial.bv_len;
470 if ( !BER_BVISNULL( &sub->sa_final ) ) {
471 if ( inlen > left.bv_len ) {
472 match = 1;
473 goto done;
476 match = memcmp( sub->sa_final.bv_val,
477 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
478 sub->sa_final.bv_len );
480 if ( match != 0 ) {
481 goto done;
484 left.bv_len -= sub->sa_final.bv_len;
485 inlen -= sub->sa_final.bv_len;
488 if ( sub->sa_any ) {
489 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
490 ber_len_t idx;
491 char *p;
493 retry:
494 if ( inlen > left.bv_len ) {
495 /* not enough length */
496 match = 1;
497 goto done;
500 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
501 continue;
504 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
506 if( p == NULL ) {
507 match = 1;
508 goto done;
511 idx = p - left.bv_val;
513 if ( idx >= left.bv_len ) {
514 /* this shouldn't happen */
515 return LDAP_OTHER;
518 left.bv_val = p;
519 left.bv_len -= idx;
521 if ( sub->sa_any[i].bv_len > left.bv_len ) {
522 /* not enough left */
523 match = 1;
524 goto done;
527 match = memcmp( left.bv_val,
528 sub->sa_any[i].bv_val,
529 sub->sa_any[i].bv_len );
531 if ( match != 0 ) {
532 left.bv_val++;
533 left.bv_len--;
534 goto retry;
537 left.bv_val += sub->sa_any[i].bv_len;
538 left.bv_len -= sub->sa_any[i].bv_len;
539 inlen -= sub->sa_any[i].bv_len;
543 done:
544 *matchp = match;
545 return LDAP_SUCCESS;
548 /* Substrings Index generation function */
549 static int
550 octetStringSubstringsIndexer(
551 slap_mask_t use,
552 slap_mask_t flags,
553 Syntax *syntax,
554 MatchingRule *mr,
555 struct berval *prefix,
556 BerVarray values,
557 BerVarray *keysp,
558 void *ctx )
560 ber_len_t i, nkeys;
561 size_t slen, mlen;
562 BerVarray keys;
564 HASH_CONTEXT HCany, HCini, HCfin;
565 unsigned char HASHdigest[HASH_BYTES];
566 struct berval digest;
567 digest.bv_val = (char *)HASHdigest;
568 digest.bv_len = sizeof(HASHdigest);
570 nkeys = 0;
572 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
573 /* count number of indices to generate */
574 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
575 if( values[i].bv_len >= index_substr_if_maxlen ) {
576 nkeys += index_substr_if_maxlen -
577 (index_substr_if_minlen - 1);
578 } else if( values[i].bv_len >= index_substr_if_minlen ) {
579 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
583 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
584 if( values[i].bv_len >= index_substr_any_len ) {
585 nkeys += values[i].bv_len - (index_substr_any_len - 1);
589 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
590 if( values[i].bv_len >= index_substr_if_maxlen ) {
591 nkeys += index_substr_if_maxlen -
592 (index_substr_if_minlen - 1);
593 } else if( values[i].bv_len >= index_substr_if_minlen ) {
594 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
599 if( nkeys == 0 ) {
600 /* no keys to generate */
601 *keysp = NULL;
602 return LDAP_SUCCESS;
605 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
607 slen = syntax->ssyn_oidlen;
608 mlen = mr->smr_oidlen;
610 if ( flags & SLAP_INDEX_SUBSTR_ANY )
611 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
612 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
613 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
614 if( flags & SLAP_INDEX_SUBSTR_FINAL )
615 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
617 nkeys = 0;
618 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
619 ber_len_t j,max;
621 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
622 ( values[i].bv_len >= index_substr_any_len ) )
624 max = values[i].bv_len - (index_substr_any_len - 1);
626 for( j=0; j<max; j++ ) {
627 hashIter( &HCany, HASHdigest,
628 (unsigned char *)&values[i].bv_val[j],
629 index_substr_any_len );
630 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
634 /* skip if too short */
635 if( values[i].bv_len < index_substr_if_minlen ) continue;
637 max = index_substr_if_maxlen < values[i].bv_len
638 ? index_substr_if_maxlen : values[i].bv_len;
640 for( j=index_substr_if_minlen; j<=max; j++ ) {
642 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
643 hashIter( &HCini, HASHdigest,
644 (unsigned char *)values[i].bv_val, j );
645 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
648 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
649 hashIter( &HCfin, HASHdigest,
650 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
651 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
657 if( nkeys > 0 ) {
658 BER_BVZERO( &keys[nkeys] );
659 *keysp = keys;
660 } else {
661 ch_free( keys );
662 *keysp = NULL;
665 return LDAP_SUCCESS;
668 static int
669 octetStringSubstringsFilter (
670 slap_mask_t use,
671 slap_mask_t flags,
672 Syntax *syntax,
673 MatchingRule *mr,
674 struct berval *prefix,
675 void * assertedValue,
676 BerVarray *keysp,
677 void *ctx)
679 SubstringsAssertion *sa;
680 char pre;
681 ber_len_t nkeys = 0;
682 size_t slen, mlen, klen;
683 BerVarray keys;
684 HASH_CONTEXT HASHcontext;
685 unsigned char HASHdigest[HASH_BYTES];
686 struct berval *value;
687 struct berval digest;
689 sa = (SubstringsAssertion *) assertedValue;
691 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
692 !BER_BVISNULL( &sa->sa_initial ) &&
693 sa->sa_initial.bv_len >= index_substr_if_minlen )
695 nkeys++;
696 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
697 ( flags & SLAP_INDEX_SUBSTR_ANY ))
699 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
703 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
704 ber_len_t i;
705 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
706 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
707 /* don't bother accounting with stepping */
708 nkeys += sa->sa_any[i].bv_len -
709 ( index_substr_any_len - 1 );
714 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
715 !BER_BVISNULL( &sa->sa_final ) &&
716 sa->sa_final.bv_len >= index_substr_if_minlen )
718 nkeys++;
719 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
720 ( flags & SLAP_INDEX_SUBSTR_ANY ))
722 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
726 if( nkeys == 0 ) {
727 *keysp = NULL;
728 return LDAP_SUCCESS;
731 digest.bv_val = (char *)HASHdigest;
732 digest.bv_len = sizeof(HASHdigest);
734 slen = syntax->ssyn_oidlen;
735 mlen = mr->smr_oidlen;
737 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
738 nkeys = 0;
740 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
741 !BER_BVISNULL( &sa->sa_initial ) &&
742 sa->sa_initial.bv_len >= index_substr_if_minlen )
744 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
745 value = &sa->sa_initial;
747 klen = index_substr_if_maxlen < value->bv_len
748 ? index_substr_if_maxlen : value->bv_len;
750 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
751 hashIter( &HASHcontext, HASHdigest,
752 (unsigned char *)value->bv_val, klen );
753 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
755 /* If initial is too long and we have subany indexed, use it
756 * to match the excess...
758 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
760 ber_len_t j;
761 pre = SLAP_INDEX_SUBSTR_PREFIX;
762 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
763 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
765 hashIter( &HASHcontext, HASHdigest,
766 (unsigned char *)&value->bv_val[j], index_substr_any_len );
767 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
772 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
773 ber_len_t i, j;
774 pre = SLAP_INDEX_SUBSTR_PREFIX;
775 klen = index_substr_any_len;
777 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
778 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
779 continue;
782 value = &sa->sa_any[i];
784 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
785 for(j=0;
786 j <= value->bv_len - index_substr_any_len;
787 j += index_substr_any_step )
789 hashIter( &HASHcontext, HASHdigest,
790 (unsigned char *)&value->bv_val[j], klen );
791 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
796 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
797 !BER_BVISNULL( &sa->sa_final ) &&
798 sa->sa_final.bv_len >= index_substr_if_minlen )
800 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
801 value = &sa->sa_final;
803 klen = index_substr_if_maxlen < value->bv_len
804 ? index_substr_if_maxlen : value->bv_len;
806 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
807 hashIter( &HASHcontext, HASHdigest,
808 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
809 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
811 /* If final is too long and we have subany indexed, use it
812 * to match the excess...
814 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
816 ber_len_t j;
817 pre = SLAP_INDEX_SUBSTR_PREFIX;
818 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
819 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
821 hashIter( &HASHcontext, HASHdigest,
822 (unsigned char *)&value->bv_val[j], index_substr_any_len );
823 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
828 if( nkeys > 0 ) {
829 BER_BVZERO( &keys[nkeys] );
830 *keysp = keys;
831 } else {
832 ch_free( keys );
833 *keysp = NULL;
836 return LDAP_SUCCESS;
839 static int
840 bitStringValidate(
841 Syntax *syntax,
842 struct berval *in )
844 ber_len_t i;
846 /* very unforgiving validation, requires no normalization
847 * before simplistic matching
849 if( in->bv_len < 3 ) {
850 return LDAP_INVALID_SYNTAX;
853 /* RFC 4517 Section 3.3.2 Bit String:
854 * BitString = SQUOTE *binary-digit SQUOTE "B"
855 * binary-digit = "0" / "1"
857 * where SQUOTE [RFC4512] is
858 * SQUOTE = %x27 ; single quote ("'")
860 * Example: '0101111101'B
863 if( in->bv_val[0] != '\'' ||
864 in->bv_val[in->bv_len - 2] != '\'' ||
865 in->bv_val[in->bv_len - 1] != 'B' )
867 return LDAP_INVALID_SYNTAX;
870 for( i = in->bv_len - 3; i > 0; i-- ) {
871 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
872 return LDAP_INVALID_SYNTAX;
876 return LDAP_SUCCESS;
880 * Syntaxes from RFC 4517
883 3.3.2. Bit String
885 A value of the Bit String syntax is a sequence of binary digits. The
886 LDAP-specific encoding of a value of this syntax is defined by the
887 following ABNF:
889 BitString = SQUOTE *binary-digit SQUOTE "B"
891 binary-digit = "0" / "1"
893 The <SQUOTE> rule is defined in [MODELS].
895 Example:
896 '0101111101'B
898 The LDAP definition for the Bit String syntax is:
900 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
902 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
906 3.3.21. Name and Optional UID
908 A value of the Name and Optional UID syntax is the distinguished name
909 [MODELS] of an entity optionally accompanied by a unique identifier
910 that serves to differentiate the entity from others with an identical
911 distinguished name.
913 The LDAP-specific encoding of a value of this syntax is defined by
914 the following ABNF:
916 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
918 The <BitString> rule is defined in Section 3.3.2. The
919 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
920 defined in [MODELS].
922 Note that although the '#' character may occur in the string
923 representation of a distinguished name, no additional escaping of
924 this character is performed when a <distinguishedName> is encoded in
925 a <NameAndOptionalUID>.
927 Example:
928 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
930 The LDAP definition for the Name and Optional UID syntax is:
932 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
934 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
935 [X.520].
938 * RFC 4512 says:
941 1.4. Common ABNF Productions
944 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
946 SQUOTE = %x27 ; single quote ("'")
950 * Note: normalization strips any leading "0"s, unless the
951 * bit string is exactly "'0'B", so the normalized example,
952 * in slapd, would result in
954 * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
956 * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
957 * be escaped except when at the beginning of a value, the
958 * definition of Name and Optional UID appears to be flawed,
959 * because there is no clear means to determine whether the
960 * UID part is present or not.
962 * Example:
964 * cn=Someone,dc=example,dc=com#'1'B
966 * could be either a NameAndOptionalUID with trailing UID, i.e.
968 * DN = "cn=Someone,dc=example,dc=com"
969 * UID = "'1'B"
971 * or a NameAndOptionalUID with no trailing UID, and the AVA
972 * in the last RDN made of
974 * attributeType = dc
975 * attributeValue = com#'1'B
977 * in fact "com#'1'B" is a valid IA5 string.
979 * As a consequence, current slapd code assumes that the
980 * presence of portions of a BitString at the end of the string
981 * representation of a NameAndOptionalUID means a BitString
982 * is expected, and cause an error otherwise. This is quite
983 * arbitrary, and might change in the future.
987 static int
988 nameUIDValidate(
989 Syntax *syntax,
990 struct berval *in )
992 int rc;
993 struct berval dn, uid;
995 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
997 ber_dupbv( &dn, in );
998 if( !dn.bv_val ) return LDAP_OTHER;
1000 /* if there's a "#", try bitStringValidate()... */
1001 uid.bv_val = strrchr( dn.bv_val, '#' );
1002 if ( !BER_BVISNULL( &uid ) ) {
1003 uid.bv_val++;
1004 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1006 rc = bitStringValidate( NULL, &uid );
1007 if ( rc == LDAP_SUCCESS ) {
1008 /* in case of success, trim the UID,
1009 * otherwise treat it as part of the DN */
1010 dn.bv_len -= uid.bv_len + 1;
1011 uid.bv_val[-1] = '\0';
1015 rc = dnValidate( NULL, &dn );
1017 ber_memfree( dn.bv_val );
1018 return rc;
1022 nameUIDPretty(
1023 Syntax *syntax,
1024 struct berval *val,
1025 struct berval *out,
1026 void *ctx )
1028 assert( val != NULL );
1029 assert( out != NULL );
1032 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1034 if( BER_BVISEMPTY( val ) ) {
1035 ber_dupbv_x( out, val, ctx );
1037 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1038 return LDAP_INVALID_SYNTAX;
1040 } else {
1041 int rc;
1042 struct berval dnval = *val;
1043 struct berval uidval = BER_BVNULL;
1045 uidval.bv_val = strrchr( val->bv_val, '#' );
1046 if ( !BER_BVISNULL( &uidval ) ) {
1047 uidval.bv_val++;
1048 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1050 rc = bitStringValidate( NULL, &uidval );
1052 if ( rc == LDAP_SUCCESS ) {
1053 ber_dupbv_x( &dnval, val, ctx );
1054 dnval.bv_len -= uidval.bv_len + 1;
1055 dnval.bv_val[dnval.bv_len] = '\0';
1057 } else {
1058 BER_BVZERO( &uidval );
1062 rc = dnPretty( syntax, &dnval, out, ctx );
1063 if ( dnval.bv_val != val->bv_val ) {
1064 slap_sl_free( dnval.bv_val, ctx );
1066 if( rc != LDAP_SUCCESS ) {
1067 return rc;
1070 if( !BER_BVISNULL( &uidval ) ) {
1071 int i, c, got1;
1072 char *tmp;
1074 tmp = slap_sl_realloc( out->bv_val, out->bv_len
1075 + STRLENOF( "#" ) + uidval.bv_len + 1,
1076 ctx );
1077 if( tmp == NULL ) {
1078 ber_memfree_x( out->bv_val, ctx );
1079 return LDAP_OTHER;
1081 out->bv_val = tmp;
1082 out->bv_val[out->bv_len++] = '#';
1083 out->bv_val[out->bv_len++] = '\'';
1085 got1 = uidval.bv_len < sizeof("'0'B");
1086 for( i = 1; i < uidval.bv_len - 2; i++ ) {
1087 c = uidval.bv_val[i];
1088 switch(c) {
1089 case '0':
1090 if( got1 ) out->bv_val[out->bv_len++] = c;
1091 break;
1092 case '1':
1093 got1 = 1;
1094 out->bv_val[out->bv_len++] = c;
1095 break;
1099 out->bv_val[out->bv_len++] = '\'';
1100 out->bv_val[out->bv_len++] = 'B';
1101 out->bv_val[out->bv_len] = '\0';
1105 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1107 return LDAP_SUCCESS;
1110 static int
1111 uniqueMemberNormalize(
1112 slap_mask_t usage,
1113 Syntax *syntax,
1114 MatchingRule *mr,
1115 struct berval *val,
1116 struct berval *normalized,
1117 void *ctx )
1119 struct berval out;
1120 int rc;
1122 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1124 ber_dupbv_x( &out, val, ctx );
1125 if ( BER_BVISEMPTY( &out ) ) {
1126 *normalized = out;
1128 } else {
1129 struct berval uid = BER_BVNULL;
1131 uid.bv_val = strrchr( out.bv_val, '#' );
1132 if ( !BER_BVISNULL( &uid ) ) {
1133 uid.bv_val++;
1134 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1136 rc = bitStringValidate( NULL, &uid );
1137 if ( rc == LDAP_SUCCESS ) {
1138 uid.bv_val[-1] = '\0';
1139 out.bv_len -= uid.bv_len + 1;
1140 } else {
1141 BER_BVZERO( &uid );
1145 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1147 if( rc != LDAP_SUCCESS ) {
1148 slap_sl_free( out.bv_val, ctx );
1149 return LDAP_INVALID_SYNTAX;
1152 if( !BER_BVISNULL( &uid ) ) {
1153 char *tmp;
1155 tmp = ch_realloc( normalized->bv_val,
1156 normalized->bv_len + uid.bv_len
1157 + STRLENOF("#") + 1 );
1158 if ( tmp == NULL ) {
1159 ber_memfree_x( normalized->bv_val, ctx );
1160 return LDAP_OTHER;
1163 normalized->bv_val = tmp;
1165 /* insert the separator */
1166 normalized->bv_val[normalized->bv_len++] = '#';
1168 /* append the UID */
1169 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1170 uid.bv_val, uid.bv_len );
1171 normalized->bv_len += uid.bv_len;
1173 /* terminate */
1174 normalized->bv_val[normalized->bv_len] = '\0';
1177 slap_sl_free( out.bv_val, ctx );
1180 return LDAP_SUCCESS;
1183 static int
1184 uniqueMemberMatch(
1185 int *matchp,
1186 slap_mask_t flags,
1187 Syntax *syntax,
1188 MatchingRule *mr,
1189 struct berval *value,
1190 void *assertedValue )
1192 int match;
1193 struct berval *asserted = (struct berval *) assertedValue;
1194 struct berval assertedDN = *asserted;
1195 struct berval assertedUID = BER_BVNULL;
1196 struct berval valueDN = *value;
1197 struct berval valueUID = BER_BVNULL;
1198 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1200 if ( !BER_BVISEMPTY( asserted ) ) {
1201 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1202 if ( !BER_BVISNULL( &assertedUID ) ) {
1203 assertedUID.bv_val++;
1204 assertedUID.bv_len = assertedDN.bv_len
1205 - ( assertedUID.bv_val - assertedDN.bv_val );
1207 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1208 assertedDN.bv_len -= assertedUID.bv_len + 1;
1210 } else {
1211 BER_BVZERO( &assertedUID );
1216 if ( !BER_BVISEMPTY( value ) ) {
1218 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1219 if ( !BER_BVISNULL( &valueUID ) ) {
1220 valueUID.bv_val++;
1221 valueUID.bv_len = valueDN.bv_len
1222 - ( valueUID.bv_val - valueDN.bv_val );
1224 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1225 valueDN.bv_len -= valueUID.bv_len + 1;
1227 } else {
1228 BER_BVZERO( &valueUID );
1233 if( valueUID.bv_len && assertedUID.bv_len ) {
1234 match = valueUID.bv_len - assertedUID.bv_len;
1235 if ( match ) {
1236 *matchp = match;
1237 return LDAP_SUCCESS;
1240 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1241 if( match ) {
1242 *matchp = match;
1243 return LDAP_SUCCESS;
1246 } else if ( !approx && valueUID.bv_len ) {
1247 match = -1;
1248 *matchp = match;
1249 return LDAP_SUCCESS;
1251 } else if ( !approx && assertedUID.bv_len ) {
1252 match = 1;
1253 *matchp = match;
1254 return LDAP_SUCCESS;
1257 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1260 static int
1261 uniqueMemberIndexer(
1262 slap_mask_t use,
1263 slap_mask_t flags,
1264 Syntax *syntax,
1265 MatchingRule *mr,
1266 struct berval *prefix,
1267 BerVarray values,
1268 BerVarray *keysp,
1269 void *ctx )
1271 BerVarray dnvalues;
1272 int rc;
1273 int i;
1274 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1275 /* just count them */
1277 assert( i > 0 );
1279 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1281 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1282 struct berval assertedDN = values[i];
1283 struct berval assertedUID = BER_BVNULL;
1285 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1286 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1287 if ( !BER_BVISNULL( &assertedUID ) ) {
1288 assertedUID.bv_val++;
1289 assertedUID.bv_len = assertedDN.bv_len
1290 - ( assertedUID.bv_val - assertedDN.bv_val );
1292 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1293 assertedDN.bv_len -= assertedUID.bv_len + 1;
1295 } else {
1296 BER_BVZERO( &assertedUID );
1301 dnvalues[i] = assertedDN;
1303 BER_BVZERO( &dnvalues[i] );
1305 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1306 dnvalues, keysp, ctx );
1308 slap_sl_free( dnvalues, ctx );
1309 return rc;
1312 static int
1313 uniqueMemberFilter(
1314 slap_mask_t use,
1315 slap_mask_t flags,
1316 Syntax *syntax,
1317 MatchingRule *mr,
1318 struct berval *prefix,
1319 void * assertedValue,
1320 BerVarray *keysp,
1321 void *ctx )
1323 struct berval *asserted = (struct berval *) assertedValue;
1324 struct berval assertedDN = *asserted;
1325 struct berval assertedUID = BER_BVNULL;
1327 if ( !BER_BVISEMPTY( asserted ) ) {
1328 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1329 if ( !BER_BVISNULL( &assertedUID ) ) {
1330 assertedUID.bv_val++;
1331 assertedUID.bv_len = assertedDN.bv_len
1332 - ( assertedUID.bv_val - assertedDN.bv_val );
1334 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1335 assertedDN.bv_len -= assertedUID.bv_len + 1;
1337 } else {
1338 BER_BVZERO( &assertedUID );
1343 return octetStringFilter( use, flags, syntax, mr, prefix,
1344 &assertedDN, keysp, ctx );
1349 * Handling boolean syntax and matching is quite rigid.
1350 * A more flexible approach would be to allow a variety
1351 * of strings to be normalized and prettied into TRUE
1352 * and FALSE.
1354 static int
1355 booleanValidate(
1356 Syntax *syntax,
1357 struct berval *in )
1359 /* very unforgiving validation, requires no normalization
1360 * before simplistic matching
1363 if( in->bv_len == 4 ) {
1364 if( bvmatch( in, &slap_true_bv ) ) {
1365 return LDAP_SUCCESS;
1367 } else if( in->bv_len == 5 ) {
1368 if( bvmatch( in, &slap_false_bv ) ) {
1369 return LDAP_SUCCESS;
1373 return LDAP_INVALID_SYNTAX;
1376 static int
1377 booleanMatch(
1378 int *matchp,
1379 slap_mask_t flags,
1380 Syntax *syntax,
1381 MatchingRule *mr,
1382 struct berval *value,
1383 void *assertedValue )
1385 /* simplistic matching allowed by rigid validation */
1386 struct berval *asserted = (struct berval *) assertedValue;
1387 *matchp = value->bv_len != asserted->bv_len;
1388 return LDAP_SUCCESS;
1391 /*-------------------------------------------------------------------
1392 LDAP/X.500 string syntax / matching rules have a few oddities. This
1393 comment attempts to detail how slapd(8) treats them.
1395 Summary:
1396 StringSyntax X.500 LDAP Matching/Comments
1397 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1398 PrintableString subset subset i/e + ignore insignificant spaces
1399 PrintableString subset subset i/e + ignore insignificant spaces
1400 NumericString subset subset ignore all spaces
1401 IA5String ASCII ASCII i/e + ignore insignificant spaces
1402 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1404 TelephoneNumber subset subset i + ignore all spaces and "-"
1406 See RFC 4518 for details.
1409 Directory String -
1410 In X.500(93), a directory string can be either a PrintableString,
1411 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1412 In later versions, more CHOICEs were added. In all cases the string
1413 must be non-empty.
1415 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1416 A directory string cannot be zero length.
1418 For matching, there are both case ignore and exact rules. Both
1419 also require that "insignificant" spaces be ignored.
1420 spaces before the first non-space are ignored;
1421 spaces after the last non-space are ignored;
1422 spaces after a space are ignored.
1423 Note: by these rules (and as clarified in X.520), a string of only
1424 spaces is to be treated as if held one space, not empty (which
1425 would be a syntax error).
1427 NumericString
1428 In ASN.1, numeric string is just a string of digits and spaces
1429 and could be empty. However, in X.500, all attribute values of
1430 numeric string carry a non-empty constraint. For example:
1432 internationalISDNNumber ATTRIBUTE ::= {
1433 WITH SYNTAX InternationalISDNNumber
1434 EQUALITY MATCHING RULE numericStringMatch
1435 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1436 ID id-at-internationalISDNNumber }
1437 InternationalISDNNumber ::=
1438 NumericString (SIZE(1..ub-international-isdn-number))
1440 Unforunately, some assertion values are don't carry the same
1441 constraint (but its unclear how such an assertion could ever
1442 be true). In LDAP, there is one syntax (numericString) not two
1443 (numericString with constraint, numericString without constraint).
1444 This should be treated as numericString with non-empty constraint.
1445 Note that while someone may have no ISDN number, there are no ISDN
1446 numbers which are zero length.
1448 In matching, spaces are ignored.
1450 PrintableString
1451 In ASN.1, Printable string is just a string of printable characters
1452 and can be empty. In X.500, semantics much like NumericString (see
1453 serialNumber for a like example) excepting uses insignificant space
1454 handling instead of ignore all spaces. They must be non-empty.
1456 IA5String
1457 Basically same as PrintableString. There are no examples in X.500,
1458 but same logic applies. Empty strings are allowed.
1460 -------------------------------------------------------------------*/
1462 static int
1463 UTF8StringValidate(
1464 Syntax *syntax,
1465 struct berval *in )
1467 ber_len_t count;
1468 int len;
1469 unsigned char *u = (unsigned char *)in->bv_val;
1471 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1472 /* directory strings cannot be empty */
1473 return LDAP_INVALID_SYNTAX;
1476 for( count = in->bv_len; count > 0; count -= len, u += len ) {
1477 /* get the length indicated by the first byte */
1478 len = LDAP_UTF8_CHARLEN2( u, len );
1480 /* very basic checks */
1481 switch( len ) {
1482 case 6:
1483 if( (u[5] & 0xC0) != 0x80 ) {
1484 return LDAP_INVALID_SYNTAX;
1486 case 5:
1487 if( (u[4] & 0xC0) != 0x80 ) {
1488 return LDAP_INVALID_SYNTAX;
1490 case 4:
1491 if( (u[3] & 0xC0) != 0x80 ) {
1492 return LDAP_INVALID_SYNTAX;
1494 case 3:
1495 if( (u[2] & 0xC0 )!= 0x80 ) {
1496 return LDAP_INVALID_SYNTAX;
1498 case 2:
1499 if( (u[1] & 0xC0) != 0x80 ) {
1500 return LDAP_INVALID_SYNTAX;
1502 case 1:
1503 /* CHARLEN already validated it */
1504 break;
1505 default:
1506 return LDAP_INVALID_SYNTAX;
1509 /* make sure len corresponds with the offset
1510 to the next character */
1511 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1514 if( count != 0 ) {
1515 return LDAP_INVALID_SYNTAX;
1518 return LDAP_SUCCESS;
1521 static int
1522 UTF8StringNormalize(
1523 slap_mask_t use,
1524 Syntax *syntax,
1525 MatchingRule *mr,
1526 struct berval *val,
1527 struct berval *normalized,
1528 void *ctx )
1530 struct berval tmp, nvalue;
1531 int flags;
1532 int i, wasspace;
1534 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1536 if( BER_BVISNULL( val ) ) {
1537 /* assume we're dealing with a syntax (e.g., UTF8String)
1538 * which allows empty strings
1540 BER_BVZERO( normalized );
1541 return LDAP_SUCCESS;
1544 flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1545 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1546 flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1547 ? LDAP_UTF8_APPROX : 0;
1549 val = UTF8bvnormalize( val, &tmp, flags, ctx );
1550 if( val == NULL ) {
1551 return LDAP_OTHER;
1554 /* collapse spaces (in place) */
1555 nvalue.bv_len = 0;
1556 nvalue.bv_val = tmp.bv_val;
1558 /* trim leading spaces? */
1559 wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1560 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1562 for( i = 0; i < tmp.bv_len; i++) {
1563 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1564 if( wasspace++ == 0 ) {
1565 /* trim repeated spaces */
1566 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1568 } else {
1569 wasspace = 0;
1570 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1574 if( !BER_BVISEMPTY( &nvalue ) ) {
1575 /* trim trailing space? */
1576 if( wasspace && (
1577 (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1578 ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1580 --nvalue.bv_len;
1582 nvalue.bv_val[nvalue.bv_len] = '\0';
1584 } else {
1585 /* string of all spaces is treated as one space */
1586 nvalue.bv_val[0] = ' ';
1587 nvalue.bv_val[1] = '\0';
1588 nvalue.bv_len = 1;
1591 *normalized = nvalue;
1592 return LDAP_SUCCESS;
1595 static int
1596 directoryStringSubstringsMatch(
1597 int *matchp,
1598 slap_mask_t flags,
1599 Syntax *syntax,
1600 MatchingRule *mr,
1601 struct berval *value,
1602 void *assertedValue )
1604 int match = 0;
1605 SubstringsAssertion *sub = assertedValue;
1606 struct berval left = *value;
1607 int i;
1608 int priorspace=0;
1610 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1611 if ( sub->sa_initial.bv_len > left.bv_len ) {
1612 /* not enough left */
1613 match = 1;
1614 goto done;
1617 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1618 sub->sa_initial.bv_len );
1620 if ( match != 0 ) {
1621 goto done;
1624 left.bv_val += sub->sa_initial.bv_len;
1625 left.bv_len -= sub->sa_initial.bv_len;
1627 priorspace = ASCII_SPACE(
1628 sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1631 if ( sub->sa_any ) {
1632 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1633 ber_len_t idx;
1634 char *p;
1636 if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1637 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1639 /* allow next space to match */
1640 left.bv_val--;
1641 left.bv_len++;
1643 priorspace=0;
1645 retry:
1646 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1647 continue;
1650 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1651 /* not enough left */
1652 match = 1;
1653 goto done;
1656 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1658 if( p == NULL ) {
1659 match = 1;
1660 goto done;
1663 idx = p - left.bv_val;
1665 if ( idx >= left.bv_len ) {
1666 /* this shouldn't happen */
1667 return LDAP_OTHER;
1670 left.bv_val = p;
1671 left.bv_len -= idx;
1673 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1674 /* not enough left */
1675 match = 1;
1676 goto done;
1679 match = memcmp( left.bv_val,
1680 sub->sa_any[i].bv_val,
1681 sub->sa_any[i].bv_len );
1683 if ( match != 0 ) {
1684 left.bv_val++;
1685 left.bv_len--;
1686 goto retry;
1689 left.bv_val += sub->sa_any[i].bv_len;
1690 left.bv_len -= sub->sa_any[i].bv_len;
1692 priorspace = ASCII_SPACE(
1693 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1697 if ( !BER_BVISNULL( &sub->sa_final ) ) {
1698 if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
1699 && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1701 /* allow next space to match */
1702 left.bv_val--;
1703 left.bv_len++;
1706 if ( sub->sa_final.bv_len > left.bv_len ) {
1707 /* not enough left */
1708 match = 1;
1709 goto done;
1712 match = memcmp( sub->sa_final.bv_val,
1713 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1714 sub->sa_final.bv_len );
1716 if ( match != 0 ) {
1717 goto done;
1721 done:
1722 *matchp = match;
1723 return LDAP_SUCCESS;
1726 #if defined(SLAPD_APPROX_INITIALS)
1727 # define SLAPD_APPROX_DELIMITER "._ "
1728 # define SLAPD_APPROX_WORDLEN 2
1729 #else
1730 # define SLAPD_APPROX_DELIMITER " "
1731 # define SLAPD_APPROX_WORDLEN 1
1732 #endif
1734 static int
1735 approxMatch(
1736 int *matchp,
1737 slap_mask_t flags,
1738 Syntax *syntax,
1739 MatchingRule *mr,
1740 struct berval *value,
1741 void *assertedValue )
1743 struct berval *nval, *assertv;
1744 char *val, **values, **words, *c;
1745 int i, count, len, nextchunk=0, nextavail=0;
1747 /* Yes, this is necessary */
1748 nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
1749 if( nval == NULL ) {
1750 *matchp = 1;
1751 return LDAP_SUCCESS;
1754 /* Yes, this is necessary */
1755 assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
1756 NULL, LDAP_UTF8_APPROX, NULL );
1757 if( assertv == NULL ) {
1758 ber_bvfree( nval );
1759 *matchp = 1;
1760 return LDAP_SUCCESS;
1763 /* Isolate how many words there are */
1764 for ( c = nval->bv_val, count = 1; *c; c++ ) {
1765 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
1766 if ( c == NULL ) break;
1767 *c = '\0';
1768 count++;
1771 /* Get a phonetic copy of each word */
1772 words = (char **)ch_malloc( count * sizeof(char *) );
1773 values = (char **)ch_malloc( count * sizeof(char *) );
1774 for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) {
1775 words[i] = c;
1776 values[i] = phonetic(c);
1779 /* Work through the asserted value's words, to see if at least some
1780 of the words are there, in the same order. */
1781 len = 0;
1782 while ( (ber_len_t) nextchunk < assertv->bv_len ) {
1783 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
1784 if( len == 0 ) {
1785 nextchunk++;
1786 continue;
1788 #if defined(SLAPD_APPROX_INITIALS)
1789 else if( len == 1 ) {
1790 /* Single letter words need to at least match one word's initial */
1791 for( i=nextavail; i<count; i++ )
1792 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
1793 nextavail=i+1;
1794 break;
1797 #endif
1798 else {
1799 /* Isolate the next word in the asserted value and phonetic it */
1800 assertv->bv_val[nextchunk+len] = '\0';
1801 val = phonetic( assertv->bv_val + nextchunk );
1803 /* See if this phonetic chunk is in the remaining words of *value */
1804 for( i=nextavail; i<count; i++ ){
1805 if( !strcmp( val, values[i] ) ){
1806 nextavail = i+1;
1807 break;
1810 ch_free( val );
1813 /* This chunk in the asserted value was NOT within the *value. */
1814 if( i >= count ) {
1815 nextavail=-1;
1816 break;
1819 /* Go on to the next word in the asserted value */
1820 nextchunk += len+1;
1823 /* If some of the words were seen, call it a match */
1824 if( nextavail > 0 ) {
1825 *matchp = 0;
1827 else {
1828 *matchp = 1;
1831 /* Cleanup allocs */
1832 ber_bvfree( assertv );
1833 for( i=0; i<count; i++ ) {
1834 ch_free( values[i] );
1836 ch_free( values );
1837 ch_free( words );
1838 ber_bvfree( nval );
1840 return LDAP_SUCCESS;
1843 static int
1844 approxIndexer(
1845 slap_mask_t use,
1846 slap_mask_t flags,
1847 Syntax *syntax,
1848 MatchingRule *mr,
1849 struct berval *prefix,
1850 BerVarray values,
1851 BerVarray *keysp,
1852 void *ctx )
1854 char *c;
1855 int i,j, len, wordcount, keycount=0;
1856 struct berval *newkeys;
1857 BerVarray keys=NULL;
1859 for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
1860 struct berval val = BER_BVNULL;
1861 /* Yes, this is necessary */
1862 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
1863 assert( !BER_BVISNULL( &val ) );
1865 /* Isolate how many words there are. There will be a key for each */
1866 for( wordcount = 0, c = val.bv_val; *c; c++) {
1867 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1868 if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
1869 c+= len;
1870 if (*c == '\0') break;
1871 *c = '\0';
1874 /* Allocate/increase storage to account for new keys */
1875 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
1876 * sizeof(struct berval) );
1877 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
1878 if( keys ) ch_free( keys );
1879 keys = newkeys;
1881 /* Get a phonetic copy of each word */
1882 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
1883 len = strlen( c );
1884 if( len < SLAPD_APPROX_WORDLEN ) continue;
1885 ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
1886 keycount++;
1887 i++;
1890 ber_memfree( val.bv_val );
1892 BER_BVZERO( &keys[keycount] );
1893 *keysp = keys;
1895 return LDAP_SUCCESS;
1898 static int
1899 approxFilter(
1900 slap_mask_t use,
1901 slap_mask_t flags,
1902 Syntax *syntax,
1903 MatchingRule *mr,
1904 struct berval *prefix,
1905 void * assertedValue,
1906 BerVarray *keysp,
1907 void *ctx )
1909 char *c;
1910 int i, count, len;
1911 struct berval *val;
1912 BerVarray keys;
1914 /* Yes, this is necessary */
1915 val = UTF8bvnormalize( ((struct berval *)assertedValue),
1916 NULL, LDAP_UTF8_APPROX, NULL );
1917 if( val == NULL || BER_BVISNULL( val ) ) {
1918 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
1919 BER_BVZERO( &keys[0] );
1920 *keysp = keys;
1921 ber_bvfree( val );
1922 return LDAP_SUCCESS;
1925 /* Isolate how many words there are. There will be a key for each */
1926 for( count = 0,c = val->bv_val; *c; c++) {
1927 len = strcspn(c, SLAPD_APPROX_DELIMITER);
1928 if( len >= SLAPD_APPROX_WORDLEN ) count++;
1929 c+= len;
1930 if (*c == '\0') break;
1931 *c = '\0';
1934 /* Allocate storage for new keys */
1935 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
1937 /* Get a phonetic copy of each word */
1938 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
1939 len = strlen(c);
1940 if( len < SLAPD_APPROX_WORDLEN ) continue;
1941 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
1942 i++;
1945 ber_bvfree( val );
1947 BER_BVZERO( &keys[count] );
1948 *keysp = keys;
1950 return LDAP_SUCCESS;
1953 /* Remove all spaces and '-' characters */
1954 static int
1955 telephoneNumberNormalize(
1956 slap_mask_t usage,
1957 Syntax *syntax,
1958 MatchingRule *mr,
1959 struct berval *val,
1960 struct berval *normalized,
1961 void *ctx )
1963 char *p, *q;
1965 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1967 /* validator should have refused an empty string */
1968 assert( !BER_BVISEMPTY( val ) );
1970 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
1972 for( p = val->bv_val; *p; p++ ) {
1973 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
1974 *q++ = *p;
1977 *q = '\0';
1979 normalized->bv_len = q - normalized->bv_val;
1981 if( BER_BVISEMPTY( normalized ) ) {
1982 slap_sl_free( normalized->bv_val, ctx );
1983 BER_BVZERO( normalized );
1984 return LDAP_INVALID_SYNTAX;
1987 return LDAP_SUCCESS;
1991 numericoidValidate(
1992 Syntax *syntax,
1993 struct berval *in )
1995 struct berval val = *in;
1997 if( BER_BVISEMPTY( &val ) ) {
1998 /* disallow empty strings */
1999 return LDAP_INVALID_SYNTAX;
2002 while( OID_LEADCHAR( val.bv_val[0] ) ) {
2003 if ( val.bv_len == 1 ) {
2004 return LDAP_SUCCESS;
2007 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2008 break;
2011 val.bv_val++;
2012 val.bv_len--;
2014 while ( OID_LEADCHAR( val.bv_val[0] )) {
2015 val.bv_val++;
2016 val.bv_len--;
2018 if ( val.bv_len == 0 ) {
2019 return LDAP_SUCCESS;
2023 if( !OID_SEPARATOR( val.bv_val[0] )) {
2024 break;
2027 val.bv_val++;
2028 val.bv_len--;
2031 return LDAP_INVALID_SYNTAX;
2034 static int
2035 integerValidate(
2036 Syntax *syntax,
2037 struct berval *in )
2039 ber_len_t i;
2040 struct berval val = *in;
2042 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2044 if ( val.bv_val[0] == '-' ) {
2045 val.bv_len--;
2046 val.bv_val++;
2048 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2049 return LDAP_INVALID_SYNTAX;
2052 if( val.bv_val[0] == '0' ) { /* "-0" */
2053 return LDAP_INVALID_SYNTAX;
2056 } else if ( val.bv_val[0] == '0' ) {
2057 if( val.bv_len > 1 ) { /* "0<more>" */
2058 return LDAP_INVALID_SYNTAX;
2061 return LDAP_SUCCESS;
2064 for( i=0; i < val.bv_len; i++ ) {
2065 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2066 return LDAP_INVALID_SYNTAX;
2070 return LDAP_SUCCESS;
2073 static int
2074 integerMatch(
2075 int *matchp,
2076 slap_mask_t flags,
2077 Syntax *syntax,
2078 MatchingRule *mr,
2079 struct berval *value,
2080 void *assertedValue )
2082 struct berval *asserted = (struct berval *) assertedValue;
2083 int vsign = 1, asign = 1; /* default sign = '+' */
2084 struct berval v, a;
2085 int match;
2087 v = *value;
2088 if( v.bv_val[0] == '-' ) {
2089 vsign = -1;
2090 v.bv_val++;
2091 v.bv_len--;
2094 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2096 a = *asserted;
2097 if( a.bv_val[0] == '-' ) {
2098 asign = -1;
2099 a.bv_val++;
2100 a.bv_len--;
2103 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2105 match = vsign - asign;
2106 if( match == 0 ) {
2107 match = ( v.bv_len != a.bv_len
2108 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2109 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2110 if( vsign < 0 ) match = -match;
2113 *matchp = match;
2114 return LDAP_SUCCESS;
2117 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2118 #define INDEX_INTLEN_CHOP 7
2119 #define INDEX_INTLEN_CHOPBYTES 3
2121 static int
2122 integerVal2Key(
2123 struct berval *in,
2124 struct berval *key,
2125 struct berval *tmp,
2126 void *ctx )
2128 /* index format:
2129 * only if too large: one's complement <sign*exponent (chopped bytes)>,
2130 * two's complement value (sign-extended or chopped as needed),
2131 * however the top <number of exponent-bytes + 1> bits of first byte
2132 * above is the inverse sign. The next bit is the sign as delimiter.
2134 ber_slen_t k = index_intlen_strlen;
2135 ber_len_t chop = 0;
2136 unsigned signmask = ~0x7fU;
2137 unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2138 struct berval val = *in, itmp = *tmp;
2140 if ( val.bv_val[0] != '-' ) {
2141 neg = 0;
2142 --k;
2145 /* Chop least significant digits, increase length instead */
2146 if ( val.bv_len > (ber_len_t) k ) {
2147 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2148 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2149 chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
2152 if ( lutil_str2bin( &val, &itmp, ctx )) {
2153 return LDAP_INVALID_SYNTAX;
2156 /* Omit leading sign byte */
2157 if ( itmp.bv_val[0] == neg ) {
2158 itmp.bv_val++;
2159 itmp.bv_len--;
2162 k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2163 if ( k > 0 ) {
2164 assert( chop == 0 );
2165 memset( key->bv_val, neg, k ); /* sign-extend */
2166 } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2167 lenp = lenbuf + sizeof(lenbuf);
2168 chop = - (ber_len_t) k;
2169 do {
2170 *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2171 signmask >>= 1;
2172 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2173 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2174 * are 1, and the top n+2 bits of lenp[] are the sign bit. */
2175 k = (lenbuf + sizeof(lenbuf)) - lenp;
2176 if ( k > (ber_slen_t) index_intlen )
2177 k = index_intlen;
2178 memcpy( key->bv_val, lenp, k );
2179 itmp.bv_len = index_intlen - k;
2181 memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2182 key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2183 return 0;
2186 /* Index generation function */
2187 static int
2188 integerIndexer(
2189 slap_mask_t use,
2190 slap_mask_t flags,
2191 Syntax *syntax,
2192 MatchingRule *mr,
2193 struct berval *prefix,
2194 BerVarray values,
2195 BerVarray *keysp,
2196 void *ctx )
2198 char ibuf[64];
2199 struct berval itmp;
2200 BerVarray keys;
2201 ber_len_t vlen;
2202 int i, rc;
2203 unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2205 /* count the values and find max needed length */
2206 vlen = 0;
2207 for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2208 if ( vlen < values[i].bv_len )
2209 vlen = values[i].bv_len;
2211 if ( vlen > maxstrlen )
2212 vlen = maxstrlen;
2214 /* we should have at least one value at this point */
2215 assert( i > 0 );
2217 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2218 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2219 keys[i].bv_len = index_intlen;
2220 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2222 keys[i].bv_len = 0;
2223 keys[i].bv_val = NULL;
2225 if ( vlen > sizeof(ibuf) ) {
2226 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2227 } else {
2228 itmp.bv_val = ibuf;
2230 itmp.bv_len = sizeof(ibuf);
2232 for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2233 if ( itmp.bv_val != ibuf ) {
2234 itmp.bv_len = values[i].bv_len;
2235 if ( itmp.bv_len <= sizeof(ibuf) )
2236 itmp.bv_len = sizeof(ibuf);
2237 else if ( itmp.bv_len > maxstrlen )
2238 itmp.bv_len = maxstrlen;
2240 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2241 if ( rc )
2242 goto func_leave;
2244 *keysp = keys;
2245 func_leave:
2246 if ( itmp.bv_val != ibuf ) {
2247 slap_sl_free( itmp.bv_val, ctx );
2249 return rc;
2252 /* Index generation function */
2253 static int
2254 integerFilter(
2255 slap_mask_t use,
2256 slap_mask_t flags,
2257 Syntax *syntax,
2258 MatchingRule *mr,
2259 struct berval *prefix,
2260 void * assertedValue,
2261 BerVarray *keysp,
2262 void *ctx )
2264 char ibuf[64];
2265 struct berval iv;
2266 BerVarray keys;
2267 struct berval *value;
2268 int rc;
2270 value = (struct berval *) assertedValue;
2272 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2274 keys[0].bv_len = index_intlen;
2275 keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2276 keys[1].bv_len = 0;
2277 keys[1].bv_val = NULL;
2279 iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2280 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2281 if ( iv.bv_len > (int) sizeof(ibuf) ) {
2282 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2283 } else {
2284 iv.bv_val = ibuf;
2285 iv.bv_len = sizeof(ibuf);
2288 rc = integerVal2Key( value, keys, &iv, ctx );
2289 if ( rc == 0 )
2290 *keysp = keys;
2292 if ( iv.bv_val != ibuf ) {
2293 slap_sl_free( iv.bv_val, ctx );
2295 return rc;
2298 static int
2299 countryStringValidate(
2300 Syntax *syntax,
2301 struct berval *val )
2303 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2305 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2306 return LDAP_INVALID_SYNTAX;
2308 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2309 return LDAP_INVALID_SYNTAX;
2312 return LDAP_SUCCESS;
2315 static int
2316 printableStringValidate(
2317 Syntax *syntax,
2318 struct berval *val )
2320 ber_len_t i;
2322 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2324 for(i=0; i < val->bv_len; i++) {
2325 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2326 return LDAP_INVALID_SYNTAX;
2330 return LDAP_SUCCESS;
2333 static int
2334 printablesStringValidate(
2335 Syntax *syntax,
2336 struct berval *val )
2338 ber_len_t i, len;
2340 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2342 for(i=0,len=0; i < val->bv_len; i++) {
2343 int c = val->bv_val[i];
2345 if( c == '$' ) {
2346 if( len == 0 ) {
2347 return LDAP_INVALID_SYNTAX;
2349 len = 0;
2351 } else if ( SLAP_PRINTABLE(c) ) {
2352 len++;
2353 } else {
2354 return LDAP_INVALID_SYNTAX;
2358 if( len == 0 ) {
2359 return LDAP_INVALID_SYNTAX;
2362 return LDAP_SUCCESS;
2365 static int
2366 IA5StringValidate(
2367 Syntax *syntax,
2368 struct berval *val )
2370 ber_len_t i;
2372 for(i=0; i < val->bv_len; i++) {
2373 if( !LDAP_ASCII(val->bv_val[i]) ) {
2374 return LDAP_INVALID_SYNTAX;
2378 return LDAP_SUCCESS;
2381 static int
2382 IA5StringNormalize(
2383 slap_mask_t use,
2384 Syntax *syntax,
2385 MatchingRule *mr,
2386 struct berval *val,
2387 struct berval *normalized,
2388 void *ctx )
2390 char *p, *q;
2391 int casefold = !SLAP_MR_ASSOCIATED( mr,
2392 slap_schema.si_mr_caseExactIA5Match );
2394 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2396 p = val->bv_val;
2398 /* Ignore initial whitespace */
2399 while ( ASCII_SPACE( *p ) ) p++;
2401 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2402 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2403 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2404 normalized->bv_val[normalized->bv_len] = '\0';
2406 p = q = normalized->bv_val;
2408 while ( *p ) {
2409 if ( ASCII_SPACE( *p ) ) {
2410 *q++ = *p++;
2412 /* Ignore the extra whitespace */
2413 while ( ASCII_SPACE( *p ) ) {
2414 p++;
2417 } else if ( casefold ) {
2418 /* Most IA5 rules require casefolding */
2419 *q++ = TOLOWER(*p); p++;
2421 } else {
2422 *q++ = *p++;
2426 assert( normalized->bv_val <= p );
2427 assert( q <= p );
2430 * If the string ended in space, backup the pointer one
2431 * position. One is enough because the above loop collapsed
2432 * all whitespace to a single space.
2434 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2436 /* null terminate */
2437 *q = '\0';
2439 normalized->bv_len = q - normalized->bv_val;
2441 return LDAP_SUCCESS;
2444 static int
2445 UUIDValidate(
2446 Syntax *syntax,
2447 struct berval *in )
2449 int i;
2450 if( in->bv_len != 36 ) {
2451 return LDAP_INVALID_SYNTAX;
2454 for( i=0; i<36; i++ ) {
2455 switch(i) {
2456 case 8:
2457 case 13:
2458 case 18:
2459 case 23:
2460 if( in->bv_val[i] != '-' ) {
2461 return LDAP_INVALID_SYNTAX;
2463 break;
2464 default:
2465 if( !ASCII_HEX( in->bv_val[i]) ) {
2466 return LDAP_INVALID_SYNTAX;
2471 return LDAP_SUCCESS;
2474 static int
2475 UUIDPretty(
2476 Syntax *syntax,
2477 struct berval *in,
2478 struct berval *out,
2479 void *ctx )
2481 int i;
2482 int rc=LDAP_INVALID_SYNTAX;
2484 assert( in != NULL );
2485 assert( out != NULL );
2487 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2489 out->bv_len = 36;
2490 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2492 for( i=0; i<36; i++ ) {
2493 switch(i) {
2494 case 8:
2495 case 13:
2496 case 18:
2497 case 23:
2498 if( in->bv_val[i] != '-' ) {
2499 goto handle_error;
2501 out->bv_val[i] = '-';
2502 break;
2504 default:
2505 if( !ASCII_HEX( in->bv_val[i]) ) {
2506 goto handle_error;
2508 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2512 rc = LDAP_SUCCESS;
2513 out->bv_val[ out->bv_len ] = '\0';
2515 if( 0 ) {
2516 handle_error:
2517 slap_sl_free( out->bv_val, ctx );
2518 out->bv_val = NULL;
2521 return rc;
2525 UUIDNormalize(
2526 slap_mask_t usage,
2527 Syntax *syntax,
2528 MatchingRule *mr,
2529 struct berval *val,
2530 struct berval *normalized,
2531 void *ctx )
2533 unsigned char octet = '\0';
2534 int i;
2535 int j;
2537 if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2538 /* NOTE: must be a normalized UUID */
2539 assert( val->bv_len == 16 );
2541 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2542 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2543 val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2544 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2546 return LDAP_SUCCESS;
2549 normalized->bv_len = 16;
2550 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2552 for( i=0, j=0; i<36; i++ ) {
2553 unsigned char nibble;
2554 if( val->bv_val[i] == '-' ) {
2555 continue;
2557 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2558 nibble = val->bv_val[i] - '0';
2560 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2561 nibble = val->bv_val[i] - ('a'-10);
2563 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2564 nibble = val->bv_val[i] - ('A'-10);
2566 } else {
2567 slap_sl_free( normalized->bv_val, ctx );
2568 return LDAP_INVALID_SYNTAX;
2571 if( j & 1 ) {
2572 octet |= nibble;
2573 normalized->bv_val[j>>1] = octet;
2574 } else {
2575 octet = nibble << 4;
2577 j++;
2580 normalized->bv_val[normalized->bv_len] = 0;
2581 return LDAP_SUCCESS;
2587 numericStringValidate(
2588 Syntax *syntax,
2589 struct berval *in )
2591 ber_len_t i;
2593 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2595 for(i=0; i < in->bv_len; i++) {
2596 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2597 return LDAP_INVALID_SYNTAX;
2601 return LDAP_SUCCESS;
2604 static int
2605 numericStringNormalize(
2606 slap_mask_t usage,
2607 Syntax *syntax,
2608 MatchingRule *mr,
2609 struct berval *val,
2610 struct berval *normalized,
2611 void *ctx )
2613 /* removal all spaces */
2614 char *p, *q;
2616 assert( !BER_BVISEMPTY( val ) );
2618 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2620 p = val->bv_val;
2621 q = normalized->bv_val;
2623 while ( *p ) {
2624 if ( ASCII_SPACE( *p ) ) {
2625 /* Ignore whitespace */
2626 p++;
2627 } else {
2628 *q++ = *p++;
2632 /* we should have copied no more than is in val */
2633 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
2635 /* null terminate */
2636 *q = '\0';
2638 normalized->bv_len = q - normalized->bv_val;
2640 if( BER_BVISEMPTY( normalized ) ) {
2641 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
2642 normalized->bv_val[0] = ' ';
2643 normalized->bv_val[1] = '\0';
2644 normalized->bv_len = 1;
2647 return LDAP_SUCCESS;
2651 * Integer conversion macros that will use the largest available
2652 * type.
2654 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
2655 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
2656 # define SLAP_LONG long long
2657 #else
2658 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
2659 # define SLAP_LONG long
2660 #endif /* HAVE_STRTOLL ... */
2662 static int
2663 integerBitAndMatch(
2664 int *matchp,
2665 slap_mask_t flags,
2666 Syntax *syntax,
2667 MatchingRule *mr,
2668 struct berval *value,
2669 void *assertedValue )
2671 SLAP_LONG lValue, lAssertedValue;
2673 errno = 0;
2674 /* safe to assume integers are NUL terminated? */
2675 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2676 if( errno == ERANGE )
2678 return LDAP_CONSTRAINT_VIOLATION;
2681 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
2682 NULL, 10);
2683 if( errno == ERANGE )
2685 return LDAP_CONSTRAINT_VIOLATION;
2688 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
2689 return LDAP_SUCCESS;
2692 static int
2693 integerBitOrMatch(
2694 int *matchp,
2695 slap_mask_t flags,
2696 Syntax *syntax,
2697 MatchingRule *mr,
2698 struct berval *value,
2699 void *assertedValue )
2701 SLAP_LONG lValue, lAssertedValue;
2703 errno = 0;
2704 /* safe to assume integers are NUL terminated? */
2705 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
2706 if( errno == ERANGE )
2708 return LDAP_CONSTRAINT_VIOLATION;
2711 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
2712 NULL, 10);
2713 if( errno == ERANGE )
2715 return LDAP_CONSTRAINT_VIOLATION;
2718 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
2719 return LDAP_SUCCESS;
2722 static int
2723 serialNumberAndIssuerCheck(
2724 struct berval *in,
2725 struct berval *sn,
2726 struct berval *is,
2727 void *ctx
2730 int is_hex = 0, n;
2732 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
2734 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
2735 /* Parse old format */
2736 is->bv_val = ber_bvchr( in, '$' );
2737 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
2739 sn->bv_val = in->bv_val;
2740 sn->bv_len = is->bv_val - in->bv_val;
2742 is->bv_val++;
2743 is->bv_len = in->bv_len - (sn->bv_len + 1);
2745 /* eat leading zeros */
2746 for( n=0; n < (sn->bv_len-1); n++ ) {
2747 if( sn->bv_val[n] != '0' ) break;
2749 sn->bv_val += n;
2750 sn->bv_len -= n;
2752 for( n=0; n < sn->bv_len; n++ ) {
2753 if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
2756 } else {
2757 /* Parse GSER format */
2758 int havesn = 0, haveissuer = 0, numdquotes = 0;
2759 struct berval x = *in;
2760 struct berval ni;
2761 x.bv_val++;
2762 x.bv_len-=2;
2764 /* eat leading spaces */
2765 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2766 /* empty */;
2769 if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
2770 return LDAP_INVALID_SYNTAX;
2773 /* should be at issuer or serialNumber NamedValue */
2774 if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
2775 /* parse issuer */
2776 x.bv_val += STRLENOF("issuer");
2777 x.bv_len -= STRLENOF("issuer");
2779 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2780 x.bv_val++; x.bv_len--;
2782 /* eat leading spaces */
2783 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2784 /* empty */;
2787 /* For backward compatibility, this part is optional */
2788 if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2789 x.bv_val += STRLENOF("rdnSequence:");
2790 x.bv_len -= STRLENOF("rdnSequence:");
2793 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2794 x.bv_val++; x.bv_len--;
2796 is->bv_val = x.bv_val;
2797 is->bv_len = 0;
2799 for( ; is->bv_len < x.bv_len; ) {
2800 if ( is->bv_val[is->bv_len] != '"' ) {
2801 is->bv_len++;
2802 continue;
2804 if ( is->bv_val[is->bv_len+1] == '"' ) {
2805 /* double dquote */
2806 is->bv_len+=2;
2807 continue;
2809 break;
2811 x.bv_val += is->bv_len+1;
2812 x.bv_len -= is->bv_len+1;
2814 if ( x.bv_len < STRLENOF(",serialNumber 0")) {
2815 return LDAP_INVALID_SYNTAX;
2818 haveissuer++;
2820 } else if( strncasecmp( x.bv_val, "serialNumber",
2821 STRLENOF("serialNumber")) == 0 )
2823 /* parse serialNumber */
2824 int neg = 0;
2825 char first = '\0';
2826 int extra = 0;
2828 x.bv_val += STRLENOF("serialNumber");
2829 x.bv_len -= STRLENOF("serialNumber");
2831 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2832 x.bv_val++; x.bv_len--;
2834 /* eat leading spaces */
2835 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2836 /* empty */;
2839 sn->bv_val = x.bv_val;
2840 sn->bv_len = 0;
2842 if( sn->bv_val[0] == '-' ) {
2843 neg++;
2844 sn->bv_len++;
2847 if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2848 sn->bv_val[1] == 'X' ))
2850 is_hex = 1;
2851 first = sn->bv_val[2];
2852 extra = 2;
2854 sn->bv_len += STRLENOF("0x");
2855 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2856 if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2859 } else if ( sn->bv_val[0] == '\'' ) {
2860 first = sn->bv_val[1];
2861 extra = 3;
2863 sn->bv_len += STRLENOF("'");
2865 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2866 if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2868 if ( sn->bv_val[sn->bv_len] == '\'' &&
2869 sn->bv_val[sn->bv_len + 1] == 'H' )
2871 sn->bv_len += STRLENOF("'H");
2872 is_hex = 1;
2874 } else {
2875 return LDAP_INVALID_SYNTAX;
2878 } else {
2879 first = sn->bv_val[0];
2880 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2881 if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2885 if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2886 if (( sn->bv_len > extra+1+neg ) && ( first == '0' )) {
2887 return LDAP_INVALID_SYNTAX;
2890 x.bv_val += sn->bv_len; x.bv_len -= sn->bv_len;
2892 if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
2893 return LDAP_INVALID_SYNTAX;
2896 havesn++;
2898 } else return LDAP_INVALID_SYNTAX;
2900 if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
2901 x.bv_val++; x.bv_len--;
2903 /* eat spaces */
2904 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2905 /* empty */;
2908 /* should be at remaining NamedValue */
2909 if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
2910 STRLENOF("issuer" )) == 0 ))
2912 /* parse issuer */
2913 x.bv_val += STRLENOF("issuer");
2914 x.bv_len -= STRLENOF("issuer");
2916 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2917 x.bv_val++; x.bv_len--;
2919 /* eat leading spaces */
2920 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
2921 /* empty */;
2924 /* For backward compatibility, this part is optional */
2925 if( !strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:"))) {
2926 x.bv_val += STRLENOF("rdnSequence:");
2927 x.bv_len -= STRLENOF("rdnSequence:");
2930 if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
2931 x.bv_val++; x.bv_len--;
2933 is->bv_val = x.bv_val;
2934 is->bv_len = 0;
2936 for( ; is->bv_len < x.bv_len; ) {
2937 if ( is->bv_val[is->bv_len] != '"' ) {
2938 is->bv_len++;
2939 continue;
2941 if ( is->bv_val[is->bv_len+1] == '"' ) {
2942 /* double dquote */
2943 numdquotes++;
2944 is->bv_len+=2;
2945 continue;
2947 break;
2949 x.bv_val += is->bv_len+1;
2950 x.bv_len -= is->bv_len+1;
2952 } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
2953 STRLENOF("serialNumber")) == 0 ))
2955 /* parse serialNumber */
2956 int neg=0;
2957 x.bv_val += STRLENOF("serialNumber");
2958 x.bv_len -= STRLENOF("serialNumber");
2960 if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
2961 x.bv_val++; x.bv_len--;
2963 /* eat leading spaces */
2964 for( ; (x.bv_val[0] == ' ') && x.bv_len ; x.bv_val++, x.bv_len--) {
2965 /* empty */;
2968 sn->bv_val = x.bv_val;
2969 sn->bv_len = 0;
2971 if( sn->bv_val[0] == '-' ) {
2972 neg++;
2973 sn->bv_len++;
2976 if ( sn->bv_val[0] == '0' && ( sn->bv_val[1] == 'x' ||
2977 sn->bv_val[1] == 'X' )) {
2978 is_hex = 1;
2979 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2980 if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2982 } else if ( sn->bv_val[0] == '\'' ) {
2983 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2984 if ( !ASCII_HEX( sn->bv_val[sn->bv_len] )) break;
2986 if ( sn->bv_val[sn->bv_len] == '\'' &&
2987 sn->bv_val[sn->bv_len+1] == 'H' )
2988 is_hex = 1;
2989 else
2990 return LDAP_INVALID_SYNTAX;
2991 sn->bv_len += 2;
2992 } else {
2993 for( ; sn->bv_len < x.bv_len; sn->bv_len++ ) {
2994 if ( !ASCII_DIGIT( sn->bv_val[sn->bv_len] )) break;
2998 if (!( sn->bv_len > neg )) return LDAP_INVALID_SYNTAX;
2999 if (( sn->bv_len > 1+neg ) && ( sn->bv_val[neg] == '0' )) {
3000 return LDAP_INVALID_SYNTAX;
3003 x.bv_val += sn->bv_len;
3004 x.bv_len -= sn->bv_len;
3006 } else return LDAP_INVALID_SYNTAX;
3008 /* eat trailing spaces */
3009 for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
3010 /* empty */;
3013 /* should have no characters left... */
3014 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
3016 if ( numdquotes == 0 ) {
3017 ber_dupbv_x( &ni, is, ctx );
3018 } else {
3019 ber_int_t src, dst;
3021 ni.bv_len = is->bv_len - numdquotes;
3022 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3023 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3024 if ( is->bv_val[src] == '"' ) {
3025 src++;
3027 ni.bv_val[dst] = is->bv_val[src];
3029 ni.bv_val[dst] = '\0';
3032 *is = ni;
3035 return 0;
3038 static int
3039 serialNumberAndIssuerValidate(
3040 Syntax *syntax,
3041 struct berval *in )
3043 int rc;
3044 struct berval sn, i;
3046 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3047 in->bv_val, 0, 0 );
3049 rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3050 if ( rc )
3051 return rc;
3053 /* validate DN -- doesn't handle double dquote */
3054 rc = dnValidate( NULL, &i );
3055 if( rc )
3056 rc = LDAP_INVALID_SYNTAX;
3058 if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3059 slap_sl_free( i.bv_val, NULL );
3062 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: OKAY\n",
3063 0, 0, 0 );
3064 return rc;
3068 serialNumberAndIssuerPretty(
3069 Syntax *syntax,
3070 struct berval *in,
3071 struct berval *out,
3072 void *ctx )
3074 int n, rc;
3075 struct berval sn, i, ni;
3077 assert( in != NULL );
3078 assert( out != NULL );
3080 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3081 in->bv_val, 0, 0 );
3083 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3084 if ( rc )
3085 return rc;
3087 rc = dnPretty( syntax, &i, &ni, ctx );
3089 if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3090 slap_sl_free( i.bv_val, ctx );
3093 if( rc ) return LDAP_INVALID_SYNTAX;
3095 /* make room from sn + "$" */
3096 out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3097 + sn.bv_len + ni.bv_len;
3098 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3100 if( out->bv_val == NULL ) {
3101 out->bv_len = 0;
3102 slap_sl_free( ni.bv_val, ctx );
3103 return LDAP_OTHER;
3106 n = 0;
3107 AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3108 STRLENOF("{ serialNumber "));
3109 n = STRLENOF("{ serialNumber ");
3111 AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3112 n += sn.bv_len;
3114 AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF(", issuer rdnSequence:\""));
3115 n += STRLENOF(", issuer rdnSequence:\"");
3117 AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3118 n += ni.bv_len;
3120 AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
3121 n += STRLENOF("\" }");
3123 out->bv_val[n] = '\0';
3125 assert( n == out->bv_len );
3127 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
3128 out->bv_val, 0, 0 );
3130 slap_sl_free( ni.bv_val, ctx );
3132 return LDAP_SUCCESS;
3136 * This routine is called by certificateExactNormalize when
3137 * certificateExactNormalize receives a search string instead of
3138 * a certificate. This routine checks if the search value is valid
3139 * and then returns the normalized value
3141 static int
3142 serialNumberAndIssuerNormalize(
3143 slap_mask_t usage,
3144 Syntax *syntax,
3145 MatchingRule *mr,
3146 struct berval *in,
3147 struct berval *out,
3148 void *ctx )
3150 struct berval sn, sn2, i, ni;
3151 char sbuf[64], *stmp = sbuf;
3152 int rc;
3153 ber_len_t n;
3155 assert( in != NULL );
3156 assert( out != NULL );
3158 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3159 in->bv_val, 0, 0 );
3161 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3162 if ( rc )
3163 return rc;
3165 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3167 if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3168 slap_sl_free( i.bv_val, ctx );
3171 if( rc ) return LDAP_INVALID_SYNTAX;
3173 /* Convert sn to canonical hex */
3174 if ( sn.bv_len > sizeof( sbuf )) {
3175 stmp = slap_sl_malloc( sn.bv_len, ctx );
3177 sn2.bv_val = stmp;
3178 sn2.bv_len = sn.bv_len;
3179 if ( lutil_str2bin( &sn, &sn2, ctx )) {
3180 rc = LDAP_INVALID_SYNTAX;
3181 goto func_leave;
3184 /* make room for sn + "$" */
3185 out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3186 + ( sn2.bv_len * 2 + 3 ) + ni.bv_len;
3187 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3189 if( out->bv_val == NULL ) {
3190 out->bv_len = 0;
3191 slap_sl_free( ni.bv_val, ctx );
3192 rc = LDAP_OTHER;
3193 goto func_leave;
3196 n = 0;
3197 AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
3198 STRLENOF( "{ serialNumber " ));
3199 n = STRLENOF( "{ serialNumber " );
3201 AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
3203 int j;
3204 unsigned char *v = (unsigned char *)sn2.bv_val;
3205 out->bv_val[n++] = '\'';
3206 for ( j = 0; j < sn2.bv_len; j++ ) {
3207 snprintf( &out->bv_val[n], out->bv_len - n + 1,
3208 "%02X", v[j] );
3209 n += 2;
3211 out->bv_val[n++] = '\'';
3212 out->bv_val[n++] = 'H';
3215 AC_MEMCPY( &out->bv_val[n], ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3216 n += STRLENOF( ", issuer rdnSequence:\"" );
3218 AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
3219 n += ni.bv_len;
3221 AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
3222 n += STRLENOF( "\" }" );
3224 out->bv_val[n] = '\0';
3226 assert( n == out->bv_len );
3228 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
3229 out->bv_val, 0, 0 );
3231 func_leave:
3232 if ( stmp != sbuf )
3233 slap_sl_free( stmp, ctx );
3234 slap_sl_free( ni.bv_val, ctx );
3236 return rc;
3239 static int
3240 certificateExactNormalize(
3241 slap_mask_t usage,
3242 Syntax *syntax,
3243 MatchingRule *mr,
3244 struct berval *val,
3245 struct berval *normalized,
3246 void *ctx )
3248 BerElementBuffer berbuf;
3249 BerElement *ber = (BerElement *)&berbuf;
3250 ber_tag_t tag;
3251 ber_len_t len;
3252 ber_int_t i;
3253 char serialbuf[64], *serial = serialbuf;
3254 ber_len_t seriallen;
3255 struct berval issuer_dn = BER_BVNULL, bvdn;
3256 unsigned char *p;
3257 int rc = LDAP_INVALID_SYNTAX;
3259 if( BER_BVISEMPTY( val ) ) goto done;
3261 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3262 return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
3265 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3267 ber_init2( ber, val, LBER_USE_DER );
3268 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3269 tag = ber_skip_tag( ber, &len ); /* Sequence */
3270 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3271 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3272 tag = ber_skip_tag( ber, &len );
3273 tag = ber_get_int( ber, &i ); /* version */
3276 /* NOTE: move the test here from certificateValidate,
3277 * so that we can validate certs with serial longer
3278 * than sizeof(ber_int_t) */
3279 tag = ber_peek_tag( ber, &len ); /* serial */
3281 /* Use hex format. '123456789abcdef'H
3284 unsigned char *ptr;
3285 char *sptr;
3287 tag = ber_skip_tag( ber, &len );
3288 ptr = (unsigned char *)ber->ber_ptr;
3289 ber_skip_data( ber, len );
3291 /* Check for minimal encodings */
3292 if ( len > 1 ) {
3293 if ( ptr[0] & 0x80 ) {
3294 if (( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ))
3295 return LDAP_INVALID_SYNTAX;
3296 } else if ( ptr[0] == 0 ) {
3297 if (!( ptr[1] & 0x80 ))
3298 return LDAP_INVALID_SYNTAX;
3302 seriallen = len * 2 + 4; /* quotes, H, NUL */
3303 if ( seriallen > sizeof( serialbuf ))
3304 serial = slap_sl_malloc( seriallen, ctx );
3305 sptr = serial;
3306 *sptr++ = '\'';
3307 for ( i = 0; i<len; i++ ) {
3308 sprintf( sptr, "%02X", ptr[i] );
3309 sptr += 2;
3311 *sptr++ = '\'';
3312 *sptr++ = 'H';
3313 seriallen--;
3315 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3316 ber_skip_data( ber, len );
3317 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3318 len = ber_ptrlen( ber );
3319 bvdn.bv_val = val->bv_val + len;
3320 bvdn.bv_len = val->bv_len - len;
3322 rc = dnX509normalize( &bvdn, &issuer_dn );
3323 if( rc != LDAP_SUCCESS ) goto done;
3325 normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3326 + seriallen + issuer_dn.bv_len;
3327 normalized->bv_val = ch_malloc(normalized->bv_len+1);
3329 p = (unsigned char *)normalized->bv_val;
3331 AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
3332 p += STRLENOF( "{ serialNumber " );
3334 AC_MEMCPY(p, serial, seriallen);
3335 p += seriallen;
3337 AC_MEMCPY(p, ", issuer rdnSequence:\"", STRLENOF( ", issuer rdnSequence:\"" ));
3338 p += STRLENOF( ", issuer rdnSequence:\"" );
3340 AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
3341 p += issuer_dn.bv_len;
3343 AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
3344 p += STRLENOF( "\" }" );
3346 *p = '\0';
3348 Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
3349 normalized->bv_val, NULL, NULL );
3351 rc = LDAP_SUCCESS;
3353 done:
3354 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3355 if ( serial != serialbuf ) ber_memfree_x( serial, ctx );
3357 return rc;
3360 static int
3361 hexValidate(
3362 Syntax *syntax,
3363 struct berval *in )
3365 int i;
3367 assert( in != NULL );
3368 assert( !BER_BVISNULL( in ) );
3370 for ( i = 0; i < in->bv_len; i++ ) {
3371 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
3372 return LDAP_INVALID_SYNTAX;
3376 return LDAP_SUCCESS;
3379 /* Normalize a SID as used inside a CSN:
3380 * three-digit numeric string */
3381 static int
3382 hexNormalize(
3383 slap_mask_t usage,
3384 Syntax *syntax,
3385 MatchingRule *mr,
3386 struct berval *val,
3387 struct berval *normalized,
3388 void *ctx )
3390 int i;
3392 assert( val != NULL );
3393 assert( normalized != NULL );
3395 ber_dupbv_x( normalized, val, ctx );
3397 for ( i = 0; i < normalized->bv_len; i++ ) {
3398 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
3399 ber_memfree_x( normalized->bv_val, ctx );
3400 BER_BVZERO( normalized );
3401 return LDAP_INVALID_SYNTAX;
3404 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3407 return LDAP_SUCCESS;
3410 static int
3411 sidValidate (
3412 Syntax *syntax,
3413 struct berval *in )
3415 assert( in != NULL );
3416 assert( !BER_BVISNULL( in ) );
3418 if ( in->bv_len != 3 ) {
3419 return LDAP_INVALID_SYNTAX;
3422 return hexValidate( NULL, in );
3425 /* Normalize a SID as used inside a CSN:
3426 * three-digit numeric string */
3427 static int
3428 sidNormalize(
3429 slap_mask_t usage,
3430 Syntax *syntax,
3431 MatchingRule *mr,
3432 struct berval *val,
3433 struct berval *normalized,
3434 void *ctx )
3436 if ( val->bv_len != 3 ) {
3437 return LDAP_INVALID_SYNTAX;
3440 return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
3443 static int
3444 sidPretty(
3445 Syntax *syntax,
3446 struct berval *val,
3447 struct berval *out,
3448 void *ctx )
3450 return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3453 /* Normalize a SID as used inside a CSN, either as-is
3454 * (assertion value) or extracted from the CSN
3455 * (attribute value) */
3456 static int
3457 csnSidNormalize(
3458 slap_mask_t usage,
3459 Syntax *syntax,
3460 MatchingRule *mr,
3461 struct berval *val,
3462 struct berval *normalized,
3463 void *ctx )
3465 struct berval bv;
3466 char *ptr,
3467 buf[ 4 ];
3470 if ( BER_BVISEMPTY( val ) ) {
3471 return LDAP_INVALID_SYNTAX;
3474 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3475 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
3478 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3480 ptr = ber_bvchr( val, '#' );
3481 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3482 return LDAP_INVALID_SYNTAX;
3485 bv.bv_val = ptr + 1;
3486 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3488 ptr = ber_bvchr( &bv, '#' );
3489 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3490 return LDAP_INVALID_SYNTAX;
3493 bv.bv_val = ptr + 1;
3494 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
3496 ptr = ber_bvchr( &bv, '#' );
3497 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3498 return LDAP_INVALID_SYNTAX;
3501 bv.bv_len = ptr - bv.bv_val;
3503 if ( bv.bv_len == 2 ) {
3504 /* OpenLDAP 2.3 SID */
3505 buf[ 0 ] = '0';
3506 buf[ 1 ] = bv.bv_val[ 0 ];
3507 buf[ 2 ] = bv.bv_val[ 1 ];
3508 buf[ 3 ] = '\0';
3510 bv.bv_val = buf;
3511 bv.bv_len = 3;
3514 return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
3517 static int
3518 csnValidate(
3519 Syntax *syntax,
3520 struct berval *in )
3522 struct berval bv;
3523 char *ptr;
3524 int rc;
3526 assert( in != NULL );
3527 assert( !BER_BVISNULL( in ) );
3529 if ( BER_BVISEMPTY( in ) ) {
3530 return LDAP_INVALID_SYNTAX;
3533 bv = *in;
3535 ptr = ber_bvchr( &bv, '#' );
3536 if ( ptr == NULL || ptr - bv.bv_val == bv.bv_len ) {
3537 return LDAP_INVALID_SYNTAX;
3540 bv.bv_len = ptr - bv.bv_val;
3541 if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
3542 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
3544 return LDAP_INVALID_SYNTAX;
3547 rc = generalizedTimeValidate( NULL, &bv );
3548 if ( rc != LDAP_SUCCESS ) {
3549 return rc;
3552 bv.bv_val = ptr + 1;
3553 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3555 ptr = ber_bvchr( &bv, '#' );
3556 if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3557 return LDAP_INVALID_SYNTAX;
3560 bv.bv_len = ptr - bv.bv_val;
3561 if ( bv.bv_len != 6 ) {
3562 return LDAP_INVALID_SYNTAX;
3565 rc = hexValidate( NULL, &bv );
3566 if ( rc != LDAP_SUCCESS ) {
3567 return rc;
3570 bv.bv_val = ptr + 1;
3571 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3573 ptr = ber_bvchr( &bv, '#' );
3574 if ( ptr == NULL || ptr - in->bv_val == in->bv_len ) {
3575 return LDAP_INVALID_SYNTAX;
3578 bv.bv_len = ptr - bv.bv_val;
3579 if ( bv.bv_len == 2 ) {
3580 /* tolerate old 2-digit replica-id */
3581 rc = hexValidate( NULL, &bv );
3583 } else {
3584 rc = sidValidate( NULL, &bv );
3586 if ( rc != LDAP_SUCCESS ) {
3587 return rc;
3590 bv.bv_val = ptr + 1;
3591 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
3593 if ( bv.bv_len != 6 ) {
3594 return LDAP_INVALID_SYNTAX;
3597 return hexValidate( NULL, &bv );
3600 /* Normalize a CSN in OpenLDAP 2.1 format */
3601 static int
3602 csnNormalize21(
3603 slap_mask_t usage,
3604 Syntax *syntax,
3605 MatchingRule *mr,
3606 struct berval *val,
3607 struct berval *normalized,
3608 void *ctx )
3610 struct berval gt, cnt, sid, mod;
3611 struct berval bv;
3612 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
3613 char *ptr;
3614 int i;
3616 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3617 assert( !BER_BVISEMPTY( val ) );
3619 gt = *val;
3621 ptr = ber_bvchr( &gt, '#' );
3622 if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3623 return LDAP_INVALID_SYNTAX;
3626 gt.bv_len = ptr - gt.bv_val;
3627 if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
3628 return LDAP_INVALID_SYNTAX;
3631 if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
3632 return LDAP_INVALID_SYNTAX;
3635 cnt.bv_val = ptr + 1;
3636 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3638 ptr = ber_bvchr( &cnt, '#' );
3639 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3640 return LDAP_INVALID_SYNTAX;
3643 cnt.bv_len = ptr - cnt.bv_val;
3644 if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
3645 return LDAP_INVALID_SYNTAX;
3648 if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
3649 return LDAP_INVALID_SYNTAX;
3652 cnt.bv_val += STRLENOF( "0x" );
3653 cnt.bv_len -= STRLENOF( "0x" );
3655 sid.bv_val = ptr + 1;
3656 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3658 ptr = ber_bvchr( &sid, '#' );
3659 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3660 return LDAP_INVALID_SYNTAX;
3663 sid.bv_len = ptr - sid.bv_val;
3664 if ( sid.bv_len != STRLENOF( "0" ) ) {
3665 return LDAP_INVALID_SYNTAX;
3668 mod.bv_val = ptr + 1;
3669 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3670 if ( mod.bv_len != STRLENOF( "0000" ) ) {
3671 return LDAP_INVALID_SYNTAX;
3674 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3675 bv.bv_val = buf;
3677 ptr = bv.bv_val;
3678 ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
3679 ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
3680 STRLENOF( "MM" ) );
3681 ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
3682 STRLENOF( "SS" ) );
3683 ptr = lutil_strcopy( ptr, ".000000Z#00" );
3684 ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3685 *ptr++ = '#';
3686 *ptr++ = '0';
3687 *ptr++ = '0';
3688 *ptr++ = sid.bv_val[ 0 ];
3689 *ptr++ = '#';
3690 *ptr++ = '0';
3691 *ptr++ = '0';
3692 for ( i = 0; i < mod.bv_len; i++ ) {
3693 *ptr++ = TOLOWER( mod.bv_val[ i ] );
3695 *ptr = '\0';
3697 assert( ptr - bv.bv_val == bv.bv_len );
3699 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
3700 return LDAP_INVALID_SYNTAX;
3703 ber_dupbv_x( normalized, &bv, ctx );
3705 return LDAP_SUCCESS;
3708 /* Normalize a CSN in OpenLDAP 2.3 format */
3709 static int
3710 csnNormalize23(
3711 slap_mask_t usage,
3712 Syntax *syntax,
3713 MatchingRule *mr,
3714 struct berval *val,
3715 struct berval *normalized,
3716 void *ctx )
3718 struct berval gt, cnt, sid, mod;
3719 struct berval bv;
3720 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
3721 char *ptr;
3722 int i;
3724 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3725 assert( !BER_BVISEMPTY( val ) );
3727 gt = *val;
3729 ptr = ber_bvchr( &gt, '#' );
3730 if ( ptr == NULL || ptr - gt.bv_val == gt.bv_len ) {
3731 return LDAP_INVALID_SYNTAX;
3734 gt.bv_len = ptr - gt.bv_val;
3735 if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3736 return LDAP_INVALID_SYNTAX;
3739 cnt.bv_val = ptr + 1;
3740 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3742 ptr = ber_bvchr( &cnt, '#' );
3743 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3744 return LDAP_INVALID_SYNTAX;
3747 cnt.bv_len = ptr - cnt.bv_val;
3748 if ( cnt.bv_len != STRLENOF( "000000" ) ) {
3749 return LDAP_INVALID_SYNTAX;
3752 sid.bv_val = ptr + 1;
3753 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3755 ptr = ber_bvchr( &sid, '#' );
3756 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3757 return LDAP_INVALID_SYNTAX;
3760 sid.bv_len = ptr - sid.bv_val;
3761 if ( sid.bv_len != STRLENOF( "00" ) ) {
3762 return LDAP_INVALID_SYNTAX;
3765 mod.bv_val = ptr + 1;
3766 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3767 if ( mod.bv_len != STRLENOF( "000000" ) ) {
3768 return LDAP_INVALID_SYNTAX;
3771 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
3772 bv.bv_val = buf;
3774 ptr = bv.bv_val;
3775 ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
3776 ptr = lutil_strcopy( ptr, ".000000Z#" );
3777 ptr = lutil_strncopy( ptr, cnt.bv_val, cnt.bv_len );
3778 *ptr++ = '#';
3779 *ptr++ = '0';
3780 for ( i = 0; i < sid.bv_len; i++ ) {
3781 *ptr++ = TOLOWER( sid.bv_val[ i ] );
3783 *ptr++ = '#';
3784 for ( i = 0; i < mod.bv_len; i++ ) {
3785 *ptr++ = TOLOWER( mod.bv_val[ i ] );
3787 *ptr = '\0';
3789 assert( ptr - bv.bv_val == bv.bv_len );
3790 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
3791 return LDAP_INVALID_SYNTAX;
3794 ber_dupbv_x( normalized, &bv, ctx );
3796 return LDAP_SUCCESS;
3799 /* Normalize a CSN */
3800 static int
3801 csnNormalize(
3802 slap_mask_t usage,
3803 Syntax *syntax,
3804 MatchingRule *mr,
3805 struct berval *val,
3806 struct berval *normalized,
3807 void *ctx )
3809 struct berval cnt, sid, mod;
3810 char *ptr;
3811 int i;
3813 assert( val != NULL );
3814 assert( normalized != NULL );
3816 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
3818 if ( BER_BVISEMPTY( val ) ) {
3819 return LDAP_INVALID_SYNTAX;
3822 if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
3823 /* Openldap <= 2.3 */
3825 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
3828 if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
3829 /* Openldap 2.1 */
3831 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
3834 if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
3835 return LDAP_INVALID_SYNTAX;
3838 ptr = ber_bvchr( val, '#' );
3839 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3840 return LDAP_INVALID_SYNTAX;
3843 if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
3844 return LDAP_INVALID_SYNTAX;
3847 cnt.bv_val = ptr + 1;
3848 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
3850 ptr = ber_bvchr( &cnt, '#' );
3851 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3852 return LDAP_INVALID_SYNTAX;
3855 if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
3856 return LDAP_INVALID_SYNTAX;
3859 sid.bv_val = ptr + 1;
3860 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
3862 ptr = ber_bvchr( &sid, '#' );
3863 if ( ptr == NULL || ptr - val->bv_val == val->bv_len ) {
3864 return LDAP_INVALID_SYNTAX;
3867 sid.bv_len = ptr - sid.bv_val;
3868 if ( sid.bv_len != STRLENOF( "000" ) ) {
3869 return LDAP_INVALID_SYNTAX;
3872 mod.bv_val = ptr + 1;
3873 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
3875 if ( mod.bv_len != STRLENOF( "000000" ) ) {
3876 return LDAP_INVALID_SYNTAX;
3879 ber_dupbv_x( normalized, val, ctx );
3881 for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
3882 i < normalized->bv_len; i++ )
3884 /* assume it's already validated that's all hex digits */
3885 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
3888 return LDAP_SUCCESS;
3891 static int
3892 csnPretty(
3893 Syntax *syntax,
3894 struct berval *val,
3895 struct berval *out,
3896 void *ctx )
3898 return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
3901 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
3902 /* slight optimization - does not need the start parameter */
3903 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
3904 enum { start = 0 };
3905 #endif
3907 static int
3908 check_time_syntax (struct berval *val,
3909 int start,
3910 int *parts,
3911 struct berval *fraction)
3914 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
3915 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
3916 * GeneralizedTime supports leap seconds, UTCTime does not.
3918 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
3919 static const int mdays[2][12] = {
3920 /* non-leap years */
3921 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
3922 /* leap years */
3923 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
3925 char *p, *e;
3926 int part, c, c1, c2, tzoffset, leapyear = 0;
3928 p = val->bv_val;
3929 e = p + val->bv_len;
3931 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
3932 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
3933 #endif
3934 for (part = start; part < 7 && p < e; part++) {
3935 c1 = *p;
3936 if (!ASCII_DIGIT(c1)) {
3937 break;
3939 p++;
3940 if (p == e) {
3941 return LDAP_INVALID_SYNTAX;
3943 c = *p++;
3944 if (!ASCII_DIGIT(c)) {
3945 return LDAP_INVALID_SYNTAX;
3947 c += c1 * 10 - '0' * 11;
3948 if ((part | 1) == 3) {
3949 --c;
3950 if (c < 0) {
3951 return LDAP_INVALID_SYNTAX;
3954 if (c >= ceiling[part]) {
3955 if (! (c == 60 && part == 6 && start == 0))
3956 return LDAP_INVALID_SYNTAX;
3958 parts[part] = c;
3960 if (part < 5 + start) {
3961 return LDAP_INVALID_SYNTAX;
3963 for (; part < 9; part++) {
3964 parts[part] = 0;
3967 /* leapyear check for the Gregorian calendar (year>1581) */
3968 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
3969 leapyear = 1;
3972 if (parts[3] >= mdays[leapyear][parts[2]]) {
3973 return LDAP_INVALID_SYNTAX;
3976 if (start == 0) {
3977 fraction->bv_val = p;
3978 fraction->bv_len = 0;
3979 if (p < e && (*p == '.' || *p == ',')) {
3980 char *end_num;
3981 while (++p < e && ASCII_DIGIT(*p)) {
3982 /* EMTPY */;
3984 if (p - fraction->bv_val == 1) {
3985 return LDAP_INVALID_SYNTAX;
3987 for (end_num = p; end_num[-1] == '0'; --end_num) {
3988 /* EMPTY */;
3990 c = end_num - fraction->bv_val;
3991 if (c != 1) fraction->bv_len = c;
3995 if (p == e) {
3996 /* no time zone */
3997 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
4000 tzoffset = *p++;
4001 switch (tzoffset) {
4002 default:
4003 return LDAP_INVALID_SYNTAX;
4004 case 'Z':
4005 /* UTC */
4006 break;
4007 case '+':
4008 case '-':
4009 for (part = 7; part < 9 && p < e; part++) {
4010 c1 = *p;
4011 if (!ASCII_DIGIT(c1)) {
4012 break;
4014 p++;
4015 if (p == e) {
4016 return LDAP_INVALID_SYNTAX;
4018 c2 = *p++;
4019 if (!ASCII_DIGIT(c2)) {
4020 return LDAP_INVALID_SYNTAX;
4022 parts[part] = c1 * 10 + c2 - '0' * 11;
4023 if (parts[part] >= ceiling[part]) {
4024 return LDAP_INVALID_SYNTAX;
4027 if (part < 8 + start) {
4028 return LDAP_INVALID_SYNTAX;
4031 if (tzoffset == '-') {
4032 /* negative offset to UTC, ie west of Greenwich */
4033 parts[4] += parts[7];
4034 parts[5] += parts[8];
4035 /* offset is just hhmm, no seconds */
4036 for (part = 6; --part >= 0; ) {
4037 if (part != 3) {
4038 c = ceiling[part];
4039 } else {
4040 c = mdays[leapyear][parts[2]];
4042 if (parts[part] >= c) {
4043 if (part == 0) {
4044 return LDAP_INVALID_SYNTAX;
4046 parts[part] -= c;
4047 parts[part - 1]++;
4048 continue;
4049 } else if (part != 5) {
4050 break;
4053 } else {
4054 /* positive offset to UTC, ie east of Greenwich */
4055 parts[4] -= parts[7];
4056 parts[5] -= parts[8];
4057 for (part = 6; --part >= 0; ) {
4058 if (parts[part] < 0) {
4059 if (part == 0) {
4060 return LDAP_INVALID_SYNTAX;
4062 if (part != 3) {
4063 c = ceiling[part];
4064 } else {
4065 /* make first arg to % non-negative */
4066 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
4068 parts[part] += c;
4069 parts[part - 1]--;
4070 continue;
4071 } else if (part != 5) {
4072 break;
4078 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
4081 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4083 #if 0
4084 static int
4085 xutcTimeNormalize(
4086 Syntax *syntax,
4087 struct berval *val,
4088 struct berval *normalized )
4090 int parts[9], rc;
4092 rc = check_time_syntax(val, 1, parts, NULL);
4093 if (rc != LDAP_SUCCESS) {
4094 return rc;
4097 normalized->bv_val = ch_malloc( 14 );
4098 if ( normalized->bv_val == NULL ) {
4099 return LBER_ERROR_MEMORY;
4102 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
4103 parts[1], parts[2] + 1, parts[3] + 1,
4104 parts[4], parts[5], parts[6] );
4105 normalized->bv_len = 13;
4107 return LDAP_SUCCESS;
4109 #endif /* 0 */
4111 static int
4112 utcTimeValidate(
4113 Syntax *syntax,
4114 struct berval *in )
4116 int parts[9];
4117 return check_time_syntax(in, 1, parts, NULL);
4120 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
4122 static int
4123 generalizedTimeValidate(
4124 Syntax *syntax,
4125 struct berval *in )
4127 int parts[9];
4128 struct berval fraction;
4129 return check_time_syntax(in, 0, parts, &fraction);
4132 static int
4133 generalizedTimeNormalize(
4134 slap_mask_t usage,
4135 Syntax *syntax,
4136 MatchingRule *mr,
4137 struct berval *val,
4138 struct berval *normalized,
4139 void *ctx )
4141 int parts[9], rc;
4142 unsigned int len;
4143 struct berval fraction;
4145 rc = check_time_syntax(val, 0, parts, &fraction);
4146 if (rc != LDAP_SUCCESS) {
4147 return rc;
4150 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
4151 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
4152 if ( BER_BVISNULL( normalized ) ) {
4153 return LBER_ERROR_MEMORY;
4156 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
4157 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
4158 parts[4], parts[5], parts[6] );
4159 if ( !BER_BVISEMPTY( &fraction ) ) {
4160 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
4161 fraction.bv_val, fraction.bv_len );
4162 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
4164 strcpy( normalized->bv_val + len-1, "Z" );
4165 normalized->bv_len = len;
4167 return LDAP_SUCCESS;
4170 static int
4171 generalizedTimeOrderingMatch(
4172 int *matchp,
4173 slap_mask_t flags,
4174 Syntax *syntax,
4175 MatchingRule *mr,
4176 struct berval *value,
4177 void *assertedValue )
4179 struct berval *asserted = (struct berval *) assertedValue;
4180 ber_len_t v_len = value->bv_len;
4181 ber_len_t av_len = asserted->bv_len;
4183 /* ignore trailing 'Z' when comparing */
4184 int match = memcmp( value->bv_val, asserted->bv_val,
4185 (v_len < av_len ? v_len : av_len) - 1 );
4186 if ( match == 0 ) match = v_len - av_len;
4188 *matchp = match;
4189 return LDAP_SUCCESS;
4192 /* Index generation function */
4193 int generalizedTimeIndexer(
4194 slap_mask_t use,
4195 slap_mask_t flags,
4196 Syntax *syntax,
4197 MatchingRule *mr,
4198 struct berval *prefix,
4199 BerVarray values,
4200 BerVarray *keysp,
4201 void *ctx )
4203 int i, j;
4204 BerVarray keys;
4205 char tmp[5];
4206 BerValue bvtmp; /* 40 bit index */
4207 struct lutil_tm tm;
4208 struct lutil_timet tt;
4210 bvtmp.bv_len = sizeof(tmp);
4211 bvtmp.bv_val = tmp;
4212 for( i=0; values[i].bv_val != NULL; i++ ) {
4213 /* just count them */
4216 /* we should have at least one value at this point */
4217 assert( i > 0 );
4219 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
4221 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4222 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
4223 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
4224 /* Use 40 bits of time for key */
4225 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
4226 lutil_tm2time( &tm, &tt );
4227 tmp[0] = tt.tt_gsec & 0xff;
4228 tmp[4] = tt.tt_sec & 0xff;
4229 tt.tt_sec >>= 8;
4230 tmp[3] = tt.tt_sec & 0xff;
4231 tt.tt_sec >>= 8;
4232 tmp[2] = tt.tt_sec & 0xff;
4233 tt.tt_sec >>= 8;
4234 tmp[1] = tt.tt_sec & 0xff;
4236 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
4240 keys[j].bv_val = NULL;
4241 keys[j].bv_len = 0;
4243 *keysp = keys;
4245 return LDAP_SUCCESS;
4248 /* Index generation function */
4249 int generalizedTimeFilter(
4250 slap_mask_t use,
4251 slap_mask_t flags,
4252 Syntax *syntax,
4253 MatchingRule *mr,
4254 struct berval *prefix,
4255 void * assertedValue,
4256 BerVarray *keysp,
4257 void *ctx )
4259 BerVarray keys;
4260 char tmp[5];
4261 BerValue bvtmp; /* 40 bit index */
4262 BerValue *value = (BerValue *) assertedValue;
4263 struct lutil_tm tm;
4264 struct lutil_timet tt;
4266 bvtmp.bv_len = sizeof(tmp);
4267 bvtmp.bv_val = tmp;
4268 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
4269 /* Use 40 bits of time for key */
4270 if ( value->bv_val && value->bv_len >= 10 &&
4271 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
4273 lutil_tm2time( &tm, &tt );
4274 tmp[0] = tt.tt_gsec & 0xff;
4275 tmp[4] = tt.tt_sec & 0xff;
4276 tt.tt_sec >>= 8;
4277 tmp[3] = tt.tt_sec & 0xff;
4278 tt.tt_sec >>= 8;
4279 tmp[2] = tt.tt_sec & 0xff;
4280 tt.tt_sec >>= 8;
4281 tmp[1] = tt.tt_sec & 0xff;
4283 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
4284 ber_dupbv_x(keys, &bvtmp, ctx );
4285 keys[1].bv_val = NULL;
4286 keys[1].bv_len = 0;
4287 } else {
4288 keys = NULL;
4291 *keysp = keys;
4293 return LDAP_SUCCESS;
4296 static int
4297 deliveryMethodValidate(
4298 Syntax *syntax,
4299 struct berval *val )
4301 #undef LENOF
4302 #define LENOF(s) (sizeof(s)-1)
4303 struct berval tmp = *val;
4305 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
4306 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
4307 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
4309 again:
4310 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4312 switch( tmp.bv_val[0] ) {
4313 case 'a':
4314 case 'A':
4315 if(( tmp.bv_len >= LENOF("any") ) &&
4316 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
4318 tmp.bv_len -= LENOF("any");
4319 tmp.bv_val += LENOF("any");
4320 break;
4322 return LDAP_INVALID_SYNTAX;
4324 case 'm':
4325 case 'M':
4326 if(( tmp.bv_len >= LENOF("mhs") ) &&
4327 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
4329 tmp.bv_len -= LENOF("mhs");
4330 tmp.bv_val += LENOF("mhs");
4331 break;
4333 return LDAP_INVALID_SYNTAX;
4335 case 'p':
4336 case 'P':
4337 if(( tmp.bv_len >= LENOF("physical") ) &&
4338 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
4340 tmp.bv_len -= LENOF("physical");
4341 tmp.bv_val += LENOF("physical");
4342 break;
4344 return LDAP_INVALID_SYNTAX;
4346 case 't':
4347 case 'T': /* telex or teletex or telephone */
4348 if(( tmp.bv_len >= LENOF("telex") ) &&
4349 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
4351 tmp.bv_len -= LENOF("telex");
4352 tmp.bv_val += LENOF("telex");
4353 break;
4355 if(( tmp.bv_len >= LENOF("teletex") ) &&
4356 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
4358 tmp.bv_len -= LENOF("teletex");
4359 tmp.bv_val += LENOF("teletex");
4360 break;
4362 if(( tmp.bv_len >= LENOF("telephone") ) &&
4363 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
4365 tmp.bv_len -= LENOF("telephone");
4366 tmp.bv_val += LENOF("telephone");
4367 break;
4369 return LDAP_INVALID_SYNTAX;
4371 case 'g':
4372 case 'G': /* g3fax or g4fax */
4373 if(( tmp.bv_len >= LENOF("g3fax") ) && (
4374 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
4375 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
4377 tmp.bv_len -= LENOF("g3fax");
4378 tmp.bv_val += LENOF("g3fax");
4379 break;
4381 return LDAP_INVALID_SYNTAX;
4383 case 'i':
4384 case 'I':
4385 if(( tmp.bv_len >= LENOF("ia5") ) &&
4386 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
4388 tmp.bv_len -= LENOF("ia5");
4389 tmp.bv_val += LENOF("ia5");
4390 break;
4392 return LDAP_INVALID_SYNTAX;
4394 case 'v':
4395 case 'V':
4396 if(( tmp.bv_len >= LENOF("videotex") ) &&
4397 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
4399 tmp.bv_len -= LENOF("videotex");
4400 tmp.bv_val += LENOF("videotex");
4401 break;
4403 return LDAP_INVALID_SYNTAX;
4405 default:
4406 return LDAP_INVALID_SYNTAX;
4409 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
4411 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4412 tmp.bv_len++;
4413 tmp.bv_val--;
4415 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
4416 tmp.bv_len++;
4417 tmp.bv_val--;
4418 } else {
4419 return LDAP_INVALID_SYNTAX;
4421 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
4422 tmp.bv_len++;
4423 tmp.bv_val--;
4426 goto again;
4429 static int
4430 nisNetgroupTripleValidate(
4431 Syntax *syntax,
4432 struct berval *val )
4434 char *p, *e;
4435 int commas = 0;
4437 if ( BER_BVISEMPTY( val ) ) {
4438 return LDAP_INVALID_SYNTAX;
4441 p = (char *)val->bv_val;
4442 e = p + val->bv_len;
4444 if ( *p != '(' /*')'*/ ) {
4445 return LDAP_INVALID_SYNTAX;
4448 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
4449 if ( *p == ',' ) {
4450 commas++;
4451 if ( commas > 2 ) {
4452 return LDAP_INVALID_SYNTAX;
4455 } else if ( !AD_CHAR( *p ) ) {
4456 return LDAP_INVALID_SYNTAX;
4460 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
4461 return LDAP_INVALID_SYNTAX;
4464 p++;
4466 if (p != e) {
4467 return LDAP_INVALID_SYNTAX;
4470 return LDAP_SUCCESS;
4473 static int
4474 bootParameterValidate(
4475 Syntax *syntax,
4476 struct berval *val )
4478 char *p, *e;
4480 if ( BER_BVISEMPTY( val ) ) {
4481 return LDAP_INVALID_SYNTAX;
4484 p = (char *)val->bv_val;
4485 e = p + val->bv_len;
4487 /* key */
4488 for (; ( p < e ) && ( *p != '=' ); p++ ) {
4489 if ( !AD_CHAR( *p ) ) {
4490 return LDAP_INVALID_SYNTAX;
4494 if ( *p != '=' ) {
4495 return LDAP_INVALID_SYNTAX;
4498 /* server */
4499 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
4500 if ( !AD_CHAR( *p ) ) {
4501 return LDAP_INVALID_SYNTAX;
4505 if ( *p != ':' ) {
4506 return LDAP_INVALID_SYNTAX;
4509 /* path */
4510 for ( p++; p < e; p++ ) {
4511 if ( !SLAP_PRINTABLE( *p ) ) {
4512 return LDAP_INVALID_SYNTAX;
4516 return LDAP_SUCCESS;
4519 static int
4520 firstComponentNormalize(
4521 slap_mask_t usage,
4522 Syntax *syntax,
4523 MatchingRule *mr,
4524 struct berval *val,
4525 struct berval *normalized,
4526 void *ctx )
4528 int rc;
4529 struct berval comp;
4530 ber_len_t len;
4532 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
4533 ber_dupbv_x( normalized, val, ctx );
4534 return LDAP_SUCCESS;
4537 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4539 if( val->bv_val[0] != '(' /*')'*/ &&
4540 val->bv_val[0] != '{' /*'}'*/ )
4542 return LDAP_INVALID_SYNTAX;
4545 /* trim leading white space */
4546 for( len=1;
4547 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
4548 len++ )
4550 /* empty */
4553 /* grab next word */
4554 comp.bv_val = &val->bv_val[len];
4555 len = val->bv_len - len;
4556 for( comp.bv_len = 0;
4557 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
4558 comp.bv_len++ )
4560 /* empty */
4563 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
4564 rc = numericoidValidate( NULL, &comp );
4565 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
4566 rc = integerValidate( NULL, &comp );
4567 } else {
4568 rc = LDAP_INVALID_SYNTAX;
4572 if( rc == LDAP_SUCCESS ) {
4573 ber_dupbv_x( normalized, &comp, ctx );
4576 return rc;
4579 static char *country_gen_syn[] = {
4580 "1.3.6.1.4.1.1466.115.121.1.15",
4581 "1.3.6.1.4.1.1466.115.121.1.26",
4582 "1.3.6.1.4.1.1466.115.121.1.44",
4583 NULL
4586 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
4587 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
4589 static slap_syntax_defs_rec syntax_defs[] = {
4590 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
4591 X_BINARY X_NOT_H_R ")",
4592 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
4593 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
4594 0, NULL, NULL, NULL},
4595 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
4596 0, NULL, NULL, NULL},
4597 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
4598 X_NOT_H_R ")",
4599 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4600 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
4601 X_NOT_H_R ")",
4602 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4603 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
4604 0, NULL, bitStringValidate, NULL },
4605 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
4606 0, NULL, booleanValidate, NULL},
4607 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
4608 X_BINARY X_NOT_H_R ")",
4609 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4610 NULL, certificateValidate, NULL},
4611 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
4612 X_BINARY X_NOT_H_R ")",
4613 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4614 NULL, certificateListValidate, NULL},
4615 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
4616 X_BINARY X_NOT_H_R ")",
4617 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
4618 NULL, sequenceValidate, NULL},
4619 #if 0 /* need to go __after__ printableString */
4620 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4621 0, "1.3.6.1.4.1.1466.115.121.1.44",
4622 countryStringValidate, NULL},
4623 #endif
4624 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
4625 0, NULL, dnValidate, dnPretty},
4626 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
4627 0, NULL, rdnValidate, rdnPretty},
4628 #ifdef LDAP_COMP_MATCH
4629 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
4630 0, NULL, allComponentsValidate, NULL},
4631 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
4632 0, NULL, componentFilterValidate, NULL},
4633 #endif
4634 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
4635 0, NULL, NULL, NULL},
4636 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
4637 0, NULL, deliveryMethodValidate, NULL},
4638 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
4639 0, NULL, UTF8StringValidate, NULL},
4640 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
4641 0, NULL, NULL, NULL},
4642 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
4643 0, NULL, NULL, NULL},
4644 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
4645 0, NULL, NULL, NULL},
4646 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
4647 0, NULL, NULL, NULL},
4648 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
4649 0, NULL, NULL, NULL},
4650 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
4651 0, NULL, printablesStringValidate, NULL},
4652 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
4653 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
4654 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
4655 0, NULL, generalizedTimeValidate, NULL},
4656 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
4657 0, NULL, NULL, NULL},
4658 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
4659 0, NULL, IA5StringValidate, NULL},
4660 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
4661 0, NULL, integerValidate, NULL},
4662 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
4663 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
4664 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
4665 0, NULL, NULL, NULL},
4666 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
4667 0, NULL, NULL, NULL},
4668 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
4669 0, NULL, NULL, NULL},
4670 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
4671 0, NULL, NULL, NULL},
4672 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
4673 0, NULL, NULL, NULL},
4674 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
4675 0, NULL, nameUIDValidate, nameUIDPretty },
4676 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
4677 0, NULL, NULL, NULL},
4678 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
4679 0, NULL, numericStringValidate, NULL},
4680 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
4681 0, NULL, NULL, NULL},
4682 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
4683 0, NULL, numericoidValidate, NULL},
4684 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
4685 0, NULL, IA5StringValidate, NULL},
4686 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
4687 0, NULL, blobValidate, NULL},
4688 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
4689 0, NULL, UTF8StringValidate, NULL},
4690 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
4691 0, NULL, NULL, NULL},
4692 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
4693 0, NULL, NULL, NULL},
4694 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
4695 0, NULL, printableStringValidate, NULL},
4696 /* moved here because now depends on Directory String, IA5 String
4697 * and Printable String */
4698 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
4699 0, country_gen_syn, countryStringValidate, NULL},
4700 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
4701 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
4702 0, NULL, subtreeSpecificationValidate, NULL},
4703 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
4704 X_BINARY X_NOT_H_R ")",
4705 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
4706 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
4707 0, NULL, printableStringValidate, NULL},
4708 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
4709 0, NULL, NULL, NULL},
4710 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
4711 0, NULL, printablesStringValidate, NULL},
4712 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
4713 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
4714 0, NULL, utcTimeValidate, NULL},
4715 #endif
4716 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
4717 0, NULL, NULL, NULL},
4718 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
4719 0, NULL, NULL, NULL},
4720 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
4721 0, NULL, NULL, NULL},
4722 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
4723 0, NULL, NULL, NULL},
4724 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
4725 0, NULL, NULL, NULL},
4727 /* RFC 2307 NIS Syntaxes */
4728 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
4729 0, NULL, nisNetgroupTripleValidate, NULL},
4730 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
4731 0, NULL, bootParameterValidate, NULL},
4733 /* draft-zeilenga-ldap-x509 */
4734 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
4735 SLAP_SYNTAX_HIDE, NULL,
4736 serialNumberAndIssuerValidate,
4737 serialNumberAndIssuerPretty},
4738 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
4739 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4740 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
4741 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4742 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
4743 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4744 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
4745 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4746 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
4747 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4748 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
4749 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4751 #ifdef SLAPD_AUTHPASSWD
4752 /* needs updating */
4753 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
4754 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
4755 #endif
4757 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
4758 0, NULL, UUIDValidate, UUIDPretty},
4760 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
4761 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
4763 {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
4764 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
4766 /* OpenLDAP Void Syntax */
4767 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
4768 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
4770 /* FIXME: OID is unused, but not registered yet */
4771 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
4772 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
4774 {NULL, 0, NULL, NULL, NULL}
4777 char *csnSIDMatchSyntaxes[] = {
4778 "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
4779 NULL
4781 char *certificateExactMatchSyntaxes[] = {
4782 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4783 NULL
4785 #ifdef LDAP_COMP_MATCH
4786 char *componentFilterMatchSyntaxes[] = {
4787 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
4788 NULL
4790 #endif
4791 char *directoryStringSyntaxes[] = {
4792 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
4793 NULL
4795 char *integerFirstComponentMatchSyntaxes[] = {
4796 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
4797 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
4798 NULL
4800 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
4801 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
4802 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
4803 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
4804 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
4805 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
4806 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
4807 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
4808 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
4809 NULL
4813 * Other matching rules in X.520 that we do not use (yet):
4815 * 2.5.13.25 uTCTimeMatch
4816 * 2.5.13.26 uTCTimeOrderingMatch
4817 * 2.5.13.31* directoryStringFirstComponentMatch
4818 * 2.5.13.32* wordMatch
4819 * 2.5.13.33* keywordMatch
4820 * 2.5.13.36+ certificatePairExactMatch
4821 * 2.5.13.37+ certificatePairMatch
4822 * 2.5.13.38+ certificateListExactMatch
4823 * 2.5.13.39+ certificateListMatch
4824 * 2.5.13.40+ algorithmIdentifierMatch
4825 * 2.5.13.41* storedPrefixMatch
4826 * 2.5.13.42 attributeCertificateMatch
4827 * 2.5.13.43 readerAndKeyIDMatch
4828 * 2.5.13.44 attributeIntegrityMatch
4830 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
4831 * (+) described in draft-zeilenga-ldap-x509
4833 static slap_mrule_defs_rec mrule_defs[] = {
4835 * EQUALITY matching rules must be listed after associated APPROX
4836 * matching rules. So, we list all APPROX matching rules first.
4838 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
4839 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4840 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4841 NULL, NULL, directoryStringApproxMatch,
4842 directoryStringApproxIndexer, directoryStringApproxFilter,
4843 NULL},
4845 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
4846 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
4847 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
4848 NULL, NULL, IA5StringApproxMatch,
4849 IA5StringApproxIndexer, IA5StringApproxFilter,
4850 NULL},
4853 * Other matching rules
4856 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
4857 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
4858 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4859 NULL, NULL, octetStringMatch,
4860 octetStringIndexer, octetStringFilter,
4861 NULL },
4863 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
4864 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4865 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4866 NULL, dnNormalize, dnMatch,
4867 octetStringIndexer, octetStringFilter,
4868 NULL },
4870 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
4871 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4872 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4873 NULL, dnNormalize, dnRelativeMatch,
4874 NULL, NULL,
4875 NULL },
4877 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
4878 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4879 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4880 NULL, dnNormalize, dnRelativeMatch,
4881 NULL, NULL,
4882 NULL },
4884 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
4885 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4886 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4887 NULL, dnNormalize, dnRelativeMatch,
4888 NULL, NULL,
4889 NULL },
4891 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
4892 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
4893 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
4894 NULL, dnNormalize, dnRelativeMatch,
4895 NULL, NULL,
4896 NULL },
4898 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
4899 "SYNTAX 1.2.36.79672281.1.5.0 )",
4900 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4901 NULL, rdnNormalize, rdnMatch,
4902 octetStringIndexer, octetStringFilter,
4903 NULL },
4905 #ifdef LDAP_COMP_MATCH
4906 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
4907 "SYNTAX 1.2.36.79672281.1.5.2 )",
4908 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
4909 NULL, NULL , componentFilterMatch,
4910 octetStringIndexer, octetStringFilter,
4911 NULL },
4913 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
4914 "SYNTAX 1.2.36.79672281.1.5.3 )",
4915 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4916 NULL, NULL , allComponentsMatch,
4917 octetStringIndexer, octetStringFilter,
4918 NULL },
4920 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
4921 "SYNTAX 1.2.36.79672281.1.5.3 )",
4922 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
4923 NULL, NULL , directoryComponentsMatch,
4924 octetStringIndexer, octetStringFilter,
4925 NULL },
4926 #endif
4928 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
4929 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4930 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4931 NULL, UTF8StringNormalize, octetStringMatch,
4932 octetStringIndexer, octetStringFilter,
4933 directoryStringApproxMatchOID },
4935 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
4936 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4937 SLAP_MR_ORDERING, directoryStringSyntaxes,
4938 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4939 NULL, NULL,
4940 "caseIgnoreMatch" },
4942 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
4943 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4944 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4945 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4946 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4947 "caseIgnoreMatch" },
4949 {"( 2.5.13.5 NAME 'caseExactMatch' "
4950 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4951 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
4952 NULL, UTF8StringNormalize, octetStringMatch,
4953 octetStringIndexer, octetStringFilter,
4954 directoryStringApproxMatchOID },
4956 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
4957 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
4958 SLAP_MR_ORDERING, directoryStringSyntaxes,
4959 NULL, UTF8StringNormalize, octetStringOrderingMatch,
4960 NULL, NULL,
4961 "caseExactMatch" },
4963 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
4964 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4965 SLAP_MR_SUBSTR, directoryStringSyntaxes,
4966 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
4967 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4968 "caseExactMatch" },
4970 {"( 2.5.13.8 NAME 'numericStringMatch' "
4971 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4972 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4973 NULL, numericStringNormalize, octetStringMatch,
4974 octetStringIndexer, octetStringFilter,
4975 NULL },
4977 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
4978 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
4979 SLAP_MR_ORDERING, NULL,
4980 NULL, numericStringNormalize, octetStringOrderingMatch,
4981 NULL, NULL,
4982 "numericStringMatch" },
4984 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
4985 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4986 SLAP_MR_SUBSTR, NULL,
4987 NULL, numericStringNormalize, octetStringSubstringsMatch,
4988 octetStringSubstringsIndexer, octetStringSubstringsFilter,
4989 "numericStringMatch" },
4991 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
4992 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )",
4993 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
4994 NULL, NULL, NULL, NULL, NULL, NULL },
4996 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
4997 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
4998 SLAP_MR_SUBSTR, NULL,
4999 NULL, NULL, NULL, NULL, NULL,
5000 "caseIgnoreListMatch" },
5002 {"( 2.5.13.13 NAME 'booleanMatch' "
5003 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
5004 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5005 NULL, NULL, booleanMatch,
5006 octetStringIndexer, octetStringFilter,
5007 NULL },
5009 {"( 2.5.13.14 NAME 'integerMatch' "
5010 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5011 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5012 NULL, NULL, integerMatch,
5013 integerIndexer, integerFilter,
5014 NULL },
5016 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
5017 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5018 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5019 NULL, NULL, integerMatch,
5020 NULL, NULL,
5021 "integerMatch" },
5023 {"( 2.5.13.16 NAME 'bitStringMatch' "
5024 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
5025 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5026 NULL, NULL, octetStringMatch,
5027 octetStringIndexer, octetStringFilter,
5028 NULL },
5030 {"( 2.5.13.17 NAME 'octetStringMatch' "
5031 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5032 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5033 NULL, NULL, octetStringMatch,
5034 octetStringIndexer, octetStringFilter,
5035 NULL },
5037 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
5038 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5039 SLAP_MR_ORDERING, NULL,
5040 NULL, NULL, octetStringOrderingMatch,
5041 NULL, NULL,
5042 "octetStringMatch" },
5044 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
5045 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5046 SLAP_MR_SUBSTR, NULL,
5047 NULL, NULL, octetStringSubstringsMatch,
5048 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5049 "octetStringMatch" },
5051 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
5052 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
5053 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5054 NULL,
5055 telephoneNumberNormalize, octetStringMatch,
5056 octetStringIndexer, octetStringFilter,
5057 NULL },
5059 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
5060 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
5061 SLAP_MR_SUBSTR, NULL,
5062 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
5063 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5064 "telephoneNumberMatch" },
5066 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
5067 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
5068 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5069 NULL, NULL, NULL, NULL, NULL, NULL },
5071 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
5072 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )",
5073 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5074 NULL, uniqueMemberNormalize, uniqueMemberMatch,
5075 uniqueMemberIndexer, uniqueMemberFilter,
5076 NULL },
5078 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
5079 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
5080 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5081 NULL, NULL, NULL, NULL, NULL, NULL },
5083 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
5084 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5085 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
5086 NULL, generalizedTimeNormalize, octetStringMatch,
5087 generalizedTimeIndexer, generalizedTimeFilter,
5088 NULL },
5090 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
5091 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
5092 SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5093 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
5094 NULL, NULL,
5095 "generalizedTimeMatch" },
5097 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
5098 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5099 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5100 integerFirstComponentMatchSyntaxes,
5101 NULL, firstComponentNormalize, integerMatch,
5102 octetStringIndexer, octetStringFilter,
5103 NULL },
5105 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
5106 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
5107 SLAP_MR_EQUALITY | SLAP_MR_EXT,
5108 objectIdentifierFirstComponentMatchSyntaxes,
5109 NULL, firstComponentNormalize, octetStringMatch,
5110 octetStringIndexer, octetStringFilter,
5111 NULL },
5113 {"( 2.5.13.34 NAME 'certificateExactMatch' "
5114 "SYNTAX 1.3.6.1.1.15.1 )",
5115 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
5116 NULL, certificateExactNormalize, octetStringMatch,
5117 octetStringIndexer, octetStringFilter,
5118 NULL },
5120 {"( 2.5.13.35 NAME 'certificateMatch' "
5121 "SYNTAX 1.3.6.1.1.15.2 )",
5122 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5123 NULL, NULL, NULL, NULL, NULL,
5124 NULL },
5126 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
5127 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5128 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5129 NULL, IA5StringNormalize, octetStringMatch,
5130 octetStringIndexer, octetStringFilter,
5131 IA5StringApproxMatchOID },
5133 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
5134 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5135 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
5136 NULL, IA5StringNormalize, octetStringMatch,
5137 octetStringIndexer, octetStringFilter,
5138 IA5StringApproxMatchOID },
5140 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
5141 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5142 SLAP_MR_SUBSTR, NULL,
5143 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5144 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5145 "caseIgnoreIA5Match" },
5147 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
5148 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
5149 SLAP_MR_SUBSTR, NULL,
5150 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
5151 octetStringSubstringsIndexer, octetStringSubstringsFilter,
5152 "caseExactIA5Match" },
5154 #ifdef SLAPD_AUTHPASSWD
5155 /* needs updating */
5156 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
5157 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
5158 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5159 NULL, NULL, authPasswordMatch,
5160 NULL, NULL,
5161 NULL},
5162 #endif
5164 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
5165 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5166 SLAP_MR_EXT, NULL,
5167 NULL, NULL, integerBitAndMatch,
5168 NULL, NULL,
5169 "integerMatch" },
5171 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
5172 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
5173 SLAP_MR_EXT, NULL,
5174 NULL, NULL, integerBitOrMatch,
5175 NULL, NULL,
5176 "integerMatch" },
5178 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
5179 "SYNTAX 1.3.6.1.1.16.1 )",
5180 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
5181 NULL, UUIDNormalize, octetStringMatch,
5182 octetStringIndexer, octetStringFilter,
5183 NULL},
5185 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
5186 "SYNTAX 1.3.6.1.1.16.1 )",
5187 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
5188 NULL, UUIDNormalize, octetStringOrderingMatch,
5189 octetStringIndexer, octetStringFilter,
5190 "UUIDMatch"},
5192 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
5193 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5194 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
5195 NULL, csnNormalize, csnMatch,
5196 csnIndexer, csnFilter,
5197 NULL},
5199 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
5200 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
5201 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
5202 NULL, NULL, csnOrderingMatch,
5203 NULL, NULL,
5204 "CSNMatch" },
5206 {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
5207 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
5208 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
5209 NULL, csnSidNormalize, octetStringMatch,
5210 octetStringIndexer, octetStringFilter,
5211 NULL },
5213 /* FIXME: OID is unused, but not registered yet */
5214 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
5215 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )",
5216 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
5217 NULL, authzNormalize, authzMatch,
5218 NULL, NULL,
5219 NULL},
5221 {NULL, SLAP_MR_NONE, NULL,
5222 NULL, NULL, NULL, NULL, NULL,
5223 NULL }
5227 slap_schema_init( void )
5229 int res;
5230 int i;
5232 /* we should only be called once (from main) */
5233 assert( schema_init_done == 0 );
5235 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
5236 res = register_syntax( &syntax_defs[i] );
5238 if ( res ) {
5239 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
5240 syntax_defs[i].sd_desc );
5241 return LDAP_OTHER;
5245 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
5246 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
5247 mrule_defs[i].mrd_compat_syntaxes == NULL )
5249 fprintf( stderr,
5250 "slap_schema_init: Ignoring unusable matching rule %s\n",
5251 mrule_defs[i].mrd_desc );
5252 continue;
5255 res = register_matching_rule( &mrule_defs[i] );
5257 if ( res ) {
5258 fprintf( stderr,
5259 "slap_schema_init: Error registering matching rule %s\n",
5260 mrule_defs[i].mrd_desc );
5261 return LDAP_OTHER;
5265 res = slap_schema_load();
5266 schema_init_done = 1;
5267 return res;
5270 void
5271 schema_destroy( void )
5273 oidm_destroy();
5274 oc_destroy();
5275 at_destroy();
5276 mr_destroy();
5277 mru_destroy();
5278 syn_destroy();
5280 if( schema_init_done ) {
5281 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
5282 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );