1 /* schema_init.c - init builtin schema */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2011 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
18 * Syntaxes - implementation notes:
20 * Validate function(syntax, value):
21 * Called before the other functions here to check if the value
22 * is valid according to the syntax.
24 * Pretty function(syntax, input value, output prettified...):
25 * If it exists, maps different notations of the same value to a
26 * unique representation which can be stored in the directory and
27 * possibly be passed to the Match/Indexer/Filter() functions.
29 * E.g. DN "2.5.4.3 = foo\,bar, o = BAZ" -> "cn=foo\2Cbar,o=BAZ",
30 * but unlike DN normalization, "BAZ" is not mapped to "baz".
34 * Matching rules - implementation notes:
36 * Matching rules match an attribute value (often from the directory)
37 * against an asserted value (e.g. from a filter).
39 * Invoked with validated and commonly pretty/normalized arguments, thus
40 * a number of matching rules can simply use the octetString functions.
42 * Normalize function(...input value, output normalized...):
43 * If it exists, maps matching values to a unique representation
44 * which is passed to the Match/Indexer/Filter() functions.
46 * Different matching rules can normalize values of the same syntax
47 * differently. E.g. caseIgnore rules normalize to lowercase,
48 * caseExact rules do not.
50 * Match function(*output matchp, ...value, asserted value):
51 * On success, set *matchp. 0 means match. For ORDERING/most EQUALITY,
52 * less/greater than 0 means value less/greater than asserted. However:
54 * In extensible match filters, ORDERING rules match if value<asserted.
56 * EQUALITY rules may order values differently than ORDERING rules for
57 * speed, since EQUALITY ordering is only used for SLAP_AT_SORTED_VAL.
58 * Some EQUALITY rules do not order values (ITS#6722).
60 * Indexer function(...attribute values, *output keysp,...):
61 * Generates index keys for the attribute values. Backends can store
62 * them in an index, a {key->entry ID set} mapping, for the attribute.
64 * A search can look up the DN/scope and asserted values in the
65 * indexes, if any, to narrow down the number of entires to check
66 * against the search criteria.
68 * Filter function(...asserted value, *output keysp,...):
69 * Generates index key(s) for the asserted value, to be looked up in
70 * the index from the Indexer function. *keysp is an array because
71 * substring matching rules can generate multiple lookup keys.
74 * A key is usually a hash of match type, attribute value and schema
75 * info, because one index can contain keys for many filtering types.
77 * Some indexes instead have EQUALITY keys ordered so that if
78 * key(val1) < key(val2), then val1 < val2 by the ORDERING rule.
79 * That way the ORDERING rule can use the EQUALITY index.
82 * This chops the attribute values up in small chunks and indexes all
83 * possible chunks of certain sizes. Substring filtering looks up
84 * SOME of the asserted value's chunks, and the caller uses the
85 * intersection of the resulting entry ID sets.
86 * See the index_substr_* keywords in slapd.conf(5).
98 #include <ac/string.h>
99 #include <ac/socket.h>
102 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
104 #include "ldap_utf8.h"
107 #include "lutil_hash.h"
108 #define HASH_BYTES LUTIL_HASH_BYTES
109 #define HASH_CONTEXT lutil_HASH_CTX
110 #define HASH_Init(c) lutil_HASHInit(c)
111 #define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
112 #define HASH_Final(d,c) lutil_HASHFinal(d,c)
114 /* approx matching rules */
115 #define directoryStringApproxMatchOID "1.3.6.1.4.1.4203.666.4.4"
116 #define directoryStringApproxMatch approxMatch
117 #define directoryStringApproxIndexer approxIndexer
118 #define directoryStringApproxFilter approxFilter
119 #define IA5StringApproxMatchOID "1.3.6.1.4.1.4203.666.4.5"
120 #define IA5StringApproxMatch approxMatch
121 #define IA5StringApproxIndexer approxIndexer
122 #define IA5StringApproxFilter approxFilter
124 /* Change Sequence Number (CSN) - much of this will change */
125 #define csnMatch octetStringMatch
126 #define csnOrderingMatch octetStringOrderingMatch
127 #define csnIndexer generalizedTimeIndexer
128 #define csnFilter generalizedTimeFilter
130 #define authzMatch octetStringMatch
132 /* X.509 PMI ldapSyntaxes */
133 /* FIXME: need to create temporary OIDs under OpenLDAP's arc;
134 * these are currently hijacked
136 * 1.3.6.1.4.1.4203.666 OpenLDAP
137 * 1.3.6.1.4.1.4203.666.11 self-contained works
138 * 1.3.6.1.4.1.4203.666.11.10 X.509 PMI
139 * 1.3.6.1.4.1.4203.666.11.10.2 X.509 PMI ldapSyntaxes
140 * 1.3.6.1.4.1.4203.666.11.10.2.1 AttributeCertificate (supported)
141 * 1.3.6.1.4.1.4203.666.11.10.2.2 AttributeCertificateExactAssertion (supported)
142 * 1.3.6.1.4.1.4203.666.11.10.2.3 AttributeCertificateAssertion (not supported)
143 * 1.3.6.1.4.1.4203.666.11.10.2.4 AttCertPath (X-SUBST'ed right now in pmi.schema)
144 * 1.3.6.1.4.1.4203.666.11.10.2.5 PolicySyntax (X-SUBST'ed right now in pmi.schema)
145 * 1.3.6.1.4.1.4203.666.11.10.2.6 RoleSyntax (X-SUBST'ed right now in pmi.schema)
147 #if 0 /* from <draft-ietf-pkix-ldap-schema-02.txt> (expired) */
148 #define attributeCertificateSyntaxOID "1.2.826.0.1.3344810.7.5"
149 #define attributeCertificateExactAssertionSyntaxOID "1.2.826.0.1.3344810.7.6"
150 #define attributeCertificateAssertionSyntaxOID "1.2.826.0.1.3344810.7.7"
151 #else /* from OpenLDAP's experimental oid arc */
152 #define X509_PMI_SyntaxOID "1.3.6.1.4.1.4203.666.11.10.2"
153 #define attributeCertificateSyntaxOID X509_PMI_SyntaxOID ".1"
154 #define attributeCertificateExactAssertionSyntaxOID X509_PMI_SyntaxOID ".2"
155 #define attributeCertificateAssertionSyntaxOID X509_PMI_SyntaxOID ".3"
158 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
159 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
160 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
161 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
163 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
164 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
165 SLAP_INDEX_INTLEN_DEFAULT );
167 ldap_pvt_thread_mutex_t ad_index_mutex;
168 ldap_pvt_thread_mutex_t ad_undef_mutex;
169 ldap_pvt_thread_mutex_t oc_undef_mutex;
172 generalizedTimeValidate(
176 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
181 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
188 /* no value allowed */
189 return LDAP_INVALID_SYNTAX;
197 /* any value allowed */
201 #define berValidate blobValidate
208 if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
209 if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
214 /* X.509 related stuff */
223 SLAP_TAG_UTCTIME = 0x17U,
224 SLAP_TAG_GENERALIZEDTIME = 0x18U
228 #define SLAP_X509_OPTION (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
231 SLAP_X509_OPT_C_VERSION = SLAP_X509_OPTION + 0,
232 SLAP_X509_OPT_C_ISSUERUNIQUEID = LBER_CLASS_CONTEXT + 1,
233 SLAP_X509_OPT_C_SUBJECTUNIQUEID = LBER_CLASS_CONTEXT + 2,
234 SLAP_X509_OPT_C_EXTENSIONS = SLAP_X509_OPTION + 3
238 SLAP_X509_OPT_CL_CRLEXTENSIONS = SLAP_X509_OPTION + 0
242 GeneralName ::= CHOICE {
243 otherName [0] INSTANCE OF OTHER-NAME,
244 rfc822Name [1] IA5String,
245 dNSName [2] IA5String,
246 x400Address [3] ORAddress,
247 directoryName [4] Name,
248 ediPartyName [5] EDIPartyName,
249 uniformResourceIdentifier [6] IA5String,
250 iPAddress [7] OCTET STRING,
251 registeredID [8] OBJECT IDENTIFIER }
254 SLAP_X509_GN_OTHERNAME = SLAP_X509_OPTION + 0,
255 SLAP_X509_GN_RFC822NAME = SLAP_X509_OPTION + 1,
256 SLAP_X509_GN_DNSNAME = SLAP_X509_OPTION + 2,
257 SLAP_X509_GN_X400ADDRESS = SLAP_X509_OPTION + 3,
258 SLAP_X509_GN_DIRECTORYNAME = SLAP_X509_OPTION + 4,
259 SLAP_X509_GN_EDIPARTYNAME = SLAP_X509_OPTION + 5,
260 SLAP_X509_GN_URI = SLAP_X509_OPTION + 6,
261 SLAP_X509_GN_IPADDRESS = SLAP_X509_OPTION + 7,
262 SLAP_X509_GN_REGISTEREDID = SLAP_X509_OPTION + 8
265 /* X.509 PMI related stuff */
272 SLAP_X509AC_ISSUER = SLAP_X509_OPTION + 0
275 /* X.509 certificate validation */
277 certificateValidate( Syntax *syntax, struct berval *in )
279 BerElementBuffer berbuf;
280 BerElement *ber = (BerElement *)&berbuf;
283 ber_int_t version = SLAP_X509_V1;
285 ber_init2( ber, in, LBER_USE_DER );
286 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
287 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
288 tag = ber_skip_tag( ber, &len ); /* Sequence */
289 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
290 tag = ber_peek_tag( ber, &len );
291 /* Optional version */
292 if ( tag == SLAP_X509_OPT_C_VERSION ) {
293 tag = ber_skip_tag( ber, &len );
294 tag = ber_get_int( ber, &version );
295 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
297 /* NOTE: don't try to parse Serial, because it might be longer
298 * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
299 tag = ber_skip_tag( ber, &len ); /* Serial */
300 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
301 ber_skip_data( ber, len );
302 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
303 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
304 ber_skip_data( ber, len );
305 tag = ber_skip_tag( ber, &len ); /* Issuer DN */
306 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
307 ber_skip_data( ber, len );
308 tag = ber_skip_tag( ber, &len ); /* Validity */
309 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
310 ber_skip_data( ber, len );
311 tag = ber_skip_tag( ber, &len ); /* Subject DN */
312 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
313 ber_skip_data( ber, len );
314 tag = ber_skip_tag( ber, &len ); /* Subject PublicKeyInfo */
315 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
316 ber_skip_data( ber, len );
317 tag = ber_skip_tag( ber, &len );
318 if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) { /* issuerUniqueID */
319 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
320 ber_skip_data( ber, len );
321 tag = ber_skip_tag( ber, &len );
323 if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
324 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
325 ber_skip_data( ber, len );
326 tag = ber_skip_tag( ber, &len );
328 if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) { /* Extensions */
329 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
330 tag = ber_skip_tag( ber, &len );
331 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
332 ber_skip_data( ber, len );
333 tag = ber_skip_tag( ber, &len );
335 /* signatureAlgorithm */
336 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
337 ber_skip_data( ber, len );
338 tag = ber_skip_tag( ber, &len );
340 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
341 ber_skip_data( ber, len );
342 tag = ber_skip_tag( ber, &len );
343 /* Must be at end now */
344 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
348 /* X.509 certificate list validation */
350 checkTime( struct berval *in, struct berval *out );
353 certificateListValidate( Syntax *syntax, struct berval *in )
355 BerElementBuffer berbuf;
356 BerElement *ber = (BerElement *)&berbuf;
358 ber_len_t len, wrapper_len;
361 ber_int_t version = SLAP_X509_V1;
362 struct berval bvdn, bvtu;
364 ber_init2( ber, in, LBER_USE_DER );
365 tag = ber_skip_tag( ber, &wrapper_len ); /* Signed wrapper */
366 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
367 wrapper_start = ber->ber_ptr;
368 tag = ber_skip_tag( ber, &len ); /* Sequence */
369 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
370 tag = ber_peek_tag( ber, &len );
371 /* Optional version */
372 if ( tag == LBER_INTEGER ) {
373 tag = ber_get_int( ber, &version );
374 assert( tag == LBER_INTEGER );
375 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
377 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
378 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
379 ber_skip_data( ber, len );
380 tag = ber_peek_tag( ber, &len ); /* Issuer DN */
381 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
382 len = ber_ptrlen( ber );
383 bvdn.bv_val = in->bv_val + len;
384 bvdn.bv_len = in->bv_len - len;
385 tag = ber_skip_tag( ber, &len );
386 ber_skip_data( ber, len );
387 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
388 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
389 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
390 bvtu.bv_val = (char *)ber->ber_ptr;
392 ber_skip_data( ber, len );
393 /* Optional nextUpdate */
394 tag = ber_skip_tag( ber, &len );
395 if ( tag == SLAP_TAG_UTCTIME || tag == SLAP_TAG_GENERALIZEDTIME ) {
396 ber_skip_data( ber, len );
397 tag = ber_skip_tag( ber, &len );
399 /* revokedCertificates - Sequence of Sequence, Optional */
400 if ( tag == LBER_SEQUENCE ) {
403 stag = ber_peek_tag( ber, &seqlen );
404 if ( stag == LBER_SEQUENCE || !len ) {
405 /* RFC5280 requires non-empty, but X.509(2005) allows empty. */
407 ber_skip_data( ber, len );
408 tag = ber_skip_tag( ber, &len );
411 /* Optional Extensions - Sequence of Sequence */
412 if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
414 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
415 tag = ber_peek_tag( ber, &seqlen );
416 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
417 ber_skip_data( ber, len );
418 tag = ber_skip_tag( ber, &len );
420 /* signatureAlgorithm */
421 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
422 ber_skip_data( ber, len );
423 tag = ber_skip_tag( ber, &len );
425 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
426 ber_skip_data( ber, len );
427 if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1;
428 tag = ber_skip_tag( ber, &len );
429 /* Must be at end now */
430 /* NOTE: OpenSSL tolerates CL with garbage past the end */
431 if ( len || tag != LBER_DEFAULT ) {
432 struct berval issuer_dn = BER_BVNULL, thisUpdate;
433 char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
436 if ( ! wrapper_ok ) {
437 return LDAP_INVALID_SYNTAX;
440 rc = dnX509normalize( &bvdn, &issuer_dn );
441 if ( rc != LDAP_SUCCESS ) {
442 rc = LDAP_INVALID_SYNTAX;
446 thisUpdate.bv_val = tubuf;
447 thisUpdate.bv_len = sizeof(tubuf);
448 if ( checkTime( &bvtu, &thisUpdate ) ) {
449 rc = LDAP_INVALID_SYNTAX;
453 Debug( LDAP_DEBUG_ANY,
454 "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n",
455 issuer_dn.bv_val, thisUpdate.bv_val, 0 );
458 if ( ! BER_BVISNULL( &issuer_dn ) ) {
459 ber_memfree( issuer_dn.bv_val );
468 /* X.509 PMI Attribute Certificate Validate */
470 attributeCertificateValidate( Syntax *syntax, struct berval *in )
472 BerElementBuffer berbuf;
473 BerElement *ber = (BerElement *)&berbuf;
479 ber_init2( ber, in, LBER_USE_DER );
481 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
482 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
484 tag = ber_skip_tag( ber, &len ); /* Sequence */
485 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
487 tag = ber_peek_tag( ber, &len ); /* Version */
488 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
489 tag = ber_get_int( ber, &version ); /* X.509 only allows v2 */
490 if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX;
492 tag = ber_skip_tag( ber, &len ); /* Holder */
493 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
494 ber_skip_data( ber, len );
496 tag = ber_skip_tag( ber, &len ); /* Issuer */
497 if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX;
498 ber_skip_data( ber, len );
500 tag = ber_skip_tag( ber, &len ); /* Signature */
501 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
502 ber_skip_data( ber, len );
504 tag = ber_skip_tag( ber, &len ); /* Serial number */
505 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
506 ber_skip_data( ber, len );
508 tag = ber_skip_tag( ber, &len ); /* AttCertValidityPeriod */
509 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
510 ber_skip_data( ber, len );
512 tag = ber_skip_tag( ber, &len ); /* Attributes */
513 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
514 ber_skip_data( ber, len );
516 tag = ber_peek_tag( ber, &len );
518 if ( tag == LBER_BITSTRING ) { /* issuerUniqueID */
519 tag = ber_skip_tag( ber, &len );
520 ber_skip_data( ber, len );
521 tag = ber_peek_tag( ber, &len );
524 if ( tag == LBER_SEQUENCE ) { /* extensions or signatureAlgorithm */
525 tag = ber_skip_tag( ber, &len );
526 ber_skip_data( ber, len );
528 tag = ber_peek_tag( ber, &len );
531 if ( tag == LBER_SEQUENCE ) { /* signatureAlgorithm */
532 tag = ber_skip_tag( ber, &len );
533 ber_skip_data( ber, len );
535 tag = ber_peek_tag( ber, &len );
538 if ( tag == LBER_BITSTRING ) { /* Signature */
539 tag = ber_skip_tag( ber, &len );
540 ber_skip_data( ber, len );
542 tag = ber_peek_tag( ber, &len );
545 /* Must be at end now */
546 if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX;
557 struct berval *value,
558 void *assertedValue )
560 struct berval *asserted = (struct berval *) assertedValue;
561 ber_slen_t d = (ber_slen_t) value->bv_len - (ber_slen_t) asserted->bv_len;
563 /* For speed, order first by length, then by contents */
564 *matchp = d ? (sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1)
565 : memcmp( value->bv_val, asserted->bv_val, value->bv_len );
571 octetStringOrderingMatch(
576 struct berval *value,
577 void *assertedValue )
579 struct berval *asserted = (struct berval *) assertedValue;
580 ber_len_t v_len = value->bv_len;
581 ber_len_t av_len = asserted->bv_len;
583 int match = memcmp( value->bv_val, asserted->bv_val,
584 (v_len < av_len ? v_len : av_len) );
587 match = sizeof(v_len) == sizeof(int)
588 ? (int) v_len - (int) av_len
589 : v_len < av_len ? -1 : v_len > av_len;
591 /* If used in extensible match filter, match if value < asserted */
592 if ( flags & SLAP_MR_EXT )
593 match = (match >= 0);
599 /* Initialize HASHcontext from match type and schema info */
602 HASH_CONTEXT *HASHcontext,
603 struct berval *prefix,
608 HASH_Init(HASHcontext);
609 if(prefix && prefix->bv_len > 0) {
610 HASH_Update(HASHcontext,
611 (unsigned char *)prefix->bv_val, prefix->bv_len);
613 if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
614 HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
615 HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
619 /* Set HASHdigest from HASHcontext and value:len */
622 HASH_CONTEXT *HASHcontext,
623 unsigned char *HASHdigest,
624 unsigned char *value,
627 HASH_CONTEXT ctx = *HASHcontext;
628 HASH_Update( &ctx, value, len );
629 HASH_Final( HASHdigest, &ctx );
632 /* Index generation function: Attribute values -> index hash keys */
633 int octetStringIndexer(
638 struct berval *prefix,
646 HASH_CONTEXT HASHcontext;
647 unsigned char HASHdigest[HASH_BYTES];
648 struct berval digest;
649 digest.bv_val = (char *)HASHdigest;
650 digest.bv_len = sizeof(HASHdigest);
652 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
653 /* just count them */
656 /* we should have at least one value at this point */
659 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
661 slen = syntax->ssyn_oidlen;
662 mlen = mr->smr_oidlen;
664 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
665 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
666 hashIter( &HASHcontext, HASHdigest,
667 (unsigned char *)values[i].bv_val, values[i].bv_len );
668 ber_dupbv_x( &keys[i], &digest, ctx );
671 BER_BVZERO( &keys[i] );
678 /* Index generation function: Asserted value -> index hash key */
679 int octetStringFilter(
684 struct berval *prefix,
685 void * assertedValue,
691 HASH_CONTEXT HASHcontext;
692 unsigned char HASHdigest[HASH_BYTES];
693 struct berval *value = (struct berval *) assertedValue;
694 struct berval digest;
695 digest.bv_val = (char *)HASHdigest;
696 digest.bv_len = sizeof(HASHdigest);
698 slen = syntax->ssyn_oidlen;
699 mlen = mr->smr_oidlen;
701 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
703 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
704 hashIter( &HASHcontext, HASHdigest,
705 (unsigned char *)value->bv_val, value->bv_len );
707 ber_dupbv_x( keys, &digest, ctx );
708 BER_BVZERO( &keys[1] );
716 octetStringSubstringsMatch(
721 struct berval *value,
722 void *assertedValue )
725 SubstringsAssertion *sub = assertedValue;
726 struct berval left = *value;
730 /* Add up asserted input length */
731 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
732 inlen += sub->sa_initial.bv_len;
735 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
736 inlen += sub->sa_any[i].bv_len;
739 if ( !BER_BVISNULL( &sub->sa_final ) ) {
740 inlen += sub->sa_final.bv_len;
743 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
744 if ( inlen > left.bv_len ) {
749 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
750 sub->sa_initial.bv_len );
756 left.bv_val += sub->sa_initial.bv_len;
757 left.bv_len -= sub->sa_initial.bv_len;
758 inlen -= sub->sa_initial.bv_len;
761 if ( !BER_BVISNULL( &sub->sa_final ) ) {
762 if ( inlen > left.bv_len ) {
767 match = memcmp( sub->sa_final.bv_val,
768 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
769 sub->sa_final.bv_len );
775 left.bv_len -= sub->sa_final.bv_len;
776 inlen -= sub->sa_final.bv_len;
780 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
785 if ( inlen > left.bv_len ) {
786 /* not enough length */
791 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
795 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
802 idx = p - left.bv_val;
804 if ( idx >= left.bv_len ) {
805 /* this shouldn't happen */
812 if ( sub->sa_any[i].bv_len > left.bv_len ) {
813 /* not enough left */
818 match = memcmp( left.bv_val,
819 sub->sa_any[i].bv_val,
820 sub->sa_any[i].bv_len );
828 left.bv_val += sub->sa_any[i].bv_len;
829 left.bv_len -= sub->sa_any[i].bv_len;
830 inlen -= sub->sa_any[i].bv_len;
839 /* Substring index generation function: Attribute values -> index hash keys */
841 octetStringSubstringsIndexer(
846 struct berval *prefix,
855 HASH_CONTEXT HCany, HCini, HCfin;
856 unsigned char HASHdigest[HASH_BYTES];
857 struct berval digest;
858 digest.bv_val = (char *)HASHdigest;
859 digest.bv_len = sizeof(HASHdigest);
863 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
864 /* count number of indices to generate */
865 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
866 if( values[i].bv_len >= index_substr_if_maxlen ) {
867 nkeys += index_substr_if_maxlen -
868 (index_substr_if_minlen - 1);
869 } else if( values[i].bv_len >= index_substr_if_minlen ) {
870 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
874 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
875 if( values[i].bv_len >= index_substr_any_len ) {
876 nkeys += values[i].bv_len - (index_substr_any_len - 1);
880 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
881 if( values[i].bv_len >= index_substr_if_maxlen ) {
882 nkeys += index_substr_if_maxlen -
883 (index_substr_if_minlen - 1);
884 } else if( values[i].bv_len >= index_substr_if_minlen ) {
885 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
891 /* no keys to generate */
896 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
898 slen = syntax->ssyn_oidlen;
899 mlen = mr->smr_oidlen;
901 if ( flags & SLAP_INDEX_SUBSTR_ANY )
902 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
903 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
904 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
905 if( flags & SLAP_INDEX_SUBSTR_FINAL )
906 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
909 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
912 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
913 ( values[i].bv_len >= index_substr_any_len ) )
915 max = values[i].bv_len - (index_substr_any_len - 1);
917 for( j=0; j<max; j++ ) {
918 hashIter( &HCany, HASHdigest,
919 (unsigned char *)&values[i].bv_val[j],
920 index_substr_any_len );
921 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
925 /* skip if too short */
926 if( values[i].bv_len < index_substr_if_minlen ) continue;
928 max = index_substr_if_maxlen < values[i].bv_len
929 ? index_substr_if_maxlen : values[i].bv_len;
931 for( j=index_substr_if_minlen; j<=max; j++ ) {
933 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
934 hashIter( &HCini, HASHdigest,
935 (unsigned char *)values[i].bv_val, j );
936 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
939 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
940 hashIter( &HCfin, HASHdigest,
941 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
942 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
949 BER_BVZERO( &keys[nkeys] );
959 /* Substring index generation function: Assertion value -> index hash keys */
961 octetStringSubstringsFilter (
966 struct berval *prefix,
967 void * assertedValue,
971 SubstringsAssertion *sa;
974 size_t slen, mlen, klen;
976 HASH_CONTEXT HASHcontext;
977 unsigned char HASHdigest[HASH_BYTES];
978 struct berval *value;
979 struct berval digest;
981 sa = (SubstringsAssertion *) assertedValue;
983 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
984 !BER_BVISNULL( &sa->sa_initial ) &&
985 sa->sa_initial.bv_len >= index_substr_if_minlen )
988 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
989 ( flags & SLAP_INDEX_SUBSTR_ANY ))
991 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
995 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
997 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
998 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
999 /* don't bother accounting with stepping */
1000 nkeys += sa->sa_any[i].bv_len -
1001 ( index_substr_any_len - 1 );
1006 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1007 !BER_BVISNULL( &sa->sa_final ) &&
1008 sa->sa_final.bv_len >= index_substr_if_minlen )
1011 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
1012 ( flags & SLAP_INDEX_SUBSTR_ANY ))
1014 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1020 return LDAP_SUCCESS;
1023 digest.bv_val = (char *)HASHdigest;
1024 digest.bv_len = sizeof(HASHdigest);
1026 slen = syntax->ssyn_oidlen;
1027 mlen = mr->smr_oidlen;
1029 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
1032 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1033 !BER_BVISNULL( &sa->sa_initial ) &&
1034 sa->sa_initial.bv_len >= index_substr_if_minlen )
1036 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1037 value = &sa->sa_initial;
1039 klen = index_substr_if_maxlen < value->bv_len
1040 ? index_substr_if_maxlen : value->bv_len;
1042 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1043 hashIter( &HASHcontext, HASHdigest,
1044 (unsigned char *)value->bv_val, klen );
1045 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1047 /* If initial is too long and we have subany indexed, use it
1048 * to match the excess...
1050 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1053 pre = SLAP_INDEX_SUBSTR_PREFIX;
1054 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1055 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
1057 hashIter( &HASHcontext, HASHdigest,
1058 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1059 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1064 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1066 pre = SLAP_INDEX_SUBSTR_PREFIX;
1067 klen = index_substr_any_len;
1069 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1070 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
1074 value = &sa->sa_any[i];
1076 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1078 j <= value->bv_len - index_substr_any_len;
1079 j += index_substr_any_step )
1081 hashIter( &HASHcontext, HASHdigest,
1082 (unsigned char *)&value->bv_val[j], klen );
1083 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1088 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1089 !BER_BVISNULL( &sa->sa_final ) &&
1090 sa->sa_final.bv_len >= index_substr_if_minlen )
1092 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1093 value = &sa->sa_final;
1095 klen = index_substr_if_maxlen < value->bv_len
1096 ? index_substr_if_maxlen : value->bv_len;
1098 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1099 hashIter( &HASHcontext, HASHdigest,
1100 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
1101 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1103 /* If final is too long and we have subany indexed, use it
1104 * to match the excess...
1106 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1109 pre = SLAP_INDEX_SUBSTR_PREFIX;
1110 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1111 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
1113 hashIter( &HASHcontext, HASHdigest,
1114 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1115 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1121 BER_BVZERO( &keys[nkeys] );
1128 return LDAP_SUCCESS;
1138 /* very unforgiving validation, requires no normalization
1139 * before simplistic matching
1141 if( in->bv_len < 3 ) {
1142 return LDAP_INVALID_SYNTAX;
1145 /* RFC 4517 Section 3.3.2 Bit String:
1146 * BitString = SQUOTE *binary-digit SQUOTE "B"
1147 * binary-digit = "0" / "1"
1149 * where SQUOTE [RFC4512] is
1150 * SQUOTE = %x27 ; single quote ("'")
1152 * Example: '0101111101'B
1155 if( in->bv_val[0] != '\'' ||
1156 in->bv_val[in->bv_len - 2] != '\'' ||
1157 in->bv_val[in->bv_len - 1] != 'B' )
1159 return LDAP_INVALID_SYNTAX;
1162 for( i = in->bv_len - 3; i > 0; i-- ) {
1163 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
1164 return LDAP_INVALID_SYNTAX;
1168 return LDAP_SUCCESS;
1172 * Syntaxes from RFC 4517
1177 A value of the Bit String syntax is a sequence of binary digits. The
1178 LDAP-specific encoding of a value of this syntax is defined by the
1181 BitString = SQUOTE *binary-digit SQUOTE "B"
1183 binary-digit = "0" / "1"
1185 The <SQUOTE> rule is defined in [MODELS].
1190 The LDAP definition for the Bit String syntax is:
1192 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
1194 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
1198 3.3.21. Name and Optional UID
1200 A value of the Name and Optional UID syntax is the distinguished name
1201 [MODELS] of an entity optionally accompanied by a unique identifier
1202 that serves to differentiate the entity from others with an identical
1205 The LDAP-specific encoding of a value of this syntax is defined by
1208 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
1210 The <BitString> rule is defined in Section 3.3.2. The
1211 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
1212 defined in [MODELS].
1214 Note that although the '#' character may occur in the string
1215 representation of a distinguished name, no additional escaping of
1216 this character is performed when a <distinguishedName> is encoded in
1217 a <NameAndOptionalUID>.
1220 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
1222 The LDAP definition for the Name and Optional UID syntax is:
1224 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
1226 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
1233 1.4. Common ABNF Productions
1236 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
1238 SQUOTE = %x27 ; single quote ("'")
1243 * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
1244 * be escaped except when at the beginning of a value, the
1245 * definition of Name and Optional UID appears to be flawed,
1246 * because there is no clear means to determine whether the
1247 * UID part is present or not.
1251 * cn=Someone,dc=example,dc=com#'1'B
1253 * could be either a NameAndOptionalUID with trailing UID, i.e.
1255 * DN = "cn=Someone,dc=example,dc=com"
1258 * or a NameAndOptionalUID with no trailing UID, and the AVA
1259 * in the last RDN made of
1261 * attributeType = dc
1262 * attributeValue = com#'1'B
1264 * in fact "com#'1'B" is a valid IA5 string.
1266 * As a consequence, current slapd code takes the presence of
1267 * #<valid BitString> at the end of the string representation
1268 * of a NameAndOptionalUID to mean this is indeed a BitString.
1269 * This is quite arbitrary - it has changed the past and might
1270 * change in the future.
1280 struct berval dn, uid;
1282 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
1284 ber_dupbv( &dn, in );
1285 if( !dn.bv_val ) return LDAP_OTHER;
1287 /* if there's a "#", try bitStringValidate()... */
1288 uid.bv_val = strrchr( dn.bv_val, '#' );
1289 if ( !BER_BVISNULL( &uid ) ) {
1291 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1293 rc = bitStringValidate( NULL, &uid );
1294 if ( rc == LDAP_SUCCESS ) {
1295 /* in case of success, trim the UID,
1296 * otherwise treat it as part of the DN */
1297 dn.bv_len -= uid.bv_len + 1;
1298 uid.bv_val[-1] = '\0';
1302 rc = dnValidate( NULL, &dn );
1304 ber_memfree( dn.bv_val );
1315 assert( val != NULL );
1316 assert( out != NULL );
1319 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1321 if( BER_BVISEMPTY( val ) ) {
1322 ber_dupbv_x( out, val, ctx );
1324 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1325 return LDAP_INVALID_SYNTAX;
1329 struct berval dnval = *val;
1330 struct berval uidval = BER_BVNULL;
1332 uidval.bv_val = strrchr( val->bv_val, '#' );
1333 if ( !BER_BVISNULL( &uidval ) ) {
1335 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1337 rc = bitStringValidate( NULL, &uidval );
1339 if ( rc == LDAP_SUCCESS ) {
1340 ber_dupbv_x( &dnval, val, ctx );
1342 dnval.bv_len -= ++uidval.bv_len;
1343 dnval.bv_val[dnval.bv_len] = '\0';
1346 BER_BVZERO( &uidval );
1350 rc = dnPretty( syntax, &dnval, out, ctx );
1351 if ( dnval.bv_val != val->bv_val ) {
1352 slap_sl_free( dnval.bv_val, ctx );
1354 if( rc != LDAP_SUCCESS ) {
1358 if( !BER_BVISNULL( &uidval ) ) {
1361 tmp = slap_sl_realloc( out->bv_val, out->bv_len
1362 + uidval.bv_len + 1,
1365 ber_memfree_x( out->bv_val, ctx );
1369 memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
1370 out->bv_len += uidval.bv_len;
1371 out->bv_val[out->bv_len] = '\0';
1375 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1377 return LDAP_SUCCESS;
1381 uniqueMemberNormalize(
1386 struct berval *normalized,
1392 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1394 ber_dupbv_x( &out, val, ctx );
1395 if ( BER_BVISEMPTY( &out ) ) {
1399 struct berval uid = BER_BVNULL;
1401 uid.bv_val = strrchr( out.bv_val, '#' );
1402 if ( !BER_BVISNULL( &uid ) ) {
1404 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1406 rc = bitStringValidate( NULL, &uid );
1407 if ( rc == LDAP_SUCCESS ) {
1408 uid.bv_val[-1] = '\0';
1409 out.bv_len -= uid.bv_len + 1;
1415 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1417 if( rc != LDAP_SUCCESS ) {
1418 slap_sl_free( out.bv_val, ctx );
1419 return LDAP_INVALID_SYNTAX;
1422 if( !BER_BVISNULL( &uid ) ) {
1425 tmp = ch_realloc( normalized->bv_val,
1426 normalized->bv_len + uid.bv_len
1427 + STRLENOF("#") + 1 );
1428 if ( tmp == NULL ) {
1429 ber_memfree_x( normalized->bv_val, ctx );
1433 normalized->bv_val = tmp;
1435 /* insert the separator */
1436 normalized->bv_val[normalized->bv_len++] = '#';
1438 /* append the UID */
1439 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1440 uid.bv_val, uid.bv_len );
1441 normalized->bv_len += uid.bv_len;
1444 normalized->bv_val[normalized->bv_len] = '\0';
1447 slap_sl_free( out.bv_val, ctx );
1450 return LDAP_SUCCESS;
1459 struct berval *value,
1460 void *assertedValue )
1463 struct berval *asserted = (struct berval *) assertedValue;
1464 struct berval assertedDN = *asserted;
1465 struct berval assertedUID = BER_BVNULL;
1466 struct berval valueDN = *value;
1467 struct berval valueUID = BER_BVNULL;
1468 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1470 if ( !BER_BVISEMPTY( asserted ) ) {
1471 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1472 if ( !BER_BVISNULL( &assertedUID ) ) {
1473 assertedUID.bv_val++;
1474 assertedUID.bv_len = assertedDN.bv_len
1475 - ( assertedUID.bv_val - assertedDN.bv_val );
1477 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1478 assertedDN.bv_len -= assertedUID.bv_len + 1;
1481 BER_BVZERO( &assertedUID );
1486 if ( !BER_BVISEMPTY( value ) ) {
1488 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1489 if ( !BER_BVISNULL( &valueUID ) ) {
1491 valueUID.bv_len = valueDN.bv_len
1492 - ( valueUID.bv_val - valueDN.bv_val );
1494 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1495 valueDN.bv_len -= valueUID.bv_len + 1;
1498 BER_BVZERO( &valueUID );
1503 if( valueUID.bv_len && assertedUID.bv_len ) {
1505 d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len;
1507 *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1;
1508 return LDAP_SUCCESS;
1511 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1514 return LDAP_SUCCESS;
1517 } else if ( !approx && valueUID.bv_len ) {
1520 return LDAP_SUCCESS;
1522 } else if ( !approx && assertedUID.bv_len ) {
1525 return LDAP_SUCCESS;
1528 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1532 uniqueMemberIndexer(
1537 struct berval *prefix,
1545 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1546 /* just count them */
1550 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1552 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1553 struct berval assertedDN = values[i];
1554 struct berval assertedUID = BER_BVNULL;
1556 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1557 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1558 if ( !BER_BVISNULL( &assertedUID ) ) {
1559 assertedUID.bv_val++;
1560 assertedUID.bv_len = assertedDN.bv_len
1561 - ( assertedUID.bv_val - assertedDN.bv_val );
1563 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1564 assertedDN.bv_len -= assertedUID.bv_len + 1;
1567 BER_BVZERO( &assertedUID );
1572 dnvalues[i] = assertedDN;
1574 BER_BVZERO( &dnvalues[i] );
1576 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1577 dnvalues, keysp, ctx );
1579 slap_sl_free( dnvalues, ctx );
1589 struct berval *prefix,
1590 void * assertedValue,
1594 struct berval *asserted = (struct berval *) assertedValue;
1595 struct berval assertedDN = *asserted;
1596 struct berval assertedUID = BER_BVNULL;
1598 if ( !BER_BVISEMPTY( asserted ) ) {
1599 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1600 if ( !BER_BVISNULL( &assertedUID ) ) {
1601 assertedUID.bv_val++;
1602 assertedUID.bv_len = assertedDN.bv_len
1603 - ( assertedUID.bv_val - assertedDN.bv_val );
1605 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1606 assertedDN.bv_len -= assertedUID.bv_len + 1;
1609 BER_BVZERO( &assertedUID );
1614 return octetStringFilter( use, flags, syntax, mr, prefix,
1615 &assertedDN, keysp, ctx );
1620 * Handling boolean syntax and matching is quite rigid.
1621 * A more flexible approach would be to allow a variety
1622 * of strings to be normalized and prettied into TRUE
1630 /* very unforgiving validation, requires no normalization
1631 * before simplistic matching
1634 if( in->bv_len == 4 ) {
1635 if( bvmatch( in, &slap_true_bv ) ) {
1636 return LDAP_SUCCESS;
1638 } else if( in->bv_len == 5 ) {
1639 if( bvmatch( in, &slap_false_bv ) ) {
1640 return LDAP_SUCCESS;
1644 return LDAP_INVALID_SYNTAX;
1653 struct berval *value,
1654 void *assertedValue )
1656 /* simplistic matching allowed by rigid validation */
1657 struct berval *asserted = (struct berval *) assertedValue;
1658 *matchp = (int) asserted->bv_len - (int) value->bv_len;
1659 return LDAP_SUCCESS;
1662 /*-------------------------------------------------------------------
1663 LDAP/X.500 string syntax / matching rules have a few oddities. This
1664 comment attempts to detail how slapd(8) treats them.
1667 StringSyntax X.500 LDAP Matching/Comments
1668 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1669 PrintableString subset subset i/e + ignore insignificant spaces
1670 PrintableString subset subset i/e + ignore insignificant spaces
1671 NumericString subset subset ignore all spaces
1672 IA5String ASCII ASCII i/e + ignore insignificant spaces
1673 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1675 TelephoneNumber subset subset i + ignore all spaces and "-"
1677 See RFC 4518 for details.
1681 In X.500(93), a directory string can be either a PrintableString,
1682 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1683 In later versions, more CHOICEs were added. In all cases the string
1686 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1687 A directory string cannot be zero length.
1689 For matching, there are both case ignore and exact rules. Both
1690 also require that "insignificant" spaces be ignored.
1691 spaces before the first non-space are ignored;
1692 spaces after the last non-space are ignored;
1693 spaces after a space are ignored.
1694 Note: by these rules (and as clarified in X.520), a string of only
1695 spaces is to be treated as if held one space, not empty (which
1696 would be a syntax error).
1699 In ASN.1, numeric string is just a string of digits and spaces
1700 and could be empty. However, in X.500, all attribute values of
1701 numeric string carry a non-empty constraint. For example:
1703 internationalISDNNumber ATTRIBUTE ::= {
1704 WITH SYNTAX InternationalISDNNumber
1705 EQUALITY MATCHING RULE numericStringMatch
1706 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1707 ID id-at-internationalISDNNumber }
1708 InternationalISDNNumber ::=
1709 NumericString (SIZE(1..ub-international-isdn-number))
1711 Unforunately, some assertion values are don't carry the same
1712 constraint (but its unclear how such an assertion could ever
1713 be true). In LDAP, there is one syntax (numericString) not two
1714 (numericString with constraint, numericString without constraint).
1715 This should be treated as numericString with non-empty constraint.
1716 Note that while someone may have no ISDN number, there are no ISDN
1717 numbers which are zero length.
1719 In matching, spaces are ignored.
1722 In ASN.1, Printable string is just a string of printable characters
1723 and can be empty. In X.500, semantics much like NumericString (see
1724 serialNumber for a like example) excepting uses insignificant space
1725 handling instead of ignore all spaces. They must be non-empty.
1728 Basically same as PrintableString. There are no examples in X.500,
1729 but same logic applies. Empty strings are allowed.
1731 -------------------------------------------------------------------*/
1740 unsigned char *u = (unsigned char *)in->bv_val;
1742 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1743 /* directory strings cannot be empty */
1744 return LDAP_INVALID_SYNTAX;
1747 for( count = in->bv_len; count > 0; count -= len, u += len ) {
1748 /* get the length indicated by the first byte */
1749 len = LDAP_UTF8_CHARLEN2( u, len );
1751 /* very basic checks */
1754 if( (u[5] & 0xC0) != 0x80 ) {
1755 return LDAP_INVALID_SYNTAX;
1758 if( (u[4] & 0xC0) != 0x80 ) {
1759 return LDAP_INVALID_SYNTAX;
1762 if( (u[3] & 0xC0) != 0x80 ) {
1763 return LDAP_INVALID_SYNTAX;
1766 if( (u[2] & 0xC0 )!= 0x80 ) {
1767 return LDAP_INVALID_SYNTAX;
1770 if( (u[1] & 0xC0) != 0x80 ) {
1771 return LDAP_INVALID_SYNTAX;
1774 /* CHARLEN already validated it */
1777 return LDAP_INVALID_SYNTAX;
1780 /* make sure len corresponds with the offset
1781 to the next character */
1782 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1786 return LDAP_INVALID_SYNTAX;
1789 return LDAP_SUCCESS;
1793 UTF8StringNormalize(
1798 struct berval *normalized,
1801 struct berval tmp, nvalue;
1802 int flags, wasspace;
1805 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1807 if( BER_BVISNULL( val ) ) {
1808 /* assume we're dealing with a syntax (e.g., UTF8String)
1809 * which allows empty strings
1811 BER_BVZERO( normalized );
1812 return LDAP_SUCCESS;
1815 flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1816 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1817 flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1818 ? LDAP_UTF8_APPROX : 0;
1820 val = UTF8bvnormalize( val, &tmp, flags, ctx );
1821 /* out of memory or syntax error, the former is unlikely */
1823 return LDAP_INVALID_SYNTAX;
1826 /* collapse spaces (in place) */
1828 nvalue.bv_val = tmp.bv_val;
1830 /* trim leading spaces? */
1831 wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1832 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1834 for( i = 0; i < tmp.bv_len; i++) {
1835 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1836 if( wasspace++ == 0 ) {
1837 /* trim repeated spaces */
1838 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1842 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1846 if( !BER_BVISEMPTY( &nvalue ) ) {
1847 /* trim trailing space? */
1849 (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1850 ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1854 nvalue.bv_val[nvalue.bv_len] = '\0';
1857 /* string of all spaces is treated as one space */
1858 nvalue.bv_val[0] = ' ';
1859 nvalue.bv_val[1] = '\0';
1863 *normalized = nvalue;
1864 return LDAP_SUCCESS;
1868 directoryStringSubstringsMatch(
1873 struct berval *value,
1874 void *assertedValue )
1877 SubstringsAssertion *sub = assertedValue;
1878 struct berval left = *value;
1882 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1883 if ( sub->sa_initial.bv_len > left.bv_len ) {
1884 /* not enough left */
1889 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1890 sub->sa_initial.bv_len );
1896 left.bv_val += sub->sa_initial.bv_len;
1897 left.bv_len -= sub->sa_initial.bv_len;
1899 priorspace = ASCII_SPACE(
1900 sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1903 if ( sub->sa_any ) {
1904 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1908 if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1909 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1911 /* allow next space to match */
1918 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1922 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1923 /* not enough left */
1928 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1935 idx = p - left.bv_val;
1937 if ( idx >= left.bv_len ) {
1938 /* this shouldn't happen */
1945 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1946 /* not enough left */
1951 match = memcmp( left.bv_val,
1952 sub->sa_any[i].bv_val,
1953 sub->sa_any[i].bv_len );
1961 left.bv_val += sub->sa_any[i].bv_len;
1962 left.bv_len -= sub->sa_any[i].bv_len;
1964 priorspace = ASCII_SPACE(
1965 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1969 if ( !BER_BVISNULL( &sub->sa_final ) ) {
1970 if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
1971 && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1973 /* allow next space to match */
1978 if ( sub->sa_final.bv_len > left.bv_len ) {
1979 /* not enough left */
1984 match = memcmp( sub->sa_final.bv_val,
1985 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1986 sub->sa_final.bv_len );
1995 return LDAP_SUCCESS;
1998 #if defined(SLAPD_APPROX_INITIALS)
1999 # define SLAPD_APPROX_DELIMITER "._ "
2000 # define SLAPD_APPROX_WORDLEN 2
2002 # define SLAPD_APPROX_DELIMITER " "
2003 # define SLAPD_APPROX_WORDLEN 1
2012 struct berval *value,
2013 void *assertedValue )
2015 struct berval *nval, *assertv;
2016 char *val, **values, **words, *c;
2017 int i, count, len, nextchunk=0, nextavail=0;
2019 /* Yes, this is necessary */
2020 nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
2021 if( nval == NULL ) {
2023 return LDAP_SUCCESS;
2026 /* Yes, this is necessary */
2027 assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
2028 NULL, LDAP_UTF8_APPROX, NULL );
2029 if( assertv == NULL ) {
2032 return LDAP_SUCCESS;
2035 /* Isolate how many words there are */
2036 for ( c = nval->bv_val, count = 1; *c; c++ ) {
2037 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
2038 if ( c == NULL ) break;
2043 /* Get a phonetic copy of each word */
2044 words = (char **)ch_malloc( count * sizeof(char *) );
2045 values = (char **)ch_malloc( count * sizeof(char *) );
2046 for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) {
2048 values[i] = phonetic(c);
2051 /* Work through the asserted value's words, to see if at least some
2052 * of the words are there, in the same order. */
2054 while ( (ber_len_t) nextchunk < assertv->bv_len ) {
2055 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
2060 #if defined(SLAPD_APPROX_INITIALS)
2061 else if( len == 1 ) {
2062 /* Single letter words need to at least match one word's initial */
2063 for( i=nextavail; i<count; i++ )
2064 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
2071 /* Isolate the next word in the asserted value and phonetic it */
2072 assertv->bv_val[nextchunk+len] = '\0';
2073 val = phonetic( assertv->bv_val + nextchunk );
2075 /* See if this phonetic chunk is in the remaining words of *value */
2076 for( i=nextavail; i<count; i++ ){
2077 if( !strcmp( val, values[i] ) ){
2085 /* This chunk in the asserted value was NOT within the *value. */
2091 /* Go on to the next word in the asserted value */
2095 /* If some of the words were seen, call it a match */
2096 if( nextavail > 0 ) {
2103 /* Cleanup allocs */
2104 ber_bvfree( assertv );
2105 for( i=0; i<count; i++ ) {
2106 ch_free( values[i] );
2112 return LDAP_SUCCESS;
2121 struct berval *prefix,
2127 int i,j, len, wordcount, keycount=0;
2128 struct berval *newkeys;
2129 BerVarray keys=NULL;
2131 for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
2132 struct berval val = BER_BVNULL;
2133 /* Yes, this is necessary */
2134 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
2135 assert( !BER_BVISNULL( &val ) );
2137 /* Isolate how many words there are. There will be a key for each */
2138 for( wordcount = 0, c = val.bv_val; *c; c++) {
2139 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2140 if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
2142 if (*c == '\0') break;
2146 /* Allocate/increase storage to account for new keys */
2147 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
2148 * sizeof(struct berval) );
2149 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
2150 if( keys ) ch_free( keys );
2153 /* Get a phonetic copy of each word */
2154 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
2156 if( len < SLAPD_APPROX_WORDLEN ) continue;
2157 ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
2162 ber_memfree( val.bv_val );
2164 BER_BVZERO( &keys[keycount] );
2167 return LDAP_SUCCESS;
2176 struct berval *prefix,
2177 void * assertedValue,
2186 /* Yes, this is necessary */
2187 val = UTF8bvnormalize( ((struct berval *)assertedValue),
2188 NULL, LDAP_UTF8_APPROX, NULL );
2189 if( val == NULL || BER_BVISNULL( val ) ) {
2190 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2191 BER_BVZERO( &keys[0] );
2194 return LDAP_SUCCESS;
2197 /* Isolate how many words there are. There will be a key for each */
2198 for( count = 0,c = val->bv_val; *c; c++) {
2199 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2200 if( len >= SLAPD_APPROX_WORDLEN ) count++;
2202 if (*c == '\0') break;
2206 /* Allocate storage for new keys */
2207 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2209 /* Get a phonetic copy of each word */
2210 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2212 if( len < SLAPD_APPROX_WORDLEN ) continue;
2213 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2219 BER_BVZERO( &keys[count] );
2222 return LDAP_SUCCESS;
2225 /* Remove all spaces and '-' characters */
2227 telephoneNumberNormalize(
2232 struct berval *normalized,
2237 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2239 /* validator should have refused an empty string */
2240 assert( !BER_BVISEMPTY( val ) );
2242 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2244 for( p = val->bv_val; *p; p++ ) {
2245 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
2251 normalized->bv_len = q - normalized->bv_val;
2253 if( BER_BVISEMPTY( normalized ) ) {
2254 slap_sl_free( normalized->bv_val, ctx );
2255 BER_BVZERO( normalized );
2256 return LDAP_INVALID_SYNTAX;
2259 return LDAP_SUCCESS;
2263 postalAddressValidate(
2267 struct berval bv = *in;
2270 for ( c = 0; c < in->bv_len; c++ ) {
2271 if ( in->bv_val[c] == '\\' ) {
2273 if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2274 && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2276 return LDAP_INVALID_SYNTAX;
2281 if ( in->bv_val[c] == '$' ) {
2282 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2283 if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2284 return LDAP_INVALID_SYNTAX;
2286 bv.bv_val = &in->bv_val[c] + 1;
2290 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2291 return UTF8StringValidate( NULL, &bv );
2295 postalAddressNormalize(
2300 struct berval *normalized,
2303 BerVarray lines = NULL, nlines = NULL;
2305 int rc = LDAP_SUCCESS;
2306 MatchingRule *xmr = NULL;
2309 if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2310 xmr = slap_schema.si_mr_caseIgnoreMatch;
2313 xmr = slap_schema.si_mr_caseExactMatch;
2316 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2317 if ( val->bv_val[c] == '$' ) {
2322 lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2323 nlines = &lines[l + 2];
2325 lines[0].bv_val = val->bv_val;
2326 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2327 if ( val->bv_val[c] == '$' ) {
2328 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2330 lines[l].bv_val = &val->bv_val[c + 1];
2333 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2335 normalized->bv_len = l;
2337 for ( l = 0; !BER_BVISNULL( &lines[l] ); l++ ) {
2338 /* NOTE: we directly normalize each line,
2339 * without unescaping the values, since the special
2340 * values '\24' ('$') and '\5C' ('\') are not affected
2341 * by normalization */
2342 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2343 if ( rc != LDAP_SUCCESS ) {
2344 rc = LDAP_INVALID_SYNTAX;
2348 normalized->bv_len += nlines[l].bv_len;
2351 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2353 p = normalized->bv_val;
2354 for ( l = 0; !BER_BVISNULL( &nlines[l] ); l++ ) {
2355 p = lutil_strbvcopy( p, &nlines[l] );
2360 assert( p == &normalized->bv_val[normalized->bv_len] );
2363 if ( nlines != NULL ) {
2364 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2365 slap_sl_free( nlines[l].bv_val, ctx );
2368 slap_sl_free( lines, ctx );
2379 struct berval val = *in;
2381 if( BER_BVISEMPTY( &val ) ) {
2382 /* disallow empty strings */
2383 return LDAP_INVALID_SYNTAX;
2386 while( OID_LEADCHAR( val.bv_val[0] ) ) {
2387 if ( val.bv_len == 1 ) {
2388 return LDAP_SUCCESS;
2391 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2398 while ( OID_LEADCHAR( val.bv_val[0] )) {
2402 if ( val.bv_len == 0 ) {
2403 return LDAP_SUCCESS;
2407 if( !OID_SEPARATOR( val.bv_val[0] )) {
2415 return LDAP_INVALID_SYNTAX;
2424 struct berval val = *in;
2426 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2428 if ( val.bv_val[0] == '-' ) {
2432 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2433 return LDAP_INVALID_SYNTAX;
2436 if( val.bv_val[0] == '0' ) { /* "-0" */
2437 return LDAP_INVALID_SYNTAX;
2440 } else if ( val.bv_val[0] == '0' ) {
2441 if( val.bv_len > 1 ) { /* "0<more>" */
2442 return LDAP_INVALID_SYNTAX;
2445 return LDAP_SUCCESS;
2448 for( i=0; i < val.bv_len; i++ ) {
2449 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2450 return LDAP_INVALID_SYNTAX;
2454 return LDAP_SUCCESS;
2463 struct berval *value,
2464 void *assertedValue )
2466 struct berval *asserted = (struct berval *) assertedValue;
2467 int vsign = 1, asign = 1; /* default sign = '+' */
2472 if( v.bv_val[0] == '-' ) {
2478 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2481 if( a.bv_val[0] == '-' ) {
2487 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2489 match = vsign - asign;
2491 match = ( v.bv_len != a.bv_len
2492 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2493 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2494 if( vsign < 0 ) match = -match;
2497 /* Ordering rule used in extensible match filter? */
2498 if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2499 match = (match >= 0);
2502 return LDAP_SUCCESS;
2505 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2506 #define INDEX_INTLEN_CHOP 7
2507 #define INDEX_INTLEN_CHOPBYTES 3
2516 /* Integer index key format, designed for memcmp to collate correctly:
2517 * if too large: one's complement sign*<approx exponent=chopped bytes>,
2518 * two's complement value (sign-extended or chopped as needed),
2519 * however in first byte above, the top <number of exponent-bytes + 1>
2520 * bits are the inverse sign and next bit is the sign as delimiter.
2522 ber_slen_t k = index_intlen_strlen;
2524 unsigned signmask = ~0x7fU;
2525 unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2526 struct berval val = *in, itmp = *tmp;
2528 if ( val.bv_val[0] != '-' ) {
2533 /* Chop least significant digits, increase length instead */
2534 if ( val.bv_len > (ber_len_t) k ) {
2535 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2536 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2537 chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
2540 if ( lutil_str2bin( &val, &itmp, ctx )) {
2541 return LDAP_INVALID_SYNTAX;
2544 /* Omit leading sign byte */
2545 if ( itmp.bv_val[0] == neg ) {
2550 k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2552 assert( chop == 0 );
2553 memset( key->bv_val, neg, k ); /* sign-extend */
2554 } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2555 /* Got exponent -k, or no room for 2 sign bits */
2556 lenp = lenbuf + sizeof(lenbuf);
2557 chop = - (ber_len_t) k;
2559 *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2561 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2562 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2563 * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2564 k = (lenbuf + sizeof(lenbuf)) - lenp;
2565 if ( k > (ber_slen_t) index_intlen )
2567 memcpy( key->bv_val, lenp, k );
2568 itmp.bv_len = index_intlen - k;
2570 memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2571 key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2575 /* Index generation function: Ordered index */
2582 struct berval *prefix,
2592 unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2594 /* count the values and find max needed length */
2596 for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2597 if ( vlen < values[i].bv_len )
2598 vlen = values[i].bv_len;
2600 if ( vlen > maxstrlen )
2603 /* we should have at least one value at this point */
2606 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2607 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2608 keys[i].bv_len = index_intlen;
2609 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2612 keys[i].bv_val = NULL;
2614 if ( vlen > sizeof(ibuf) ) {
2615 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2619 itmp.bv_len = sizeof(ibuf);
2621 for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2622 if ( itmp.bv_val != ibuf ) {
2623 itmp.bv_len = values[i].bv_len;
2624 if ( itmp.bv_len <= sizeof(ibuf) )
2625 itmp.bv_len = sizeof(ibuf);
2626 else if ( itmp.bv_len > maxstrlen )
2627 itmp.bv_len = maxstrlen;
2629 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2635 if ( itmp.bv_val != ibuf ) {
2636 slap_sl_free( itmp.bv_val, ctx );
2641 /* Index generation function: Ordered index */
2648 struct berval *prefix,
2649 void * assertedValue,
2656 struct berval *value;
2659 value = (struct berval *) assertedValue;
2661 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2663 keys[0].bv_len = index_intlen;
2664 keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2666 keys[1].bv_val = NULL;
2668 iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2669 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2670 if ( iv.bv_len > (int) sizeof(ibuf) ) {
2671 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2674 iv.bv_len = sizeof(ibuf);
2677 rc = integerVal2Key( value, keys, &iv, ctx );
2681 if ( iv.bv_val != ibuf ) {
2682 slap_sl_free( iv.bv_val, ctx );
2688 countryStringValidate(
2690 struct berval *val )
2692 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2694 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2695 return LDAP_INVALID_SYNTAX;
2697 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2698 return LDAP_INVALID_SYNTAX;
2701 return LDAP_SUCCESS;
2705 printableStringValidate(
2707 struct berval *val )
2711 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2713 for(i=0; i < val->bv_len; i++) {
2714 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2715 return LDAP_INVALID_SYNTAX;
2719 return LDAP_SUCCESS;
2723 printablesStringValidate(
2725 struct berval *val )
2729 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2731 for(i=0,len=0; i < val->bv_len; i++) {
2732 int c = val->bv_val[i];
2736 return LDAP_INVALID_SYNTAX;
2740 } else if ( SLAP_PRINTABLE(c) ) {
2743 return LDAP_INVALID_SYNTAX;
2748 return LDAP_INVALID_SYNTAX;
2751 return LDAP_SUCCESS;
2757 struct berval *val )
2761 for(i=0; i < val->bv_len; i++) {
2762 if( !LDAP_ASCII(val->bv_val[i]) ) {
2763 return LDAP_INVALID_SYNTAX;
2767 return LDAP_SUCCESS;
2776 struct berval *normalized,
2780 int casefold = !SLAP_MR_ASSOCIATED( mr,
2781 slap_schema.si_mr_caseExactIA5Match );
2783 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2787 /* Ignore initial whitespace */
2788 while ( ASCII_SPACE( *p ) ) p++;
2790 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2791 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2792 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2793 normalized->bv_val[normalized->bv_len] = '\0';
2795 p = q = normalized->bv_val;
2798 if ( ASCII_SPACE( *p ) ) {
2801 /* Ignore the extra whitespace */
2802 while ( ASCII_SPACE( *p ) ) {
2806 } else if ( casefold ) {
2807 /* Most IA5 rules require casefolding */
2808 *q++ = TOLOWER(*p); p++;
2815 assert( normalized->bv_val <= p );
2819 * If the string ended in space, backup the pointer one
2820 * position. One is enough because the above loop collapsed
2821 * all whitespace to a single space.
2823 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2825 /* null terminate */
2828 normalized->bv_len = q - normalized->bv_val;
2830 return LDAP_SUCCESS;
2839 if( in->bv_len != 36 ) {
2840 return LDAP_INVALID_SYNTAX;
2843 for( i=0; i<36; i++ ) {
2849 if( in->bv_val[i] != '-' ) {
2850 return LDAP_INVALID_SYNTAX;
2854 if( !ASCII_HEX( in->bv_val[i]) ) {
2855 return LDAP_INVALID_SYNTAX;
2860 return LDAP_SUCCESS;
2871 int rc=LDAP_INVALID_SYNTAX;
2873 assert( in != NULL );
2874 assert( out != NULL );
2876 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2879 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2881 for( i=0; i<36; i++ ) {
2887 if( in->bv_val[i] != '-' ) {
2890 out->bv_val[i] = '-';
2894 if( !ASCII_HEX( in->bv_val[i]) ) {
2897 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2902 out->bv_val[ out->bv_len ] = '\0';
2906 slap_sl_free( out->bv_val, ctx );
2919 struct berval *normalized,
2922 unsigned char octet = '\0';
2926 if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2927 /* NOTE: must be a normalized UUID */
2928 assert( val->bv_len == 16 );
2930 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2931 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2932 val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2933 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2935 return LDAP_SUCCESS;
2938 normalized->bv_len = 16;
2939 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2941 for( i=0, j=0; i<36; i++ ) {
2942 unsigned char nibble;
2943 if( val->bv_val[i] == '-' ) {
2946 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2947 nibble = val->bv_val[i] - '0';
2949 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2950 nibble = val->bv_val[i] - ('a'-10);
2952 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2953 nibble = val->bv_val[i] - ('A'-10);
2956 slap_sl_free( normalized->bv_val, ctx );
2957 BER_BVZERO( normalized );
2958 return LDAP_INVALID_SYNTAX;
2963 normalized->bv_val[j>>1] = octet;
2965 octet = nibble << 4;
2970 normalized->bv_val[normalized->bv_len] = 0;
2971 return LDAP_SUCCESS;
2977 numericStringValidate(
2983 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2985 for(i=0; i < in->bv_len; i++) {
2986 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2987 return LDAP_INVALID_SYNTAX;
2991 return LDAP_SUCCESS;
2995 numericStringNormalize(
3000 struct berval *normalized,
3003 /* removal all spaces */
3006 assert( !BER_BVISEMPTY( val ) );
3008 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3011 q = normalized->bv_val;
3014 if ( ASCII_SPACE( *p ) ) {
3015 /* Ignore whitespace */
3022 /* we should have copied no more than is in val */
3023 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3025 /* null terminate */
3028 normalized->bv_len = q - normalized->bv_val;
3030 if( BER_BVISEMPTY( normalized ) ) {
3031 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3032 normalized->bv_val[0] = ' ';
3033 normalized->bv_val[1] = '\0';
3034 normalized->bv_len = 1;
3037 return LDAP_SUCCESS;
3041 * Integer conversion macros that will use the largest available
3044 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3045 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
3046 # define SLAP_LONG long long
3048 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
3049 # define SLAP_LONG long
3050 #endif /* HAVE_STRTOLL ... */
3058 struct berval *value,
3059 void *assertedValue )
3061 SLAP_LONG lValue, lAssertedValue;
3064 /* safe to assume integers are NUL terminated? */
3065 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3066 if( errno == ERANGE )
3068 return LDAP_CONSTRAINT_VIOLATION;
3071 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3073 if( errno == ERANGE )
3075 return LDAP_CONSTRAINT_VIOLATION;
3078 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3079 return LDAP_SUCCESS;
3088 struct berval *value,
3089 void *assertedValue )
3091 SLAP_LONG lValue, lAssertedValue;
3094 /* safe to assume integers are NUL terminated? */
3095 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3096 if( errno == ERANGE )
3098 return LDAP_CONSTRAINT_VIOLATION;
3101 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3103 if( errno == ERANGE )
3105 return LDAP_CONSTRAINT_VIOLATION;
3108 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3109 return LDAP_SUCCESS;
3113 checkNum( struct berval *in, struct berval *out )
3115 /* parse serialNumber */
3116 ber_len_t neg = 0, extra = 0;
3119 out->bv_val = in->bv_val;
3122 if ( out->bv_val[0] == '-' ) {
3127 if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3128 first = out->bv_val[2];
3131 out->bv_len += STRLENOF("0x");
3132 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3133 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3136 } else if ( out->bv_val[0] == '\'' ) {
3137 first = out->bv_val[1];
3140 out->bv_len += STRLENOF("'");
3142 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3143 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3145 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3148 out->bv_len += STRLENOF("'H");
3151 first = out->bv_val[0];
3152 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3153 if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3157 if ( !( out->bv_len > neg ) ) {
3161 if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3169 serialNumberAndIssuerCheck(
3177 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3179 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3180 /* Parse old format */
3181 is->bv_val = ber_bvchr( in, '$' );
3182 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3184 sn->bv_val = in->bv_val;
3185 sn->bv_len = is->bv_val - in->bv_val;
3188 is->bv_len = in->bv_len - (sn->bv_len + 1);
3190 /* eat leading zeros */
3191 for( n=0; n < (sn->bv_len-1); n++ ) {
3192 if( sn->bv_val[n] != '0' ) break;
3197 for( n=0; n < sn->bv_len; n++ ) {
3198 if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3202 /* Parse GSER format */
3207 HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3211 struct berval x = *in;
3217 /* eat leading spaces */
3218 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3222 /* should be at issuer or serialNumber NamedValue */
3223 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3224 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3227 x.bv_val += STRLENOF("issuer");
3228 x.bv_len -= STRLENOF("issuer");
3230 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3234 /* eat leading spaces */
3235 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3239 /* For backward compatibility, this part is optional */
3240 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3241 x.bv_val += STRLENOF("rdnSequence:");
3242 x.bv_len -= STRLENOF("rdnSequence:");
3245 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3249 is->bv_val = x.bv_val;
3252 for ( ; is->bv_len < x.bv_len; ) {
3253 if ( is->bv_val[is->bv_len] != '"' ) {
3257 if ( is->bv_val[is->bv_len+1] == '"' ) {
3264 x.bv_val += is->bv_len + 1;
3265 x.bv_len -= is->bv_len + 1;
3267 have |= HAVE_ISSUER;
3269 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3271 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3273 /* parse serialNumber */
3274 x.bv_val += STRLENOF("serialNumber");
3275 x.bv_len -= STRLENOF("serialNumber");
3277 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3281 /* eat leading spaces */
3282 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3286 if ( checkNum( &x, sn ) ) {
3287 return LDAP_INVALID_SYNTAX;
3290 x.bv_val += sn->bv_len;
3291 x.bv_len -= sn->bv_len;
3296 return LDAP_INVALID_SYNTAX;
3299 /* eat leading spaces */
3300 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3304 if ( have == HAVE_ALL ) {
3308 if ( x.bv_val[0] != ',' ) {
3309 return LDAP_INVALID_SYNTAX;
3316 /* should have no characters left... */
3317 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3319 if ( numdquotes == 0 ) {
3320 ber_dupbv_x( &ni, is, ctx );
3325 ni.bv_len = is->bv_len - numdquotes;
3326 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3327 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3328 if ( is->bv_val[src] == '"' ) {
3331 ni.bv_val[dst] = is->bv_val[src];
3333 ni.bv_val[dst] = '\0';
3343 serialNumberAndIssuerValidate(
3348 struct berval sn, i;
3350 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3353 rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3358 /* validate DN -- doesn't handle double dquote */
3359 rc = dnValidate( NULL, &i );
3361 rc = LDAP_INVALID_SYNTAX;
3364 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3365 slap_sl_free( i.bv_val, NULL );
3368 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3369 in->bv_val, rc, 0 );
3376 serialNumberAndIssuerPretty(
3383 struct berval sn, i, ni = BER_BVNULL;
3386 assert( in != NULL );
3387 assert( out != NULL );
3391 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3394 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3399 rc = dnPretty( syntax, &i, &ni, ctx );
3401 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3402 slap_sl_free( i.bv_val, ctx );
3406 rc = LDAP_INVALID_SYNTAX;
3410 /* make room from sn + "$" */
3411 out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3412 + sn.bv_len + ni.bv_len;
3413 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3415 if ( out->bv_val == NULL ) {
3422 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3423 p = lutil_strbvcopy( p, &sn );
3424 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3425 p = lutil_strbvcopy( p, &ni );
3426 p = lutil_strcopy( p, /*{*/ "\" }" );
3428 assert( p == &out->bv_val[out->bv_len] );
3431 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3432 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3434 slap_sl_free( ni.bv_val, ctx );
3436 return LDAP_SUCCESS;
3446 /* Use hex format. '123456789abcdef'H */
3447 unsigned char *ptr, zero = '\0';
3450 ber_len_t i, len, nlen;
3452 assert( in != NULL );
3453 assert( !BER_BVISNULL( in ) );
3454 assert( out != NULL );
3455 assert( !BER_BVISNULL( out ) );
3457 ptr = (unsigned char *)in->bv_val;
3460 /* Check for minimal encodings */
3462 if ( ptr[0] & 0x80 ) {
3463 if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3467 } else if ( ptr[0] == 0 ) {
3468 if ( !( ptr[1] & 0x80 ) ) {
3475 } else if ( len == 0 ) {
3476 /* FIXME: this should not be possible,
3477 * since a value of zero would have length 1 */
3482 first = !( ptr[0] & 0xf0U );
3483 nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3484 if ( nlen >= out->bv_len ) {
3485 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3491 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3495 for ( ; i < len; i++ ) {
3496 sprintf( sptr, "%02X", ptr[i] );
3503 assert( sptr == &out->bv_val[nlen] );
3510 #define SLAP_SN_BUFLEN (64)
3513 * This routine is called by certificateExactNormalize when
3514 * certificateExactNormalize receives a search string instead of
3515 * a certificate. This routine checks if the search value is valid
3516 * and then returns the normalized value
3519 serialNumberAndIssuerNormalize(
3527 struct berval sn, sn2, sn3, i, ni;
3528 char sbuf2[SLAP_SN_BUFLEN];
3529 char sbuf3[SLAP_SN_BUFLEN];
3533 assert( in != NULL );
3534 assert( out != NULL );
3536 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3539 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3544 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3546 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3547 slap_sl_free( i.bv_val, ctx );
3551 return LDAP_INVALID_SYNTAX;
3554 /* Convert sn to canonical hex */
3556 if ( sn.bv_len > sizeof( sbuf2 ) ) {
3557 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3559 sn2.bv_len = sn.bv_len;
3561 sn3.bv_len = sizeof(sbuf3);
3562 if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
3563 rc = LDAP_INVALID_SYNTAX;
3567 out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3568 + sn3.bv_len + ni.bv_len;
3569 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3570 if ( out->bv_val == NULL ) {
3578 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3579 p = lutil_strbvcopy( p, &sn3 );
3580 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3581 p = lutil_strbvcopy( p, &ni );
3582 p = lutil_strcopy( p, /*{*/ "\" }" );
3584 assert( p == &out->bv_val[out->bv_len] );
3587 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3588 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3590 if ( sn2.bv_val != sbuf2 ) {
3591 slap_sl_free( sn2.bv_val, ctx );
3594 if ( sn3.bv_val != sbuf3 ) {
3595 slap_sl_free( sn3.bv_val, ctx );
3598 slap_sl_free( ni.bv_val, ctx );
3604 certificateExactNormalize(
3609 struct berval *normalized,
3612 BerElementBuffer berbuf;
3613 BerElement *ber = (BerElement *)&berbuf;
3617 char serialbuf2[SLAP_SN_BUFLEN];
3618 struct berval sn, sn2 = BER_BVNULL;
3619 struct berval issuer_dn = BER_BVNULL, bvdn;
3621 int rc = LDAP_INVALID_SYNTAX;
3623 assert( val != NULL );
3625 Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3626 val->bv_val, val->bv_len, 0 );
3628 if ( BER_BVISEMPTY( val ) ) goto done;
3630 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3631 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3634 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3636 ber_init2( ber, val, LBER_USE_DER );
3637 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3638 tag = ber_skip_tag( ber, &len ); /* Sequence */
3639 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3640 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3641 tag = ber_skip_tag( ber, &len );
3642 tag = ber_get_int( ber, &i ); /* version */
3645 /* NOTE: move the test here from certificateValidate,
3646 * so that we can validate certs with serial longer
3647 * than sizeof(ber_int_t) */
3648 tag = ber_skip_tag( ber, &len ); /* serial */
3650 sn.bv_val = (char *)ber->ber_ptr;
3651 sn2.bv_val = serialbuf2;
3652 sn2.bv_len = sizeof(serialbuf2);
3653 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3654 rc = LDAP_INVALID_SYNTAX;
3657 ber_skip_data( ber, len );
3659 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3660 ber_skip_data( ber, len );
3661 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3662 len = ber_ptrlen( ber );
3663 bvdn.bv_val = val->bv_val + len;
3664 bvdn.bv_len = val->bv_len - len;
3666 rc = dnX509normalize( &bvdn, &issuer_dn );
3667 if ( rc != LDAP_SUCCESS ) goto done;
3669 normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3670 + sn2.bv_len + issuer_dn.bv_len;
3671 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3673 p = normalized->bv_val;
3675 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3676 p = lutil_strbvcopy( p, &sn2 );
3677 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3678 p = lutil_strbvcopy( p, &issuer_dn );
3679 p = lutil_strcopy( p, /*{*/ "\" }" );
3684 Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3685 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3687 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3688 if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3693 /* X.509 PKI certificateList stuff */
3695 checkTime( struct berval *in, struct berval *out )
3699 char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3702 assert( in != NULL );
3703 assert( !BER_BVISNULL( in ) );
3704 assert( !BER_BVISEMPTY( in ) );
3706 if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3710 if ( out != NULL ) {
3711 assert( !BER_BVISNULL( out ) );
3712 assert( out->bv_len >= sizeof( buf ) );
3713 bv.bv_val = out->bv_val;
3719 for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3720 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3723 if ( in->bv_val[i] != 'Z' ) {
3728 if ( i != in->bv_len ) {
3732 if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3733 lutil_strncopy( bv.bv_val, in->bv_val, i );
3736 } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3737 char *p = bv.bv_val;
3738 if ( in->bv_val[0] < '7' ) {
3739 p = lutil_strcopy( p, "20" );
3742 p = lutil_strcopy( p, "19" );
3744 lutil_strncopy( p, in->bv_val, i );
3751 rc = generalizedTimeValidate( NULL, &bv );
3752 if ( rc == LDAP_SUCCESS && out != NULL ) {
3753 if ( out->bv_len > bv.bv_len ) {
3754 out->bv_val[ bv.bv_len ] = '\0';
3756 out->bv_len = bv.bv_len;
3759 return rc != LDAP_SUCCESS;
3763 issuerAndThisUpdateCheck(
3770 struct berval x = *in;
3771 struct berval ni = BER_BVNULL;
3772 /* Parse GSER format */
3776 HAVE_THISUPDATE = 0x2,
3777 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3781 if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3783 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3784 return LDAP_INVALID_SYNTAX;
3788 x.bv_len -= STRLENOF("{}");
3791 /* eat leading spaces */
3792 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3796 /* should be at issuer or thisUpdate */
3797 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3798 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3801 x.bv_val += STRLENOF("issuer");
3802 x.bv_len -= STRLENOF("issuer");
3804 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3808 /* eat leading spaces */
3809 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3813 /* For backward compatibility, this part is optional */
3814 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3815 return LDAP_INVALID_SYNTAX;
3817 x.bv_val += STRLENOF("rdnSequence:");
3818 x.bv_len -= STRLENOF("rdnSequence:");
3820 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3824 is->bv_val = x.bv_val;
3827 for ( ; is->bv_len < x.bv_len; ) {
3828 if ( is->bv_val[is->bv_len] != '"' ) {
3832 if ( is->bv_val[is->bv_len+1] == '"' ) {
3839 x.bv_val += is->bv_len + 1;
3840 x.bv_len -= is->bv_len + 1;
3842 have |= HAVE_ISSUER;
3844 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3846 if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3848 /* parse thisUpdate */
3849 x.bv_val += STRLENOF("thisUpdate");
3850 x.bv_len -= STRLENOF("thisUpdate");
3852 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3856 /* eat leading spaces */
3857 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3861 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3865 tu->bv_val = x.bv_val;
3868 for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3869 if ( tu->bv_val[tu->bv_len] == '"' ) {
3873 x.bv_val += tu->bv_len + 1;
3874 x.bv_len -= tu->bv_len + 1;
3876 have |= HAVE_THISUPDATE;
3879 return LDAP_INVALID_SYNTAX;
3882 /* eat leading spaces */
3883 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3887 if ( have == HAVE_ALL ) {
3891 if ( x.bv_val[0] != ',' ) {
3892 return LDAP_INVALID_SYNTAX;
3899 /* should have no characters left... */
3900 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3902 if ( numdquotes == 0 ) {
3903 ber_dupbv_x( &ni, is, ctx );
3908 ni.bv_len = is->bv_len - numdquotes;
3909 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3910 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3911 if ( is->bv_val[src] == '"' ) {
3914 ni.bv_val[dst] = is->bv_val[src];
3916 ni.bv_val[dst] = '\0';
3925 issuerAndThisUpdateValidate(
3930 struct berval i, tu;
3932 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3935 rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3940 /* validate DN -- doesn't handle double dquote */
3941 rc = dnValidate( NULL, &i );
3943 rc = LDAP_INVALID_SYNTAX;
3945 } else if ( checkTime( &tu, NULL ) ) {
3946 rc = LDAP_INVALID_SYNTAX;
3949 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3950 slap_sl_free( i.bv_val, NULL );
3953 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3954 in->bv_val, rc, 0 );
3961 issuerAndThisUpdatePretty(
3968 struct berval i, tu, ni = BER_BVNULL;
3971 assert( in != NULL );
3972 assert( out != NULL );
3976 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3979 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3984 rc = dnPretty( syntax, &i, &ni, ctx );
3986 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3987 slap_sl_free( i.bv_val, ctx );
3990 if ( rc || checkTime( &tu, NULL ) ) {
3991 rc = LDAP_INVALID_SYNTAX;
3996 out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
3997 + ni.bv_len + tu.bv_len;
3998 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4000 if ( out->bv_val == NULL ) {
4007 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4008 p = lutil_strbvcopy( p, &ni );
4009 p = lutil_strcopy( p, "\", thisUpdate \"" );
4010 p = lutil_strbvcopy( p, &tu );
4011 p = lutil_strcopy( p, /*{*/ "\" }" );
4013 assert( p == &out->bv_val[out->bv_len] );
4016 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4017 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4019 slap_sl_free( ni.bv_val, ctx );
4025 issuerAndThisUpdateNormalize(
4033 struct berval i, ni, tu, tu2;
4034 char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4038 assert( in != NULL );
4039 assert( out != NULL );
4041 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4044 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4049 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4051 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4052 slap_sl_free( i.bv_val, ctx );
4056 tu2.bv_len = sizeof( sbuf );
4057 if ( rc || checkTime( &tu, &tu2 ) ) {
4058 return LDAP_INVALID_SYNTAX;
4061 out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4062 + ni.bv_len + tu2.bv_len;
4063 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4065 if ( out->bv_val == NULL ) {
4073 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4074 p = lutil_strbvcopy( p, &ni );
4075 p = lutil_strcopy( p, "\", thisUpdate \"" );
4076 p = lutil_strbvcopy( p, &tu2 );
4077 p = lutil_strcopy( p, /*{*/ "\" }" );
4079 assert( p == &out->bv_val[out->bv_len] );
4082 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4083 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4085 slap_sl_free( ni.bv_val, ctx );
4091 certificateListExactNormalize(
4096 struct berval *normalized,
4099 BerElementBuffer berbuf;
4100 BerElement *ber = (BerElement *)&berbuf;
4104 struct berval issuer_dn = BER_BVNULL, bvdn,
4106 char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4107 int rc = LDAP_INVALID_SYNTAX;
4109 assert( val != NULL );
4111 Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4112 val->bv_val, val->bv_len, 0 );
4114 if ( BER_BVISEMPTY( val ) ) goto done;
4116 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4117 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4120 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4122 ber_init2( ber, val, LBER_USE_DER );
4123 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
4124 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4125 tag = ber_skip_tag( ber, &len ); /* Sequence */
4126 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4127 tag = ber_peek_tag( ber, &len );
4128 /* Optional version */
4129 if ( tag == LBER_INTEGER ) {
4130 tag = ber_get_int( ber, &version );
4131 assert( tag == LBER_INTEGER );
4132 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4134 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
4135 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4136 ber_skip_data( ber, len );
4138 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
4139 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4140 len = ber_ptrlen( ber );
4141 bvdn.bv_val = val->bv_val + len;
4142 bvdn.bv_len = val->bv_len - len;
4143 tag = ber_skip_tag( ber, &len );
4144 ber_skip_data( ber, len );
4146 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
4147 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4148 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4149 bvtu.bv_val = (char *)ber->ber_ptr;
4152 rc = dnX509normalize( &bvdn, &issuer_dn );
4153 if ( rc != LDAP_SUCCESS ) goto done;
4155 thisUpdate.bv_val = tubuf;
4156 thisUpdate.bv_len = sizeof(tubuf);
4157 if ( checkTime( &bvtu, &thisUpdate ) ) {
4158 rc = LDAP_INVALID_SYNTAX;
4162 normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4163 + issuer_dn.bv_len + thisUpdate.bv_len;
4164 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4166 p = normalized->bv_val;
4168 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4169 p = lutil_strbvcopy( p, &issuer_dn );
4170 p = lutil_strcopy( p, "\", thisUpdate \"" );
4171 p = lutil_strbvcopy( p, &thisUpdate );
4172 p = lutil_strcopy( p, /*{*/ "\" }" );
4177 Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4178 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4180 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4185 /* X.509 PMI serialNumberAndIssuerSerialCheck
4187 AttributeCertificateExactAssertion ::= SEQUENCE {
4188 serialNumber CertificateSerialNumber,
4189 issuer AttCertIssuer }
4191 CertificateSerialNumber ::= INTEGER
4193 AttCertIssuer ::= [0] SEQUENCE {
4194 issuerName GeneralNames OPTIONAL,
4195 baseCertificateID [0] IssuerSerial OPTIONAL,
4196 objectDigestInfo [1] ObjectDigestInfo OPTIONAL }
4197 -- At least one component shall be present
4199 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4201 GeneralName ::= CHOICE {
4202 otherName [0] INSTANCE OF OTHER-NAME,
4203 rfc822Name [1] IA5String,
4204 dNSName [2] IA5String,
4205 x400Address [3] ORAddress,
4206 directoryName [4] Name,
4207 ediPartyName [5] EDIPartyName,
4208 uniformResourceIdentifier [6] IA5String,
4209 iPAddress [7] OCTET STRING,
4210 registeredID [8] OBJECT IDENTIFIER }
4212 IssuerSerial ::= SEQUENCE {
4213 issuer GeneralNames,
4214 serial CertificateSerialNumber,
4215 issuerUID UniqueIdentifier OPTIONAL }
4217 ObjectDigestInfo ::= SEQUENCE {
4218 digestedObjectType ENUMERATED {
4221 otherObjectTypes (2) },
4222 otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
4223 digestAlgorithm AlgorithmIdentifier,
4224 objectDigest BIT STRING }
4226 * The way I interpret it, an assertion should look like
4228 { serialNumber 'dd'H,
4229 issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4230 baseCertificateID { serial '1d'H,
4231 issuer { directoryName:rdnSequence:"cn=zzz" },
4232 issuerUID <value> -- optional
4234 objectDigestInfo { ... } -- optional
4238 * with issuerName, baseCertificateID and objectDigestInfo optional,
4239 * at least one present; the way it's currently implemented, it is
4241 { serialNumber 'dd'H,
4242 issuer { baseCertificateID { serial '1d'H,
4243 issuer { directoryName:rdnSequence:"cn=zzz" }
4248 * with all the above parts mandatory.
4251 serialNumberAndIssuerSerialCheck(
4255 struct berval *i_sn, /* contain serial of baseCertificateID */
4258 /* Parse GSER format */
4263 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4264 } have = HAVE_NONE, have2 = HAVE_NONE;
4266 struct berval x = *in;
4269 if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4272 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4279 /* eat leading spaces */
4280 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4284 /* should be at issuer or serialNumber NamedValue */
4285 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4286 if ( have & HAVE_ISSUER ) {
4287 return LDAP_INVALID_SYNTAX;
4290 /* parse IssuerSerial */
4291 x.bv_val += STRLENOF("issuer");
4292 x.bv_len -= STRLENOF("issuer");
4294 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4298 /* eat leading spaces */
4299 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4303 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4307 /* eat leading spaces */
4308 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4312 if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4313 return LDAP_INVALID_SYNTAX;
4315 x.bv_val += STRLENOF("baseCertificateID ");
4316 x.bv_len -= STRLENOF("baseCertificateID ");
4318 /* eat leading spaces */
4319 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4323 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4328 /* eat leading spaces */
4329 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4333 /* parse issuer of baseCertificateID */
4334 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4335 if ( have2 & HAVE_ISSUER ) {
4336 return LDAP_INVALID_SYNTAX;
4339 x.bv_val += STRLENOF("issuer ");
4340 x.bv_len -= STRLENOF("issuer ");
4342 /* eat leading spaces */
4343 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4347 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4351 /* eat leading spaces */
4352 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4356 if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4357 return LDAP_INVALID_SYNTAX;
4359 x.bv_val += STRLENOF("directoryName:rdnSequence:");
4360 x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4362 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4366 is->bv_val = x.bv_val;
4369 for ( ; is->bv_len < x.bv_len; ) {
4370 if ( is->bv_val[is->bv_len] != '"' ) {
4374 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4381 x.bv_val += is->bv_len + 1;
4382 x.bv_len -= is->bv_len + 1;
4384 /* eat leading spaces */
4385 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4389 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4393 have2 |= HAVE_ISSUER;
4395 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4396 if ( have2 & HAVE_SN ) {
4397 return LDAP_INVALID_SYNTAX;
4400 x.bv_val += STRLENOF("serial ");
4401 x.bv_len -= STRLENOF("serial ");
4403 /* eat leading spaces */
4404 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4408 if ( checkNum( &x, i_sn ) ) {
4409 return LDAP_INVALID_SYNTAX;
4412 x.bv_val += i_sn->bv_len;
4413 x.bv_len -= i_sn->bv_len;
4418 return LDAP_INVALID_SYNTAX;
4421 /* eat leading spaces */
4422 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4426 if ( have2 == HAVE_ALL ) {
4430 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4435 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4439 /* eat leading spaces */
4440 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4444 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4448 have |= HAVE_ISSUER;
4450 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4451 if ( have & HAVE_SN ) {
4452 return LDAP_INVALID_SYNTAX;
4455 /* parse serialNumber */
4456 x.bv_val += STRLENOF("serialNumber");
4457 x.bv_len -= STRLENOF("serialNumber");
4459 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4463 /* eat leading spaces */
4464 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4468 if ( checkNum( &x, sn ) ) {
4469 return LDAP_INVALID_SYNTAX;
4472 x.bv_val += sn->bv_len;
4473 x.bv_len -= sn->bv_len;
4478 return LDAP_INVALID_SYNTAX;
4482 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4486 if ( have == HAVE_ALL ) {
4490 if ( x.bv_val[0] != ',' ) {
4491 return LDAP_INVALID_SYNTAX;
4497 /* should have no characters left... */
4498 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4500 if ( numdquotes == 0 ) {
4501 ber_dupbv_x( &ni, is, ctx );
4506 ni.bv_len = is->bv_len - numdquotes;
4507 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4508 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4509 if ( is->bv_val[src] == '"' ) {
4512 ni.bv_val[dst] = is->bv_val[src];
4514 ni.bv_val[dst] = '\0';
4519 /* need to handle double dquotes here */
4523 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4525 serialNumberAndIssuerSerialValidate(
4530 struct berval sn, i, i_sn;
4532 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4535 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4540 /* validate DN -- doesn't handle double dquote */
4541 rc = dnValidate( NULL, &i );
4543 rc = LDAP_INVALID_SYNTAX;
4546 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4547 slap_sl_free( i.bv_val, NULL );
4551 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4552 in->bv_val, rc, 0 );
4557 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4559 serialNumberAndIssuerSerialPretty(
4565 struct berval sn, i, i_sn, ni = BER_BVNULL;
4569 assert( in != NULL );
4570 assert( out != NULL );
4572 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4575 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4580 rc = dnPretty( syntax, &i, &ni, ctx );
4582 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4583 slap_sl_free( i.bv_val, ctx );
4587 rc = LDAP_INVALID_SYNTAX;
4591 /* make room from sn + "$" */
4592 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4593 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4594 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4596 if ( out->bv_val == NULL ) {
4603 p = lutil_strcopy( p, "{ serialNumber " );
4604 p = lutil_strbvcopy( p, &sn );
4605 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4606 p = lutil_strbvcopy( p, &ni );
4607 p = lutil_strcopy( p, "\" }, serial " );
4608 p = lutil_strbvcopy( p, &i_sn );
4609 p = lutil_strcopy( p, " } } }" );
4611 assert( p == &out->bv_val[out->bv_len] );
4614 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4615 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4617 slap_sl_free( ni.bv_val, ctx );
4622 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4624 * This routine is called by attributeCertificateExactNormalize
4625 * when attributeCertificateExactNormalize receives a search
4626 * string instead of a attribute certificate. This routine
4627 * checks if the search value is valid and then returns the
4631 serialNumberAndIssuerSerialNormalize(
4639 struct berval i, ni = BER_BVNULL,
4640 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4641 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4642 char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4643 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4647 assert( in != NULL );
4648 assert( out != NULL );
4650 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4653 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4658 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4660 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4661 slap_sl_free( i.bv_val, ctx );
4665 rc = LDAP_INVALID_SYNTAX;
4669 /* Convert sn to canonical hex */
4671 sn2.bv_len = sn.bv_len;
4672 if ( sn.bv_len > sizeof( sbuf2 ) ) {
4673 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4675 if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4676 rc = LDAP_INVALID_SYNTAX;
4680 /* Convert i_sn to canonical hex */
4681 i_sn2.bv_val = i_sbuf2;
4682 i_sn2.bv_len = i_sn.bv_len;
4683 if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4684 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4686 if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4687 rc = LDAP_INVALID_SYNTAX;
4692 sn3.bv_len = sizeof(sbuf3);
4693 if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4694 rc = LDAP_INVALID_SYNTAX;
4698 i_sn3.bv_val = i_sbuf3;
4699 i_sn3.bv_len = sizeof(i_sbuf3);
4700 if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4701 rc = LDAP_INVALID_SYNTAX;
4705 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4706 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4707 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4709 if ( out->bv_val == NULL ) {
4717 p = lutil_strcopy( p, "{ serialNumber " );
4718 p = lutil_strbvcopy( p, &sn3 );
4719 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4720 p = lutil_strbvcopy( p, &ni );
4721 p = lutil_strcopy( p, "\" }, serial " );
4722 p = lutil_strbvcopy( p, &i_sn3 );
4723 p = lutil_strcopy( p, " } } }" );
4725 assert( p == &out->bv_val[out->bv_len] );
4728 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4729 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4731 if ( sn2.bv_val != sbuf2 ) {
4732 slap_sl_free( sn2.bv_val, ctx );
4735 if ( i_sn2.bv_val != i_sbuf2 ) {
4736 slap_sl_free( i_sn2.bv_val, ctx );
4739 if ( sn3.bv_val != sbuf3 ) {
4740 slap_sl_free( sn3.bv_val, ctx );
4743 if ( i_sn3.bv_val != i_sbuf3 ) {
4744 slap_sl_free( i_sn3.bv_val, ctx );
4747 slap_sl_free( ni.bv_val, ctx );
4752 /* X.509 PMI attributeCertificateExactNormalize */
4754 attributeCertificateExactNormalize(
4759 struct berval *normalized,
4762 BerElementBuffer berbuf;
4763 BerElement *ber = (BerElement *)&berbuf;
4766 char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4767 struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4768 struct berval issuer_dn = BER_BVNULL, bvdn;
4770 int rc = LDAP_INVALID_SYNTAX;
4772 if ( BER_BVISEMPTY( val ) ) {
4776 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4777 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4780 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4782 ber_init2( ber, val, LBER_USE_DER );
4783 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
4784 tag = ber_skip_tag( ber, &len ); /* Sequence */
4785 tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */
4786 ber_skip_data( ber, len );
4787 tag = ber_skip_tag( ber, &len ); /* Holder Sequence */
4788 ber_skip_data( ber, len );
4791 tag = ber_skip_tag( ber, &len ); /* Sequence */
4792 /* issuerName (GeneralNames sequence; optional)? */
4793 tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */
4794 tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */
4795 tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */
4796 if ( tag != SLAP_X509_GN_DIRECTORYNAME ) {
4797 return LDAP_INVALID_SYNTAX;
4799 tag = ber_peek_tag( ber, &len ); /* sequence of RDN */
4800 len = ber_ptrlen( ber );
4801 bvdn.bv_val = val->bv_val + len;
4802 bvdn.bv_len = val->bv_len - len;
4803 rc = dnX509normalize( &bvdn, &issuer_dn );
4804 if ( rc != LDAP_SUCCESS ) goto done;
4806 tag = ber_skip_tag( ber, &len ); /* sequence of RDN */
4807 ber_skip_data( ber, len );
4808 tag = ber_skip_tag( ber, &len ); /* serial number */
4809 if ( tag != LBER_INTEGER ) {
4810 rc = LDAP_INVALID_SYNTAX;
4813 i_sn.bv_val = (char *)ber->ber_ptr;
4815 i_sn2.bv_val = issuer_serialbuf;
4816 i_sn2.bv_len = sizeof(issuer_serialbuf);
4817 if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4818 rc = LDAP_INVALID_SYNTAX;
4821 ber_skip_data( ber, len );
4823 /* issuerUID (bitstring; optional)? */
4824 /* objectDigestInfo (sequence; optional)? */
4826 tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */
4827 ber_skip_data( ber, len );
4828 tag = ber_skip_tag( ber, &len ); /* serial number */
4829 if ( tag != LBER_INTEGER ) {
4830 rc = LDAP_INVALID_SYNTAX;
4833 sn.bv_val = (char *)ber->ber_ptr;
4835 sn2.bv_val = serialbuf;
4836 sn2.bv_len = sizeof(serialbuf);
4837 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4838 rc = LDAP_INVALID_SYNTAX;
4841 ber_skip_data( ber, len );
4843 normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" )
4844 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4845 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4847 p = normalized->bv_val;
4849 p = lutil_strcopy( p, "{ serialNumber " );
4850 p = lutil_strbvcopy( p, &sn2 );
4851 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4852 p = lutil_strbvcopy( p, &issuer_dn );
4853 p = lutil_strcopy( p, "\" }, serial " );
4854 p = lutil_strbvcopy( p, &i_sn2 );
4855 p = lutil_strcopy( p, " } } }" );
4857 Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4858 normalized->bv_val, NULL, NULL );
4863 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4864 if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4865 if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4878 assert( in != NULL );
4879 assert( !BER_BVISNULL( in ) );
4881 for ( i = 0; i < in->bv_len; i++ ) {
4882 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4883 return LDAP_INVALID_SYNTAX;
4887 return LDAP_SUCCESS;
4890 /* Normalize a SID as used inside a CSN:
4891 * three-digit numeric string */
4898 struct berval *normalized,
4903 assert( val != NULL );
4904 assert( normalized != NULL );
4906 ber_dupbv_x( normalized, val, ctx );
4908 for ( i = 0; i < normalized->bv_len; i++ ) {
4909 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4910 ber_memfree_x( normalized->bv_val, ctx );
4911 BER_BVZERO( normalized );
4912 return LDAP_INVALID_SYNTAX;
4915 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4918 return LDAP_SUCCESS;
4926 assert( in != NULL );
4927 assert( !BER_BVISNULL( in ) );
4929 if ( in->bv_len != 3 ) {
4930 return LDAP_INVALID_SYNTAX;
4933 return hexValidate( NULL, in );
4936 /* Normalize a SID as used inside a CSN:
4937 * three-digit numeric string */
4944 struct berval *normalized,
4947 if ( val->bv_len != 3 ) {
4948 return LDAP_INVALID_SYNTAX;
4951 return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4961 return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4964 /* Normalize a SID as used inside a CSN, either as-is
4965 * (assertion value) or extracted from the CSN
4966 * (attribute value) */
4973 struct berval *normalized,
4981 if ( BER_BVISEMPTY( val ) ) {
4982 return LDAP_INVALID_SYNTAX;
4985 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4986 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
4989 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4991 ptr = ber_bvchr( val, '#' );
4992 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4993 return LDAP_INVALID_SYNTAX;
4996 bv.bv_val = ptr + 1;
4997 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
4999 ptr = ber_bvchr( &bv, '#' );
5000 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5001 return LDAP_INVALID_SYNTAX;
5004 bv.bv_val = ptr + 1;
5005 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5007 ptr = ber_bvchr( &bv, '#' );
5008 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5009 return LDAP_INVALID_SYNTAX;
5012 bv.bv_len = ptr - bv.bv_val;
5014 if ( bv.bv_len == 2 ) {
5015 /* OpenLDAP 2.3 SID */
5017 buf[ 1 ] = bv.bv_val[ 0 ];
5018 buf[ 2 ] = bv.bv_val[ 1 ];
5025 return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5037 assert( in != NULL );
5038 assert( !BER_BVISNULL( in ) );
5040 if ( BER_BVISEMPTY( in ) ) {
5041 return LDAP_INVALID_SYNTAX;
5046 ptr = ber_bvchr( &bv, '#' );
5047 if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5048 return LDAP_INVALID_SYNTAX;
5051 bv.bv_len = ptr - bv.bv_val;
5052 if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5053 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5055 return LDAP_INVALID_SYNTAX;
5058 rc = generalizedTimeValidate( NULL, &bv );
5059 if ( rc != LDAP_SUCCESS ) {
5063 bv.bv_val = ptr + 1;
5064 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5066 ptr = ber_bvchr( &bv, '#' );
5067 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5068 return LDAP_INVALID_SYNTAX;
5071 bv.bv_len = ptr - bv.bv_val;
5072 if ( bv.bv_len != 6 ) {
5073 return LDAP_INVALID_SYNTAX;
5076 rc = hexValidate( NULL, &bv );
5077 if ( rc != LDAP_SUCCESS ) {
5081 bv.bv_val = ptr + 1;
5082 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5084 ptr = ber_bvchr( &bv, '#' );
5085 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5086 return LDAP_INVALID_SYNTAX;
5089 bv.bv_len = ptr - bv.bv_val;
5090 if ( bv.bv_len == 2 ) {
5091 /* tolerate old 2-digit replica-id */
5092 rc = hexValidate( NULL, &bv );
5095 rc = sidValidate( NULL, &bv );
5097 if ( rc != LDAP_SUCCESS ) {
5101 bv.bv_val = ptr + 1;
5102 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5104 if ( bv.bv_len != 6 ) {
5105 return LDAP_INVALID_SYNTAX;
5108 return hexValidate( NULL, &bv );
5111 /* Normalize a CSN in OpenLDAP 2.1 format */
5118 struct berval *normalized,
5121 struct berval gt, cnt, sid, mod;
5123 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5127 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5128 assert( !BER_BVISEMPTY( val ) );
5132 ptr = ber_bvchr( >, '#' );
5133 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5134 return LDAP_INVALID_SYNTAX;
5137 gt.bv_len = ptr - gt.bv_val;
5138 if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5139 return LDAP_INVALID_SYNTAX;
5142 if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5143 return LDAP_INVALID_SYNTAX;
5146 cnt.bv_val = ptr + 1;
5147 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5149 ptr = ber_bvchr( &cnt, '#' );
5150 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5151 return LDAP_INVALID_SYNTAX;
5154 cnt.bv_len = ptr - cnt.bv_val;
5155 if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5156 return LDAP_INVALID_SYNTAX;
5159 if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5160 return LDAP_INVALID_SYNTAX;
5163 cnt.bv_val += STRLENOF( "0x" );
5164 cnt.bv_len -= STRLENOF( "0x" );
5166 sid.bv_val = ptr + 1;
5167 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5169 ptr = ber_bvchr( &sid, '#' );
5170 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5171 return LDAP_INVALID_SYNTAX;
5174 sid.bv_len = ptr - sid.bv_val;
5175 if ( sid.bv_len != STRLENOF( "0" ) ) {
5176 return LDAP_INVALID_SYNTAX;
5179 mod.bv_val = ptr + 1;
5180 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5181 if ( mod.bv_len != STRLENOF( "0000" ) ) {
5182 return LDAP_INVALID_SYNTAX;
5185 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5189 ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5190 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5192 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5194 ptr = lutil_strcopy( ptr, ".000000Z#00" );
5195 ptr = lutil_strbvcopy( ptr, &cnt );
5199 *ptr++ = sid.bv_val[ 0 ];
5203 for ( i = 0; i < mod.bv_len; i++ ) {
5204 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5208 assert( ptr == &bv.bv_val[bv.bv_len] );
5210 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5211 return LDAP_INVALID_SYNTAX;
5214 ber_dupbv_x( normalized, &bv, ctx );
5216 return LDAP_SUCCESS;
5219 /* Normalize a CSN in OpenLDAP 2.3 format */
5226 struct berval *normalized,
5229 struct berval gt, cnt, sid, mod;
5231 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5235 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5236 assert( !BER_BVISEMPTY( val ) );
5240 ptr = ber_bvchr( >, '#' );
5241 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5242 return LDAP_INVALID_SYNTAX;
5245 gt.bv_len = ptr - gt.bv_val;
5246 if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5247 return LDAP_INVALID_SYNTAX;
5250 cnt.bv_val = ptr + 1;
5251 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5253 ptr = ber_bvchr( &cnt, '#' );
5254 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5255 return LDAP_INVALID_SYNTAX;
5258 cnt.bv_len = ptr - cnt.bv_val;
5259 if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5260 return LDAP_INVALID_SYNTAX;
5263 sid.bv_val = ptr + 1;
5264 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5266 ptr = ber_bvchr( &sid, '#' );
5267 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5268 return LDAP_INVALID_SYNTAX;
5271 sid.bv_len = ptr - sid.bv_val;
5272 if ( sid.bv_len != STRLENOF( "00" ) ) {
5273 return LDAP_INVALID_SYNTAX;
5276 mod.bv_val = ptr + 1;
5277 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5278 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5279 return LDAP_INVALID_SYNTAX;
5282 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5286 ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5287 ptr = lutil_strcopy( ptr, ".000000Z#" );
5288 ptr = lutil_strbvcopy( ptr, &cnt );
5291 for ( i = 0; i < sid.bv_len; i++ ) {
5292 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5295 for ( i = 0; i < mod.bv_len; i++ ) {
5296 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5300 assert( ptr == &bv.bv_val[bv.bv_len] );
5301 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5302 return LDAP_INVALID_SYNTAX;
5305 ber_dupbv_x( normalized, &bv, ctx );
5307 return LDAP_SUCCESS;
5310 /* Normalize a CSN */
5317 struct berval *normalized,
5320 struct berval cnt, sid, mod;
5324 assert( val != NULL );
5325 assert( normalized != NULL );
5327 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5329 if ( BER_BVISEMPTY( val ) ) {
5330 return LDAP_INVALID_SYNTAX;
5333 if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5334 /* Openldap <= 2.3 */
5336 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5339 if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5342 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5345 if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5346 return LDAP_INVALID_SYNTAX;
5349 ptr = ber_bvchr( val, '#' );
5350 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5351 return LDAP_INVALID_SYNTAX;
5354 if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5355 return LDAP_INVALID_SYNTAX;
5358 cnt.bv_val = ptr + 1;
5359 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5361 ptr = ber_bvchr( &cnt, '#' );
5362 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5363 return LDAP_INVALID_SYNTAX;
5366 if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5367 return LDAP_INVALID_SYNTAX;
5370 sid.bv_val = ptr + 1;
5371 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5373 ptr = ber_bvchr( &sid, '#' );
5374 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5375 return LDAP_INVALID_SYNTAX;
5378 sid.bv_len = ptr - sid.bv_val;
5379 if ( sid.bv_len != STRLENOF( "000" ) ) {
5380 return LDAP_INVALID_SYNTAX;
5383 mod.bv_val = ptr + 1;
5384 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5386 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5387 return LDAP_INVALID_SYNTAX;
5390 ber_dupbv_x( normalized, val, ctx );
5392 for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5393 i < normalized->bv_len; i++ )
5395 /* assume it's already validated that's all hex digits */
5396 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5399 return LDAP_SUCCESS;
5409 return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5412 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5413 /* slight optimization - does not need the start parameter */
5414 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5419 check_time_syntax (struct berval *val,
5422 struct berval *fraction)
5425 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5426 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
5427 * GeneralizedTime supports leap seconds, UTCTime does not.
5429 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5430 static const int mdays[2][12] = {
5431 /* non-leap years */
5432 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5434 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5437 int part, c, c1, c2, tzoffset, leapyear = 0;
5440 e = p + val->bv_len;
5442 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5443 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5445 for (part = start; part < 7 && p < e; part++) {
5447 if (!ASCII_DIGIT(c1)) {
5452 return LDAP_INVALID_SYNTAX;
5455 if (!ASCII_DIGIT(c)) {
5456 return LDAP_INVALID_SYNTAX;
5458 c += c1 * 10 - '0' * 11;
5459 if ((part | 1) == 3) {
5462 return LDAP_INVALID_SYNTAX;
5465 if (c >= ceiling[part]) {
5466 if (! (c == 60 && part == 6 && start == 0))
5467 return LDAP_INVALID_SYNTAX;
5471 if (part < 5 + start) {
5472 return LDAP_INVALID_SYNTAX;
5474 for (; part < 9; part++) {
5478 /* leapyear check for the Gregorian calendar (year>1581) */
5479 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5483 if (parts[3] >= mdays[leapyear][parts[2]]) {
5484 return LDAP_INVALID_SYNTAX;
5488 fraction->bv_val = p;
5489 fraction->bv_len = 0;
5490 if (p < e && (*p == '.' || *p == ',')) {
5492 while (++p < e && ASCII_DIGIT(*p)) {
5495 if (p - fraction->bv_val == 1) {
5496 return LDAP_INVALID_SYNTAX;
5498 for (end_num = p; end_num[-1] == '0'; --end_num) {
5501 c = end_num - fraction->bv_val;
5502 if (c != 1) fraction->bv_len = c;
5508 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5514 return LDAP_INVALID_SYNTAX;
5520 for (part = 7; part < 9 && p < e; part++) {
5522 if (!ASCII_DIGIT(c1)) {
5527 return LDAP_INVALID_SYNTAX;
5530 if (!ASCII_DIGIT(c2)) {
5531 return LDAP_INVALID_SYNTAX;
5533 parts[part] = c1 * 10 + c2 - '0' * 11;
5534 if (parts[part] >= ceiling[part]) {
5535 return LDAP_INVALID_SYNTAX;
5538 if (part < 8 + start) {
5539 return LDAP_INVALID_SYNTAX;
5542 if (tzoffset == '-') {
5543 /* negative offset to UTC, ie west of Greenwich */
5544 parts[4] += parts[7];
5545 parts[5] += parts[8];
5546 /* offset is just hhmm, no seconds */
5547 for (part = 6; --part >= 0; ) {
5551 c = mdays[leapyear][parts[2]];
5553 if (parts[part] >= c) {
5555 return LDAP_INVALID_SYNTAX;
5560 } else if (part != 5) {
5565 /* positive offset to UTC, ie east of Greenwich */
5566 parts[4] -= parts[7];
5567 parts[5] -= parts[8];
5568 for (part = 6; --part >= 0; ) {
5569 if (parts[part] < 0) {
5571 return LDAP_INVALID_SYNTAX;
5576 /* make first arg to % non-negative */
5577 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5582 } else if (part != 5) {
5589 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5592 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5599 struct berval *normalized )
5603 rc = check_time_syntax(val, 1, parts, NULL);
5604 if (rc != LDAP_SUCCESS) {
5608 normalized->bv_val = ch_malloc( 14 );
5609 if ( normalized->bv_val == NULL ) {
5610 return LBER_ERROR_MEMORY;
5613 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5614 parts[1], parts[2] + 1, parts[3] + 1,
5615 parts[4], parts[5], parts[6] );
5616 normalized->bv_len = 13;
5618 return LDAP_SUCCESS;
5628 return check_time_syntax(in, 1, parts, NULL);
5631 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5634 generalizedTimeValidate(
5639 struct berval fraction;
5640 return check_time_syntax(in, 0, parts, &fraction);
5644 generalizedTimeNormalize(
5649 struct berval *normalized,
5654 struct berval fraction;
5656 rc = check_time_syntax(val, 0, parts, &fraction);
5657 if (rc != LDAP_SUCCESS) {
5661 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5662 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5663 if ( BER_BVISNULL( normalized ) ) {
5664 return LBER_ERROR_MEMORY;
5667 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5668 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5669 parts[4], parts[5], parts[6] );
5670 if ( !BER_BVISEMPTY( &fraction ) ) {
5671 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5672 fraction.bv_val, fraction.bv_len );
5673 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5675 strcpy( normalized->bv_val + len-1, "Z" );
5676 normalized->bv_len = len;
5678 return LDAP_SUCCESS;
5682 generalizedTimeOrderingMatch(
5687 struct berval *value,
5688 void *assertedValue )
5690 struct berval *asserted = (struct berval *) assertedValue;
5691 ber_len_t v_len = value->bv_len;
5692 ber_len_t av_len = asserted->bv_len;
5694 /* ignore trailing 'Z' when comparing */
5695 int match = memcmp( value->bv_val, asserted->bv_val,
5696 (v_len < av_len ? v_len : av_len) - 1 );
5697 if ( match == 0 ) match = v_len - av_len;
5699 /* If used in extensible match filter, match if value < asserted */
5700 if ( flags & SLAP_MR_EXT )
5701 match = (match >= 0);
5704 return LDAP_SUCCESS;
5707 /* Index generation function: Ordered index */
5708 int generalizedTimeIndexer(
5713 struct berval *prefix,
5721 BerValue bvtmp; /* 40 bit index */
5723 struct lutil_timet tt;
5725 bvtmp.bv_len = sizeof(tmp);
5727 for( i=0; values[i].bv_val != NULL; i++ ) {
5728 /* just count them */
5731 /* we should have at least one value at this point */
5734 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5736 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5737 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5738 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5739 /* Use 40 bits of time for key */
5740 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5741 lutil_tm2time( &tm, &tt );
5742 tmp[0] = tt.tt_gsec & 0xff;
5743 tmp[4] = tt.tt_sec & 0xff;
5745 tmp[3] = tt.tt_sec & 0xff;
5747 tmp[2] = tt.tt_sec & 0xff;
5749 tmp[1] = tt.tt_sec & 0xff;
5751 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5755 keys[j].bv_val = NULL;
5760 return LDAP_SUCCESS;
5763 /* Index generation function: Ordered index */
5764 int generalizedTimeFilter(
5769 struct berval *prefix,
5770 void * assertedValue,
5776 BerValue bvtmp; /* 40 bit index */
5777 BerValue *value = (BerValue *) assertedValue;
5779 struct lutil_timet tt;
5781 bvtmp.bv_len = sizeof(tmp);
5783 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5784 /* Use 40 bits of time for key */
5785 if ( value->bv_val && value->bv_len >= 10 &&
5786 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5788 lutil_tm2time( &tm, &tt );
5789 tmp[0] = tt.tt_gsec & 0xff;
5790 tmp[4] = tt.tt_sec & 0xff;
5792 tmp[3] = tt.tt_sec & 0xff;
5794 tmp[2] = tt.tt_sec & 0xff;
5796 tmp[1] = tt.tt_sec & 0xff;
5798 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5799 ber_dupbv_x(keys, &bvtmp, ctx );
5800 keys[1].bv_val = NULL;
5808 return LDAP_SUCCESS;
5812 deliveryMethodValidate(
5814 struct berval *val )
5817 #define LENOF(s) (sizeof(s)-1)
5818 struct berval tmp = *val;
5820 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5821 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5822 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5825 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5827 switch( tmp.bv_val[0] ) {
5830 if(( tmp.bv_len >= LENOF("any") ) &&
5831 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5833 tmp.bv_len -= LENOF("any");
5834 tmp.bv_val += LENOF("any");
5837 return LDAP_INVALID_SYNTAX;
5841 if(( tmp.bv_len >= LENOF("mhs") ) &&
5842 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5844 tmp.bv_len -= LENOF("mhs");
5845 tmp.bv_val += LENOF("mhs");
5848 return LDAP_INVALID_SYNTAX;
5852 if(( tmp.bv_len >= LENOF("physical") ) &&
5853 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5855 tmp.bv_len -= LENOF("physical");
5856 tmp.bv_val += LENOF("physical");
5859 return LDAP_INVALID_SYNTAX;
5862 case 'T': /* telex or teletex or telephone */
5863 if(( tmp.bv_len >= LENOF("telex") ) &&
5864 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5866 tmp.bv_len -= LENOF("telex");
5867 tmp.bv_val += LENOF("telex");
5870 if(( tmp.bv_len >= LENOF("teletex") ) &&
5871 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5873 tmp.bv_len -= LENOF("teletex");
5874 tmp.bv_val += LENOF("teletex");
5877 if(( tmp.bv_len >= LENOF("telephone") ) &&
5878 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5880 tmp.bv_len -= LENOF("telephone");
5881 tmp.bv_val += LENOF("telephone");
5884 return LDAP_INVALID_SYNTAX;
5887 case 'G': /* g3fax or g4fax */
5888 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5889 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5890 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5892 tmp.bv_len -= LENOF("g3fax");
5893 tmp.bv_val += LENOF("g3fax");
5896 return LDAP_INVALID_SYNTAX;
5900 if(( tmp.bv_len >= LENOF("ia5") ) &&
5901 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5903 tmp.bv_len -= LENOF("ia5");
5904 tmp.bv_val += LENOF("ia5");
5907 return LDAP_INVALID_SYNTAX;
5911 if(( tmp.bv_len >= LENOF("videotex") ) &&
5912 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5914 tmp.bv_len -= LENOF("videotex");
5915 tmp.bv_val += LENOF("videotex");
5918 return LDAP_INVALID_SYNTAX;
5921 return LDAP_INVALID_SYNTAX;
5924 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
5926 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5930 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
5934 return LDAP_INVALID_SYNTAX;
5936 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5945 nisNetgroupTripleValidate(
5947 struct berval *val )
5952 if ( BER_BVISEMPTY( val ) ) {
5953 return LDAP_INVALID_SYNTAX;
5956 p = (char *)val->bv_val;
5957 e = p + val->bv_len;
5959 if ( *p != '(' /*')'*/ ) {
5960 return LDAP_INVALID_SYNTAX;
5963 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5967 return LDAP_INVALID_SYNTAX;
5970 } else if ( !AD_CHAR( *p ) ) {
5971 return LDAP_INVALID_SYNTAX;
5975 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5976 return LDAP_INVALID_SYNTAX;
5982 return LDAP_INVALID_SYNTAX;
5985 return LDAP_SUCCESS;
5989 bootParameterValidate(
5991 struct berval *val )
5995 if ( BER_BVISEMPTY( val ) ) {
5996 return LDAP_INVALID_SYNTAX;
5999 p = (char *)val->bv_val;
6000 e = p + val->bv_len;
6003 for (; ( p < e ) && ( *p != '=' ); p++ ) {
6004 if ( !AD_CHAR( *p ) ) {
6005 return LDAP_INVALID_SYNTAX;
6010 return LDAP_INVALID_SYNTAX;
6014 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6015 if ( !AD_CHAR( *p ) ) {
6016 return LDAP_INVALID_SYNTAX;
6021 return LDAP_INVALID_SYNTAX;
6025 for ( p++; p < e; p++ ) {
6026 if ( !SLAP_PRINTABLE( *p ) ) {
6027 return LDAP_INVALID_SYNTAX;
6031 return LDAP_SUCCESS;
6035 firstComponentNormalize(
6040 struct berval *normalized,
6047 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6048 ber_dupbv_x( normalized, val, ctx );
6049 return LDAP_SUCCESS;
6052 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6054 if( ! ( val->bv_val[0] == '(' /*')'*/
6055 && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6056 && ! ( val->bv_val[0] == '{' /*'}'*/
6057 && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6059 return LDAP_INVALID_SYNTAX;
6062 /* trim leading white space */
6064 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6070 /* grab next word */
6071 comp.bv_val = &val->bv_val[len];
6072 len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6073 for( comp.bv_len = 0;
6074 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6080 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6081 rc = numericoidValidate( NULL, &comp );
6082 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6083 rc = integerValidate( NULL, &comp );
6085 rc = LDAP_INVALID_SYNTAX;
6089 if( rc == LDAP_SUCCESS ) {
6090 ber_dupbv_x( normalized, &comp, ctx );
6096 static char *country_gen_syn[] = {
6097 "1.3.6.1.4.1.1466.115.121.1.15", /* Directory String */
6098 "1.3.6.1.4.1.1466.115.121.1.26", /* IA5 String */
6099 "1.3.6.1.4.1.1466.115.121.1.44", /* Printable String */
6103 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6104 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6106 static slap_syntax_defs_rec syntax_defs[] = {
6107 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6108 X_BINARY X_NOT_H_R ")",
6109 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6110 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6111 0, NULL, NULL, NULL},
6112 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6113 0, NULL, NULL, NULL},
6114 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6116 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6117 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6119 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6120 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6121 0, NULL, bitStringValidate, NULL },
6122 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6123 0, NULL, booleanValidate, NULL},
6124 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6125 X_BINARY X_NOT_H_R ")",
6126 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6127 NULL, certificateValidate, NULL},
6128 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6129 X_BINARY X_NOT_H_R ")",
6130 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6131 NULL, certificateListValidate, NULL},
6132 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6133 X_BINARY X_NOT_H_R ")",
6134 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6135 NULL, sequenceValidate, NULL},
6136 {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6137 X_BINARY X_NOT_H_R ")",
6138 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6139 NULL, attributeCertificateValidate, NULL},
6140 #if 0 /* need to go __after__ printableString */
6141 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6142 0, "1.3.6.1.4.1.1466.115.121.1.44",
6143 countryStringValidate, NULL},
6145 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6146 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6147 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6148 0, NULL, rdnValidate, rdnPretty},
6149 #ifdef LDAP_COMP_MATCH
6150 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6151 0, NULL, allComponentsValidate, NULL},
6152 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6153 0, NULL, componentFilterValidate, NULL},
6155 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6156 0, NULL, NULL, NULL},
6157 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6158 0, NULL, deliveryMethodValidate, NULL},
6159 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6160 0, NULL, UTF8StringValidate, NULL},
6161 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6162 0, NULL, NULL, NULL},
6163 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6164 0, NULL, NULL, NULL},
6165 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6166 0, NULL, NULL, NULL},
6167 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6168 0, NULL, NULL, NULL},
6169 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6170 0, NULL, NULL, NULL},
6171 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6172 0, NULL, printablesStringValidate, NULL},
6173 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6174 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6175 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6176 0, NULL, generalizedTimeValidate, NULL},
6177 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6178 0, NULL, NULL, NULL},
6179 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6180 0, NULL, IA5StringValidate, NULL},
6181 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6182 0, NULL, integerValidate, NULL},
6183 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6184 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6185 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6186 0, NULL, NULL, NULL},
6187 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6188 0, NULL, NULL, NULL},
6189 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6190 0, NULL, NULL, NULL},
6191 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6192 0, NULL, NULL, NULL},
6193 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6194 0, NULL, NULL, NULL},
6195 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6196 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6197 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6198 0, NULL, NULL, NULL},
6199 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6200 0, NULL, numericStringValidate, NULL},
6201 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6202 0, NULL, NULL, NULL},
6203 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6204 0, NULL, numericoidValidate, NULL},
6205 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6206 0, NULL, IA5StringValidate, NULL},
6207 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6208 0, NULL, blobValidate, NULL},
6209 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6210 0, NULL, postalAddressValidate, NULL},
6211 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6212 0, NULL, NULL, NULL},
6213 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6214 0, NULL, NULL, NULL},
6215 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6216 0, NULL, printableStringValidate, NULL},
6217 /* moved here because now depends on Directory String, IA5 String
6218 * and Printable String */
6219 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6220 0, country_gen_syn, countryStringValidate, NULL},
6221 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6222 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6223 0, NULL, subtreeSpecificationValidate, NULL},
6224 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6225 X_BINARY X_NOT_H_R ")",
6226 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6227 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6228 0, NULL, printableStringValidate, NULL},
6229 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6230 0, NULL, NULL, NULL},
6231 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6232 0, NULL, printablesStringValidate, NULL},
6233 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6234 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6235 0, NULL, utcTimeValidate, NULL},
6237 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6238 0, NULL, NULL, NULL},
6239 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6240 0, NULL, NULL, NULL},
6241 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6242 0, NULL, NULL, NULL},
6243 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6244 0, NULL, NULL, NULL},
6245 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6246 0, NULL, NULL, NULL},
6248 /* RFC 2307 NIS Syntaxes */
6249 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
6250 0, NULL, nisNetgroupTripleValidate, NULL},
6251 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
6252 0, NULL, bootParameterValidate, NULL},
6254 /* draft-zeilenga-ldap-x509 */
6255 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6256 SLAP_SYNTAX_HIDE, NULL,
6257 serialNumberAndIssuerValidate,
6258 serialNumberAndIssuerPretty},
6259 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6260 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6261 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6262 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6263 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6264 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6265 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6266 SLAP_SYNTAX_HIDE, NULL,
6267 issuerAndThisUpdateValidate,
6268 issuerAndThisUpdatePretty},
6269 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6270 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6271 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6272 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6273 {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6274 SLAP_SYNTAX_HIDE, NULL,
6275 serialNumberAndIssuerSerialValidate,
6276 serialNumberAndIssuerSerialPretty},
6277 {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6278 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6280 #ifdef SLAPD_AUTHPASSWD
6281 /* needs updating */
6282 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6283 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6286 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6287 0, NULL, UUIDValidate, UUIDPretty},
6289 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6290 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6292 {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6293 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6295 /* OpenLDAP Void Syntax */
6296 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6297 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6299 /* FIXME: OID is unused, but not registered yet */
6300 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6301 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6303 {NULL, 0, NULL, NULL, NULL}
6306 char *csnSIDMatchSyntaxes[] = {
6307 "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6310 char *certificateExactMatchSyntaxes[] = {
6311 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6314 char *certificateListExactMatchSyntaxes[] = {
6315 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6318 char *attributeCertificateExactMatchSyntaxes[] = {
6319 attributeCertificateSyntaxOID /* attributeCertificate */,
6323 #ifdef LDAP_COMP_MATCH
6324 char *componentFilterMatchSyntaxes[] = {
6325 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6326 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6327 attributeCertificateSyntaxOID /* attributeCertificate */,
6332 char *directoryStringSyntaxes[] = {
6333 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6336 char *integerFirstComponentMatchSyntaxes[] = {
6337 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6338 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6341 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6342 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6343 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
6344 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6345 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6346 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6347 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6348 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6349 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6354 * Other matching rules in X.520 that we do not use (yet):
6356 * 2.5.13.25 uTCTimeMatch
6357 * 2.5.13.26 uTCTimeOrderingMatch
6358 * 2.5.13.31* directoryStringFirstComponentMatch
6359 * 2.5.13.32* wordMatch
6360 * 2.5.13.33* keywordMatch
6361 * 2.5.13.36+ certificatePairExactMatch
6362 * 2.5.13.37+ certificatePairMatch
6363 * 2.5.13.40+ algorithmIdentifierMatch
6364 * 2.5.13.41* storedPrefixMatch
6365 * 2.5.13.42 attributeCertificateMatch
6366 * 2.5.13.43 readerAndKeyIDMatch
6367 * 2.5.13.44 attributeIntegrityMatch
6369 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6370 * (+) described in draft-zeilenga-ldap-x509
6372 static slap_mrule_defs_rec mrule_defs[] = {
6374 * EQUALITY matching rules must be listed after associated APPROX
6375 * matching rules. So, we list all APPROX matching rules first.
6377 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6378 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6379 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6380 NULL, NULL, directoryStringApproxMatch,
6381 directoryStringApproxIndexer, directoryStringApproxFilter,
6384 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6385 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6386 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6387 NULL, NULL, IA5StringApproxMatch,
6388 IA5StringApproxIndexer, IA5StringApproxFilter,
6392 * Other matching rules
6395 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6396 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6397 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6398 NULL, NULL, octetStringMatch,
6399 octetStringIndexer, octetStringFilter,
6402 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6403 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6404 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6405 NULL, dnNormalize, dnMatch,
6406 octetStringIndexer, octetStringFilter,
6409 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6410 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6411 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6412 NULL, dnNormalize, dnRelativeMatch,
6416 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6417 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6418 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6419 NULL, dnNormalize, dnRelativeMatch,
6423 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6424 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6425 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6426 NULL, dnNormalize, dnRelativeMatch,
6430 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6431 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6432 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6433 NULL, dnNormalize, dnRelativeMatch,
6437 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6438 "SYNTAX 1.2.36.79672281.1.5.0 )",
6439 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6440 NULL, rdnNormalize, rdnMatch,
6441 octetStringIndexer, octetStringFilter,
6444 #ifdef LDAP_COMP_MATCH
6445 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6446 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6447 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6448 NULL, NULL , componentFilterMatch,
6449 octetStringIndexer, octetStringFilter,
6452 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6453 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6454 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6455 NULL, NULL , allComponentsMatch,
6456 octetStringIndexer, octetStringFilter,
6459 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6460 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6461 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6462 NULL, NULL , directoryComponentsMatch,
6463 octetStringIndexer, octetStringFilter,
6467 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6468 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6469 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6470 NULL, UTF8StringNormalize, octetStringMatch,
6471 octetStringIndexer, octetStringFilter,
6472 directoryStringApproxMatchOID },
6474 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6475 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6476 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6477 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6479 "caseIgnoreMatch" },
6481 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6482 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6483 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6484 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6485 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6486 "caseIgnoreMatch" },
6488 {"( 2.5.13.5 NAME 'caseExactMatch' "
6489 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6490 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6491 NULL, UTF8StringNormalize, octetStringMatch,
6492 octetStringIndexer, octetStringFilter,
6493 directoryStringApproxMatchOID },
6495 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6496 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6497 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6498 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6502 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6503 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6504 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6505 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6506 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6509 {"( 2.5.13.8 NAME 'numericStringMatch' "
6510 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6511 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6512 NULL, numericStringNormalize, octetStringMatch,
6513 octetStringIndexer, octetStringFilter,
6516 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6517 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6518 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6519 NULL, numericStringNormalize, octetStringOrderingMatch,
6521 "numericStringMatch" },
6523 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6524 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6525 SLAP_MR_SUBSTR, NULL,
6526 NULL, numericStringNormalize, octetStringSubstringsMatch,
6527 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6528 "numericStringMatch" },
6530 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6531 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6532 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6533 NULL, postalAddressNormalize, octetStringMatch,
6534 octetStringIndexer, octetStringFilter,
6537 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6538 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6539 SLAP_MR_SUBSTR, NULL,
6540 NULL, NULL, NULL, NULL, NULL,
6541 "caseIgnoreListMatch" },
6543 {"( 2.5.13.13 NAME 'booleanMatch' "
6544 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6545 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6546 NULL, NULL, booleanMatch,
6547 octetStringIndexer, octetStringFilter,
6550 {"( 2.5.13.14 NAME 'integerMatch' "
6551 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6552 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6553 NULL, NULL, integerMatch,
6554 integerIndexer, integerFilter,
6557 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6558 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6559 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6560 NULL, NULL, integerMatch,
6564 {"( 2.5.13.16 NAME 'bitStringMatch' "
6565 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6566 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6567 NULL, NULL, octetStringMatch,
6568 octetStringIndexer, octetStringFilter,
6571 {"( 2.5.13.17 NAME 'octetStringMatch' "
6572 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6573 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6574 NULL, NULL, octetStringMatch,
6575 octetStringIndexer, octetStringFilter,
6578 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6579 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6580 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6581 NULL, NULL, octetStringOrderingMatch,
6583 "octetStringMatch" },
6585 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6586 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6587 SLAP_MR_SUBSTR, NULL,
6588 NULL, NULL, octetStringSubstringsMatch,
6589 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6590 "octetStringMatch" },
6592 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6593 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6594 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6596 telephoneNumberNormalize, octetStringMatch,
6597 octetStringIndexer, octetStringFilter,
6600 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6601 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6602 SLAP_MR_SUBSTR, NULL,
6603 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6604 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6605 "telephoneNumberMatch" },
6607 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6608 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6609 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6610 NULL, NULL, NULL, NULL, NULL, NULL },
6612 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6613 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6614 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6615 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6616 uniqueMemberIndexer, uniqueMemberFilter,
6619 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6620 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6621 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6622 NULL, NULL, NULL, NULL, NULL, NULL },
6624 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6625 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6626 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6627 NULL, generalizedTimeNormalize, octetStringMatch,
6628 generalizedTimeIndexer, generalizedTimeFilter,
6631 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6632 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6633 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6634 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6636 "generalizedTimeMatch" },
6638 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6639 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6640 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6641 integerFirstComponentMatchSyntaxes,
6642 NULL, firstComponentNormalize, integerMatch,
6643 octetStringIndexer, octetStringFilter,
6646 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6647 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6648 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6649 objectIdentifierFirstComponentMatchSyntaxes,
6650 NULL, firstComponentNormalize, octetStringMatch,
6651 octetStringIndexer, octetStringFilter,
6654 {"( 2.5.13.34 NAME 'certificateExactMatch' "
6655 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6656 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6657 NULL, certificateExactNormalize, octetStringMatch,
6658 octetStringIndexer, octetStringFilter,
6661 {"( 2.5.13.35 NAME 'certificateMatch' "
6662 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6663 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6664 NULL, NULL, NULL, NULL, NULL,
6667 {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6668 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6669 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6670 NULL, certificateListExactNormalize, octetStringMatch,
6671 octetStringIndexer, octetStringFilter,
6674 {"( 2.5.13.39 NAME 'certificateListMatch' "
6675 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6676 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6677 NULL, NULL, NULL, NULL, NULL,
6680 {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6681 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6682 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6683 NULL, attributeCertificateExactNormalize, octetStringMatch,
6684 octetStringIndexer, octetStringFilter,
6687 {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6688 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6689 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6690 NULL, NULL, NULL, NULL, NULL,
6693 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6694 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6695 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6696 NULL, IA5StringNormalize, octetStringMatch,
6697 octetStringIndexer, octetStringFilter,
6698 IA5StringApproxMatchOID },
6700 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6701 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6702 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6703 NULL, IA5StringNormalize, octetStringMatch,
6704 octetStringIndexer, octetStringFilter,
6705 IA5StringApproxMatchOID },
6707 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6708 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6709 SLAP_MR_SUBSTR, NULL,
6710 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6711 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6712 "caseIgnoreIA5Match" },
6714 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6715 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6716 SLAP_MR_SUBSTR, NULL,
6717 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6718 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6719 "caseExactIA5Match" },
6721 #ifdef SLAPD_AUTHPASSWD
6722 /* needs updating */
6723 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6724 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6725 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6726 NULL, NULL, authPasswordMatch,
6731 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6732 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6734 NULL, NULL, integerBitAndMatch,
6738 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6739 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6741 NULL, NULL, integerBitOrMatch,
6745 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6746 "SYNTAX 1.3.6.1.1.16.1 )",
6747 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6748 NULL, UUIDNormalize, octetStringMatch,
6749 octetStringIndexer, octetStringFilter,
6752 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6753 "SYNTAX 1.3.6.1.1.16.1 )",
6754 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6755 NULL, UUIDNormalize, octetStringOrderingMatch,
6756 octetStringIndexer, octetStringFilter,
6759 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6760 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6761 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6762 NULL, csnNormalize, csnMatch,
6763 csnIndexer, csnFilter,
6766 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6767 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6768 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6769 NULL, csnNormalize, csnOrderingMatch,
6773 {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6774 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6775 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6776 NULL, csnSidNormalize, octetStringMatch,
6777 octetStringIndexer, octetStringFilter,
6780 /* FIXME: OID is unused, but not registered yet */
6781 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6782 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6783 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6784 NULL, authzNormalize, authzMatch,
6788 {NULL, SLAP_MR_NONE, NULL,
6789 NULL, NULL, NULL, NULL, NULL,
6794 slap_schema_init( void )
6799 /* we should only be called once (from main) */
6800 assert( schema_init_done == 0 );
6802 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6803 res = register_syntax( &syntax_defs[i] );
6806 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6807 syntax_defs[i].sd_desc );
6812 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6813 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6814 mrule_defs[i].mrd_compat_syntaxes == NULL )
6817 "slap_schema_init: Ignoring unusable matching rule %s\n",
6818 mrule_defs[i].mrd_desc );
6822 res = register_matching_rule( &mrule_defs[i] );
6826 "slap_schema_init: Error registering matching rule %s\n",
6827 mrule_defs[i].mrd_desc );
6832 res = slap_schema_load();
6833 schema_init_done = 1;
6838 schema_destroy( void )
6847 if( schema_init_done ) {
6848 ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6849 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6850 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );