1 /* schema_init.c - init builtin schema */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2013 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] );
2158 if( keys[keycount].bv_len ) {
2161 ch_free( keys[keycount].bv_val );
2166 ber_memfree( val.bv_val );
2168 BER_BVZERO( &keys[keycount] );
2171 return LDAP_SUCCESS;
2180 struct berval *prefix,
2181 void * assertedValue,
2190 /* Yes, this is necessary */
2191 val = UTF8bvnormalize( ((struct berval *)assertedValue),
2192 NULL, LDAP_UTF8_APPROX, NULL );
2193 if( val == NULL || BER_BVISNULL( val ) ) {
2194 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2195 BER_BVZERO( &keys[0] );
2198 return LDAP_SUCCESS;
2201 /* Isolate how many words there are. There will be a key for each */
2202 for( count = 0,c = val->bv_val; *c; c++) {
2203 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2204 if( len >= SLAPD_APPROX_WORDLEN ) count++;
2206 if (*c == '\0') break;
2210 /* Allocate storage for new keys */
2211 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2213 /* Get a phonetic copy of each word */
2214 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2216 if( len < SLAPD_APPROX_WORDLEN ) continue;
2217 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2223 BER_BVZERO( &keys[count] );
2226 return LDAP_SUCCESS;
2229 /* Remove all spaces and '-' characters */
2231 telephoneNumberNormalize(
2236 struct berval *normalized,
2241 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2243 /* validator should have refused an empty string */
2244 assert( !BER_BVISEMPTY( val ) );
2246 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2248 for( p = val->bv_val; *p; p++ ) {
2249 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
2255 normalized->bv_len = q - normalized->bv_val;
2257 if( BER_BVISEMPTY( normalized ) ) {
2258 slap_sl_free( normalized->bv_val, ctx );
2259 BER_BVZERO( normalized );
2260 return LDAP_INVALID_SYNTAX;
2263 return LDAP_SUCCESS;
2267 postalAddressValidate(
2271 struct berval bv = *in;
2274 for ( c = 0; c < in->bv_len; c++ ) {
2275 if ( in->bv_val[c] == '\\' ) {
2277 if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2278 && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2280 return LDAP_INVALID_SYNTAX;
2285 if ( in->bv_val[c] == '$' ) {
2286 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2287 if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2288 return LDAP_INVALID_SYNTAX;
2290 bv.bv_val = &in->bv_val[c] + 1;
2294 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2295 return UTF8StringValidate( NULL, &bv );
2299 postalAddressNormalize(
2304 struct berval *normalized,
2307 BerVarray lines = NULL, nlines = NULL;
2309 int rc = LDAP_SUCCESS;
2310 MatchingRule *xmr = NULL;
2313 if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2314 xmr = slap_schema.si_mr_caseIgnoreMatch;
2317 xmr = slap_schema.si_mr_caseExactMatch;
2320 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2321 if ( val->bv_val[c] == '$' ) {
2326 lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2327 nlines = &lines[l + 2];
2329 lines[0].bv_val = val->bv_val;
2330 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2331 if ( val->bv_val[c] == '$' ) {
2332 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2334 lines[l].bv_val = &val->bv_val[c + 1];
2337 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2339 normalized->bv_len = c = l;
2341 for ( l = 0; l <= c; l++ ) {
2342 /* NOTE: we directly normalize each line,
2343 * without unescaping the values, since the special
2344 * values '\24' ('$') and '\5C' ('\') are not affected
2345 * by normalization */
2346 if ( !lines[l].bv_len ) {
2347 nlines[l].bv_len = 0;
2348 nlines[l].bv_val = NULL;
2351 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2352 if ( rc != LDAP_SUCCESS ) {
2353 rc = LDAP_INVALID_SYNTAX;
2357 normalized->bv_len += nlines[l].bv_len;
2360 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2362 p = normalized->bv_val;
2363 for ( l = 0; l <= c ; l++ ) {
2364 p = lutil_strbvcopy( p, &nlines[l] );
2369 assert( p == &normalized->bv_val[normalized->bv_len] );
2372 if ( nlines != NULL ) {
2373 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2374 slap_sl_free( nlines[l].bv_val, ctx );
2377 slap_sl_free( lines, ctx );
2388 struct berval val = *in;
2390 if( BER_BVISEMPTY( &val ) ) {
2391 /* disallow empty strings */
2392 return LDAP_INVALID_SYNTAX;
2395 while( OID_LEADCHAR( val.bv_val[0] ) ) {
2396 if ( val.bv_len == 1 ) {
2397 return LDAP_SUCCESS;
2400 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2407 while ( OID_LEADCHAR( val.bv_val[0] )) {
2411 if ( val.bv_len == 0 ) {
2412 return LDAP_SUCCESS;
2416 if( !OID_SEPARATOR( val.bv_val[0] )) {
2424 return LDAP_INVALID_SYNTAX;
2433 struct berval val = *in;
2435 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2437 if ( val.bv_val[0] == '-' ) {
2441 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2442 return LDAP_INVALID_SYNTAX;
2445 if( val.bv_val[0] == '0' ) { /* "-0" */
2446 return LDAP_INVALID_SYNTAX;
2449 } else if ( val.bv_val[0] == '0' ) {
2450 if( val.bv_len > 1 ) { /* "0<more>" */
2451 return LDAP_INVALID_SYNTAX;
2454 return LDAP_SUCCESS;
2457 for( i=0; i < val.bv_len; i++ ) {
2458 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2459 return LDAP_INVALID_SYNTAX;
2463 return LDAP_SUCCESS;
2472 struct berval *value,
2473 void *assertedValue )
2475 struct berval *asserted = (struct berval *) assertedValue;
2476 int vsign = 1, asign = 1; /* default sign = '+' */
2481 if( v.bv_val[0] == '-' ) {
2487 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2490 if( a.bv_val[0] == '-' ) {
2496 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2498 match = vsign - asign;
2500 match = ( v.bv_len != a.bv_len
2501 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2502 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2503 if( vsign < 0 ) match = -match;
2506 /* Ordering rule used in extensible match filter? */
2507 if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2508 match = (match >= 0);
2511 return LDAP_SUCCESS;
2514 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2515 #define INDEX_INTLEN_CHOP 7
2516 #define INDEX_INTLEN_CHOPBYTES 3
2525 /* Integer index key format, designed for memcmp to collate correctly:
2526 * if too large: one's complement sign*<approx exponent=chopped bytes>,
2527 * two's complement value (sign-extended or chopped as needed),
2528 * however in first byte above, the top <number of exponent-bytes + 1>
2529 * bits are the inverse sign and next bit is the sign as delimiter.
2531 ber_slen_t k = index_intlen_strlen;
2533 unsigned signmask = ~0x7fU;
2534 unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2535 struct berval val = *in, itmp = *tmp;
2537 if ( val.bv_val[0] != '-' ) {
2542 /* Chop least significant digits, increase length instead */
2543 if ( val.bv_len > (ber_len_t) k ) {
2544 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2545 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2546 chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
2549 if ( lutil_str2bin( &val, &itmp, ctx )) {
2550 return LDAP_INVALID_SYNTAX;
2553 /* Omit leading sign byte */
2554 if ( itmp.bv_val[0] == neg ) {
2559 k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2561 assert( chop == 0 );
2562 memset( key->bv_val, neg, k ); /* sign-extend */
2563 } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2564 /* Got exponent -k, or no room for 2 sign bits */
2565 lenp = lenbuf + sizeof(lenbuf);
2566 chop = - (ber_len_t) k;
2568 *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2570 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2571 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2572 * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2573 k = (lenbuf + sizeof(lenbuf)) - lenp;
2574 if ( k > (ber_slen_t) index_intlen )
2576 memcpy( key->bv_val, lenp, k );
2577 itmp.bv_len = index_intlen - k;
2579 memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2580 key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2584 /* Index generation function: Ordered index */
2591 struct berval *prefix,
2601 unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2603 /* count the values and find max needed length */
2605 for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2606 if ( vlen < values[i].bv_len )
2607 vlen = values[i].bv_len;
2609 if ( vlen > maxstrlen )
2612 /* we should have at least one value at this point */
2615 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2616 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2617 keys[i].bv_len = index_intlen;
2618 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2621 keys[i].bv_val = NULL;
2623 if ( vlen > sizeof(ibuf) ) {
2624 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2628 itmp.bv_len = sizeof(ibuf);
2630 for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2631 if ( itmp.bv_val != ibuf ) {
2632 itmp.bv_len = values[i].bv_len;
2633 if ( itmp.bv_len <= sizeof(ibuf) )
2634 itmp.bv_len = sizeof(ibuf);
2635 else if ( itmp.bv_len > maxstrlen )
2636 itmp.bv_len = maxstrlen;
2638 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2644 if ( itmp.bv_val != ibuf ) {
2645 slap_sl_free( itmp.bv_val, ctx );
2650 /* Index generation function: Ordered index */
2657 struct berval *prefix,
2658 void * assertedValue,
2665 struct berval *value;
2668 value = (struct berval *) assertedValue;
2670 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2672 keys[0].bv_len = index_intlen;
2673 keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2675 keys[1].bv_val = NULL;
2677 iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2678 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2679 if ( iv.bv_len > (int) sizeof(ibuf) ) {
2680 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2683 iv.bv_len = sizeof(ibuf);
2686 rc = integerVal2Key( value, keys, &iv, ctx );
2690 if ( iv.bv_val != ibuf ) {
2691 slap_sl_free( iv.bv_val, ctx );
2697 countryStringValidate(
2699 struct berval *val )
2701 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2703 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2704 return LDAP_INVALID_SYNTAX;
2706 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2707 return LDAP_INVALID_SYNTAX;
2710 return LDAP_SUCCESS;
2714 printableStringValidate(
2716 struct berval *val )
2720 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2722 for(i=0; i < val->bv_len; i++) {
2723 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2724 return LDAP_INVALID_SYNTAX;
2728 return LDAP_SUCCESS;
2732 printablesStringValidate(
2734 struct berval *val )
2738 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2740 for(i=0,len=0; i < val->bv_len; i++) {
2741 int c = val->bv_val[i];
2745 return LDAP_INVALID_SYNTAX;
2749 } else if ( SLAP_PRINTABLE(c) ) {
2752 return LDAP_INVALID_SYNTAX;
2757 return LDAP_INVALID_SYNTAX;
2760 return LDAP_SUCCESS;
2766 struct berval *val )
2770 for(i=0; i < val->bv_len; i++) {
2771 if( !LDAP_ASCII(val->bv_val[i]) ) {
2772 return LDAP_INVALID_SYNTAX;
2776 return LDAP_SUCCESS;
2785 struct berval *normalized,
2789 int casefold = !SLAP_MR_ASSOCIATED( mr,
2790 slap_schema.si_mr_caseExactIA5Match );
2792 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2796 /* Ignore initial whitespace */
2797 while ( ASCII_SPACE( *p ) ) p++;
2799 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2800 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2801 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2802 normalized->bv_val[normalized->bv_len] = '\0';
2804 p = q = normalized->bv_val;
2807 if ( ASCII_SPACE( *p ) ) {
2810 /* Ignore the extra whitespace */
2811 while ( ASCII_SPACE( *p ) ) {
2815 } else if ( casefold ) {
2816 /* Most IA5 rules require casefolding */
2817 *q++ = TOLOWER(*p); p++;
2824 assert( normalized->bv_val <= p );
2828 * If the string ended in space, backup the pointer one
2829 * position. One is enough because the above loop collapsed
2830 * all whitespace to a single space.
2832 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2834 /* null terminate */
2837 normalized->bv_len = q - normalized->bv_val;
2839 return LDAP_SUCCESS;
2848 if( in->bv_len != 36 ) {
2849 return LDAP_INVALID_SYNTAX;
2852 for( i=0; i<36; i++ ) {
2858 if( in->bv_val[i] != '-' ) {
2859 return LDAP_INVALID_SYNTAX;
2863 if( !ASCII_HEX( in->bv_val[i]) ) {
2864 return LDAP_INVALID_SYNTAX;
2869 return LDAP_SUCCESS;
2880 int rc=LDAP_INVALID_SYNTAX;
2882 assert( in != NULL );
2883 assert( out != NULL );
2885 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2888 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2890 for( i=0; i<36; i++ ) {
2896 if( in->bv_val[i] != '-' ) {
2899 out->bv_val[i] = '-';
2903 if( !ASCII_HEX( in->bv_val[i]) ) {
2906 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2911 out->bv_val[ out->bv_len ] = '\0';
2915 slap_sl_free( out->bv_val, ctx );
2928 struct berval *normalized,
2931 unsigned char octet = '\0';
2935 if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2936 /* NOTE: must be a normalized UUID */
2937 assert( val->bv_len == 16 );
2939 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2940 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2941 val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2942 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2944 return LDAP_SUCCESS;
2947 normalized->bv_len = 16;
2948 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2950 for( i=0, j=0; i<36; i++ ) {
2951 unsigned char nibble;
2952 if( val->bv_val[i] == '-' ) {
2955 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2956 nibble = val->bv_val[i] - '0';
2958 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2959 nibble = val->bv_val[i] - ('a'-10);
2961 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2962 nibble = val->bv_val[i] - ('A'-10);
2965 slap_sl_free( normalized->bv_val, ctx );
2966 BER_BVZERO( normalized );
2967 return LDAP_INVALID_SYNTAX;
2972 normalized->bv_val[j>>1] = octet;
2974 octet = nibble << 4;
2979 normalized->bv_val[normalized->bv_len] = 0;
2980 return LDAP_SUCCESS;
2986 numericStringValidate(
2992 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2994 for(i=0; i < in->bv_len; i++) {
2995 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2996 return LDAP_INVALID_SYNTAX;
3000 return LDAP_SUCCESS;
3004 numericStringNormalize(
3009 struct berval *normalized,
3012 /* removal all spaces */
3015 assert( !BER_BVISEMPTY( val ) );
3017 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3020 q = normalized->bv_val;
3023 if ( ASCII_SPACE( *p ) ) {
3024 /* Ignore whitespace */
3031 /* we should have copied no more than is in val */
3032 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3034 /* null terminate */
3037 normalized->bv_len = q - normalized->bv_val;
3039 if( BER_BVISEMPTY( normalized ) ) {
3040 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3041 normalized->bv_val[0] = ' ';
3042 normalized->bv_val[1] = '\0';
3043 normalized->bv_len = 1;
3046 return LDAP_SUCCESS;
3050 * Integer conversion macros that will use the largest available
3053 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3054 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
3055 # define SLAP_LONG long long
3057 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
3058 # define SLAP_LONG long
3059 #endif /* HAVE_STRTOLL ... */
3067 struct berval *value,
3068 void *assertedValue )
3070 SLAP_LONG lValue, lAssertedValue;
3073 /* safe to assume integers are NUL terminated? */
3074 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3075 if( errno == ERANGE )
3077 return LDAP_CONSTRAINT_VIOLATION;
3080 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3082 if( errno == ERANGE )
3084 return LDAP_CONSTRAINT_VIOLATION;
3087 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3088 return LDAP_SUCCESS;
3097 struct berval *value,
3098 void *assertedValue )
3100 SLAP_LONG lValue, lAssertedValue;
3103 /* safe to assume integers are NUL terminated? */
3104 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3105 if( errno == ERANGE )
3107 return LDAP_CONSTRAINT_VIOLATION;
3110 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3112 if( errno == ERANGE )
3114 return LDAP_CONSTRAINT_VIOLATION;
3117 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3118 return LDAP_SUCCESS;
3122 checkNum( struct berval *in, struct berval *out )
3124 /* parse serialNumber */
3125 ber_len_t neg = 0, extra = 0;
3128 out->bv_val = in->bv_val;
3131 if ( out->bv_val[0] == '-' ) {
3136 if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3137 first = out->bv_val[2];
3140 out->bv_len += STRLENOF("0x");
3141 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3142 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3145 } else if ( out->bv_val[0] == '\'' ) {
3146 first = out->bv_val[1];
3149 out->bv_len += STRLENOF("'");
3151 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3152 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3154 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3157 out->bv_len += STRLENOF("'H");
3160 first = out->bv_val[0];
3161 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3162 if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3166 if ( !( out->bv_len > neg ) ) {
3170 if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3178 serialNumberAndIssuerCheck(
3186 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3188 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3189 /* Parse old format */
3190 is->bv_val = ber_bvchr( in, '$' );
3191 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3193 sn->bv_val = in->bv_val;
3194 sn->bv_len = is->bv_val - in->bv_val;
3197 is->bv_len = in->bv_len - (sn->bv_len + 1);
3199 /* eat leading zeros */
3200 for( n=0; n < (sn->bv_len-1); n++ ) {
3201 if( sn->bv_val[n] != '0' ) break;
3206 for( n=0; n < sn->bv_len; n++ ) {
3207 if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3211 /* Parse GSER format */
3216 HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3220 struct berval x = *in;
3226 /* eat leading spaces */
3227 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3231 /* should be at issuer or serialNumber NamedValue */
3232 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3233 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3236 x.bv_val += STRLENOF("issuer");
3237 x.bv_len -= STRLENOF("issuer");
3239 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3243 /* eat leading spaces */
3244 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3248 /* For backward compatibility, this part is optional */
3249 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3250 x.bv_val += STRLENOF("rdnSequence:");
3251 x.bv_len -= STRLENOF("rdnSequence:");
3254 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3258 is->bv_val = x.bv_val;
3261 for ( ; is->bv_len < x.bv_len; ) {
3262 if ( is->bv_val[is->bv_len] != '"' ) {
3266 if ( is->bv_val[is->bv_len+1] == '"' ) {
3273 x.bv_val += is->bv_len + 1;
3274 x.bv_len -= is->bv_len + 1;
3276 have |= HAVE_ISSUER;
3278 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3280 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3282 /* parse serialNumber */
3283 x.bv_val += STRLENOF("serialNumber");
3284 x.bv_len -= STRLENOF("serialNumber");
3286 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3290 /* eat leading spaces */
3291 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3295 if ( checkNum( &x, sn ) ) {
3296 return LDAP_INVALID_SYNTAX;
3299 x.bv_val += sn->bv_len;
3300 x.bv_len -= sn->bv_len;
3305 return LDAP_INVALID_SYNTAX;
3308 /* eat leading spaces */
3309 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3313 if ( have == HAVE_ALL ) {
3317 if ( x.bv_val[0] != ',' ) {
3318 return LDAP_INVALID_SYNTAX;
3325 /* should have no characters left... */
3326 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3328 if ( numdquotes == 0 ) {
3329 ber_dupbv_x( &ni, is, ctx );
3334 ni.bv_len = is->bv_len - numdquotes;
3335 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3336 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3337 if ( is->bv_val[src] == '"' ) {
3340 ni.bv_val[dst] = is->bv_val[src];
3342 ni.bv_val[dst] = '\0';
3352 serialNumberAndIssuerValidate(
3357 struct berval sn, i;
3359 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3362 rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3367 /* validate DN -- doesn't handle double dquote */
3368 rc = dnValidate( NULL, &i );
3370 rc = LDAP_INVALID_SYNTAX;
3373 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3374 slap_sl_free( i.bv_val, NULL );
3377 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3378 in->bv_val, rc, 0 );
3385 serialNumberAndIssuerPretty(
3392 struct berval sn, i, ni = BER_BVNULL;
3395 assert( in != NULL );
3396 assert( out != NULL );
3400 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3403 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3408 rc = dnPretty( syntax, &i, &ni, ctx );
3410 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3411 slap_sl_free( i.bv_val, ctx );
3415 rc = LDAP_INVALID_SYNTAX;
3419 /* make room from sn + "$" */
3420 out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3421 + sn.bv_len + ni.bv_len;
3422 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3424 if ( out->bv_val == NULL ) {
3431 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3432 p = lutil_strbvcopy( p, &sn );
3433 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3434 p = lutil_strbvcopy( p, &ni );
3435 p = lutil_strcopy( p, /*{*/ "\" }" );
3437 assert( p == &out->bv_val[out->bv_len] );
3440 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3441 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3443 slap_sl_free( ni.bv_val, ctx );
3445 return LDAP_SUCCESS;
3455 /* Use hex format. '123456789abcdef'H */
3456 unsigned char *ptr, zero = '\0';
3459 ber_len_t i, len, nlen;
3461 assert( in != NULL );
3462 assert( !BER_BVISNULL( in ) );
3463 assert( out != NULL );
3464 assert( !BER_BVISNULL( out ) );
3466 ptr = (unsigned char *)in->bv_val;
3469 /* Check for minimal encodings */
3471 if ( ptr[0] & 0x80 ) {
3472 if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3476 } else if ( ptr[0] == 0 ) {
3477 if ( !( ptr[1] & 0x80 ) ) {
3484 } else if ( len == 0 ) {
3485 /* FIXME: this should not be possible,
3486 * since a value of zero would have length 1 */
3491 first = !( ptr[0] & 0xf0U );
3492 nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3493 if ( nlen >= out->bv_len ) {
3494 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3500 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3504 for ( ; i < len; i++ ) {
3505 sprintf( sptr, "%02X", ptr[i] );
3512 assert( sptr == &out->bv_val[nlen] );
3519 #define SLAP_SN_BUFLEN (64)
3522 * This routine is called by certificateExactNormalize when
3523 * certificateExactNormalize receives a search string instead of
3524 * a certificate. This routine checks if the search value is valid
3525 * and then returns the normalized value
3528 serialNumberAndIssuerNormalize(
3536 struct berval sn, sn2, sn3, i, ni;
3537 char sbuf2[SLAP_SN_BUFLEN];
3538 char sbuf3[SLAP_SN_BUFLEN];
3542 assert( in != NULL );
3543 assert( out != NULL );
3545 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3548 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3553 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3555 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3556 slap_sl_free( i.bv_val, ctx );
3560 return LDAP_INVALID_SYNTAX;
3563 /* Convert sn to canonical hex */
3565 if ( sn.bv_len > sizeof( sbuf2 ) ) {
3566 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3568 sn2.bv_len = sn.bv_len;
3570 sn3.bv_len = sizeof(sbuf3);
3571 if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
3572 rc = LDAP_INVALID_SYNTAX;
3576 out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3577 + sn3.bv_len + ni.bv_len;
3578 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3579 if ( out->bv_val == NULL ) {
3587 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3588 p = lutil_strbvcopy( p, &sn3 );
3589 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3590 p = lutil_strbvcopy( p, &ni );
3591 p = lutil_strcopy( p, /*{*/ "\" }" );
3593 assert( p == &out->bv_val[out->bv_len] );
3596 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3597 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3599 if ( sn2.bv_val != sbuf2 ) {
3600 slap_sl_free( sn2.bv_val, ctx );
3603 if ( sn3.bv_val != sbuf3 ) {
3604 slap_sl_free( sn3.bv_val, ctx );
3607 slap_sl_free( ni.bv_val, ctx );
3613 certificateExactNormalize(
3618 struct berval *normalized,
3621 BerElementBuffer berbuf;
3622 BerElement *ber = (BerElement *)&berbuf;
3626 char serialbuf2[SLAP_SN_BUFLEN];
3627 struct berval sn, sn2 = BER_BVNULL;
3628 struct berval issuer_dn = BER_BVNULL, bvdn;
3630 int rc = LDAP_INVALID_SYNTAX;
3632 assert( val != NULL );
3634 Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3635 val->bv_val, val->bv_len, 0 );
3637 if ( BER_BVISEMPTY( val ) ) goto done;
3639 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3640 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3643 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3645 ber_init2( ber, val, LBER_USE_DER );
3646 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3647 tag = ber_skip_tag( ber, &len ); /* Sequence */
3648 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3649 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3650 tag = ber_skip_tag( ber, &len );
3651 tag = ber_get_int( ber, &i ); /* version */
3654 /* NOTE: move the test here from certificateValidate,
3655 * so that we can validate certs with serial longer
3656 * than sizeof(ber_int_t) */
3657 tag = ber_skip_tag( ber, &len ); /* serial */
3659 sn.bv_val = (char *)ber->ber_ptr;
3660 sn2.bv_val = serialbuf2;
3661 sn2.bv_len = sizeof(serialbuf2);
3662 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3663 rc = LDAP_INVALID_SYNTAX;
3666 ber_skip_data( ber, len );
3668 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3669 ber_skip_data( ber, len );
3670 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3672 len = ber_ptrlen( ber );
3673 bvdn.bv_val = val->bv_val + len;
3674 bvdn.bv_len = val->bv_len - len;
3676 rc = dnX509normalize( &bvdn, &issuer_dn );
3677 if ( rc != LDAP_SUCCESS ) goto done;
3680 normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3681 + sn2.bv_len + issuer_dn.bv_len;
3682 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3684 p = normalized->bv_val;
3686 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3687 p = lutil_strbvcopy( p, &sn2 );
3688 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3689 p = lutil_strbvcopy( p, &issuer_dn );
3690 p = lutil_strcopy( p, /*{*/ "\" }" );
3695 Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3696 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3698 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3699 if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3704 /* X.509 PKI certificateList stuff */
3706 checkTime( struct berval *in, struct berval *out )
3710 char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3713 assert( in != NULL );
3714 assert( !BER_BVISNULL( in ) );
3715 assert( !BER_BVISEMPTY( in ) );
3717 if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3721 if ( out != NULL ) {
3722 assert( !BER_BVISNULL( out ) );
3723 assert( out->bv_len >= sizeof( buf ) );
3724 bv.bv_val = out->bv_val;
3730 for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3731 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3734 if ( in->bv_val[i] != 'Z' ) {
3739 if ( i != in->bv_len ) {
3743 if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3744 lutil_strncopy( bv.bv_val, in->bv_val, i );
3747 } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3748 char *p = bv.bv_val;
3749 if ( in->bv_val[0] < '7' ) {
3750 p = lutil_strcopy( p, "20" );
3753 p = lutil_strcopy( p, "19" );
3755 lutil_strncopy( p, in->bv_val, i );
3762 rc = generalizedTimeValidate( NULL, &bv );
3763 if ( rc == LDAP_SUCCESS && out != NULL ) {
3764 if ( out->bv_len > bv.bv_len ) {
3765 out->bv_val[ bv.bv_len ] = '\0';
3767 out->bv_len = bv.bv_len;
3770 return rc != LDAP_SUCCESS;
3774 issuerAndThisUpdateCheck(
3781 struct berval x = *in;
3782 struct berval ni = BER_BVNULL;
3783 /* Parse GSER format */
3787 HAVE_THISUPDATE = 0x2,
3788 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3792 if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3794 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3795 return LDAP_INVALID_SYNTAX;
3799 x.bv_len -= STRLENOF("{}");
3802 /* eat leading spaces */
3803 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3807 /* should be at issuer or thisUpdate */
3808 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3809 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3812 x.bv_val += STRLENOF("issuer");
3813 x.bv_len -= STRLENOF("issuer");
3815 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3819 /* eat leading spaces */
3820 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3824 /* For backward compatibility, this part is optional */
3825 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3826 return LDAP_INVALID_SYNTAX;
3828 x.bv_val += STRLENOF("rdnSequence:");
3829 x.bv_len -= STRLENOF("rdnSequence:");
3831 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3835 is->bv_val = x.bv_val;
3838 for ( ; is->bv_len < x.bv_len; ) {
3839 if ( is->bv_val[is->bv_len] != '"' ) {
3843 if ( is->bv_val[is->bv_len+1] == '"' ) {
3850 x.bv_val += is->bv_len + 1;
3851 x.bv_len -= is->bv_len + 1;
3853 have |= HAVE_ISSUER;
3855 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3857 if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3859 /* parse thisUpdate */
3860 x.bv_val += STRLENOF("thisUpdate");
3861 x.bv_len -= STRLENOF("thisUpdate");
3863 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3867 /* eat leading spaces */
3868 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3872 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3876 tu->bv_val = x.bv_val;
3879 for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3880 if ( tu->bv_val[tu->bv_len] == '"' ) {
3884 x.bv_val += tu->bv_len + 1;
3885 x.bv_len -= tu->bv_len + 1;
3887 have |= HAVE_THISUPDATE;
3890 return LDAP_INVALID_SYNTAX;
3893 /* eat leading spaces */
3894 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3898 if ( have == HAVE_ALL ) {
3902 if ( x.bv_val[0] != ',' ) {
3903 return LDAP_INVALID_SYNTAX;
3910 /* should have no characters left... */
3911 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3913 if ( numdquotes == 0 ) {
3914 ber_dupbv_x( &ni, is, ctx );
3919 ni.bv_len = is->bv_len - numdquotes;
3920 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3921 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3922 if ( is->bv_val[src] == '"' ) {
3925 ni.bv_val[dst] = is->bv_val[src];
3927 ni.bv_val[dst] = '\0';
3936 issuerAndThisUpdateValidate(
3941 struct berval i, tu;
3943 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3946 rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3951 /* validate DN -- doesn't handle double dquote */
3952 rc = dnValidate( NULL, &i );
3954 rc = LDAP_INVALID_SYNTAX;
3956 } else if ( checkTime( &tu, NULL ) ) {
3957 rc = LDAP_INVALID_SYNTAX;
3960 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3961 slap_sl_free( i.bv_val, NULL );
3964 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3965 in->bv_val, rc, 0 );
3972 issuerAndThisUpdatePretty(
3979 struct berval i, tu, ni = BER_BVNULL;
3982 assert( in != NULL );
3983 assert( out != NULL );
3987 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3990 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3995 rc = dnPretty( syntax, &i, &ni, ctx );
3997 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3998 slap_sl_free( i.bv_val, ctx );
4001 if ( rc || checkTime( &tu, NULL ) ) {
4002 rc = LDAP_INVALID_SYNTAX;
4007 out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
4008 + ni.bv_len + tu.bv_len;
4009 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4011 if ( out->bv_val == NULL ) {
4018 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4019 p = lutil_strbvcopy( p, &ni );
4020 p = lutil_strcopy( p, "\", thisUpdate \"" );
4021 p = lutil_strbvcopy( p, &tu );
4022 p = lutil_strcopy( p, /*{*/ "\" }" );
4024 assert( p == &out->bv_val[out->bv_len] );
4027 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4028 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4030 slap_sl_free( ni.bv_val, ctx );
4036 issuerAndThisUpdateNormalize(
4044 struct berval i, ni, tu, tu2;
4045 char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4049 assert( in != NULL );
4050 assert( out != NULL );
4052 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4055 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4060 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4062 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4063 slap_sl_free( i.bv_val, ctx );
4067 tu2.bv_len = sizeof( sbuf );
4068 if ( rc || checkTime( &tu, &tu2 ) ) {
4069 return LDAP_INVALID_SYNTAX;
4072 out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4073 + ni.bv_len + tu2.bv_len;
4074 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4076 if ( out->bv_val == NULL ) {
4084 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4085 p = lutil_strbvcopy( p, &ni );
4086 p = lutil_strcopy( p, "\", thisUpdate \"" );
4087 p = lutil_strbvcopy( p, &tu2 );
4088 p = lutil_strcopy( p, /*{*/ "\" }" );
4090 assert( p == &out->bv_val[out->bv_len] );
4093 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4094 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4096 slap_sl_free( ni.bv_val, ctx );
4102 certificateListExactNormalize(
4107 struct berval *normalized,
4110 BerElementBuffer berbuf;
4111 BerElement *ber = (BerElement *)&berbuf;
4115 struct berval issuer_dn = BER_BVNULL, bvdn,
4117 char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4118 int rc = LDAP_INVALID_SYNTAX;
4120 assert( val != NULL );
4122 Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4123 val->bv_val, val->bv_len, 0 );
4125 if ( BER_BVISEMPTY( val ) ) goto done;
4127 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4128 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4131 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4133 ber_init2( ber, val, LBER_USE_DER );
4134 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
4135 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4136 tag = ber_skip_tag( ber, &len ); /* Sequence */
4137 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4138 tag = ber_peek_tag( ber, &len );
4139 /* Optional version */
4140 if ( tag == LBER_INTEGER ) {
4141 tag = ber_get_int( ber, &version );
4142 assert( tag == LBER_INTEGER );
4143 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4145 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
4146 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4147 ber_skip_data( ber, len );
4149 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
4150 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4151 len = ber_ptrlen( ber );
4152 bvdn.bv_val = val->bv_val + len;
4153 bvdn.bv_len = val->bv_len - len;
4154 tag = ber_skip_tag( ber, &len );
4155 ber_skip_data( ber, len );
4157 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
4158 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4159 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4160 bvtu.bv_val = (char *)ber->ber_ptr;
4163 rc = dnX509normalize( &bvdn, &issuer_dn );
4164 if ( rc != LDAP_SUCCESS ) goto done;
4166 thisUpdate.bv_val = tubuf;
4167 thisUpdate.bv_len = sizeof(tubuf);
4168 if ( checkTime( &bvtu, &thisUpdate ) ) {
4169 rc = LDAP_INVALID_SYNTAX;
4173 normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4174 + issuer_dn.bv_len + thisUpdate.bv_len;
4175 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4177 p = normalized->bv_val;
4179 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4180 p = lutil_strbvcopy( p, &issuer_dn );
4181 p = lutil_strcopy( p, "\", thisUpdate \"" );
4182 p = lutil_strbvcopy( p, &thisUpdate );
4183 p = lutil_strcopy( p, /*{*/ "\" }" );
4188 Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4189 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4191 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4196 /* X.509 PMI serialNumberAndIssuerSerialCheck
4198 AttributeCertificateExactAssertion ::= SEQUENCE {
4199 serialNumber CertificateSerialNumber,
4200 issuer AttCertIssuer }
4202 CertificateSerialNumber ::= INTEGER
4204 AttCertIssuer ::= [0] SEQUENCE {
4205 issuerName GeneralNames OPTIONAL,
4206 baseCertificateID [0] IssuerSerial OPTIONAL,
4207 objectDigestInfo [1] ObjectDigestInfo OPTIONAL }
4208 -- At least one component shall be present
4210 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4212 GeneralName ::= CHOICE {
4213 otherName [0] INSTANCE OF OTHER-NAME,
4214 rfc822Name [1] IA5String,
4215 dNSName [2] IA5String,
4216 x400Address [3] ORAddress,
4217 directoryName [4] Name,
4218 ediPartyName [5] EDIPartyName,
4219 uniformResourceIdentifier [6] IA5String,
4220 iPAddress [7] OCTET STRING,
4221 registeredID [8] OBJECT IDENTIFIER }
4223 IssuerSerial ::= SEQUENCE {
4224 issuer GeneralNames,
4225 serial CertificateSerialNumber,
4226 issuerUID UniqueIdentifier OPTIONAL }
4228 ObjectDigestInfo ::= SEQUENCE {
4229 digestedObjectType ENUMERATED {
4232 otherObjectTypes (2) },
4233 otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
4234 digestAlgorithm AlgorithmIdentifier,
4235 objectDigest BIT STRING }
4237 * The way I interpret it, an assertion should look like
4239 { serialNumber 'dd'H,
4240 issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4241 baseCertificateID { serial '1d'H,
4242 issuer { directoryName:rdnSequence:"cn=zzz" },
4243 issuerUID <value> -- optional
4245 objectDigestInfo { ... } -- optional
4249 * with issuerName, baseCertificateID and objectDigestInfo optional,
4250 * at least one present; the way it's currently implemented, it is
4252 { serialNumber 'dd'H,
4253 issuer { baseCertificateID { serial '1d'H,
4254 issuer { directoryName:rdnSequence:"cn=zzz" }
4259 * with all the above parts mandatory.
4262 serialNumberAndIssuerSerialCheck(
4266 struct berval *i_sn, /* contain serial of baseCertificateID */
4269 /* Parse GSER format */
4274 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4275 } have = HAVE_NONE, have2 = HAVE_NONE;
4277 struct berval x = *in;
4280 if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4283 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4290 /* eat leading spaces */
4291 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4295 /* should be at issuer or serialNumber NamedValue */
4296 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4297 if ( have & HAVE_ISSUER ) {
4298 return LDAP_INVALID_SYNTAX;
4301 /* parse IssuerSerial */
4302 x.bv_val += STRLENOF("issuer");
4303 x.bv_len -= STRLENOF("issuer");
4305 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4309 /* eat leading spaces */
4310 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4314 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4318 /* eat leading spaces */
4319 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4323 if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4324 return LDAP_INVALID_SYNTAX;
4326 x.bv_val += STRLENOF("baseCertificateID ");
4327 x.bv_len -= STRLENOF("baseCertificateID ");
4329 /* eat leading spaces */
4330 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4334 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4339 /* eat leading spaces */
4340 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4344 /* parse issuer of baseCertificateID */
4345 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4346 if ( have2 & HAVE_ISSUER ) {
4347 return LDAP_INVALID_SYNTAX;
4350 x.bv_val += STRLENOF("issuer ");
4351 x.bv_len -= STRLENOF("issuer ");
4353 /* eat leading spaces */
4354 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4358 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4362 /* eat leading spaces */
4363 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4367 if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4368 return LDAP_INVALID_SYNTAX;
4370 x.bv_val += STRLENOF("directoryName:rdnSequence:");
4371 x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4373 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4377 is->bv_val = x.bv_val;
4380 for ( ; is->bv_len < x.bv_len; ) {
4381 if ( is->bv_val[is->bv_len] != '"' ) {
4385 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4392 x.bv_val += is->bv_len + 1;
4393 x.bv_len -= is->bv_len + 1;
4395 /* eat leading spaces */
4396 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4400 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4404 have2 |= HAVE_ISSUER;
4406 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4407 if ( have2 & HAVE_SN ) {
4408 return LDAP_INVALID_SYNTAX;
4411 x.bv_val += STRLENOF("serial ");
4412 x.bv_len -= STRLENOF("serial ");
4414 /* eat leading spaces */
4415 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4419 if ( checkNum( &x, i_sn ) ) {
4420 return LDAP_INVALID_SYNTAX;
4423 x.bv_val += i_sn->bv_len;
4424 x.bv_len -= i_sn->bv_len;
4429 return LDAP_INVALID_SYNTAX;
4432 /* eat leading spaces */
4433 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4437 if ( have2 == HAVE_ALL ) {
4441 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4446 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4450 /* eat leading spaces */
4451 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4455 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4459 have |= HAVE_ISSUER;
4461 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4462 if ( have & HAVE_SN ) {
4463 return LDAP_INVALID_SYNTAX;
4466 /* parse serialNumber */
4467 x.bv_val += STRLENOF("serialNumber");
4468 x.bv_len -= STRLENOF("serialNumber");
4470 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4474 /* eat leading spaces */
4475 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4479 if ( checkNum( &x, sn ) ) {
4480 return LDAP_INVALID_SYNTAX;
4483 x.bv_val += sn->bv_len;
4484 x.bv_len -= sn->bv_len;
4489 return LDAP_INVALID_SYNTAX;
4493 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4497 if ( have == HAVE_ALL ) {
4501 if ( x.bv_val[0] != ',' ) {
4502 return LDAP_INVALID_SYNTAX;
4508 /* should have no characters left... */
4509 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4511 if ( numdquotes == 0 ) {
4512 ber_dupbv_x( &ni, is, ctx );
4517 ni.bv_len = is->bv_len - numdquotes;
4518 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4519 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4520 if ( is->bv_val[src] == '"' ) {
4523 ni.bv_val[dst] = is->bv_val[src];
4525 ni.bv_val[dst] = '\0';
4530 /* need to handle double dquotes here */
4534 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4536 serialNumberAndIssuerSerialValidate(
4541 struct berval sn, i, i_sn;
4543 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4546 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4551 /* validate DN -- doesn't handle double dquote */
4552 rc = dnValidate( NULL, &i );
4554 rc = LDAP_INVALID_SYNTAX;
4557 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4558 slap_sl_free( i.bv_val, NULL );
4562 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4563 in->bv_val, rc, 0 );
4568 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4570 serialNumberAndIssuerSerialPretty(
4576 struct berval sn, i, i_sn, ni = BER_BVNULL;
4580 assert( in != NULL );
4581 assert( out != NULL );
4583 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4586 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4591 rc = dnPretty( syntax, &i, &ni, ctx );
4593 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4594 slap_sl_free( i.bv_val, ctx );
4598 rc = LDAP_INVALID_SYNTAX;
4602 /* make room from sn + "$" */
4603 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4604 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4605 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4607 if ( out->bv_val == NULL ) {
4614 p = lutil_strcopy( p, "{ serialNumber " );
4615 p = lutil_strbvcopy( p, &sn );
4616 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4617 p = lutil_strbvcopy( p, &ni );
4618 p = lutil_strcopy( p, "\" }, serial " );
4619 p = lutil_strbvcopy( p, &i_sn );
4620 p = lutil_strcopy( p, " } } }" );
4622 assert( p == &out->bv_val[out->bv_len] );
4625 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4626 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4628 slap_sl_free( ni.bv_val, ctx );
4633 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4635 * This routine is called by attributeCertificateExactNormalize
4636 * when attributeCertificateExactNormalize receives a search
4637 * string instead of a attribute certificate. This routine
4638 * checks if the search value is valid and then returns the
4642 serialNumberAndIssuerSerialNormalize(
4650 struct berval i, ni = BER_BVNULL,
4651 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4652 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4653 char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4654 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4658 assert( in != NULL );
4659 assert( out != NULL );
4661 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4664 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4669 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4671 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4672 slap_sl_free( i.bv_val, ctx );
4676 rc = LDAP_INVALID_SYNTAX;
4680 /* Convert sn to canonical hex */
4682 sn2.bv_len = sn.bv_len;
4683 if ( sn.bv_len > sizeof( sbuf2 ) ) {
4684 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4686 if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4687 rc = LDAP_INVALID_SYNTAX;
4691 /* Convert i_sn to canonical hex */
4692 i_sn2.bv_val = i_sbuf2;
4693 i_sn2.bv_len = i_sn.bv_len;
4694 if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4695 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4697 if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4698 rc = LDAP_INVALID_SYNTAX;
4703 sn3.bv_len = sizeof(sbuf3);
4704 if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4705 rc = LDAP_INVALID_SYNTAX;
4709 i_sn3.bv_val = i_sbuf3;
4710 i_sn3.bv_len = sizeof(i_sbuf3);
4711 if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4712 rc = LDAP_INVALID_SYNTAX;
4716 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4717 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4718 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4720 if ( out->bv_val == NULL ) {
4728 p = lutil_strcopy( p, "{ serialNumber " );
4729 p = lutil_strbvcopy( p, &sn3 );
4730 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4731 p = lutil_strbvcopy( p, &ni );
4732 p = lutil_strcopy( p, "\" }, serial " );
4733 p = lutil_strbvcopy( p, &i_sn3 );
4734 p = lutil_strcopy( p, " } } }" );
4736 assert( p == &out->bv_val[out->bv_len] );
4739 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4740 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4742 if ( sn2.bv_val != sbuf2 ) {
4743 slap_sl_free( sn2.bv_val, ctx );
4746 if ( i_sn2.bv_val != i_sbuf2 ) {
4747 slap_sl_free( i_sn2.bv_val, ctx );
4750 if ( sn3.bv_val != sbuf3 ) {
4751 slap_sl_free( sn3.bv_val, ctx );
4754 if ( i_sn3.bv_val != i_sbuf3 ) {
4755 slap_sl_free( i_sn3.bv_val, ctx );
4758 slap_sl_free( ni.bv_val, ctx );
4763 /* X.509 PMI attributeCertificateExactNormalize */
4765 attributeCertificateExactNormalize(
4770 struct berval *normalized,
4773 BerElementBuffer berbuf;
4774 BerElement *ber = (BerElement *)&berbuf;
4777 char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4778 struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4779 struct berval issuer_dn = BER_BVNULL, bvdn;
4781 int rc = LDAP_INVALID_SYNTAX;
4783 if ( BER_BVISEMPTY( val ) ) {
4787 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4788 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4791 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4793 ber_init2( ber, val, LBER_USE_DER );
4794 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
4795 tag = ber_skip_tag( ber, &len ); /* Sequence */
4796 tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */
4797 ber_skip_data( ber, len );
4798 tag = ber_skip_tag( ber, &len ); /* Holder Sequence */
4799 ber_skip_data( ber, len );
4802 tag = ber_skip_tag( ber, &len ); /* Sequence */
4803 /* issuerName (GeneralNames sequence; optional)? */
4804 tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */
4805 tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */
4806 tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */
4807 if ( tag != SLAP_X509_GN_DIRECTORYNAME ) {
4808 return LDAP_INVALID_SYNTAX;
4810 tag = ber_peek_tag( ber, &len ); /* sequence of RDN */
4811 len = ber_ptrlen( ber );
4812 bvdn.bv_val = val->bv_val + len;
4813 bvdn.bv_len = val->bv_len - len;
4814 rc = dnX509normalize( &bvdn, &issuer_dn );
4815 if ( rc != LDAP_SUCCESS ) goto done;
4817 tag = ber_skip_tag( ber, &len ); /* sequence of RDN */
4818 ber_skip_data( ber, len );
4819 tag = ber_skip_tag( ber, &len ); /* serial number */
4820 if ( tag != LBER_INTEGER ) {
4821 rc = LDAP_INVALID_SYNTAX;
4824 i_sn.bv_val = (char *)ber->ber_ptr;
4826 i_sn2.bv_val = issuer_serialbuf;
4827 i_sn2.bv_len = sizeof(issuer_serialbuf);
4828 if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4829 rc = LDAP_INVALID_SYNTAX;
4832 ber_skip_data( ber, len );
4834 /* issuerUID (bitstring; optional)? */
4835 /* objectDigestInfo (sequence; optional)? */
4837 tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */
4838 ber_skip_data( ber, len );
4839 tag = ber_skip_tag( ber, &len ); /* serial number */
4840 if ( tag != LBER_INTEGER ) {
4841 rc = LDAP_INVALID_SYNTAX;
4844 sn.bv_val = (char *)ber->ber_ptr;
4846 sn2.bv_val = serialbuf;
4847 sn2.bv_len = sizeof(serialbuf);
4848 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4849 rc = LDAP_INVALID_SYNTAX;
4852 ber_skip_data( ber, len );
4854 normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" )
4855 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4856 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4858 p = normalized->bv_val;
4860 p = lutil_strcopy( p, "{ serialNumber " );
4861 p = lutil_strbvcopy( p, &sn2 );
4862 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4863 p = lutil_strbvcopy( p, &issuer_dn );
4864 p = lutil_strcopy( p, "\" }, serial " );
4865 p = lutil_strbvcopy( p, &i_sn2 );
4866 p = lutil_strcopy( p, " } } }" );
4868 Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4869 normalized->bv_val, NULL, NULL );
4874 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4875 if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4876 if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4889 assert( in != NULL );
4890 assert( !BER_BVISNULL( in ) );
4892 for ( i = 0; i < in->bv_len; i++ ) {
4893 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4894 return LDAP_INVALID_SYNTAX;
4898 return LDAP_SUCCESS;
4901 /* Normalize a SID as used inside a CSN:
4902 * three-digit numeric string */
4909 struct berval *normalized,
4914 assert( val != NULL );
4915 assert( normalized != NULL );
4917 ber_dupbv_x( normalized, val, ctx );
4919 for ( i = 0; i < normalized->bv_len; i++ ) {
4920 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4921 ber_memfree_x( normalized->bv_val, ctx );
4922 BER_BVZERO( normalized );
4923 return LDAP_INVALID_SYNTAX;
4926 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4929 return LDAP_SUCCESS;
4937 assert( in != NULL );
4938 assert( !BER_BVISNULL( in ) );
4940 if ( in->bv_len != 3 ) {
4941 return LDAP_INVALID_SYNTAX;
4944 return hexValidate( NULL, in );
4947 /* Normalize a SID as used inside a CSN:
4948 * three-digit numeric string */
4955 struct berval *normalized,
4958 if ( val->bv_len != 3 ) {
4959 return LDAP_INVALID_SYNTAX;
4962 return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4972 return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4975 /* Normalize a SID as used inside a CSN, either as-is
4976 * (assertion value) or extracted from the CSN
4977 * (attribute value) */
4984 struct berval *normalized,
4992 if ( BER_BVISEMPTY( val ) ) {
4993 return LDAP_INVALID_SYNTAX;
4996 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4997 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
5000 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
5002 ptr = ber_bvchr( val, '#' );
5003 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5004 return LDAP_INVALID_SYNTAX;
5007 bv.bv_val = ptr + 1;
5008 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5010 ptr = ber_bvchr( &bv, '#' );
5011 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5012 return LDAP_INVALID_SYNTAX;
5015 bv.bv_val = ptr + 1;
5016 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5018 ptr = ber_bvchr( &bv, '#' );
5019 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5020 return LDAP_INVALID_SYNTAX;
5023 bv.bv_len = ptr - bv.bv_val;
5025 if ( bv.bv_len == 2 ) {
5026 /* OpenLDAP 2.3 SID */
5028 buf[ 1 ] = bv.bv_val[ 0 ];
5029 buf[ 2 ] = bv.bv_val[ 1 ];
5036 return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5048 assert( in != NULL );
5049 assert( !BER_BVISNULL( in ) );
5051 if ( BER_BVISEMPTY( in ) ) {
5052 return LDAP_INVALID_SYNTAX;
5057 ptr = ber_bvchr( &bv, '#' );
5058 if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5059 return LDAP_INVALID_SYNTAX;
5062 bv.bv_len = ptr - bv.bv_val;
5063 if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5064 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5066 return LDAP_INVALID_SYNTAX;
5069 rc = generalizedTimeValidate( NULL, &bv );
5070 if ( rc != LDAP_SUCCESS ) {
5074 bv.bv_val = ptr + 1;
5075 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5077 ptr = ber_bvchr( &bv, '#' );
5078 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5079 return LDAP_INVALID_SYNTAX;
5082 bv.bv_len = ptr - bv.bv_val;
5083 if ( bv.bv_len != 6 ) {
5084 return LDAP_INVALID_SYNTAX;
5087 rc = hexValidate( NULL, &bv );
5088 if ( rc != LDAP_SUCCESS ) {
5092 bv.bv_val = ptr + 1;
5093 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5095 ptr = ber_bvchr( &bv, '#' );
5096 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5097 return LDAP_INVALID_SYNTAX;
5100 bv.bv_len = ptr - bv.bv_val;
5101 if ( bv.bv_len == 2 ) {
5102 /* tolerate old 2-digit replica-id */
5103 rc = hexValidate( NULL, &bv );
5106 rc = sidValidate( NULL, &bv );
5108 if ( rc != LDAP_SUCCESS ) {
5112 bv.bv_val = ptr + 1;
5113 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5115 if ( bv.bv_len != 6 ) {
5116 return LDAP_INVALID_SYNTAX;
5119 return hexValidate( NULL, &bv );
5122 /* Normalize a CSN in OpenLDAP 2.1 format */
5129 struct berval *normalized,
5132 struct berval gt, cnt, sid, mod;
5134 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5138 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5139 assert( !BER_BVISEMPTY( val ) );
5143 ptr = ber_bvchr( >, '#' );
5144 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5145 return LDAP_INVALID_SYNTAX;
5148 gt.bv_len = ptr - gt.bv_val;
5149 if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5150 return LDAP_INVALID_SYNTAX;
5153 if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5154 return LDAP_INVALID_SYNTAX;
5157 cnt.bv_val = ptr + 1;
5158 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5160 ptr = ber_bvchr( &cnt, '#' );
5161 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5162 return LDAP_INVALID_SYNTAX;
5165 cnt.bv_len = ptr - cnt.bv_val;
5166 if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5167 return LDAP_INVALID_SYNTAX;
5170 if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5171 return LDAP_INVALID_SYNTAX;
5174 cnt.bv_val += STRLENOF( "0x" );
5175 cnt.bv_len -= STRLENOF( "0x" );
5177 sid.bv_val = ptr + 1;
5178 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5180 ptr = ber_bvchr( &sid, '#' );
5181 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5182 return LDAP_INVALID_SYNTAX;
5185 sid.bv_len = ptr - sid.bv_val;
5186 if ( sid.bv_len != STRLENOF( "0" ) ) {
5187 return LDAP_INVALID_SYNTAX;
5190 mod.bv_val = ptr + 1;
5191 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5192 if ( mod.bv_len != STRLENOF( "0000" ) ) {
5193 return LDAP_INVALID_SYNTAX;
5196 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5200 ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5201 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5203 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5205 ptr = lutil_strcopy( ptr, ".000000Z#00" );
5206 ptr = lutil_strbvcopy( ptr, &cnt );
5210 *ptr++ = sid.bv_val[ 0 ];
5214 for ( i = 0; i < mod.bv_len; i++ ) {
5215 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5219 assert( ptr == &bv.bv_val[bv.bv_len] );
5221 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5222 return LDAP_INVALID_SYNTAX;
5225 ber_dupbv_x( normalized, &bv, ctx );
5227 return LDAP_SUCCESS;
5230 /* Normalize a CSN in OpenLDAP 2.3 format */
5237 struct berval *normalized,
5240 struct berval gt, cnt, sid, mod;
5242 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5246 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5247 assert( !BER_BVISEMPTY( val ) );
5251 ptr = ber_bvchr( >, '#' );
5252 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5253 return LDAP_INVALID_SYNTAX;
5256 gt.bv_len = ptr - gt.bv_val;
5257 if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5258 return LDAP_INVALID_SYNTAX;
5261 cnt.bv_val = ptr + 1;
5262 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5264 ptr = ber_bvchr( &cnt, '#' );
5265 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5266 return LDAP_INVALID_SYNTAX;
5269 cnt.bv_len = ptr - cnt.bv_val;
5270 if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5271 return LDAP_INVALID_SYNTAX;
5274 sid.bv_val = ptr + 1;
5275 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5277 ptr = ber_bvchr( &sid, '#' );
5278 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5279 return LDAP_INVALID_SYNTAX;
5282 sid.bv_len = ptr - sid.bv_val;
5283 if ( sid.bv_len != STRLENOF( "00" ) ) {
5284 return LDAP_INVALID_SYNTAX;
5287 mod.bv_val = ptr + 1;
5288 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5289 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5290 return LDAP_INVALID_SYNTAX;
5293 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5297 ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5298 ptr = lutil_strcopy( ptr, ".000000Z#" );
5299 ptr = lutil_strbvcopy( ptr, &cnt );
5302 for ( i = 0; i < sid.bv_len; i++ ) {
5303 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5306 for ( i = 0; i < mod.bv_len; i++ ) {
5307 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5311 assert( ptr == &bv.bv_val[bv.bv_len] );
5312 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5313 return LDAP_INVALID_SYNTAX;
5316 ber_dupbv_x( normalized, &bv, ctx );
5318 return LDAP_SUCCESS;
5321 /* Normalize a CSN */
5328 struct berval *normalized,
5331 struct berval cnt, sid, mod;
5335 assert( val != NULL );
5336 assert( normalized != NULL );
5338 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5340 if ( BER_BVISEMPTY( val ) ) {
5341 return LDAP_INVALID_SYNTAX;
5344 if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5345 /* Openldap <= 2.3 */
5347 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5350 if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5353 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5356 if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5357 return LDAP_INVALID_SYNTAX;
5360 ptr = ber_bvchr( val, '#' );
5361 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5362 return LDAP_INVALID_SYNTAX;
5365 if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5366 return LDAP_INVALID_SYNTAX;
5369 cnt.bv_val = ptr + 1;
5370 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5372 ptr = ber_bvchr( &cnt, '#' );
5373 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5374 return LDAP_INVALID_SYNTAX;
5377 if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5378 return LDAP_INVALID_SYNTAX;
5381 sid.bv_val = ptr + 1;
5382 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5384 ptr = ber_bvchr( &sid, '#' );
5385 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5386 return LDAP_INVALID_SYNTAX;
5389 sid.bv_len = ptr - sid.bv_val;
5390 if ( sid.bv_len != STRLENOF( "000" ) ) {
5391 return LDAP_INVALID_SYNTAX;
5394 mod.bv_val = ptr + 1;
5395 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5397 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5398 return LDAP_INVALID_SYNTAX;
5401 ber_dupbv_x( normalized, val, ctx );
5403 for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5404 i < normalized->bv_len; i++ )
5406 /* assume it's already validated that's all hex digits */
5407 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5410 return LDAP_SUCCESS;
5420 return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5423 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5424 /* slight optimization - does not need the start parameter */
5425 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5430 check_time_syntax (struct berval *val,
5433 struct berval *fraction)
5436 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5437 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
5438 * GeneralizedTime supports leap seconds, UTCTime does not.
5440 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5441 static const int mdays[2][12] = {
5442 /* non-leap years */
5443 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5445 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5448 int part, c, c1, c2, tzoffset, leapyear = 0;
5451 e = p + val->bv_len;
5453 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5454 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5456 for (part = start; part < 7 && p < e; part++) {
5458 if (!ASCII_DIGIT(c1)) {
5463 return LDAP_INVALID_SYNTAX;
5466 if (!ASCII_DIGIT(c)) {
5467 return LDAP_INVALID_SYNTAX;
5469 c += c1 * 10 - '0' * 11;
5470 if ((part | 1) == 3) {
5473 return LDAP_INVALID_SYNTAX;
5476 if (c >= ceiling[part]) {
5477 if (! (c == 60 && part == 6 && start == 0))
5478 return LDAP_INVALID_SYNTAX;
5482 if (part < 5 + start) {
5483 return LDAP_INVALID_SYNTAX;
5485 for (; part < 9; part++) {
5489 /* leapyear check for the Gregorian calendar (year>1581) */
5490 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5494 if (parts[3] >= mdays[leapyear][parts[2]]) {
5495 return LDAP_INVALID_SYNTAX;
5499 fraction->bv_val = p;
5500 fraction->bv_len = 0;
5501 if (p < e && (*p == '.' || *p == ',')) {
5503 while (++p < e && ASCII_DIGIT(*p)) {
5506 if (p - fraction->bv_val == 1) {
5507 return LDAP_INVALID_SYNTAX;
5509 for (end_num = p; end_num[-1] == '0'; --end_num) {
5512 c = end_num - fraction->bv_val;
5513 if (c != 1) fraction->bv_len = c;
5519 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5525 return LDAP_INVALID_SYNTAX;
5531 for (part = 7; part < 9 && p < e; part++) {
5533 if (!ASCII_DIGIT(c1)) {
5538 return LDAP_INVALID_SYNTAX;
5541 if (!ASCII_DIGIT(c2)) {
5542 return LDAP_INVALID_SYNTAX;
5544 parts[part] = c1 * 10 + c2 - '0' * 11;
5545 if (parts[part] >= ceiling[part]) {
5546 return LDAP_INVALID_SYNTAX;
5549 if (part < 8 + start) {
5550 return LDAP_INVALID_SYNTAX;
5553 if (tzoffset == '-') {
5554 /* negative offset to UTC, ie west of Greenwich */
5555 parts[4] += parts[7];
5556 parts[5] += parts[8];
5557 /* offset is just hhmm, no seconds */
5558 for (part = 6; --part >= 0; ) {
5562 c = mdays[leapyear][parts[2]];
5564 if (parts[part] >= c) {
5566 return LDAP_INVALID_SYNTAX;
5571 } else if (part != 5) {
5576 /* positive offset to UTC, ie east of Greenwich */
5577 parts[4] -= parts[7];
5578 parts[5] -= parts[8];
5579 for (part = 6; --part >= 0; ) {
5580 if (parts[part] < 0) {
5582 return LDAP_INVALID_SYNTAX;
5587 /* make first arg to % non-negative */
5588 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5593 } else if (part != 5) {
5600 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5603 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5610 struct berval *normalized )
5614 rc = check_time_syntax(val, 1, parts, NULL);
5615 if (rc != LDAP_SUCCESS) {
5619 normalized->bv_val = ch_malloc( 14 );
5620 if ( normalized->bv_val == NULL ) {
5621 return LBER_ERROR_MEMORY;
5624 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5625 parts[1], parts[2] + 1, parts[3] + 1,
5626 parts[4], parts[5], parts[6] );
5627 normalized->bv_len = 13;
5629 return LDAP_SUCCESS;
5639 return check_time_syntax(in, 1, parts, NULL);
5642 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5645 generalizedTimeValidate(
5650 struct berval fraction;
5651 return check_time_syntax(in, 0, parts, &fraction);
5655 generalizedTimeNormalize(
5660 struct berval *normalized,
5665 struct berval fraction;
5667 rc = check_time_syntax(val, 0, parts, &fraction);
5668 if (rc != LDAP_SUCCESS) {
5672 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5673 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5674 if ( BER_BVISNULL( normalized ) ) {
5675 return LBER_ERROR_MEMORY;
5678 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5679 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5680 parts[4], parts[5], parts[6] );
5681 if ( !BER_BVISEMPTY( &fraction ) ) {
5682 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5683 fraction.bv_val, fraction.bv_len );
5684 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5686 strcpy( normalized->bv_val + len-1, "Z" );
5687 normalized->bv_len = len;
5689 return LDAP_SUCCESS;
5693 generalizedTimeOrderingMatch(
5698 struct berval *value,
5699 void *assertedValue )
5701 struct berval *asserted = (struct berval *) assertedValue;
5702 ber_len_t v_len = value->bv_len;
5703 ber_len_t av_len = asserted->bv_len;
5705 /* ignore trailing 'Z' when comparing */
5706 int match = memcmp( value->bv_val, asserted->bv_val,
5707 (v_len < av_len ? v_len : av_len) - 1 );
5708 if ( match == 0 ) match = v_len - av_len;
5710 /* If used in extensible match filter, match if value < asserted */
5711 if ( flags & SLAP_MR_EXT )
5712 match = (match >= 0);
5715 return LDAP_SUCCESS;
5718 /* Index generation function: Ordered index */
5719 int generalizedTimeIndexer(
5724 struct berval *prefix,
5732 BerValue bvtmp; /* 40 bit index */
5734 struct lutil_timet tt;
5736 bvtmp.bv_len = sizeof(tmp);
5738 for( i=0; values[i].bv_val != NULL; i++ ) {
5739 /* just count them */
5742 /* we should have at least one value at this point */
5745 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5747 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5748 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5749 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5750 /* Use 40 bits of time for key */
5751 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5752 lutil_tm2time( &tm, &tt );
5753 tmp[0] = tt.tt_gsec & 0xff;
5754 tmp[4] = tt.tt_sec & 0xff;
5756 tmp[3] = tt.tt_sec & 0xff;
5758 tmp[2] = tt.tt_sec & 0xff;
5760 tmp[1] = tt.tt_sec & 0xff;
5762 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5766 keys[j].bv_val = NULL;
5771 return LDAP_SUCCESS;
5774 /* Index generation function: Ordered index */
5775 int generalizedTimeFilter(
5780 struct berval *prefix,
5781 void * assertedValue,
5787 BerValue bvtmp; /* 40 bit index */
5788 BerValue *value = (BerValue *) assertedValue;
5790 struct lutil_timet tt;
5792 bvtmp.bv_len = sizeof(tmp);
5794 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5795 /* Use 40 bits of time for key */
5796 if ( value->bv_val && value->bv_len >= 10 &&
5797 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5799 lutil_tm2time( &tm, &tt );
5800 tmp[0] = tt.tt_gsec & 0xff;
5801 tmp[4] = tt.tt_sec & 0xff;
5803 tmp[3] = tt.tt_sec & 0xff;
5805 tmp[2] = tt.tt_sec & 0xff;
5807 tmp[1] = tt.tt_sec & 0xff;
5809 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5810 ber_dupbv_x(keys, &bvtmp, ctx );
5811 keys[1].bv_val = NULL;
5819 return LDAP_SUCCESS;
5823 deliveryMethodValidate(
5825 struct berval *val )
5828 #define LENOF(s) (sizeof(s)-1)
5829 struct berval tmp = *val;
5831 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5832 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5833 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5836 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5838 switch( tmp.bv_val[0] ) {
5841 if(( tmp.bv_len >= LENOF("any") ) &&
5842 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5844 tmp.bv_len -= LENOF("any");
5845 tmp.bv_val += LENOF("any");
5848 return LDAP_INVALID_SYNTAX;
5852 if(( tmp.bv_len >= LENOF("mhs") ) &&
5853 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5855 tmp.bv_len -= LENOF("mhs");
5856 tmp.bv_val += LENOF("mhs");
5859 return LDAP_INVALID_SYNTAX;
5863 if(( tmp.bv_len >= LENOF("physical") ) &&
5864 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5866 tmp.bv_len -= LENOF("physical");
5867 tmp.bv_val += LENOF("physical");
5870 return LDAP_INVALID_SYNTAX;
5873 case 'T': /* telex or teletex or telephone */
5874 if(( tmp.bv_len >= LENOF("telex") ) &&
5875 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5877 tmp.bv_len -= LENOF("telex");
5878 tmp.bv_val += LENOF("telex");
5881 if(( tmp.bv_len >= LENOF("teletex") ) &&
5882 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5884 tmp.bv_len -= LENOF("teletex");
5885 tmp.bv_val += LENOF("teletex");
5888 if(( tmp.bv_len >= LENOF("telephone") ) &&
5889 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5891 tmp.bv_len -= LENOF("telephone");
5892 tmp.bv_val += LENOF("telephone");
5895 return LDAP_INVALID_SYNTAX;
5898 case 'G': /* g3fax or g4fax */
5899 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5900 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5901 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5903 tmp.bv_len -= LENOF("g3fax");
5904 tmp.bv_val += LENOF("g3fax");
5907 return LDAP_INVALID_SYNTAX;
5911 if(( tmp.bv_len >= LENOF("ia5") ) &&
5912 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5914 tmp.bv_len -= LENOF("ia5");
5915 tmp.bv_val += LENOF("ia5");
5918 return LDAP_INVALID_SYNTAX;
5922 if(( tmp.bv_len >= LENOF("videotex") ) &&
5923 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5925 tmp.bv_len -= LENOF("videotex");
5926 tmp.bv_val += LENOF("videotex");
5929 return LDAP_INVALID_SYNTAX;
5932 return LDAP_INVALID_SYNTAX;
5935 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
5937 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5941 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
5945 return LDAP_INVALID_SYNTAX;
5947 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5956 nisNetgroupTripleValidate(
5958 struct berval *val )
5963 if ( BER_BVISEMPTY( val ) ) {
5964 return LDAP_INVALID_SYNTAX;
5967 p = (char *)val->bv_val;
5968 e = p + val->bv_len;
5970 if ( *p != '(' /*')'*/ ) {
5971 return LDAP_INVALID_SYNTAX;
5974 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5978 return LDAP_INVALID_SYNTAX;
5981 } else if ( !AD_CHAR( *p ) ) {
5982 return LDAP_INVALID_SYNTAX;
5986 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5987 return LDAP_INVALID_SYNTAX;
5993 return LDAP_INVALID_SYNTAX;
5996 return LDAP_SUCCESS;
6000 bootParameterValidate(
6002 struct berval *val )
6006 if ( BER_BVISEMPTY( val ) ) {
6007 return LDAP_INVALID_SYNTAX;
6010 p = (char *)val->bv_val;
6011 e = p + val->bv_len;
6014 for (; ( p < e ) && ( *p != '=' ); p++ ) {
6015 if ( !AD_CHAR( *p ) ) {
6016 return LDAP_INVALID_SYNTAX;
6021 return LDAP_INVALID_SYNTAX;
6025 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6026 if ( !AD_CHAR( *p ) ) {
6027 return LDAP_INVALID_SYNTAX;
6032 return LDAP_INVALID_SYNTAX;
6036 for ( p++; p < e; p++ ) {
6037 if ( !SLAP_PRINTABLE( *p ) ) {
6038 return LDAP_INVALID_SYNTAX;
6042 return LDAP_SUCCESS;
6046 firstComponentNormalize(
6051 struct berval *normalized,
6058 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6059 ber_dupbv_x( normalized, val, ctx );
6060 return LDAP_SUCCESS;
6063 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6065 if( ! ( val->bv_val[0] == '(' /*')'*/
6066 && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6067 && ! ( val->bv_val[0] == '{' /*'}'*/
6068 && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6070 return LDAP_INVALID_SYNTAX;
6073 /* trim leading white space */
6075 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6081 /* grab next word */
6082 comp.bv_val = &val->bv_val[len];
6083 len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6084 for( comp.bv_len = 0;
6085 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6091 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6092 rc = numericoidValidate( NULL, &comp );
6093 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6094 rc = integerValidate( NULL, &comp );
6096 rc = LDAP_INVALID_SYNTAX;
6100 if( rc == LDAP_SUCCESS ) {
6101 ber_dupbv_x( normalized, &comp, ctx );
6107 static char *country_gen_syn[] = {
6108 "1.3.6.1.4.1.1466.115.121.1.15", /* Directory String */
6109 "1.3.6.1.4.1.1466.115.121.1.26", /* IA5 String */
6110 "1.3.6.1.4.1.1466.115.121.1.44", /* Printable String */
6114 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6115 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6117 static slap_syntax_defs_rec syntax_defs[] = {
6118 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6119 X_BINARY X_NOT_H_R ")",
6120 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6121 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6122 0, NULL, NULL, NULL},
6123 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6124 0, NULL, NULL, NULL},
6125 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6127 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6128 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6130 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6131 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6132 0, NULL, bitStringValidate, NULL },
6133 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6134 0, NULL, booleanValidate, NULL},
6135 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6136 X_BINARY X_NOT_H_R ")",
6137 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6138 NULL, certificateValidate, NULL},
6139 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6140 X_BINARY X_NOT_H_R ")",
6141 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6142 NULL, certificateListValidate, NULL},
6143 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6144 X_BINARY X_NOT_H_R ")",
6145 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6146 NULL, sequenceValidate, NULL},
6147 {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6148 X_BINARY X_NOT_H_R ")",
6149 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6150 NULL, attributeCertificateValidate, NULL},
6151 #if 0 /* need to go __after__ printableString */
6152 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6153 0, "1.3.6.1.4.1.1466.115.121.1.44",
6154 countryStringValidate, NULL},
6156 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6157 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6158 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6159 0, NULL, rdnValidate, rdnPretty},
6160 #ifdef LDAP_COMP_MATCH
6161 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6162 0, NULL, allComponentsValidate, NULL},
6163 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6164 0, NULL, componentFilterValidate, NULL},
6166 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6167 0, NULL, NULL, NULL},
6168 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6169 0, NULL, deliveryMethodValidate, NULL},
6170 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6171 0, NULL, UTF8StringValidate, NULL},
6172 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6173 0, NULL, NULL, NULL},
6174 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6175 0, NULL, NULL, NULL},
6176 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6177 0, NULL, NULL, NULL},
6178 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6179 0, NULL, NULL, NULL},
6180 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6181 0, NULL, NULL, NULL},
6182 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6183 0, NULL, printablesStringValidate, NULL},
6184 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6185 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6186 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6187 0, NULL, generalizedTimeValidate, NULL},
6188 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6189 0, NULL, NULL, NULL},
6190 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6191 0, NULL, IA5StringValidate, NULL},
6192 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6193 0, NULL, integerValidate, NULL},
6194 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6195 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6196 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6197 0, NULL, NULL, NULL},
6198 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6199 0, NULL, NULL, NULL},
6200 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6201 0, NULL, NULL, NULL},
6202 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6203 0, NULL, NULL, NULL},
6204 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6205 0, NULL, NULL, NULL},
6206 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6207 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6208 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6209 0, NULL, NULL, NULL},
6210 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6211 0, NULL, numericStringValidate, NULL},
6212 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6213 0, NULL, NULL, NULL},
6214 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6215 0, NULL, numericoidValidate, NULL},
6216 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6217 0, NULL, IA5StringValidate, NULL},
6218 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6219 0, NULL, blobValidate, NULL},
6220 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6221 0, NULL, postalAddressValidate, NULL},
6222 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6223 0, NULL, NULL, NULL},
6224 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6225 0, NULL, NULL, NULL},
6226 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6227 0, NULL, printableStringValidate, NULL},
6228 /* moved here because now depends on Directory String, IA5 String
6229 * and Printable String */
6230 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6231 0, country_gen_syn, countryStringValidate, NULL},
6232 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6233 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6234 0, NULL, subtreeSpecificationValidate, NULL},
6235 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6236 X_BINARY X_NOT_H_R ")",
6237 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6238 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6239 0, NULL, printableStringValidate, NULL},
6240 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6241 0, NULL, NULL, NULL},
6242 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6243 0, NULL, printablesStringValidate, NULL},
6244 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6245 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6246 0, NULL, utcTimeValidate, NULL},
6248 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6249 0, NULL, NULL, NULL},
6250 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6251 0, NULL, NULL, NULL},
6252 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6253 0, NULL, NULL, NULL},
6254 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6255 0, NULL, NULL, NULL},
6256 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6257 0, NULL, NULL, NULL},
6259 /* RFC 2307 NIS Syntaxes */
6260 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
6261 0, NULL, nisNetgroupTripleValidate, NULL},
6262 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
6263 0, NULL, bootParameterValidate, NULL},
6265 /* draft-zeilenga-ldap-x509 */
6266 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6267 SLAP_SYNTAX_HIDE, NULL,
6268 serialNumberAndIssuerValidate,
6269 serialNumberAndIssuerPretty},
6270 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6271 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6272 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6273 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6274 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6275 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6276 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6277 SLAP_SYNTAX_HIDE, NULL,
6278 issuerAndThisUpdateValidate,
6279 issuerAndThisUpdatePretty},
6280 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6281 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6282 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6283 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6284 {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6285 SLAP_SYNTAX_HIDE, NULL,
6286 serialNumberAndIssuerSerialValidate,
6287 serialNumberAndIssuerSerialPretty},
6288 {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6289 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6291 #ifdef SLAPD_AUTHPASSWD
6292 /* needs updating */
6293 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6294 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6297 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6298 0, NULL, UUIDValidate, UUIDPretty},
6300 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6301 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6303 {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6304 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6306 /* OpenLDAP Void Syntax */
6307 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6308 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6310 /* FIXME: OID is unused, but not registered yet */
6311 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6312 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6314 {NULL, 0, NULL, NULL, NULL}
6317 char *csnSIDMatchSyntaxes[] = {
6318 "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6321 char *certificateExactMatchSyntaxes[] = {
6322 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6325 char *certificateListExactMatchSyntaxes[] = {
6326 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6329 char *attributeCertificateExactMatchSyntaxes[] = {
6330 attributeCertificateSyntaxOID /* attributeCertificate */,
6334 #ifdef LDAP_COMP_MATCH
6335 char *componentFilterMatchSyntaxes[] = {
6336 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6337 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6338 attributeCertificateSyntaxOID /* attributeCertificate */,
6343 char *directoryStringSyntaxes[] = {
6344 "1.3.6.1.4.1.1466.115.121.1.11" /* countryString */,
6345 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6346 "1.3.6.1.4.1.1466.115.121.1.50" /* telephoneNumber */,
6349 char *integerFirstComponentMatchSyntaxes[] = {
6350 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6351 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6354 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6355 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6356 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
6357 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6358 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6359 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6360 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6361 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6362 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6367 * Other matching rules in X.520 that we do not use (yet):
6369 * 2.5.13.25 uTCTimeMatch
6370 * 2.5.13.26 uTCTimeOrderingMatch
6371 * 2.5.13.31* directoryStringFirstComponentMatch
6372 * 2.5.13.32* wordMatch
6373 * 2.5.13.33* keywordMatch
6374 * 2.5.13.36+ certificatePairExactMatch
6375 * 2.5.13.37+ certificatePairMatch
6376 * 2.5.13.40+ algorithmIdentifierMatch
6377 * 2.5.13.41* storedPrefixMatch
6378 * 2.5.13.42 attributeCertificateMatch
6379 * 2.5.13.43 readerAndKeyIDMatch
6380 * 2.5.13.44 attributeIntegrityMatch
6382 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6383 * (+) described in draft-zeilenga-ldap-x509
6385 static slap_mrule_defs_rec mrule_defs[] = {
6387 * EQUALITY matching rules must be listed after associated APPROX
6388 * matching rules. So, we list all APPROX matching rules first.
6390 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6391 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6392 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6393 NULL, NULL, directoryStringApproxMatch,
6394 directoryStringApproxIndexer, directoryStringApproxFilter,
6397 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6398 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6399 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6400 NULL, NULL, IA5StringApproxMatch,
6401 IA5StringApproxIndexer, IA5StringApproxFilter,
6405 * Other matching rules
6408 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6409 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6410 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6411 NULL, NULL, octetStringMatch,
6412 octetStringIndexer, octetStringFilter,
6415 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6416 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6417 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6418 NULL, dnNormalize, dnMatch,
6419 octetStringIndexer, octetStringFilter,
6422 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6423 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6424 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6425 NULL, dnNormalize, dnRelativeMatch,
6429 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6430 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6431 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6432 NULL, dnNormalize, dnRelativeMatch,
6436 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6437 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6438 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6439 NULL, dnNormalize, dnRelativeMatch,
6443 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6444 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6445 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6446 NULL, dnNormalize, dnRelativeMatch,
6450 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6451 "SYNTAX 1.2.36.79672281.1.5.0 )",
6452 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6453 NULL, rdnNormalize, rdnMatch,
6454 octetStringIndexer, octetStringFilter,
6457 #ifdef LDAP_COMP_MATCH
6458 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6459 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6460 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6461 NULL, NULL , componentFilterMatch,
6462 octetStringIndexer, octetStringFilter,
6465 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6466 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6467 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6468 NULL, NULL , allComponentsMatch,
6469 octetStringIndexer, octetStringFilter,
6472 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6473 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6474 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6475 NULL, NULL , directoryComponentsMatch,
6476 octetStringIndexer, octetStringFilter,
6480 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6481 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6482 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6483 NULL, UTF8StringNormalize, octetStringMatch,
6484 octetStringIndexer, octetStringFilter,
6485 directoryStringApproxMatchOID },
6487 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6488 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6489 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6490 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6492 "caseIgnoreMatch" },
6494 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6495 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6496 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6497 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6498 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6499 "caseIgnoreMatch" },
6501 {"( 2.5.13.5 NAME 'caseExactMatch' "
6502 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6503 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6504 NULL, UTF8StringNormalize, octetStringMatch,
6505 octetStringIndexer, octetStringFilter,
6506 directoryStringApproxMatchOID },
6508 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6509 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6510 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6511 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6515 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6516 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6517 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6518 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6519 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6522 {"( 2.5.13.8 NAME 'numericStringMatch' "
6523 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6524 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6525 NULL, numericStringNormalize, octetStringMatch,
6526 octetStringIndexer, octetStringFilter,
6529 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6530 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6531 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6532 NULL, numericStringNormalize, octetStringOrderingMatch,
6534 "numericStringMatch" },
6536 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6537 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6538 SLAP_MR_SUBSTR, NULL,
6539 NULL, numericStringNormalize, octetStringSubstringsMatch,
6540 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6541 "numericStringMatch" },
6543 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6544 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6545 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6546 NULL, postalAddressNormalize, octetStringMatch,
6547 octetStringIndexer, octetStringFilter,
6550 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6551 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6552 SLAP_MR_SUBSTR, NULL,
6553 NULL, NULL, NULL, NULL, NULL,
6554 "caseIgnoreListMatch" },
6556 {"( 2.5.13.13 NAME 'booleanMatch' "
6557 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6558 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6559 NULL, NULL, booleanMatch,
6560 octetStringIndexer, octetStringFilter,
6563 {"( 2.5.13.14 NAME 'integerMatch' "
6564 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6565 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6566 NULL, NULL, integerMatch,
6567 integerIndexer, integerFilter,
6570 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6571 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6572 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6573 NULL, NULL, integerMatch,
6577 {"( 2.5.13.16 NAME 'bitStringMatch' "
6578 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6579 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6580 NULL, NULL, octetStringMatch,
6581 octetStringIndexer, octetStringFilter,
6584 {"( 2.5.13.17 NAME 'octetStringMatch' "
6585 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6586 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6587 NULL, NULL, octetStringMatch,
6588 octetStringIndexer, octetStringFilter,
6591 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6592 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6593 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6594 NULL, NULL, octetStringOrderingMatch,
6596 "octetStringMatch" },
6598 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6599 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6600 SLAP_MR_SUBSTR, NULL,
6601 NULL, NULL, octetStringSubstringsMatch,
6602 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6603 "octetStringMatch" },
6605 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6606 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6607 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6609 telephoneNumberNormalize, octetStringMatch,
6610 octetStringIndexer, octetStringFilter,
6613 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6614 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6615 SLAP_MR_SUBSTR, NULL,
6616 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6617 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6618 "telephoneNumberMatch" },
6620 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6621 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6622 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6623 NULL, NULL, NULL, NULL, NULL, NULL },
6625 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6626 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6627 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6628 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6629 uniqueMemberIndexer, uniqueMemberFilter,
6632 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6633 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6634 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6635 NULL, NULL, NULL, NULL, NULL, NULL },
6637 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6638 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6639 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6640 NULL, generalizedTimeNormalize, octetStringMatch,
6641 generalizedTimeIndexer, generalizedTimeFilter,
6644 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6645 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6646 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6647 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6649 "generalizedTimeMatch" },
6651 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6652 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6653 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6654 integerFirstComponentMatchSyntaxes,
6655 NULL, firstComponentNormalize, integerMatch,
6656 octetStringIndexer, octetStringFilter,
6659 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6660 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6661 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6662 objectIdentifierFirstComponentMatchSyntaxes,
6663 NULL, firstComponentNormalize, octetStringMatch,
6664 octetStringIndexer, octetStringFilter,
6667 {"( 2.5.13.34 NAME 'certificateExactMatch' "
6668 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6669 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6670 NULL, certificateExactNormalize, octetStringMatch,
6671 octetStringIndexer, octetStringFilter,
6674 {"( 2.5.13.35 NAME 'certificateMatch' "
6675 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6676 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6677 NULL, NULL, NULL, NULL, NULL,
6680 {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6681 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6682 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6683 NULL, certificateListExactNormalize, octetStringMatch,
6684 octetStringIndexer, octetStringFilter,
6687 {"( 2.5.13.39 NAME 'certificateListMatch' "
6688 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6689 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6690 NULL, NULL, NULL, NULL, NULL,
6693 {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6694 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6695 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6696 NULL, attributeCertificateExactNormalize, octetStringMatch,
6697 octetStringIndexer, octetStringFilter,
6700 {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6701 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6702 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6703 NULL, NULL, NULL, NULL, NULL,
6706 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6707 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6708 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6709 NULL, IA5StringNormalize, octetStringMatch,
6710 octetStringIndexer, octetStringFilter,
6711 IA5StringApproxMatchOID },
6713 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6714 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6715 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6716 NULL, IA5StringNormalize, octetStringMatch,
6717 octetStringIndexer, octetStringFilter,
6718 IA5StringApproxMatchOID },
6720 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6721 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6722 SLAP_MR_SUBSTR, NULL,
6723 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6724 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6725 "caseIgnoreIA5Match" },
6727 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6728 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6729 SLAP_MR_SUBSTR, NULL,
6730 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6731 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6732 "caseExactIA5Match" },
6734 #ifdef SLAPD_AUTHPASSWD
6735 /* needs updating */
6736 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6737 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6738 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6739 NULL, NULL, authPasswordMatch,
6744 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6745 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6747 NULL, NULL, integerBitAndMatch,
6751 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6752 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6754 NULL, NULL, integerBitOrMatch,
6758 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6759 "SYNTAX 1.3.6.1.1.16.1 )",
6760 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6761 NULL, UUIDNormalize, octetStringMatch,
6762 octetStringIndexer, octetStringFilter,
6765 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6766 "SYNTAX 1.3.6.1.1.16.1 )",
6767 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6768 NULL, UUIDNormalize, octetStringOrderingMatch,
6769 octetStringIndexer, octetStringFilter,
6772 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6773 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6774 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6775 NULL, csnNormalize, csnMatch,
6776 csnIndexer, csnFilter,
6779 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6780 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6781 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6782 NULL, csnNormalize, csnOrderingMatch,
6786 {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6787 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6788 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6789 NULL, csnSidNormalize, octetStringMatch,
6790 octetStringIndexer, octetStringFilter,
6793 /* FIXME: OID is unused, but not registered yet */
6794 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6795 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6796 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6797 NULL, authzNormalize, authzMatch,
6801 {NULL, SLAP_MR_NONE, NULL,
6802 NULL, NULL, NULL, NULL, NULL,
6807 slap_schema_init( void )
6812 /* we should only be called once (from main) */
6813 assert( schema_init_done == 0 );
6815 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6816 res = register_syntax( &syntax_defs[i] );
6819 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6820 syntax_defs[i].sd_desc );
6825 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6826 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6827 mrule_defs[i].mrd_compat_syntaxes == NULL )
6830 "slap_schema_init: Ignoring unusable matching rule %s\n",
6831 mrule_defs[i].mrd_desc );
6835 res = register_matching_rule( &mrule_defs[i] );
6839 "slap_schema_init: Error registering matching rule %s\n",
6840 mrule_defs[i].mrd_desc );
6845 res = slap_schema_load();
6846 schema_init_done = 1;
6851 schema_destroy( void )
6860 if( schema_init_done ) {
6861 ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6862 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6863 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );