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';
1856 } else if ( tmp.bv_len ) {
1857 /* string of all spaces is treated as one space */
1858 nvalue.bv_val[0] = ' ';
1859 nvalue.bv_val[1] = '\0';
1861 } /* should never be entered with 0-length val */
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 = c = l;
2337 for ( l = 0; l <= c; 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 if ( !lines[l].bv_len ) {
2343 nlines[l].bv_len = 0;
2344 nlines[l].bv_val = NULL;
2347 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2348 if ( rc != LDAP_SUCCESS ) {
2349 rc = LDAP_INVALID_SYNTAX;
2353 normalized->bv_len += nlines[l].bv_len;
2356 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2358 p = normalized->bv_val;
2359 for ( l = 0; l <= c ; l++ ) {
2360 p = lutil_strbvcopy( p, &nlines[l] );
2365 assert( p == &normalized->bv_val[normalized->bv_len] );
2368 if ( nlines != NULL ) {
2369 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2370 slap_sl_free( nlines[l].bv_val, ctx );
2373 slap_sl_free( lines, ctx );
2384 struct berval val = *in;
2386 if( BER_BVISEMPTY( &val ) ) {
2387 /* disallow empty strings */
2388 return LDAP_INVALID_SYNTAX;
2391 while( OID_LEADCHAR( val.bv_val[0] ) ) {
2392 if ( val.bv_len == 1 ) {
2393 return LDAP_SUCCESS;
2396 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2403 while ( OID_LEADCHAR( val.bv_val[0] )) {
2407 if ( val.bv_len == 0 ) {
2408 return LDAP_SUCCESS;
2412 if( !OID_SEPARATOR( val.bv_val[0] )) {
2420 return LDAP_INVALID_SYNTAX;
2429 struct berval val = *in;
2431 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2433 if ( val.bv_val[0] == '-' ) {
2437 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2438 return LDAP_INVALID_SYNTAX;
2441 if( val.bv_val[0] == '0' ) { /* "-0" */
2442 return LDAP_INVALID_SYNTAX;
2445 } else if ( val.bv_val[0] == '0' ) {
2446 if( val.bv_len > 1 ) { /* "0<more>" */
2447 return LDAP_INVALID_SYNTAX;
2450 return LDAP_SUCCESS;
2453 for( i=0; i < val.bv_len; i++ ) {
2454 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2455 return LDAP_INVALID_SYNTAX;
2459 return LDAP_SUCCESS;
2468 struct berval *value,
2469 void *assertedValue )
2471 struct berval *asserted = (struct berval *) assertedValue;
2472 int vsign = 1, asign = 1; /* default sign = '+' */
2477 if( v.bv_val[0] == '-' ) {
2483 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2486 if( a.bv_val[0] == '-' ) {
2492 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2494 match = vsign - asign;
2496 match = ( v.bv_len != a.bv_len
2497 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2498 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2499 if( vsign < 0 ) match = -match;
2502 /* Ordering rule used in extensible match filter? */
2503 if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2504 match = (match >= 0);
2507 return LDAP_SUCCESS;
2510 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2511 #define INDEX_INTLEN_CHOP 7
2512 #define INDEX_INTLEN_CHOPBYTES 3
2521 /* Integer index key format, designed for memcmp to collate correctly:
2522 * if too large: one's complement sign*<approx exponent=chopped bytes>,
2523 * two's complement value (sign-extended or chopped as needed),
2524 * however in first byte above, the top <number of exponent-bytes + 1>
2525 * bits are the inverse sign and next bit is the sign as delimiter.
2527 ber_slen_t k = index_intlen_strlen;
2529 unsigned signmask = ~0x7fU;
2530 unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2531 struct berval val = *in, itmp = *tmp;
2533 if ( val.bv_val[0] != '-' ) {
2538 /* Chop least significant digits, increase length instead */
2539 if ( val.bv_len > (ber_len_t) k ) {
2540 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2541 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2542 chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
2545 if ( lutil_str2bin( &val, &itmp, ctx )) {
2546 return LDAP_INVALID_SYNTAX;
2549 /* Omit leading sign byte */
2550 if ( itmp.bv_val[0] == neg ) {
2555 k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2557 assert( chop == 0 );
2558 memset( key->bv_val, neg, k ); /* sign-extend */
2559 } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2560 /* Got exponent -k, or no room for 2 sign bits */
2561 lenp = lenbuf + sizeof(lenbuf);
2562 chop = - (ber_len_t) k;
2564 *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2566 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2567 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2568 * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2569 k = (lenbuf + sizeof(lenbuf)) - lenp;
2570 if ( k > (ber_slen_t) index_intlen )
2572 memcpy( key->bv_val, lenp, k );
2573 itmp.bv_len = index_intlen - k;
2575 memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2576 key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2580 /* Index generation function: Ordered index */
2587 struct berval *prefix,
2597 unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2599 /* count the values and find max needed length */
2601 for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2602 if ( vlen < values[i].bv_len )
2603 vlen = values[i].bv_len;
2605 if ( vlen > maxstrlen )
2608 /* we should have at least one value at this point */
2611 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2612 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2613 keys[i].bv_len = index_intlen;
2614 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2617 keys[i].bv_val = NULL;
2619 if ( vlen > sizeof(ibuf) ) {
2620 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2624 itmp.bv_len = sizeof(ibuf);
2626 for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2627 if ( itmp.bv_val != ibuf ) {
2628 itmp.bv_len = values[i].bv_len;
2629 if ( itmp.bv_len <= sizeof(ibuf) )
2630 itmp.bv_len = sizeof(ibuf);
2631 else if ( itmp.bv_len > maxstrlen )
2632 itmp.bv_len = maxstrlen;
2634 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2640 if ( itmp.bv_val != ibuf ) {
2641 slap_sl_free( itmp.bv_val, ctx );
2646 /* Index generation function: Ordered index */
2653 struct berval *prefix,
2654 void * assertedValue,
2661 struct berval *value;
2664 value = (struct berval *) assertedValue;
2666 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2668 keys[0].bv_len = index_intlen;
2669 keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2671 keys[1].bv_val = NULL;
2673 iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2674 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2675 if ( iv.bv_len > (int) sizeof(ibuf) ) {
2676 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2679 iv.bv_len = sizeof(ibuf);
2682 rc = integerVal2Key( value, keys, &iv, ctx );
2686 if ( iv.bv_val != ibuf ) {
2687 slap_sl_free( iv.bv_val, ctx );
2693 countryStringValidate(
2695 struct berval *val )
2697 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2699 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2700 return LDAP_INVALID_SYNTAX;
2702 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2703 return LDAP_INVALID_SYNTAX;
2706 return LDAP_SUCCESS;
2710 printableStringValidate(
2712 struct berval *val )
2716 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2718 for(i=0; i < val->bv_len; i++) {
2719 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2720 return LDAP_INVALID_SYNTAX;
2724 return LDAP_SUCCESS;
2728 printablesStringValidate(
2730 struct berval *val )
2734 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2736 for(i=0,len=0; i < val->bv_len; i++) {
2737 int c = val->bv_val[i];
2741 return LDAP_INVALID_SYNTAX;
2745 } else if ( SLAP_PRINTABLE(c) ) {
2748 return LDAP_INVALID_SYNTAX;
2753 return LDAP_INVALID_SYNTAX;
2756 return LDAP_SUCCESS;
2762 struct berval *val )
2766 for(i=0; i < val->bv_len; i++) {
2767 if( !LDAP_ASCII(val->bv_val[i]) ) {
2768 return LDAP_INVALID_SYNTAX;
2772 return LDAP_SUCCESS;
2781 struct berval *normalized,
2785 int casefold = !SLAP_MR_ASSOCIATED( mr,
2786 slap_schema.si_mr_caseExactIA5Match );
2788 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2792 /* Ignore initial whitespace */
2793 while ( ASCII_SPACE( *p ) ) p++;
2795 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2796 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2797 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2798 normalized->bv_val[normalized->bv_len] = '\0';
2800 p = q = normalized->bv_val;
2803 if ( ASCII_SPACE( *p ) ) {
2806 /* Ignore the extra whitespace */
2807 while ( ASCII_SPACE( *p ) ) {
2811 } else if ( casefold ) {
2812 /* Most IA5 rules require casefolding */
2813 *q++ = TOLOWER(*p); p++;
2820 assert( normalized->bv_val <= p );
2824 * If the string ended in space, backup the pointer one
2825 * position. One is enough because the above loop collapsed
2826 * all whitespace to a single space.
2828 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2830 /* null terminate */
2833 normalized->bv_len = q - normalized->bv_val;
2835 return LDAP_SUCCESS;
2844 if( in->bv_len != 36 ) {
2845 return LDAP_INVALID_SYNTAX;
2848 for( i=0; i<36; i++ ) {
2854 if( in->bv_val[i] != '-' ) {
2855 return LDAP_INVALID_SYNTAX;
2859 if( !ASCII_HEX( in->bv_val[i]) ) {
2860 return LDAP_INVALID_SYNTAX;
2865 return LDAP_SUCCESS;
2876 int rc=LDAP_INVALID_SYNTAX;
2878 assert( in != NULL );
2879 assert( out != NULL );
2881 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2884 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2886 for( i=0; i<36; i++ ) {
2892 if( in->bv_val[i] != '-' ) {
2895 out->bv_val[i] = '-';
2899 if( !ASCII_HEX( in->bv_val[i]) ) {
2902 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2907 out->bv_val[ out->bv_len ] = '\0';
2911 slap_sl_free( out->bv_val, ctx );
2924 struct berval *normalized,
2927 unsigned char octet = '\0';
2931 if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2932 /* NOTE: must be a normalized UUID */
2933 assert( val->bv_len == 16 );
2935 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2936 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2937 val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2938 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2940 return LDAP_SUCCESS;
2943 normalized->bv_len = 16;
2944 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2946 for( i=0, j=0; i<36; i++ ) {
2947 unsigned char nibble;
2948 if( val->bv_val[i] == '-' ) {
2951 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2952 nibble = val->bv_val[i] - '0';
2954 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2955 nibble = val->bv_val[i] - ('a'-10);
2957 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2958 nibble = val->bv_val[i] - ('A'-10);
2961 slap_sl_free( normalized->bv_val, ctx );
2962 BER_BVZERO( normalized );
2963 return LDAP_INVALID_SYNTAX;
2968 normalized->bv_val[j>>1] = octet;
2970 octet = nibble << 4;
2975 normalized->bv_val[normalized->bv_len] = 0;
2976 return LDAP_SUCCESS;
2982 numericStringValidate(
2988 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2990 for(i=0; i < in->bv_len; i++) {
2991 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2992 return LDAP_INVALID_SYNTAX;
2996 return LDAP_SUCCESS;
3000 numericStringNormalize(
3005 struct berval *normalized,
3008 /* removal all spaces */
3011 assert( !BER_BVISEMPTY( val ) );
3013 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3016 q = normalized->bv_val;
3019 if ( ASCII_SPACE( *p ) ) {
3020 /* Ignore whitespace */
3027 /* we should have copied no more than is in val */
3028 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3030 /* null terminate */
3033 normalized->bv_len = q - normalized->bv_val;
3035 if( BER_BVISEMPTY( normalized ) ) {
3036 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3037 normalized->bv_val[0] = ' ';
3038 normalized->bv_val[1] = '\0';
3039 normalized->bv_len = 1;
3042 return LDAP_SUCCESS;
3046 * Integer conversion macros that will use the largest available
3049 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3050 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
3051 # define SLAP_LONG long long
3053 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
3054 # define SLAP_LONG long
3055 #endif /* HAVE_STRTOLL ... */
3063 struct berval *value,
3064 void *assertedValue )
3066 SLAP_LONG lValue, lAssertedValue;
3069 /* safe to assume integers are NUL terminated? */
3070 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3071 if( errno == ERANGE )
3073 return LDAP_CONSTRAINT_VIOLATION;
3076 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3078 if( errno == ERANGE )
3080 return LDAP_CONSTRAINT_VIOLATION;
3083 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3084 return LDAP_SUCCESS;
3093 struct berval *value,
3094 void *assertedValue )
3096 SLAP_LONG lValue, lAssertedValue;
3099 /* safe to assume integers are NUL terminated? */
3100 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3101 if( errno == ERANGE )
3103 return LDAP_CONSTRAINT_VIOLATION;
3106 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3108 if( errno == ERANGE )
3110 return LDAP_CONSTRAINT_VIOLATION;
3113 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3114 return LDAP_SUCCESS;
3118 checkNum( struct berval *in, struct berval *out )
3120 /* parse serialNumber */
3121 ber_len_t neg = 0, extra = 0;
3124 out->bv_val = in->bv_val;
3127 if ( out->bv_val[0] == '-' ) {
3132 if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3133 first = out->bv_val[2];
3136 out->bv_len += STRLENOF("0x");
3137 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3138 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3141 } else if ( out->bv_val[0] == '\'' ) {
3142 first = out->bv_val[1];
3145 out->bv_len += STRLENOF("'");
3147 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3148 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3150 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3153 out->bv_len += STRLENOF("'H");
3156 first = out->bv_val[0];
3157 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3158 if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3162 if ( !( out->bv_len > neg ) ) {
3166 if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3174 serialNumberAndIssuerCheck(
3182 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3184 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3185 /* Parse old format */
3186 is->bv_val = ber_bvchr( in, '$' );
3187 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3189 sn->bv_val = in->bv_val;
3190 sn->bv_len = is->bv_val - in->bv_val;
3193 is->bv_len = in->bv_len - (sn->bv_len + 1);
3195 /* eat leading zeros */
3196 for( n=0; n < (sn->bv_len-1); n++ ) {
3197 if( sn->bv_val[n] != '0' ) break;
3202 for( n=0; n < sn->bv_len; n++ ) {
3203 if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3207 /* Parse GSER format */
3212 HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3216 struct berval x = *in;
3222 /* eat leading spaces */
3223 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3227 /* should be at issuer or serialNumber NamedValue */
3228 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3229 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3232 x.bv_val += STRLENOF("issuer");
3233 x.bv_len -= STRLENOF("issuer");
3235 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3239 /* eat leading spaces */
3240 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3244 /* For backward compatibility, this part is optional */
3245 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3246 x.bv_val += STRLENOF("rdnSequence:");
3247 x.bv_len -= STRLENOF("rdnSequence:");
3250 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3254 is->bv_val = x.bv_val;
3257 for ( ; is->bv_len < x.bv_len; ) {
3258 if ( is->bv_val[is->bv_len] != '"' ) {
3262 if ( is->bv_val[is->bv_len+1] == '"' ) {
3269 x.bv_val += is->bv_len + 1;
3270 x.bv_len -= is->bv_len + 1;
3272 have |= HAVE_ISSUER;
3274 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3276 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3278 /* parse serialNumber */
3279 x.bv_val += STRLENOF("serialNumber");
3280 x.bv_len -= STRLENOF("serialNumber");
3282 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3286 /* eat leading spaces */
3287 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3291 if ( checkNum( &x, sn ) ) {
3292 return LDAP_INVALID_SYNTAX;
3295 x.bv_val += sn->bv_len;
3296 x.bv_len -= sn->bv_len;
3301 return LDAP_INVALID_SYNTAX;
3304 /* eat leading spaces */
3305 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3309 if ( have == HAVE_ALL ) {
3313 if ( x.bv_val[0] != ',' ) {
3314 return LDAP_INVALID_SYNTAX;
3321 /* should have no characters left... */
3322 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3324 if ( numdquotes == 0 ) {
3325 ber_dupbv_x( &ni, is, ctx );
3330 ni.bv_len = is->bv_len - numdquotes;
3331 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3332 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3333 if ( is->bv_val[src] == '"' ) {
3336 ni.bv_val[dst] = is->bv_val[src];
3338 ni.bv_val[dst] = '\0';
3348 serialNumberAndIssuerValidate(
3353 struct berval sn, i;
3355 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3358 rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3363 /* validate DN -- doesn't handle double dquote */
3364 rc = dnValidate( NULL, &i );
3366 rc = LDAP_INVALID_SYNTAX;
3369 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3370 slap_sl_free( i.bv_val, NULL );
3373 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3374 in->bv_val, rc, 0 );
3381 serialNumberAndIssuerPretty(
3388 struct berval sn, i, ni = BER_BVNULL;
3391 assert( in != NULL );
3392 assert( out != NULL );
3396 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3399 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3404 rc = dnPretty( syntax, &i, &ni, ctx );
3406 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3407 slap_sl_free( i.bv_val, ctx );
3411 rc = LDAP_INVALID_SYNTAX;
3415 /* make room from sn + "$" */
3416 out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3417 + sn.bv_len + ni.bv_len;
3418 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3420 if ( out->bv_val == NULL ) {
3427 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3428 p = lutil_strbvcopy( p, &sn );
3429 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3430 p = lutil_strbvcopy( p, &ni );
3431 p = lutil_strcopy( p, /*{*/ "\" }" );
3433 assert( p == &out->bv_val[out->bv_len] );
3436 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3437 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3439 slap_sl_free( ni.bv_val, ctx );
3441 return LDAP_SUCCESS;
3451 /* Use hex format. '123456789abcdef'H */
3452 unsigned char *ptr, zero = '\0';
3455 ber_len_t i, len, nlen;
3457 assert( in != NULL );
3458 assert( !BER_BVISNULL( in ) );
3459 assert( out != NULL );
3460 assert( !BER_BVISNULL( out ) );
3462 ptr = (unsigned char *)in->bv_val;
3465 /* Check for minimal encodings */
3467 if ( ptr[0] & 0x80 ) {
3468 if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3472 } else if ( ptr[0] == 0 ) {
3473 if ( !( ptr[1] & 0x80 ) ) {
3480 } else if ( len == 0 ) {
3481 /* FIXME: this should not be possible,
3482 * since a value of zero would have length 1 */
3487 first = !( ptr[0] & 0xf0U );
3488 nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3489 if ( nlen >= out->bv_len ) {
3490 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3496 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3500 for ( ; i < len; i++ ) {
3501 sprintf( sptr, "%02X", ptr[i] );
3508 assert( sptr == &out->bv_val[nlen] );
3515 #define SLAP_SN_BUFLEN (64)
3518 * This routine is called by certificateExactNormalize when
3519 * certificateExactNormalize receives a search string instead of
3520 * a certificate. This routine checks if the search value is valid
3521 * and then returns the normalized value
3524 serialNumberAndIssuerNormalize(
3532 struct berval sn, sn2, sn3, i, ni;
3533 char sbuf2[SLAP_SN_BUFLEN];
3534 char sbuf3[SLAP_SN_BUFLEN];
3538 assert( in != NULL );
3539 assert( out != NULL );
3541 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3544 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3549 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3551 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3552 slap_sl_free( i.bv_val, ctx );
3556 return LDAP_INVALID_SYNTAX;
3559 /* Convert sn to canonical hex */
3561 if ( sn.bv_len > sizeof( sbuf2 ) ) {
3562 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3564 sn2.bv_len = sn.bv_len;
3566 sn3.bv_len = sizeof(sbuf3);
3567 if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
3568 rc = LDAP_INVALID_SYNTAX;
3572 out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3573 + sn3.bv_len + ni.bv_len;
3574 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3575 if ( out->bv_val == NULL ) {
3583 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3584 p = lutil_strbvcopy( p, &sn3 );
3585 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3586 p = lutil_strbvcopy( p, &ni );
3587 p = lutil_strcopy( p, /*{*/ "\" }" );
3589 assert( p == &out->bv_val[out->bv_len] );
3592 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3593 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3595 if ( sn2.bv_val != sbuf2 ) {
3596 slap_sl_free( sn2.bv_val, ctx );
3599 if ( sn3.bv_val != sbuf3 ) {
3600 slap_sl_free( sn3.bv_val, ctx );
3603 slap_sl_free( ni.bv_val, ctx );
3609 certificateExactNormalize(
3614 struct berval *normalized,
3617 BerElementBuffer berbuf;
3618 BerElement *ber = (BerElement *)&berbuf;
3622 char serialbuf2[SLAP_SN_BUFLEN];
3623 struct berval sn, sn2 = BER_BVNULL;
3624 struct berval issuer_dn = BER_BVNULL, bvdn;
3626 int rc = LDAP_INVALID_SYNTAX;
3628 assert( val != NULL );
3630 Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3631 val->bv_val, val->bv_len, 0 );
3633 if ( BER_BVISEMPTY( val ) ) goto done;
3635 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3636 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3639 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3641 ber_init2( ber, val, LBER_USE_DER );
3642 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3643 tag = ber_skip_tag( ber, &len ); /* Sequence */
3644 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3645 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3646 tag = ber_skip_tag( ber, &len );
3647 tag = ber_get_int( ber, &i ); /* version */
3650 /* NOTE: move the test here from certificateValidate,
3651 * so that we can validate certs with serial longer
3652 * than sizeof(ber_int_t) */
3653 tag = ber_skip_tag( ber, &len ); /* serial */
3655 sn.bv_val = (char *)ber->ber_ptr;
3656 sn2.bv_val = serialbuf2;
3657 sn2.bv_len = sizeof(serialbuf2);
3658 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3659 rc = LDAP_INVALID_SYNTAX;
3662 ber_skip_data( ber, len );
3664 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3665 ber_skip_data( ber, len );
3666 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3667 len = ber_ptrlen( ber );
3668 bvdn.bv_val = val->bv_val + len;
3669 bvdn.bv_len = val->bv_len - len;
3671 rc = dnX509normalize( &bvdn, &issuer_dn );
3672 if ( rc != LDAP_SUCCESS ) goto done;
3674 normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3675 + sn2.bv_len + issuer_dn.bv_len;
3676 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3678 p = normalized->bv_val;
3680 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3681 p = lutil_strbvcopy( p, &sn2 );
3682 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3683 p = lutil_strbvcopy( p, &issuer_dn );
3684 p = lutil_strcopy( p, /*{*/ "\" }" );
3689 Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3690 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3692 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3693 if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3698 /* X.509 PKI certificateList stuff */
3700 checkTime( struct berval *in, struct berval *out )
3704 char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3707 assert( in != NULL );
3708 assert( !BER_BVISNULL( in ) );
3709 assert( !BER_BVISEMPTY( in ) );
3711 if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3715 if ( out != NULL ) {
3716 assert( !BER_BVISNULL( out ) );
3717 assert( out->bv_len >= sizeof( buf ) );
3718 bv.bv_val = out->bv_val;
3724 for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3725 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3728 if ( in->bv_val[i] != 'Z' ) {
3733 if ( i != in->bv_len ) {
3737 if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3738 lutil_strncopy( bv.bv_val, in->bv_val, i );
3741 } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3742 char *p = bv.bv_val;
3743 if ( in->bv_val[0] < '7' ) {
3744 p = lutil_strcopy( p, "20" );
3747 p = lutil_strcopy( p, "19" );
3749 lutil_strncopy( p, in->bv_val, i );
3756 rc = generalizedTimeValidate( NULL, &bv );
3757 if ( rc == LDAP_SUCCESS && out != NULL ) {
3758 if ( out->bv_len > bv.bv_len ) {
3759 out->bv_val[ bv.bv_len ] = '\0';
3761 out->bv_len = bv.bv_len;
3764 return rc != LDAP_SUCCESS;
3768 issuerAndThisUpdateCheck(
3775 struct berval x = *in;
3776 struct berval ni = BER_BVNULL;
3777 /* Parse GSER format */
3781 HAVE_THISUPDATE = 0x2,
3782 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3786 if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3788 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3789 return LDAP_INVALID_SYNTAX;
3793 x.bv_len -= STRLENOF("{}");
3796 /* eat leading spaces */
3797 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3801 /* should be at issuer or thisUpdate */
3802 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3803 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3806 x.bv_val += STRLENOF("issuer");
3807 x.bv_len -= STRLENOF("issuer");
3809 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3813 /* eat leading spaces */
3814 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3818 /* For backward compatibility, this part is optional */
3819 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3820 return LDAP_INVALID_SYNTAX;
3822 x.bv_val += STRLENOF("rdnSequence:");
3823 x.bv_len -= STRLENOF("rdnSequence:");
3825 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3829 is->bv_val = x.bv_val;
3832 for ( ; is->bv_len < x.bv_len; ) {
3833 if ( is->bv_val[is->bv_len] != '"' ) {
3837 if ( is->bv_val[is->bv_len+1] == '"' ) {
3844 x.bv_val += is->bv_len + 1;
3845 x.bv_len -= is->bv_len + 1;
3847 have |= HAVE_ISSUER;
3849 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3851 if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3853 /* parse thisUpdate */
3854 x.bv_val += STRLENOF("thisUpdate");
3855 x.bv_len -= STRLENOF("thisUpdate");
3857 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3861 /* eat leading spaces */
3862 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3866 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3870 tu->bv_val = x.bv_val;
3873 for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3874 if ( tu->bv_val[tu->bv_len] == '"' ) {
3878 x.bv_val += tu->bv_len + 1;
3879 x.bv_len -= tu->bv_len + 1;
3881 have |= HAVE_THISUPDATE;
3884 return LDAP_INVALID_SYNTAX;
3887 /* eat leading spaces */
3888 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3892 if ( have == HAVE_ALL ) {
3896 if ( x.bv_val[0] != ',' ) {
3897 return LDAP_INVALID_SYNTAX;
3904 /* should have no characters left... */
3905 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3907 if ( numdquotes == 0 ) {
3908 ber_dupbv_x( &ni, is, ctx );
3913 ni.bv_len = is->bv_len - numdquotes;
3914 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3915 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3916 if ( is->bv_val[src] == '"' ) {
3919 ni.bv_val[dst] = is->bv_val[src];
3921 ni.bv_val[dst] = '\0';
3930 issuerAndThisUpdateValidate(
3935 struct berval i, tu;
3937 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3940 rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3945 /* validate DN -- doesn't handle double dquote */
3946 rc = dnValidate( NULL, &i );
3948 rc = LDAP_INVALID_SYNTAX;
3950 } else if ( checkTime( &tu, NULL ) ) {
3951 rc = LDAP_INVALID_SYNTAX;
3954 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3955 slap_sl_free( i.bv_val, NULL );
3958 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3959 in->bv_val, rc, 0 );
3966 issuerAndThisUpdatePretty(
3973 struct berval i, tu, ni = BER_BVNULL;
3976 assert( in != NULL );
3977 assert( out != NULL );
3981 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3984 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3989 rc = dnPretty( syntax, &i, &ni, ctx );
3991 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3992 slap_sl_free( i.bv_val, ctx );
3995 if ( rc || checkTime( &tu, NULL ) ) {
3996 rc = LDAP_INVALID_SYNTAX;
4001 out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
4002 + ni.bv_len + tu.bv_len;
4003 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4005 if ( out->bv_val == NULL ) {
4012 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4013 p = lutil_strbvcopy( p, &ni );
4014 p = lutil_strcopy( p, "\", thisUpdate \"" );
4015 p = lutil_strbvcopy( p, &tu );
4016 p = lutil_strcopy( p, /*{*/ "\" }" );
4018 assert( p == &out->bv_val[out->bv_len] );
4021 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4022 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4024 slap_sl_free( ni.bv_val, ctx );
4030 issuerAndThisUpdateNormalize(
4038 struct berval i, ni, tu, tu2;
4039 char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4043 assert( in != NULL );
4044 assert( out != NULL );
4046 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4049 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4054 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4056 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4057 slap_sl_free( i.bv_val, ctx );
4061 tu2.bv_len = sizeof( sbuf );
4062 if ( rc || checkTime( &tu, &tu2 ) ) {
4063 return LDAP_INVALID_SYNTAX;
4066 out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4067 + ni.bv_len + tu2.bv_len;
4068 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4070 if ( out->bv_val == NULL ) {
4078 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4079 p = lutil_strbvcopy( p, &ni );
4080 p = lutil_strcopy( p, "\", thisUpdate \"" );
4081 p = lutil_strbvcopy( p, &tu2 );
4082 p = lutil_strcopy( p, /*{*/ "\" }" );
4084 assert( p == &out->bv_val[out->bv_len] );
4087 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4088 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4090 slap_sl_free( ni.bv_val, ctx );
4096 certificateListExactNormalize(
4101 struct berval *normalized,
4104 BerElementBuffer berbuf;
4105 BerElement *ber = (BerElement *)&berbuf;
4109 struct berval issuer_dn = BER_BVNULL, bvdn,
4111 char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4112 int rc = LDAP_INVALID_SYNTAX;
4114 assert( val != NULL );
4116 Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4117 val->bv_val, val->bv_len, 0 );
4119 if ( BER_BVISEMPTY( val ) ) goto done;
4121 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4122 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4125 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4127 ber_init2( ber, val, LBER_USE_DER );
4128 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
4129 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4130 tag = ber_skip_tag( ber, &len ); /* Sequence */
4131 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4132 tag = ber_peek_tag( ber, &len );
4133 /* Optional version */
4134 if ( tag == LBER_INTEGER ) {
4135 tag = ber_get_int( ber, &version );
4136 assert( tag == LBER_INTEGER );
4137 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4139 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
4140 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4141 ber_skip_data( ber, len );
4143 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
4144 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4145 len = ber_ptrlen( ber );
4146 bvdn.bv_val = val->bv_val + len;
4147 bvdn.bv_len = val->bv_len - len;
4148 tag = ber_skip_tag( ber, &len );
4149 ber_skip_data( ber, len );
4151 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
4152 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4153 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4154 bvtu.bv_val = (char *)ber->ber_ptr;
4157 rc = dnX509normalize( &bvdn, &issuer_dn );
4158 if ( rc != LDAP_SUCCESS ) goto done;
4160 thisUpdate.bv_val = tubuf;
4161 thisUpdate.bv_len = sizeof(tubuf);
4162 if ( checkTime( &bvtu, &thisUpdate ) ) {
4163 rc = LDAP_INVALID_SYNTAX;
4167 normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4168 + issuer_dn.bv_len + thisUpdate.bv_len;
4169 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4171 p = normalized->bv_val;
4173 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4174 p = lutil_strbvcopy( p, &issuer_dn );
4175 p = lutil_strcopy( p, "\", thisUpdate \"" );
4176 p = lutil_strbvcopy( p, &thisUpdate );
4177 p = lutil_strcopy( p, /*{*/ "\" }" );
4182 Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4183 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4185 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4190 /* X.509 PMI serialNumberAndIssuerSerialCheck
4192 AttributeCertificateExactAssertion ::= SEQUENCE {
4193 serialNumber CertificateSerialNumber,
4194 issuer AttCertIssuer }
4196 CertificateSerialNumber ::= INTEGER
4198 AttCertIssuer ::= [0] SEQUENCE {
4199 issuerName GeneralNames OPTIONAL,
4200 baseCertificateID [0] IssuerSerial OPTIONAL,
4201 objectDigestInfo [1] ObjectDigestInfo OPTIONAL }
4202 -- At least one component shall be present
4204 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4206 GeneralName ::= CHOICE {
4207 otherName [0] INSTANCE OF OTHER-NAME,
4208 rfc822Name [1] IA5String,
4209 dNSName [2] IA5String,
4210 x400Address [3] ORAddress,
4211 directoryName [4] Name,
4212 ediPartyName [5] EDIPartyName,
4213 uniformResourceIdentifier [6] IA5String,
4214 iPAddress [7] OCTET STRING,
4215 registeredID [8] OBJECT IDENTIFIER }
4217 IssuerSerial ::= SEQUENCE {
4218 issuer GeneralNames,
4219 serial CertificateSerialNumber,
4220 issuerUID UniqueIdentifier OPTIONAL }
4222 ObjectDigestInfo ::= SEQUENCE {
4223 digestedObjectType ENUMERATED {
4226 otherObjectTypes (2) },
4227 otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
4228 digestAlgorithm AlgorithmIdentifier,
4229 objectDigest BIT STRING }
4231 * The way I interpret it, an assertion should look like
4233 { serialNumber 'dd'H,
4234 issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4235 baseCertificateID { serial '1d'H,
4236 issuer { directoryName:rdnSequence:"cn=zzz" },
4237 issuerUID <value> -- optional
4239 objectDigestInfo { ... } -- optional
4243 * with issuerName, baseCertificateID and objectDigestInfo optional,
4244 * at least one present; the way it's currently implemented, it is
4246 { serialNumber 'dd'H,
4247 issuer { baseCertificateID { serial '1d'H,
4248 issuer { directoryName:rdnSequence:"cn=zzz" }
4253 * with all the above parts mandatory.
4256 serialNumberAndIssuerSerialCheck(
4260 struct berval *i_sn, /* contain serial of baseCertificateID */
4263 /* Parse GSER format */
4268 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4269 } have = HAVE_NONE, have2 = HAVE_NONE;
4271 struct berval x = *in;
4274 if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4277 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4284 /* eat leading spaces */
4285 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4289 /* should be at issuer or serialNumber NamedValue */
4290 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4291 if ( have & HAVE_ISSUER ) {
4292 return LDAP_INVALID_SYNTAX;
4295 /* parse IssuerSerial */
4296 x.bv_val += STRLENOF("issuer");
4297 x.bv_len -= STRLENOF("issuer");
4299 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4303 /* eat leading spaces */
4304 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4308 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4312 /* eat leading spaces */
4313 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4317 if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4318 return LDAP_INVALID_SYNTAX;
4320 x.bv_val += STRLENOF("baseCertificateID ");
4321 x.bv_len -= STRLENOF("baseCertificateID ");
4323 /* eat leading spaces */
4324 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4328 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4333 /* eat leading spaces */
4334 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4338 /* parse issuer of baseCertificateID */
4339 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4340 if ( have2 & HAVE_ISSUER ) {
4341 return LDAP_INVALID_SYNTAX;
4344 x.bv_val += STRLENOF("issuer ");
4345 x.bv_len -= STRLENOF("issuer ");
4347 /* eat leading spaces */
4348 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4352 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4356 /* eat leading spaces */
4357 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4361 if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4362 return LDAP_INVALID_SYNTAX;
4364 x.bv_val += STRLENOF("directoryName:rdnSequence:");
4365 x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4367 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4371 is->bv_val = x.bv_val;
4374 for ( ; is->bv_len < x.bv_len; ) {
4375 if ( is->bv_val[is->bv_len] != '"' ) {
4379 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4386 x.bv_val += is->bv_len + 1;
4387 x.bv_len -= is->bv_len + 1;
4389 /* eat leading spaces */
4390 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4394 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4398 have2 |= HAVE_ISSUER;
4400 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4401 if ( have2 & HAVE_SN ) {
4402 return LDAP_INVALID_SYNTAX;
4405 x.bv_val += STRLENOF("serial ");
4406 x.bv_len -= STRLENOF("serial ");
4408 /* eat leading spaces */
4409 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4413 if ( checkNum( &x, i_sn ) ) {
4414 return LDAP_INVALID_SYNTAX;
4417 x.bv_val += i_sn->bv_len;
4418 x.bv_len -= i_sn->bv_len;
4423 return LDAP_INVALID_SYNTAX;
4426 /* eat leading spaces */
4427 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4431 if ( have2 == HAVE_ALL ) {
4435 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4440 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4444 /* eat leading spaces */
4445 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4449 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4453 have |= HAVE_ISSUER;
4455 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4456 if ( have & HAVE_SN ) {
4457 return LDAP_INVALID_SYNTAX;
4460 /* parse serialNumber */
4461 x.bv_val += STRLENOF("serialNumber");
4462 x.bv_len -= STRLENOF("serialNumber");
4464 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4468 /* eat leading spaces */
4469 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4473 if ( checkNum( &x, sn ) ) {
4474 return LDAP_INVALID_SYNTAX;
4477 x.bv_val += sn->bv_len;
4478 x.bv_len -= sn->bv_len;
4483 return LDAP_INVALID_SYNTAX;
4487 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4491 if ( have == HAVE_ALL ) {
4495 if ( x.bv_val[0] != ',' ) {
4496 return LDAP_INVALID_SYNTAX;
4502 /* should have no characters left... */
4503 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4505 if ( numdquotes == 0 ) {
4506 ber_dupbv_x( &ni, is, ctx );
4511 ni.bv_len = is->bv_len - numdquotes;
4512 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4513 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4514 if ( is->bv_val[src] == '"' ) {
4517 ni.bv_val[dst] = is->bv_val[src];
4519 ni.bv_val[dst] = '\0';
4524 /* need to handle double dquotes here */
4528 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4530 serialNumberAndIssuerSerialValidate(
4535 struct berval sn, i, i_sn;
4537 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4540 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4545 /* validate DN -- doesn't handle double dquote */
4546 rc = dnValidate( NULL, &i );
4548 rc = LDAP_INVALID_SYNTAX;
4551 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4552 slap_sl_free( i.bv_val, NULL );
4556 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4557 in->bv_val, rc, 0 );
4562 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4564 serialNumberAndIssuerSerialPretty(
4570 struct berval sn, i, i_sn, ni = BER_BVNULL;
4574 assert( in != NULL );
4575 assert( out != NULL );
4577 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4580 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4585 rc = dnPretty( syntax, &i, &ni, ctx );
4587 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4588 slap_sl_free( i.bv_val, ctx );
4592 rc = LDAP_INVALID_SYNTAX;
4596 /* make room from sn + "$" */
4597 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4598 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4599 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4601 if ( out->bv_val == NULL ) {
4608 p = lutil_strcopy( p, "{ serialNumber " );
4609 p = lutil_strbvcopy( p, &sn );
4610 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4611 p = lutil_strbvcopy( p, &ni );
4612 p = lutil_strcopy( p, "\" }, serial " );
4613 p = lutil_strbvcopy( p, &i_sn );
4614 p = lutil_strcopy( p, " } } }" );
4616 assert( p == &out->bv_val[out->bv_len] );
4619 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4620 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4622 slap_sl_free( ni.bv_val, ctx );
4627 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4629 * This routine is called by attributeCertificateExactNormalize
4630 * when attributeCertificateExactNormalize receives a search
4631 * string instead of a attribute certificate. This routine
4632 * checks if the search value is valid and then returns the
4636 serialNumberAndIssuerSerialNormalize(
4644 struct berval i, ni = BER_BVNULL,
4645 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4646 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4647 char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4648 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4652 assert( in != NULL );
4653 assert( out != NULL );
4655 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4658 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4663 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4665 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4666 slap_sl_free( i.bv_val, ctx );
4670 rc = LDAP_INVALID_SYNTAX;
4674 /* Convert sn to canonical hex */
4676 sn2.bv_len = sn.bv_len;
4677 if ( sn.bv_len > sizeof( sbuf2 ) ) {
4678 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4680 if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4681 rc = LDAP_INVALID_SYNTAX;
4685 /* Convert i_sn to canonical hex */
4686 i_sn2.bv_val = i_sbuf2;
4687 i_sn2.bv_len = i_sn.bv_len;
4688 if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4689 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4691 if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4692 rc = LDAP_INVALID_SYNTAX;
4697 sn3.bv_len = sizeof(sbuf3);
4698 if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4699 rc = LDAP_INVALID_SYNTAX;
4703 i_sn3.bv_val = i_sbuf3;
4704 i_sn3.bv_len = sizeof(i_sbuf3);
4705 if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4706 rc = LDAP_INVALID_SYNTAX;
4710 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4711 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4712 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4714 if ( out->bv_val == NULL ) {
4722 p = lutil_strcopy( p, "{ serialNumber " );
4723 p = lutil_strbvcopy( p, &sn3 );
4724 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4725 p = lutil_strbvcopy( p, &ni );
4726 p = lutil_strcopy( p, "\" }, serial " );
4727 p = lutil_strbvcopy( p, &i_sn3 );
4728 p = lutil_strcopy( p, " } } }" );
4730 assert( p == &out->bv_val[out->bv_len] );
4733 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4734 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4736 if ( sn2.bv_val != sbuf2 ) {
4737 slap_sl_free( sn2.bv_val, ctx );
4740 if ( i_sn2.bv_val != i_sbuf2 ) {
4741 slap_sl_free( i_sn2.bv_val, ctx );
4744 if ( sn3.bv_val != sbuf3 ) {
4745 slap_sl_free( sn3.bv_val, ctx );
4748 if ( i_sn3.bv_val != i_sbuf3 ) {
4749 slap_sl_free( i_sn3.bv_val, ctx );
4752 slap_sl_free( ni.bv_val, ctx );
4757 /* X.509 PMI attributeCertificateExactNormalize */
4759 attributeCertificateExactNormalize(
4764 struct berval *normalized,
4767 BerElementBuffer berbuf;
4768 BerElement *ber = (BerElement *)&berbuf;
4771 char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4772 struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4773 struct berval issuer_dn = BER_BVNULL, bvdn;
4775 int rc = LDAP_INVALID_SYNTAX;
4777 if ( BER_BVISEMPTY( val ) ) {
4781 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4782 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4785 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4787 ber_init2( ber, val, LBER_USE_DER );
4788 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
4789 tag = ber_skip_tag( ber, &len ); /* Sequence */
4790 tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */
4791 ber_skip_data( ber, len );
4792 tag = ber_skip_tag( ber, &len ); /* Holder Sequence */
4793 ber_skip_data( ber, len );
4796 tag = ber_skip_tag( ber, &len ); /* Sequence */
4797 /* issuerName (GeneralNames sequence; optional)? */
4798 tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */
4799 tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */
4800 tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */
4801 if ( tag != SLAP_X509_GN_DIRECTORYNAME ) {
4802 return LDAP_INVALID_SYNTAX;
4804 tag = ber_peek_tag( ber, &len ); /* sequence of RDN */
4805 len = ber_ptrlen( ber );
4806 bvdn.bv_val = val->bv_val + len;
4807 bvdn.bv_len = val->bv_len - len;
4808 rc = dnX509normalize( &bvdn, &issuer_dn );
4809 if ( rc != LDAP_SUCCESS ) goto done;
4811 tag = ber_skip_tag( ber, &len ); /* sequence of RDN */
4812 ber_skip_data( ber, len );
4813 tag = ber_skip_tag( ber, &len ); /* serial number */
4814 if ( tag != LBER_INTEGER ) {
4815 rc = LDAP_INVALID_SYNTAX;
4818 i_sn.bv_val = (char *)ber->ber_ptr;
4820 i_sn2.bv_val = issuer_serialbuf;
4821 i_sn2.bv_len = sizeof(issuer_serialbuf);
4822 if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4823 rc = LDAP_INVALID_SYNTAX;
4826 ber_skip_data( ber, len );
4828 /* issuerUID (bitstring; optional)? */
4829 /* objectDigestInfo (sequence; optional)? */
4831 tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */
4832 ber_skip_data( ber, len );
4833 tag = ber_skip_tag( ber, &len ); /* serial number */
4834 if ( tag != LBER_INTEGER ) {
4835 rc = LDAP_INVALID_SYNTAX;
4838 sn.bv_val = (char *)ber->ber_ptr;
4840 sn2.bv_val = serialbuf;
4841 sn2.bv_len = sizeof(serialbuf);
4842 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4843 rc = LDAP_INVALID_SYNTAX;
4846 ber_skip_data( ber, len );
4848 normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" )
4849 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4850 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4852 p = normalized->bv_val;
4854 p = lutil_strcopy( p, "{ serialNumber " );
4855 p = lutil_strbvcopy( p, &sn2 );
4856 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4857 p = lutil_strbvcopy( p, &issuer_dn );
4858 p = lutil_strcopy( p, "\" }, serial " );
4859 p = lutil_strbvcopy( p, &i_sn2 );
4860 p = lutil_strcopy( p, " } } }" );
4862 Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4863 normalized->bv_val, NULL, NULL );
4868 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4869 if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4870 if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4883 assert( in != NULL );
4884 assert( !BER_BVISNULL( in ) );
4886 for ( i = 0; i < in->bv_len; i++ ) {
4887 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4888 return LDAP_INVALID_SYNTAX;
4892 return LDAP_SUCCESS;
4895 /* Normalize a SID as used inside a CSN:
4896 * three-digit numeric string */
4903 struct berval *normalized,
4908 assert( val != NULL );
4909 assert( normalized != NULL );
4911 ber_dupbv_x( normalized, val, ctx );
4913 for ( i = 0; i < normalized->bv_len; i++ ) {
4914 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4915 ber_memfree_x( normalized->bv_val, ctx );
4916 BER_BVZERO( normalized );
4917 return LDAP_INVALID_SYNTAX;
4920 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4923 return LDAP_SUCCESS;
4931 assert( in != NULL );
4932 assert( !BER_BVISNULL( in ) );
4934 if ( in->bv_len != 3 ) {
4935 return LDAP_INVALID_SYNTAX;
4938 return hexValidate( NULL, in );
4941 /* Normalize a SID as used inside a CSN:
4942 * three-digit numeric string */
4949 struct berval *normalized,
4952 if ( val->bv_len != 3 ) {
4953 return LDAP_INVALID_SYNTAX;
4956 return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4966 return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4969 /* Normalize a SID as used inside a CSN, either as-is
4970 * (assertion value) or extracted from the CSN
4971 * (attribute value) */
4978 struct berval *normalized,
4986 if ( BER_BVISEMPTY( val ) ) {
4987 return LDAP_INVALID_SYNTAX;
4990 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4991 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
4994 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4996 ptr = ber_bvchr( val, '#' );
4997 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4998 return LDAP_INVALID_SYNTAX;
5001 bv.bv_val = ptr + 1;
5002 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5004 ptr = ber_bvchr( &bv, '#' );
5005 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5006 return LDAP_INVALID_SYNTAX;
5009 bv.bv_val = ptr + 1;
5010 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5012 ptr = ber_bvchr( &bv, '#' );
5013 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5014 return LDAP_INVALID_SYNTAX;
5017 bv.bv_len = ptr - bv.bv_val;
5019 if ( bv.bv_len == 2 ) {
5020 /* OpenLDAP 2.3 SID */
5022 buf[ 1 ] = bv.bv_val[ 0 ];
5023 buf[ 2 ] = bv.bv_val[ 1 ];
5030 return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5042 assert( in != NULL );
5043 assert( !BER_BVISNULL( in ) );
5045 if ( BER_BVISEMPTY( in ) ) {
5046 return LDAP_INVALID_SYNTAX;
5051 ptr = ber_bvchr( &bv, '#' );
5052 if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5053 return LDAP_INVALID_SYNTAX;
5056 bv.bv_len = ptr - bv.bv_val;
5057 if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5058 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5060 return LDAP_INVALID_SYNTAX;
5063 rc = generalizedTimeValidate( NULL, &bv );
5064 if ( rc != LDAP_SUCCESS ) {
5068 bv.bv_val = ptr + 1;
5069 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5071 ptr = ber_bvchr( &bv, '#' );
5072 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5073 return LDAP_INVALID_SYNTAX;
5076 bv.bv_len = ptr - bv.bv_val;
5077 if ( bv.bv_len != 6 ) {
5078 return LDAP_INVALID_SYNTAX;
5081 rc = hexValidate( NULL, &bv );
5082 if ( rc != LDAP_SUCCESS ) {
5086 bv.bv_val = ptr + 1;
5087 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5089 ptr = ber_bvchr( &bv, '#' );
5090 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5091 return LDAP_INVALID_SYNTAX;
5094 bv.bv_len = ptr - bv.bv_val;
5095 if ( bv.bv_len == 2 ) {
5096 /* tolerate old 2-digit replica-id */
5097 rc = hexValidate( NULL, &bv );
5100 rc = sidValidate( NULL, &bv );
5102 if ( rc != LDAP_SUCCESS ) {
5106 bv.bv_val = ptr + 1;
5107 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5109 if ( bv.bv_len != 6 ) {
5110 return LDAP_INVALID_SYNTAX;
5113 return hexValidate( NULL, &bv );
5116 /* Normalize a CSN in OpenLDAP 2.1 format */
5123 struct berval *normalized,
5126 struct berval gt, cnt, sid, mod;
5128 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5132 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5133 assert( !BER_BVISEMPTY( val ) );
5137 ptr = ber_bvchr( >, '#' );
5138 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5139 return LDAP_INVALID_SYNTAX;
5142 gt.bv_len = ptr - gt.bv_val;
5143 if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5144 return LDAP_INVALID_SYNTAX;
5147 if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5148 return LDAP_INVALID_SYNTAX;
5151 cnt.bv_val = ptr + 1;
5152 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5154 ptr = ber_bvchr( &cnt, '#' );
5155 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5156 return LDAP_INVALID_SYNTAX;
5159 cnt.bv_len = ptr - cnt.bv_val;
5160 if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5161 return LDAP_INVALID_SYNTAX;
5164 if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5165 return LDAP_INVALID_SYNTAX;
5168 cnt.bv_val += STRLENOF( "0x" );
5169 cnt.bv_len -= STRLENOF( "0x" );
5171 sid.bv_val = ptr + 1;
5172 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5174 ptr = ber_bvchr( &sid, '#' );
5175 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5176 return LDAP_INVALID_SYNTAX;
5179 sid.bv_len = ptr - sid.bv_val;
5180 if ( sid.bv_len != STRLENOF( "0" ) ) {
5181 return LDAP_INVALID_SYNTAX;
5184 mod.bv_val = ptr + 1;
5185 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5186 if ( mod.bv_len != STRLENOF( "0000" ) ) {
5187 return LDAP_INVALID_SYNTAX;
5190 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5194 ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5195 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5197 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5199 ptr = lutil_strcopy( ptr, ".000000Z#00" );
5200 ptr = lutil_strbvcopy( ptr, &cnt );
5204 *ptr++ = sid.bv_val[ 0 ];
5208 for ( i = 0; i < mod.bv_len; i++ ) {
5209 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5213 assert( ptr == &bv.bv_val[bv.bv_len] );
5215 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5216 return LDAP_INVALID_SYNTAX;
5219 ber_dupbv_x( normalized, &bv, ctx );
5221 return LDAP_SUCCESS;
5224 /* Normalize a CSN in OpenLDAP 2.3 format */
5231 struct berval *normalized,
5234 struct berval gt, cnt, sid, mod;
5236 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5240 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5241 assert( !BER_BVISEMPTY( val ) );
5245 ptr = ber_bvchr( >, '#' );
5246 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5247 return LDAP_INVALID_SYNTAX;
5250 gt.bv_len = ptr - gt.bv_val;
5251 if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5252 return LDAP_INVALID_SYNTAX;
5255 cnt.bv_val = ptr + 1;
5256 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5258 ptr = ber_bvchr( &cnt, '#' );
5259 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5260 return LDAP_INVALID_SYNTAX;
5263 cnt.bv_len = ptr - cnt.bv_val;
5264 if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5265 return LDAP_INVALID_SYNTAX;
5268 sid.bv_val = ptr + 1;
5269 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5271 ptr = ber_bvchr( &sid, '#' );
5272 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5273 return LDAP_INVALID_SYNTAX;
5276 sid.bv_len = ptr - sid.bv_val;
5277 if ( sid.bv_len != STRLENOF( "00" ) ) {
5278 return LDAP_INVALID_SYNTAX;
5281 mod.bv_val = ptr + 1;
5282 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5283 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5284 return LDAP_INVALID_SYNTAX;
5287 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5291 ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5292 ptr = lutil_strcopy( ptr, ".000000Z#" );
5293 ptr = lutil_strbvcopy( ptr, &cnt );
5296 for ( i = 0; i < sid.bv_len; i++ ) {
5297 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5300 for ( i = 0; i < mod.bv_len; i++ ) {
5301 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5305 assert( ptr == &bv.bv_val[bv.bv_len] );
5306 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5307 return LDAP_INVALID_SYNTAX;
5310 ber_dupbv_x( normalized, &bv, ctx );
5312 return LDAP_SUCCESS;
5315 /* Normalize a CSN */
5322 struct berval *normalized,
5325 struct berval cnt, sid, mod;
5329 assert( val != NULL );
5330 assert( normalized != NULL );
5332 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5334 if ( BER_BVISEMPTY( val ) ) {
5335 return LDAP_INVALID_SYNTAX;
5338 if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5339 /* Openldap <= 2.3 */
5341 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5344 if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5347 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5350 if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5351 return LDAP_INVALID_SYNTAX;
5354 ptr = ber_bvchr( val, '#' );
5355 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5356 return LDAP_INVALID_SYNTAX;
5359 if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5360 return LDAP_INVALID_SYNTAX;
5363 cnt.bv_val = ptr + 1;
5364 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5366 ptr = ber_bvchr( &cnt, '#' );
5367 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5368 return LDAP_INVALID_SYNTAX;
5371 if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5372 return LDAP_INVALID_SYNTAX;
5375 sid.bv_val = ptr + 1;
5376 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5378 ptr = ber_bvchr( &sid, '#' );
5379 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5380 return LDAP_INVALID_SYNTAX;
5383 sid.bv_len = ptr - sid.bv_val;
5384 if ( sid.bv_len != STRLENOF( "000" ) ) {
5385 return LDAP_INVALID_SYNTAX;
5388 mod.bv_val = ptr + 1;
5389 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5391 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5392 return LDAP_INVALID_SYNTAX;
5395 ber_dupbv_x( normalized, val, ctx );
5397 for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5398 i < normalized->bv_len; i++ )
5400 /* assume it's already validated that's all hex digits */
5401 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5404 return LDAP_SUCCESS;
5414 return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5417 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5418 /* slight optimization - does not need the start parameter */
5419 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5424 check_time_syntax (struct berval *val,
5427 struct berval *fraction)
5430 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5431 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
5432 * GeneralizedTime supports leap seconds, UTCTime does not.
5434 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5435 static const int mdays[2][12] = {
5436 /* non-leap years */
5437 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5439 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5442 int part, c, c1, c2, tzoffset, leapyear = 0;
5445 e = p + val->bv_len;
5447 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5448 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5450 for (part = start; part < 7 && p < e; part++) {
5452 if (!ASCII_DIGIT(c1)) {
5457 return LDAP_INVALID_SYNTAX;
5460 if (!ASCII_DIGIT(c)) {
5461 return LDAP_INVALID_SYNTAX;
5463 c += c1 * 10 - '0' * 11;
5464 if ((part | 1) == 3) {
5467 return LDAP_INVALID_SYNTAX;
5470 if (c >= ceiling[part]) {
5471 if (! (c == 60 && part == 6 && start == 0))
5472 return LDAP_INVALID_SYNTAX;
5476 if (part < 5 + start) {
5477 return LDAP_INVALID_SYNTAX;
5479 for (; part < 9; part++) {
5483 /* leapyear check for the Gregorian calendar (year>1581) */
5484 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5488 if (parts[3] >= mdays[leapyear][parts[2]]) {
5489 return LDAP_INVALID_SYNTAX;
5493 fraction->bv_val = p;
5494 fraction->bv_len = 0;
5495 if (p < e && (*p == '.' || *p == ',')) {
5497 while (++p < e && ASCII_DIGIT(*p)) {
5500 if (p - fraction->bv_val == 1) {
5501 return LDAP_INVALID_SYNTAX;
5503 for (end_num = p; end_num[-1] == '0'; --end_num) {
5506 c = end_num - fraction->bv_val;
5507 if (c != 1) fraction->bv_len = c;
5513 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5519 return LDAP_INVALID_SYNTAX;
5525 for (part = 7; part < 9 && p < e; part++) {
5527 if (!ASCII_DIGIT(c1)) {
5532 return LDAP_INVALID_SYNTAX;
5535 if (!ASCII_DIGIT(c2)) {
5536 return LDAP_INVALID_SYNTAX;
5538 parts[part] = c1 * 10 + c2 - '0' * 11;
5539 if (parts[part] >= ceiling[part]) {
5540 return LDAP_INVALID_SYNTAX;
5543 if (part < 8 + start) {
5544 return LDAP_INVALID_SYNTAX;
5547 if (tzoffset == '-') {
5548 /* negative offset to UTC, ie west of Greenwich */
5549 parts[4] += parts[7];
5550 parts[5] += parts[8];
5551 /* offset is just hhmm, no seconds */
5552 for (part = 6; --part >= 0; ) {
5556 c = mdays[leapyear][parts[2]];
5558 if (parts[part] >= c) {
5560 return LDAP_INVALID_SYNTAX;
5565 } else if (part != 5) {
5570 /* positive offset to UTC, ie east of Greenwich */
5571 parts[4] -= parts[7];
5572 parts[5] -= parts[8];
5573 for (part = 6; --part >= 0; ) {
5574 if (parts[part] < 0) {
5576 return LDAP_INVALID_SYNTAX;
5581 /* make first arg to % non-negative */
5582 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5587 } else if (part != 5) {
5594 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5597 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5604 struct berval *normalized )
5608 rc = check_time_syntax(val, 1, parts, NULL);
5609 if (rc != LDAP_SUCCESS) {
5613 normalized->bv_val = ch_malloc( 14 );
5614 if ( normalized->bv_val == NULL ) {
5615 return LBER_ERROR_MEMORY;
5618 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5619 parts[1], parts[2] + 1, parts[3] + 1,
5620 parts[4], parts[5], parts[6] );
5621 normalized->bv_len = 13;
5623 return LDAP_SUCCESS;
5633 return check_time_syntax(in, 1, parts, NULL);
5636 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5639 generalizedTimeValidate(
5644 struct berval fraction;
5645 return check_time_syntax(in, 0, parts, &fraction);
5649 generalizedTimeNormalize(
5654 struct berval *normalized,
5659 struct berval fraction;
5661 rc = check_time_syntax(val, 0, parts, &fraction);
5662 if (rc != LDAP_SUCCESS) {
5666 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5667 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5668 if ( BER_BVISNULL( normalized ) ) {
5669 return LBER_ERROR_MEMORY;
5672 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5673 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5674 parts[4], parts[5], parts[6] );
5675 if ( !BER_BVISEMPTY( &fraction ) ) {
5676 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5677 fraction.bv_val, fraction.bv_len );
5678 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5680 strcpy( normalized->bv_val + len-1, "Z" );
5681 normalized->bv_len = len;
5683 return LDAP_SUCCESS;
5687 generalizedTimeOrderingMatch(
5692 struct berval *value,
5693 void *assertedValue )
5695 struct berval *asserted = (struct berval *) assertedValue;
5696 ber_len_t v_len = value->bv_len;
5697 ber_len_t av_len = asserted->bv_len;
5699 /* ignore trailing 'Z' when comparing */
5700 int match = memcmp( value->bv_val, asserted->bv_val,
5701 (v_len < av_len ? v_len : av_len) - 1 );
5702 if ( match == 0 ) match = v_len - av_len;
5704 /* If used in extensible match filter, match if value < asserted */
5705 if ( flags & SLAP_MR_EXT )
5706 match = (match >= 0);
5709 return LDAP_SUCCESS;
5712 /* Index generation function: Ordered index */
5713 int generalizedTimeIndexer(
5718 struct berval *prefix,
5726 BerValue bvtmp; /* 40 bit index */
5728 struct lutil_timet tt;
5730 bvtmp.bv_len = sizeof(tmp);
5732 for( i=0; values[i].bv_val != NULL; i++ ) {
5733 /* just count them */
5736 /* we should have at least one value at this point */
5739 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5741 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5742 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5743 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5744 /* Use 40 bits of time for key */
5745 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5746 lutil_tm2time( &tm, &tt );
5747 tmp[0] = tt.tt_gsec & 0xff;
5748 tmp[4] = tt.tt_sec & 0xff;
5750 tmp[3] = tt.tt_sec & 0xff;
5752 tmp[2] = tt.tt_sec & 0xff;
5754 tmp[1] = tt.tt_sec & 0xff;
5756 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5760 keys[j].bv_val = NULL;
5765 return LDAP_SUCCESS;
5768 /* Index generation function: Ordered index */
5769 int generalizedTimeFilter(
5774 struct berval *prefix,
5775 void * assertedValue,
5781 BerValue bvtmp; /* 40 bit index */
5782 BerValue *value = (BerValue *) assertedValue;
5784 struct lutil_timet tt;
5786 bvtmp.bv_len = sizeof(tmp);
5788 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5789 /* Use 40 bits of time for key */
5790 if ( value->bv_val && value->bv_len >= 10 &&
5791 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5793 lutil_tm2time( &tm, &tt );
5794 tmp[0] = tt.tt_gsec & 0xff;
5795 tmp[4] = tt.tt_sec & 0xff;
5797 tmp[3] = tt.tt_sec & 0xff;
5799 tmp[2] = tt.tt_sec & 0xff;
5801 tmp[1] = tt.tt_sec & 0xff;
5803 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5804 ber_dupbv_x(keys, &bvtmp, ctx );
5805 keys[1].bv_val = NULL;
5813 return LDAP_SUCCESS;
5817 deliveryMethodValidate(
5819 struct berval *val )
5822 #define LENOF(s) (sizeof(s)-1)
5823 struct berval tmp = *val;
5825 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5826 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5827 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5830 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5832 switch( tmp.bv_val[0] ) {
5835 if(( tmp.bv_len >= LENOF("any") ) &&
5836 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5838 tmp.bv_len -= LENOF("any");
5839 tmp.bv_val += LENOF("any");
5842 return LDAP_INVALID_SYNTAX;
5846 if(( tmp.bv_len >= LENOF("mhs") ) &&
5847 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5849 tmp.bv_len -= LENOF("mhs");
5850 tmp.bv_val += LENOF("mhs");
5853 return LDAP_INVALID_SYNTAX;
5857 if(( tmp.bv_len >= LENOF("physical") ) &&
5858 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5860 tmp.bv_len -= LENOF("physical");
5861 tmp.bv_val += LENOF("physical");
5864 return LDAP_INVALID_SYNTAX;
5867 case 'T': /* telex or teletex or telephone */
5868 if(( tmp.bv_len >= LENOF("telex") ) &&
5869 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5871 tmp.bv_len -= LENOF("telex");
5872 tmp.bv_val += LENOF("telex");
5875 if(( tmp.bv_len >= LENOF("teletex") ) &&
5876 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5878 tmp.bv_len -= LENOF("teletex");
5879 tmp.bv_val += LENOF("teletex");
5882 if(( tmp.bv_len >= LENOF("telephone") ) &&
5883 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5885 tmp.bv_len -= LENOF("telephone");
5886 tmp.bv_val += LENOF("telephone");
5889 return LDAP_INVALID_SYNTAX;
5892 case 'G': /* g3fax or g4fax */
5893 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5894 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5895 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5897 tmp.bv_len -= LENOF("g3fax");
5898 tmp.bv_val += LENOF("g3fax");
5901 return LDAP_INVALID_SYNTAX;
5905 if(( tmp.bv_len >= LENOF("ia5") ) &&
5906 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5908 tmp.bv_len -= LENOF("ia5");
5909 tmp.bv_val += LENOF("ia5");
5912 return LDAP_INVALID_SYNTAX;
5916 if(( tmp.bv_len >= LENOF("videotex") ) &&
5917 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5919 tmp.bv_len -= LENOF("videotex");
5920 tmp.bv_val += LENOF("videotex");
5923 return LDAP_INVALID_SYNTAX;
5926 return LDAP_INVALID_SYNTAX;
5929 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
5931 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5935 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
5939 return LDAP_INVALID_SYNTAX;
5941 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5950 nisNetgroupTripleValidate(
5952 struct berval *val )
5957 if ( BER_BVISEMPTY( val ) ) {
5958 return LDAP_INVALID_SYNTAX;
5961 p = (char *)val->bv_val;
5962 e = p + val->bv_len;
5964 if ( *p != '(' /*')'*/ ) {
5965 return LDAP_INVALID_SYNTAX;
5968 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5972 return LDAP_INVALID_SYNTAX;
5975 } else if ( !AD_CHAR( *p ) ) {
5976 return LDAP_INVALID_SYNTAX;
5980 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5981 return LDAP_INVALID_SYNTAX;
5987 return LDAP_INVALID_SYNTAX;
5990 return LDAP_SUCCESS;
5994 bootParameterValidate(
5996 struct berval *val )
6000 if ( BER_BVISEMPTY( val ) ) {
6001 return LDAP_INVALID_SYNTAX;
6004 p = (char *)val->bv_val;
6005 e = p + val->bv_len;
6008 for (; ( p < e ) && ( *p != '=' ); p++ ) {
6009 if ( !AD_CHAR( *p ) ) {
6010 return LDAP_INVALID_SYNTAX;
6015 return LDAP_INVALID_SYNTAX;
6019 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6020 if ( !AD_CHAR( *p ) ) {
6021 return LDAP_INVALID_SYNTAX;
6026 return LDAP_INVALID_SYNTAX;
6030 for ( p++; p < e; p++ ) {
6031 if ( !SLAP_PRINTABLE( *p ) ) {
6032 return LDAP_INVALID_SYNTAX;
6036 return LDAP_SUCCESS;
6040 firstComponentNormalize(
6045 struct berval *normalized,
6052 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6053 ber_dupbv_x( normalized, val, ctx );
6054 return LDAP_SUCCESS;
6057 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6059 if( ! ( val->bv_val[0] == '(' /*')'*/
6060 && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6061 && ! ( val->bv_val[0] == '{' /*'}'*/
6062 && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6064 return LDAP_INVALID_SYNTAX;
6067 /* trim leading white space */
6069 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6075 /* grab next word */
6076 comp.bv_val = &val->bv_val[len];
6077 len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6078 for( comp.bv_len = 0;
6079 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6085 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6086 rc = numericoidValidate( NULL, &comp );
6087 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6088 rc = integerValidate( NULL, &comp );
6090 rc = LDAP_INVALID_SYNTAX;
6094 if( rc == LDAP_SUCCESS ) {
6095 ber_dupbv_x( normalized, &comp, ctx );
6101 static char *country_gen_syn[] = {
6102 "1.3.6.1.4.1.1466.115.121.1.15", /* Directory String */
6103 "1.3.6.1.4.1.1466.115.121.1.26", /* IA5 String */
6104 "1.3.6.1.4.1.1466.115.121.1.44", /* Printable String */
6108 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6109 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6111 static slap_syntax_defs_rec syntax_defs[] = {
6112 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6113 X_BINARY X_NOT_H_R ")",
6114 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6115 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6116 0, NULL, NULL, NULL},
6117 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6118 0, NULL, NULL, NULL},
6119 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6121 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6122 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6124 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6125 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6126 0, NULL, bitStringValidate, NULL },
6127 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6128 0, NULL, booleanValidate, NULL},
6129 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6130 X_BINARY X_NOT_H_R ")",
6131 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6132 NULL, certificateValidate, NULL},
6133 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6134 X_BINARY X_NOT_H_R ")",
6135 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6136 NULL, certificateListValidate, NULL},
6137 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6138 X_BINARY X_NOT_H_R ")",
6139 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6140 NULL, sequenceValidate, NULL},
6141 {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6142 X_BINARY X_NOT_H_R ")",
6143 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6144 NULL, attributeCertificateValidate, NULL},
6145 #if 0 /* need to go __after__ printableString */
6146 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6147 0, "1.3.6.1.4.1.1466.115.121.1.44",
6148 countryStringValidate, NULL},
6150 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6151 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6152 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6153 0, NULL, rdnValidate, rdnPretty},
6154 #ifdef LDAP_COMP_MATCH
6155 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6156 0, NULL, allComponentsValidate, NULL},
6157 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6158 0, NULL, componentFilterValidate, NULL},
6160 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6161 0, NULL, NULL, NULL},
6162 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6163 0, NULL, deliveryMethodValidate, NULL},
6164 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6165 0, NULL, UTF8StringValidate, NULL},
6166 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6167 0, NULL, NULL, NULL},
6168 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6169 0, NULL, NULL, NULL},
6170 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6171 0, NULL, NULL, NULL},
6172 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6173 0, NULL, NULL, NULL},
6174 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6175 0, NULL, NULL, NULL},
6176 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6177 0, NULL, printablesStringValidate, NULL},
6178 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6179 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6180 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6181 0, NULL, generalizedTimeValidate, NULL},
6182 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6183 0, NULL, NULL, NULL},
6184 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6185 0, NULL, IA5StringValidate, NULL},
6186 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6187 0, NULL, integerValidate, NULL},
6188 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6189 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6190 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6191 0, NULL, NULL, NULL},
6192 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6193 0, NULL, NULL, NULL},
6194 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6195 0, NULL, NULL, NULL},
6196 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6197 0, NULL, NULL, NULL},
6198 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6199 0, NULL, NULL, NULL},
6200 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6201 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6202 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6203 0, NULL, NULL, NULL},
6204 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6205 0, NULL, numericStringValidate, NULL},
6206 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6207 0, NULL, NULL, NULL},
6208 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6209 0, NULL, numericoidValidate, NULL},
6210 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6211 0, NULL, IA5StringValidate, NULL},
6212 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6213 0, NULL, blobValidate, NULL},
6214 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6215 0, NULL, postalAddressValidate, NULL},
6216 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6217 0, NULL, NULL, NULL},
6218 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6219 0, NULL, NULL, NULL},
6220 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6221 0, NULL, printableStringValidate, NULL},
6222 /* moved here because now depends on Directory String, IA5 String
6223 * and Printable String */
6224 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6225 0, country_gen_syn, countryStringValidate, NULL},
6226 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6227 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6228 0, NULL, subtreeSpecificationValidate, NULL},
6229 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6230 X_BINARY X_NOT_H_R ")",
6231 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6232 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6233 0, NULL, printableStringValidate, NULL},
6234 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6235 0, NULL, NULL, NULL},
6236 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6237 0, NULL, printablesStringValidate, NULL},
6238 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6239 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6240 0, NULL, utcTimeValidate, NULL},
6242 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6243 0, NULL, NULL, NULL},
6244 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6245 0, NULL, NULL, NULL},
6246 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6247 0, NULL, NULL, NULL},
6248 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6249 0, NULL, NULL, NULL},
6250 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6251 0, NULL, NULL, NULL},
6253 /* RFC 2307 NIS Syntaxes */
6254 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
6255 0, NULL, nisNetgroupTripleValidate, NULL},
6256 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
6257 0, NULL, bootParameterValidate, NULL},
6259 /* draft-zeilenga-ldap-x509 */
6260 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6261 SLAP_SYNTAX_HIDE, NULL,
6262 serialNumberAndIssuerValidate,
6263 serialNumberAndIssuerPretty},
6264 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6265 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6266 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6267 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6268 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6269 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6270 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6271 SLAP_SYNTAX_HIDE, NULL,
6272 issuerAndThisUpdateValidate,
6273 issuerAndThisUpdatePretty},
6274 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6275 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6276 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6277 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6278 {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6279 SLAP_SYNTAX_HIDE, NULL,
6280 serialNumberAndIssuerSerialValidate,
6281 serialNumberAndIssuerSerialPretty},
6282 {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6283 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6285 #ifdef SLAPD_AUTHPASSWD
6286 /* needs updating */
6287 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6288 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6291 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6292 0, NULL, UUIDValidate, UUIDPretty},
6294 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6295 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6297 {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6298 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6300 /* OpenLDAP Void Syntax */
6301 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6302 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6304 /* FIXME: OID is unused, but not registered yet */
6305 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6306 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6308 {NULL, 0, NULL, NULL, NULL}
6311 char *csnSIDMatchSyntaxes[] = {
6312 "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6315 char *certificateExactMatchSyntaxes[] = {
6316 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6319 char *certificateListExactMatchSyntaxes[] = {
6320 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6323 char *attributeCertificateExactMatchSyntaxes[] = {
6324 attributeCertificateSyntaxOID /* attributeCertificate */,
6328 #ifdef LDAP_COMP_MATCH
6329 char *componentFilterMatchSyntaxes[] = {
6330 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6331 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6332 attributeCertificateSyntaxOID /* attributeCertificate */,
6337 char *directoryStringSyntaxes[] = {
6338 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6341 char *integerFirstComponentMatchSyntaxes[] = {
6342 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6343 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6346 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6347 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6348 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
6349 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6350 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6351 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6352 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6353 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6354 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6359 * Other matching rules in X.520 that we do not use (yet):
6361 * 2.5.13.25 uTCTimeMatch
6362 * 2.5.13.26 uTCTimeOrderingMatch
6363 * 2.5.13.31* directoryStringFirstComponentMatch
6364 * 2.5.13.32* wordMatch
6365 * 2.5.13.33* keywordMatch
6366 * 2.5.13.36+ certificatePairExactMatch
6367 * 2.5.13.37+ certificatePairMatch
6368 * 2.5.13.40+ algorithmIdentifierMatch
6369 * 2.5.13.41* storedPrefixMatch
6370 * 2.5.13.42 attributeCertificateMatch
6371 * 2.5.13.43 readerAndKeyIDMatch
6372 * 2.5.13.44 attributeIntegrityMatch
6374 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6375 * (+) described in draft-zeilenga-ldap-x509
6377 static slap_mrule_defs_rec mrule_defs[] = {
6379 * EQUALITY matching rules must be listed after associated APPROX
6380 * matching rules. So, we list all APPROX matching rules first.
6382 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6383 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6384 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6385 NULL, NULL, directoryStringApproxMatch,
6386 directoryStringApproxIndexer, directoryStringApproxFilter,
6389 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6390 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6391 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6392 NULL, NULL, IA5StringApproxMatch,
6393 IA5StringApproxIndexer, IA5StringApproxFilter,
6397 * Other matching rules
6400 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6401 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6402 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6403 NULL, NULL, octetStringMatch,
6404 octetStringIndexer, octetStringFilter,
6407 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6408 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6409 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6410 NULL, dnNormalize, dnMatch,
6411 octetStringIndexer, octetStringFilter,
6414 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6415 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6416 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6417 NULL, dnNormalize, dnRelativeMatch,
6421 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6422 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6423 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6424 NULL, dnNormalize, dnRelativeMatch,
6428 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6429 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6430 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6431 NULL, dnNormalize, dnRelativeMatch,
6435 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6436 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6437 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6438 NULL, dnNormalize, dnRelativeMatch,
6442 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6443 "SYNTAX 1.2.36.79672281.1.5.0 )",
6444 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6445 NULL, rdnNormalize, rdnMatch,
6446 octetStringIndexer, octetStringFilter,
6449 #ifdef LDAP_COMP_MATCH
6450 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6451 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6452 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6453 NULL, NULL , componentFilterMatch,
6454 octetStringIndexer, octetStringFilter,
6457 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6458 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6459 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6460 NULL, NULL , allComponentsMatch,
6461 octetStringIndexer, octetStringFilter,
6464 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6465 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6466 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6467 NULL, NULL , directoryComponentsMatch,
6468 octetStringIndexer, octetStringFilter,
6472 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6473 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6474 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6475 NULL, UTF8StringNormalize, octetStringMatch,
6476 octetStringIndexer, octetStringFilter,
6477 directoryStringApproxMatchOID },
6479 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6480 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6481 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6482 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6484 "caseIgnoreMatch" },
6486 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6487 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6488 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6489 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6490 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6491 "caseIgnoreMatch" },
6493 {"( 2.5.13.5 NAME 'caseExactMatch' "
6494 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6495 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6496 NULL, UTF8StringNormalize, octetStringMatch,
6497 octetStringIndexer, octetStringFilter,
6498 directoryStringApproxMatchOID },
6500 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6501 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6502 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6503 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6507 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6508 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6509 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6510 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6511 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6514 {"( 2.5.13.8 NAME 'numericStringMatch' "
6515 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6516 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6517 NULL, numericStringNormalize, octetStringMatch,
6518 octetStringIndexer, octetStringFilter,
6521 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6522 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6523 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6524 NULL, numericStringNormalize, octetStringOrderingMatch,
6526 "numericStringMatch" },
6528 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6529 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6530 SLAP_MR_SUBSTR, NULL,
6531 NULL, numericStringNormalize, octetStringSubstringsMatch,
6532 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6533 "numericStringMatch" },
6535 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6536 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6537 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6538 NULL, postalAddressNormalize, octetStringMatch,
6539 octetStringIndexer, octetStringFilter,
6542 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6543 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6544 SLAP_MR_SUBSTR, NULL,
6545 NULL, NULL, NULL, NULL, NULL,
6546 "caseIgnoreListMatch" },
6548 {"( 2.5.13.13 NAME 'booleanMatch' "
6549 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6550 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6551 NULL, NULL, booleanMatch,
6552 octetStringIndexer, octetStringFilter,
6555 {"( 2.5.13.14 NAME 'integerMatch' "
6556 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6557 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6558 NULL, NULL, integerMatch,
6559 integerIndexer, integerFilter,
6562 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6563 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6564 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6565 NULL, NULL, integerMatch,
6569 {"( 2.5.13.16 NAME 'bitStringMatch' "
6570 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6571 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6572 NULL, NULL, octetStringMatch,
6573 octetStringIndexer, octetStringFilter,
6576 {"( 2.5.13.17 NAME 'octetStringMatch' "
6577 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6578 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6579 NULL, NULL, octetStringMatch,
6580 octetStringIndexer, octetStringFilter,
6583 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6584 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6585 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6586 NULL, NULL, octetStringOrderingMatch,
6588 "octetStringMatch" },
6590 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6591 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6592 SLAP_MR_SUBSTR, NULL,
6593 NULL, NULL, octetStringSubstringsMatch,
6594 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6595 "octetStringMatch" },
6597 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6598 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6599 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6601 telephoneNumberNormalize, octetStringMatch,
6602 octetStringIndexer, octetStringFilter,
6605 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6606 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6607 SLAP_MR_SUBSTR, NULL,
6608 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6609 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6610 "telephoneNumberMatch" },
6612 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6613 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6614 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6615 NULL, NULL, NULL, NULL, NULL, NULL },
6617 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6618 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6619 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6620 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6621 uniqueMemberIndexer, uniqueMemberFilter,
6624 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6625 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6626 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6627 NULL, NULL, NULL, NULL, NULL, NULL },
6629 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6630 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6631 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6632 NULL, generalizedTimeNormalize, octetStringMatch,
6633 generalizedTimeIndexer, generalizedTimeFilter,
6636 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6637 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6638 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6639 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6641 "generalizedTimeMatch" },
6643 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6644 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6645 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6646 integerFirstComponentMatchSyntaxes,
6647 NULL, firstComponentNormalize, integerMatch,
6648 octetStringIndexer, octetStringFilter,
6651 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6652 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6653 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6654 objectIdentifierFirstComponentMatchSyntaxes,
6655 NULL, firstComponentNormalize, octetStringMatch,
6656 octetStringIndexer, octetStringFilter,
6659 {"( 2.5.13.34 NAME 'certificateExactMatch' "
6660 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6661 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6662 NULL, certificateExactNormalize, octetStringMatch,
6663 octetStringIndexer, octetStringFilter,
6666 {"( 2.5.13.35 NAME 'certificateMatch' "
6667 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6668 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6669 NULL, NULL, NULL, NULL, NULL,
6672 {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6673 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6674 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6675 NULL, certificateListExactNormalize, octetStringMatch,
6676 octetStringIndexer, octetStringFilter,
6679 {"( 2.5.13.39 NAME 'certificateListMatch' "
6680 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6681 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6682 NULL, NULL, NULL, NULL, NULL,
6685 {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6686 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6687 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6688 NULL, attributeCertificateExactNormalize, octetStringMatch,
6689 octetStringIndexer, octetStringFilter,
6692 {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6693 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6694 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6695 NULL, NULL, NULL, NULL, NULL,
6698 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6699 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6700 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6701 NULL, IA5StringNormalize, octetStringMatch,
6702 octetStringIndexer, octetStringFilter,
6703 IA5StringApproxMatchOID },
6705 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6706 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6707 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6708 NULL, IA5StringNormalize, octetStringMatch,
6709 octetStringIndexer, octetStringFilter,
6710 IA5StringApproxMatchOID },
6712 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6713 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6714 SLAP_MR_SUBSTR, NULL,
6715 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6716 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6717 "caseIgnoreIA5Match" },
6719 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6720 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6721 SLAP_MR_SUBSTR, NULL,
6722 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6723 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6724 "caseExactIA5Match" },
6726 #ifdef SLAPD_AUTHPASSWD
6727 /* needs updating */
6728 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6729 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6730 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6731 NULL, NULL, authPasswordMatch,
6736 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6737 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6739 NULL, NULL, integerBitAndMatch,
6743 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6744 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6746 NULL, NULL, integerBitOrMatch,
6750 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6751 "SYNTAX 1.3.6.1.1.16.1 )",
6752 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6753 NULL, UUIDNormalize, octetStringMatch,
6754 octetStringIndexer, octetStringFilter,
6757 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6758 "SYNTAX 1.3.6.1.1.16.1 )",
6759 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6760 NULL, UUIDNormalize, octetStringOrderingMatch,
6761 octetStringIndexer, octetStringFilter,
6764 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6765 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6766 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6767 NULL, csnNormalize, csnMatch,
6768 csnIndexer, csnFilter,
6771 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6772 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6773 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6774 NULL, csnNormalize, csnOrderingMatch,
6778 {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6779 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6780 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6781 NULL, csnSidNormalize, octetStringMatch,
6782 octetStringIndexer, octetStringFilter,
6785 /* FIXME: OID is unused, but not registered yet */
6786 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6787 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6788 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6789 NULL, authzNormalize, authzMatch,
6793 {NULL, SLAP_MR_NONE, NULL,
6794 NULL, NULL, NULL, NULL, NULL,
6799 slap_schema_init( void )
6804 /* we should only be called once (from main) */
6805 assert( schema_init_done == 0 );
6807 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6808 res = register_syntax( &syntax_defs[i] );
6811 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6812 syntax_defs[i].sd_desc );
6817 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6818 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6819 mrule_defs[i].mrd_compat_syntaxes == NULL )
6822 "slap_schema_init: Ignoring unusable matching rule %s\n",
6823 mrule_defs[i].mrd_desc );
6827 res = register_matching_rule( &mrule_defs[i] );
6831 "slap_schema_init: Error registering matching rule %s\n",
6832 mrule_defs[i].mrd_desc );
6837 res = slap_schema_load();
6838 schema_init_done = 1;
6843 schema_destroy( void )
6852 if( schema_init_done ) {
6853 ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6854 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6855 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );