1 /* schema_init.c - init builtin schema */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2011 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
18 * Syntaxes - implementation notes:
20 * Validate function(syntax, value):
21 * Called before the other functions here to check if the value
22 * is valid according to the syntax.
24 * Pretty function(syntax, input value, output prettified...):
25 * If it exists, maps different notations of the same value to a
26 * unique representation which can be stored in the directory and
27 * possibly be passed to the Match/Indexer/Filter() functions.
29 * E.g. DN "2.5.4.3 = foo\,bar, o = BAZ" -> "cn=foo\2Cbar,o=BAZ",
30 * but unlike DN normalization, "BAZ" is not mapped to "baz".
34 * Matching rules - implementation notes:
36 * Matching rules match an attribute value (often from the directory)
37 * against an asserted value (e.g. from a filter).
39 * Invoked with validated and commonly pretty/normalized arguments, thus
40 * a number of matching rules can simply use the octetString functions.
42 * Normalize function(...input value, output normalized...):
43 * If it exists, maps matching values to a unique representation
44 * which is passed to the Match/Indexer/Filter() functions.
46 * Different matching rules can normalize values of the same syntax
47 * differently. E.g. caseIgnore rules normalize to lowercase,
48 * caseExact rules do not.
50 * Match function(*output matchp, ...value, asserted value):
51 * On success, set *matchp. 0 means match. For ORDERING/most EQUALITY,
52 * less/greater than 0 means value less/greater than asserted. However:
54 * In extensible match filters, ORDERING rules match if value<asserted.
56 * EQUALITY rules may order values differently than ORDERING rules for
57 * speed, since EQUALITY ordering is only used for SLAP_AT_SORTED_VAL.
58 * Some EQUALITY rules do not order values (ITS#6722).
60 * Indexer function(...attribute values, *output keysp,...):
61 * Generates index keys for the attribute values. Backends can store
62 * them in an index, a {key->entry ID set} mapping, for the attribute.
64 * A search can look up the DN/scope and asserted values in the
65 * indexes, if any, to narrow down the number of entires to check
66 * against the search criteria.
68 * Filter function(...asserted value, *output keysp,...):
69 * Generates index key(s) for the asserted value, to be looked up in
70 * the index from the Indexer function. *keysp is an array because
71 * substring matching rules can generate multiple lookup keys.
74 * A key is usually a hash of match type, attribute value and schema
75 * info, because one index can contain keys for many filtering types.
77 * Some indexes instead have EQUALITY keys ordered so that if
78 * key(val1) < key(val2), then val1 < val2 by the ORDERING rule.
79 * That way the ORDERING rule can use the EQUALITY index.
82 * This chops the attribute values up in small chunks and indexes all
83 * possible chunks of certain sizes. Substring filtering looks up
84 * SOME of the asserted value's chunks, and the caller uses the
85 * intersection of the resulting entry ID sets.
86 * See the index_substr_* keywords in slapd.conf(5).
98 #include <ac/string.h>
99 #include <ac/socket.h>
102 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
104 #include "ldap_utf8.h"
107 #include "lutil_hash.h"
108 #define HASH_BYTES LUTIL_HASH_BYTES
109 #define HASH_CONTEXT lutil_HASH_CTX
110 #define HASH_Init(c) lutil_HASHInit(c)
111 #define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
112 #define HASH_Final(d,c) lutil_HASHFinal(d,c)
114 /* approx matching rules */
115 #define directoryStringApproxMatchOID "1.3.6.1.4.1.4203.666.4.4"
116 #define directoryStringApproxMatch approxMatch
117 #define directoryStringApproxIndexer approxIndexer
118 #define directoryStringApproxFilter approxFilter
119 #define IA5StringApproxMatchOID "1.3.6.1.4.1.4203.666.4.5"
120 #define IA5StringApproxMatch approxMatch
121 #define IA5StringApproxIndexer approxIndexer
122 #define IA5StringApproxFilter approxFilter
124 /* Change Sequence Number (CSN) - much of this will change */
125 #define csnMatch octetStringMatch
126 #define csnOrderingMatch octetStringOrderingMatch
127 #define csnIndexer generalizedTimeIndexer
128 #define csnFilter generalizedTimeFilter
130 #define authzMatch octetStringMatch
132 /* X.509 PMI ldapSyntaxes */
133 /* FIXME: need to create temporary OIDs under OpenLDAP's arc;
134 * these are currently hijacked
136 * 1.3.6.1.4.1.4203.666 OpenLDAP
137 * 1.3.6.1.4.1.4203.666.11 self-contained works
138 * 1.3.6.1.4.1.4203.666.11.10 X.509 PMI
139 * 1.3.6.1.4.1.4203.666.11.10.2 X.509 PMI ldapSyntaxes
140 * 1.3.6.1.4.1.4203.666.11.10.2.1 AttributeCertificate (supported)
141 * 1.3.6.1.4.1.4203.666.11.10.2.2 AttributeCertificateExactAssertion (supported)
142 * 1.3.6.1.4.1.4203.666.11.10.2.3 AttributeCertificateAssertion (not supported)
143 * 1.3.6.1.4.1.4203.666.11.10.2.4 AttCertPath (X-SUBST'ed right now in pmi.schema)
144 * 1.3.6.1.4.1.4203.666.11.10.2.5 PolicySyntax (X-SUBST'ed right now in pmi.schema)
145 * 1.3.6.1.4.1.4203.666.11.10.2.6 RoleSyntax (X-SUBST'ed right now in pmi.schema)
147 #if 0 /* from <draft-ietf-pkix-ldap-schema-02.txt> (expired) */
148 #define attributeCertificateSyntaxOID "1.2.826.0.1.3344810.7.5"
149 #define attributeCertificateExactAssertionSyntaxOID "1.2.826.0.1.3344810.7.6"
150 #define attributeCertificateAssertionSyntaxOID "1.2.826.0.1.3344810.7.7"
151 #else /* from OpenLDAP's experimental oid arc */
152 #define X509_PMI_SyntaxOID "1.3.6.1.4.1.4203.666.11.10.2"
153 #define attributeCertificateSyntaxOID X509_PMI_SyntaxOID ".1"
154 #define attributeCertificateExactAssertionSyntaxOID X509_PMI_SyntaxOID ".2"
155 #define attributeCertificateAssertionSyntaxOID X509_PMI_SyntaxOID ".3"
158 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
159 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
160 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
161 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
163 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
164 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
165 SLAP_INDEX_INTLEN_DEFAULT );
167 ldap_pvt_thread_mutex_t ad_undef_mutex;
168 ldap_pvt_thread_mutex_t oc_undef_mutex;
171 generalizedTimeValidate(
175 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
180 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
187 /* no value allowed */
188 return LDAP_INVALID_SYNTAX;
196 /* any value allowed */
200 #define berValidate blobValidate
207 if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
208 if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
213 /* X.509 related stuff */
222 SLAP_TAG_UTCTIME = 0x17U,
223 SLAP_TAG_GENERALIZEDTIME = 0x18U
227 #define SLAP_X509_OPTION (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
230 SLAP_X509_OPT_C_VERSION = SLAP_X509_OPTION + 0,
231 SLAP_X509_OPT_C_ISSUERUNIQUEID = LBER_CLASS_CONTEXT + 1,
232 SLAP_X509_OPT_C_SUBJECTUNIQUEID = LBER_CLASS_CONTEXT + 2,
233 SLAP_X509_OPT_C_EXTENSIONS = SLAP_X509_OPTION + 3
237 SLAP_X509_OPT_CL_CRLEXTENSIONS = SLAP_X509_OPTION + 0
241 GeneralName ::= CHOICE {
242 otherName [0] INSTANCE OF OTHER-NAME,
243 rfc822Name [1] IA5String,
244 dNSName [2] IA5String,
245 x400Address [3] ORAddress,
246 directoryName [4] Name,
247 ediPartyName [5] EDIPartyName,
248 uniformResourceIdentifier [6] IA5String,
249 iPAddress [7] OCTET STRING,
250 registeredID [8] OBJECT IDENTIFIER }
253 SLAP_X509_GN_OTHERNAME = SLAP_X509_OPTION + 0,
254 SLAP_X509_GN_RFC822NAME = SLAP_X509_OPTION + 1,
255 SLAP_X509_GN_DNSNAME = SLAP_X509_OPTION + 2,
256 SLAP_X509_GN_X400ADDRESS = SLAP_X509_OPTION + 3,
257 SLAP_X509_GN_DIRECTORYNAME = SLAP_X509_OPTION + 4,
258 SLAP_X509_GN_EDIPARTYNAME = SLAP_X509_OPTION + 5,
259 SLAP_X509_GN_URI = SLAP_X509_OPTION + 6,
260 SLAP_X509_GN_IPADDRESS = SLAP_X509_OPTION + 7,
261 SLAP_X509_GN_REGISTEREDID = SLAP_X509_OPTION + 8
264 /* X.509 PMI related stuff */
271 SLAP_X509AC_ISSUER = SLAP_X509_OPTION + 0
274 /* X.509 certificate validation */
276 certificateValidate( Syntax *syntax, struct berval *in )
278 BerElementBuffer berbuf;
279 BerElement *ber = (BerElement *)&berbuf;
282 ber_int_t version = SLAP_X509_V1;
284 ber_init2( ber, in, LBER_USE_DER );
285 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
286 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
287 tag = ber_skip_tag( ber, &len ); /* Sequence */
288 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
289 tag = ber_peek_tag( ber, &len );
290 /* Optional version */
291 if ( tag == SLAP_X509_OPT_C_VERSION ) {
292 tag = ber_skip_tag( ber, &len );
293 tag = ber_get_int( ber, &version );
294 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
296 /* NOTE: don't try to parse Serial, because it might be longer
297 * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
298 tag = ber_skip_tag( ber, &len ); /* Serial */
299 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
300 ber_skip_data( ber, len );
301 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
302 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
303 ber_skip_data( ber, len );
304 tag = ber_skip_tag( ber, &len ); /* Issuer DN */
305 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
306 ber_skip_data( ber, len );
307 tag = ber_skip_tag( ber, &len ); /* Validity */
308 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
309 ber_skip_data( ber, len );
310 tag = ber_skip_tag( ber, &len ); /* Subject DN */
311 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
312 ber_skip_data( ber, len );
313 tag = ber_skip_tag( ber, &len ); /* Subject PublicKeyInfo */
314 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
315 ber_skip_data( ber, len );
316 tag = ber_skip_tag( ber, &len );
317 if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) { /* issuerUniqueID */
318 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
319 ber_skip_data( ber, len );
320 tag = ber_skip_tag( ber, &len );
322 if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
323 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
324 ber_skip_data( ber, len );
325 tag = ber_skip_tag( ber, &len );
327 if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) { /* Extensions */
328 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
329 tag = ber_skip_tag( ber, &len );
330 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
331 ber_skip_data( ber, len );
332 tag = ber_skip_tag( ber, &len );
334 /* signatureAlgorithm */
335 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
336 ber_skip_data( ber, len );
337 tag = ber_skip_tag( ber, &len );
339 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
340 ber_skip_data( ber, len );
341 tag = ber_skip_tag( ber, &len );
342 /* Must be at end now */
343 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
347 /* X.509 certificate list validation */
349 checkTime( struct berval *in, struct berval *out );
352 certificateListValidate( Syntax *syntax, struct berval *in )
354 BerElementBuffer berbuf;
355 BerElement *ber = (BerElement *)&berbuf;
357 ber_len_t len, wrapper_len;
360 ber_int_t version = SLAP_X509_V1;
361 struct berval bvdn, bvtu;
363 ber_init2( ber, in, LBER_USE_DER );
364 tag = ber_skip_tag( ber, &wrapper_len ); /* Signed wrapper */
365 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
366 wrapper_start = ber->ber_ptr;
367 tag = ber_skip_tag( ber, &len ); /* Sequence */
368 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
369 tag = ber_peek_tag( ber, &len );
370 /* Optional version */
371 if ( tag == LBER_INTEGER ) {
372 tag = ber_get_int( ber, &version );
373 assert( tag == LBER_INTEGER );
374 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
376 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
377 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
378 ber_skip_data( ber, len );
379 tag = ber_peek_tag( ber, &len ); /* Issuer DN */
380 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
381 len = ber_ptrlen( ber );
382 bvdn.bv_val = in->bv_val + len;
383 bvdn.bv_len = in->bv_len - len;
384 tag = ber_skip_tag( ber, &len );
385 ber_skip_data( ber, len );
386 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
387 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
388 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
389 bvtu.bv_val = (char *)ber->ber_ptr;
391 ber_skip_data( ber, len );
392 /* Optional nextUpdate */
393 tag = ber_skip_tag( ber, &len );
394 if ( tag == SLAP_TAG_UTCTIME || tag == SLAP_TAG_GENERALIZEDTIME ) {
395 ber_skip_data( ber, len );
396 tag = ber_skip_tag( ber, &len );
398 /* revokedCertificates - Sequence of Sequence, Optional */
399 if ( tag == LBER_SEQUENCE ) {
402 stag = ber_peek_tag( ber, &seqlen );
403 if ( stag == LBER_SEQUENCE || !len ) {
404 /* RFC5280 requires non-empty, but X.509(2005) allows empty. */
406 ber_skip_data( ber, len );
407 tag = ber_skip_tag( ber, &len );
410 /* Optional Extensions - Sequence of Sequence */
411 if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
413 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
414 tag = ber_peek_tag( ber, &seqlen );
415 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
416 ber_skip_data( ber, len );
417 tag = ber_skip_tag( ber, &len );
419 /* signatureAlgorithm */
420 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
421 ber_skip_data( ber, len );
422 tag = ber_skip_tag( ber, &len );
424 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
425 ber_skip_data( ber, len );
426 if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1;
427 tag = ber_skip_tag( ber, &len );
428 /* Must be at end now */
429 /* NOTE: OpenSSL tolerates CL with garbage past the end */
430 if ( len || tag != LBER_DEFAULT ) {
431 struct berval issuer_dn = BER_BVNULL, thisUpdate;
432 char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
435 if ( ! wrapper_ok ) {
436 return LDAP_INVALID_SYNTAX;
439 rc = dnX509normalize( &bvdn, &issuer_dn );
440 if ( rc != LDAP_SUCCESS ) {
441 rc = LDAP_INVALID_SYNTAX;
445 thisUpdate.bv_val = tubuf;
446 thisUpdate.bv_len = sizeof(tubuf);
447 if ( checkTime( &bvtu, &thisUpdate ) ) {
448 rc = LDAP_INVALID_SYNTAX;
452 Debug( LDAP_DEBUG_ANY,
453 "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n",
454 issuer_dn.bv_val, thisUpdate.bv_val, 0 );
457 if ( ! BER_BVISNULL( &issuer_dn ) ) {
458 ber_memfree( issuer_dn.bv_val );
467 /* X.509 PMI Attribute Certificate Validate */
469 attributeCertificateValidate( Syntax *syntax, struct berval *in )
471 BerElementBuffer berbuf;
472 BerElement *ber = (BerElement *)&berbuf;
478 ber_init2( ber, in, LBER_USE_DER );
480 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
481 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
483 tag = ber_skip_tag( ber, &len ); /* Sequence */
484 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
486 tag = ber_peek_tag( ber, &len ); /* Version */
487 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
488 tag = ber_get_int( ber, &version ); /* X.509 only allows v2 */
489 if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX;
491 tag = ber_skip_tag( ber, &len ); /* Holder */
492 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
493 ber_skip_data( ber, len );
495 tag = ber_skip_tag( ber, &len ); /* Issuer */
496 if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX;
497 ber_skip_data( ber, len );
499 tag = ber_skip_tag( ber, &len ); /* Signature */
500 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
501 ber_skip_data( ber, len );
503 tag = ber_skip_tag( ber, &len ); /* Serial number */
504 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
505 ber_skip_data( ber, len );
507 tag = ber_skip_tag( ber, &len ); /* AttCertValidityPeriod */
508 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
509 ber_skip_data( ber, len );
511 tag = ber_skip_tag( ber, &len ); /* Attributes */
512 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
513 ber_skip_data( ber, len );
515 tag = ber_peek_tag( ber, &len );
517 if ( tag == LBER_BITSTRING ) { /* issuerUniqueID */
518 tag = ber_skip_tag( ber, &len );
519 ber_skip_data( ber, len );
520 tag = ber_peek_tag( ber, &len );
523 if ( tag == LBER_SEQUENCE ) { /* extensions or signatureAlgorithm */
524 tag = ber_skip_tag( ber, &len );
525 ber_skip_data( ber, len );
527 tag = ber_peek_tag( ber, &len );
530 if ( tag == LBER_SEQUENCE ) { /* signatureAlgorithm */
531 tag = ber_skip_tag( ber, &len );
532 ber_skip_data( ber, len );
534 tag = ber_peek_tag( ber, &len );
537 if ( tag == LBER_BITSTRING ) { /* Signature */
538 tag = ber_skip_tag( ber, &len );
539 ber_skip_data( ber, len );
541 tag = ber_peek_tag( ber, &len );
544 /* Must be at end now */
545 if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX;
556 struct berval *value,
557 void *assertedValue )
559 struct berval *asserted = (struct berval *) assertedValue;
560 ber_slen_t d = (ber_slen_t) value->bv_len - (ber_slen_t) asserted->bv_len;
562 /* For speed, order first by length, then by contents */
563 *matchp = d ? (sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1)
564 : memcmp( value->bv_val, asserted->bv_val, value->bv_len );
570 octetStringOrderingMatch(
575 struct berval *value,
576 void *assertedValue )
578 struct berval *asserted = (struct berval *) assertedValue;
579 ber_len_t v_len = value->bv_len;
580 ber_len_t av_len = asserted->bv_len;
582 int match = memcmp( value->bv_val, asserted->bv_val,
583 (v_len < av_len ? v_len : av_len) );
586 match = sizeof(v_len) == sizeof(int)
587 ? (int) v_len - (int) av_len
588 : v_len < av_len ? -1 : v_len > av_len;
590 /* If used in extensible match filter, match if value < asserted */
591 if ( flags & SLAP_MR_EXT )
592 match = (match >= 0);
598 /* Initialize HASHcontext from match type and schema info */
601 HASH_CONTEXT *HASHcontext,
602 struct berval *prefix,
607 HASH_Init(HASHcontext);
608 if(prefix && prefix->bv_len > 0) {
609 HASH_Update(HASHcontext,
610 (unsigned char *)prefix->bv_val, prefix->bv_len);
612 if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
613 HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
614 HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
618 /* Set HASHdigest from HASHcontext and value:len */
621 HASH_CONTEXT *HASHcontext,
622 unsigned char *HASHdigest,
623 unsigned char *value,
626 HASH_CONTEXT ctx = *HASHcontext;
627 HASH_Update( &ctx, value, len );
628 HASH_Final( HASHdigest, &ctx );
631 /* Index generation function: Attribute values -> index hash keys */
632 int octetStringIndexer(
637 struct berval *prefix,
645 HASH_CONTEXT HASHcontext;
646 unsigned char HASHdigest[HASH_BYTES];
647 struct berval digest;
648 digest.bv_val = (char *)HASHdigest;
649 digest.bv_len = sizeof(HASHdigest);
651 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
652 /* just count them */
655 /* we should have at least one value at this point */
658 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
660 slen = syntax->ssyn_oidlen;
661 mlen = mr->smr_oidlen;
663 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
664 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
665 hashIter( &HASHcontext, HASHdigest,
666 (unsigned char *)values[i].bv_val, values[i].bv_len );
667 ber_dupbv_x( &keys[i], &digest, ctx );
670 BER_BVZERO( &keys[i] );
677 /* Index generation function: Asserted value -> index hash key */
678 int octetStringFilter(
683 struct berval *prefix,
684 void * assertedValue,
690 HASH_CONTEXT HASHcontext;
691 unsigned char HASHdigest[HASH_BYTES];
692 struct berval *value = (struct berval *) assertedValue;
693 struct berval digest;
694 digest.bv_val = (char *)HASHdigest;
695 digest.bv_len = sizeof(HASHdigest);
697 slen = syntax->ssyn_oidlen;
698 mlen = mr->smr_oidlen;
700 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
702 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
703 hashIter( &HASHcontext, HASHdigest,
704 (unsigned char *)value->bv_val, value->bv_len );
706 ber_dupbv_x( keys, &digest, ctx );
707 BER_BVZERO( &keys[1] );
715 octetStringSubstringsMatch(
720 struct berval *value,
721 void *assertedValue )
724 SubstringsAssertion *sub = assertedValue;
725 struct berval left = *value;
729 /* Add up asserted input length */
730 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
731 inlen += sub->sa_initial.bv_len;
734 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
735 inlen += sub->sa_any[i].bv_len;
738 if ( !BER_BVISNULL( &sub->sa_final ) ) {
739 inlen += sub->sa_final.bv_len;
742 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
743 if ( inlen > left.bv_len ) {
748 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
749 sub->sa_initial.bv_len );
755 left.bv_val += sub->sa_initial.bv_len;
756 left.bv_len -= sub->sa_initial.bv_len;
757 inlen -= sub->sa_initial.bv_len;
760 if ( !BER_BVISNULL( &sub->sa_final ) ) {
761 if ( inlen > left.bv_len ) {
766 match = memcmp( sub->sa_final.bv_val,
767 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
768 sub->sa_final.bv_len );
774 left.bv_len -= sub->sa_final.bv_len;
775 inlen -= sub->sa_final.bv_len;
779 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
784 if ( inlen > left.bv_len ) {
785 /* not enough length */
790 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
794 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
801 idx = p - left.bv_val;
803 if ( idx >= left.bv_len ) {
804 /* this shouldn't happen */
811 if ( sub->sa_any[i].bv_len > left.bv_len ) {
812 /* not enough left */
817 match = memcmp( left.bv_val,
818 sub->sa_any[i].bv_val,
819 sub->sa_any[i].bv_len );
827 left.bv_val += sub->sa_any[i].bv_len;
828 left.bv_len -= sub->sa_any[i].bv_len;
829 inlen -= sub->sa_any[i].bv_len;
838 /* Substring index generation function: Attribute values -> index hash keys */
840 octetStringSubstringsIndexer(
845 struct berval *prefix,
854 HASH_CONTEXT HCany, HCini, HCfin;
855 unsigned char HASHdigest[HASH_BYTES];
856 struct berval digest;
857 digest.bv_val = (char *)HASHdigest;
858 digest.bv_len = sizeof(HASHdigest);
862 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
863 /* count number of indices to generate */
864 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
865 if( values[i].bv_len >= index_substr_if_maxlen ) {
866 nkeys += index_substr_if_maxlen -
867 (index_substr_if_minlen - 1);
868 } else if( values[i].bv_len >= index_substr_if_minlen ) {
869 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
873 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
874 if( values[i].bv_len >= index_substr_any_len ) {
875 nkeys += values[i].bv_len - (index_substr_any_len - 1);
879 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
880 if( values[i].bv_len >= index_substr_if_maxlen ) {
881 nkeys += index_substr_if_maxlen -
882 (index_substr_if_minlen - 1);
883 } else if( values[i].bv_len >= index_substr_if_minlen ) {
884 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
890 /* no keys to generate */
895 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
897 slen = syntax->ssyn_oidlen;
898 mlen = mr->smr_oidlen;
900 if ( flags & SLAP_INDEX_SUBSTR_ANY )
901 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
902 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
903 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
904 if( flags & SLAP_INDEX_SUBSTR_FINAL )
905 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
908 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
911 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
912 ( values[i].bv_len >= index_substr_any_len ) )
914 max = values[i].bv_len - (index_substr_any_len - 1);
916 for( j=0; j<max; j++ ) {
917 hashIter( &HCany, HASHdigest,
918 (unsigned char *)&values[i].bv_val[j],
919 index_substr_any_len );
920 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
924 /* skip if too short */
925 if( values[i].bv_len < index_substr_if_minlen ) continue;
927 max = index_substr_if_maxlen < values[i].bv_len
928 ? index_substr_if_maxlen : values[i].bv_len;
930 for( j=index_substr_if_minlen; j<=max; j++ ) {
932 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
933 hashIter( &HCini, HASHdigest,
934 (unsigned char *)values[i].bv_val, j );
935 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
938 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
939 hashIter( &HCfin, HASHdigest,
940 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
941 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
948 BER_BVZERO( &keys[nkeys] );
958 /* Substring index generation function: Assertion value -> index hash keys */
960 octetStringSubstringsFilter (
965 struct berval *prefix,
966 void * assertedValue,
970 SubstringsAssertion *sa;
973 size_t slen, mlen, klen;
975 HASH_CONTEXT HASHcontext;
976 unsigned char HASHdigest[HASH_BYTES];
977 struct berval *value;
978 struct berval digest;
980 sa = (SubstringsAssertion *) assertedValue;
982 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
983 !BER_BVISNULL( &sa->sa_initial ) &&
984 sa->sa_initial.bv_len >= index_substr_if_minlen )
987 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
988 ( flags & SLAP_INDEX_SUBSTR_ANY ))
990 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
994 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
996 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
997 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
998 /* don't bother accounting with stepping */
999 nkeys += sa->sa_any[i].bv_len -
1000 ( index_substr_any_len - 1 );
1005 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1006 !BER_BVISNULL( &sa->sa_final ) &&
1007 sa->sa_final.bv_len >= index_substr_if_minlen )
1010 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
1011 ( flags & SLAP_INDEX_SUBSTR_ANY ))
1013 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1019 return LDAP_SUCCESS;
1022 digest.bv_val = (char *)HASHdigest;
1023 digest.bv_len = sizeof(HASHdigest);
1025 slen = syntax->ssyn_oidlen;
1026 mlen = mr->smr_oidlen;
1028 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
1031 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1032 !BER_BVISNULL( &sa->sa_initial ) &&
1033 sa->sa_initial.bv_len >= index_substr_if_minlen )
1035 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1036 value = &sa->sa_initial;
1038 klen = index_substr_if_maxlen < value->bv_len
1039 ? index_substr_if_maxlen : value->bv_len;
1041 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1042 hashIter( &HASHcontext, HASHdigest,
1043 (unsigned char *)value->bv_val, klen );
1044 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1046 /* If initial is too long and we have subany indexed, use it
1047 * to match the excess...
1049 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1052 pre = SLAP_INDEX_SUBSTR_PREFIX;
1053 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1054 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
1056 hashIter( &HASHcontext, HASHdigest,
1057 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1058 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1063 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1065 pre = SLAP_INDEX_SUBSTR_PREFIX;
1066 klen = index_substr_any_len;
1068 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1069 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
1073 value = &sa->sa_any[i];
1075 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1077 j <= value->bv_len - index_substr_any_len;
1078 j += index_substr_any_step )
1080 hashIter( &HASHcontext, HASHdigest,
1081 (unsigned char *)&value->bv_val[j], klen );
1082 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1087 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1088 !BER_BVISNULL( &sa->sa_final ) &&
1089 sa->sa_final.bv_len >= index_substr_if_minlen )
1091 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1092 value = &sa->sa_final;
1094 klen = index_substr_if_maxlen < value->bv_len
1095 ? index_substr_if_maxlen : value->bv_len;
1097 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1098 hashIter( &HASHcontext, HASHdigest,
1099 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
1100 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1102 /* If final is too long and we have subany indexed, use it
1103 * to match the excess...
1105 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1108 pre = SLAP_INDEX_SUBSTR_PREFIX;
1109 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1110 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
1112 hashIter( &HASHcontext, HASHdigest,
1113 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1114 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1120 BER_BVZERO( &keys[nkeys] );
1127 return LDAP_SUCCESS;
1137 /* very unforgiving validation, requires no normalization
1138 * before simplistic matching
1140 if( in->bv_len < 3 ) {
1141 return LDAP_INVALID_SYNTAX;
1144 /* RFC 4517 Section 3.3.2 Bit String:
1145 * BitString = SQUOTE *binary-digit SQUOTE "B"
1146 * binary-digit = "0" / "1"
1148 * where SQUOTE [RFC4512] is
1149 * SQUOTE = %x27 ; single quote ("'")
1151 * Example: '0101111101'B
1154 if( in->bv_val[0] != '\'' ||
1155 in->bv_val[in->bv_len - 2] != '\'' ||
1156 in->bv_val[in->bv_len - 1] != 'B' )
1158 return LDAP_INVALID_SYNTAX;
1161 for( i = in->bv_len - 3; i > 0; i-- ) {
1162 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
1163 return LDAP_INVALID_SYNTAX;
1167 return LDAP_SUCCESS;
1171 * Syntaxes from RFC 4517
1176 A value of the Bit String syntax is a sequence of binary digits. The
1177 LDAP-specific encoding of a value of this syntax is defined by the
1180 BitString = SQUOTE *binary-digit SQUOTE "B"
1182 binary-digit = "0" / "1"
1184 The <SQUOTE> rule is defined in [MODELS].
1189 The LDAP definition for the Bit String syntax is:
1191 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
1193 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
1197 3.3.21. Name and Optional UID
1199 A value of the Name and Optional UID syntax is the distinguished name
1200 [MODELS] of an entity optionally accompanied by a unique identifier
1201 that serves to differentiate the entity from others with an identical
1204 The LDAP-specific encoding of a value of this syntax is defined by
1207 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
1209 The <BitString> rule is defined in Section 3.3.2. The
1210 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
1211 defined in [MODELS].
1213 Note that although the '#' character may occur in the string
1214 representation of a distinguished name, no additional escaping of
1215 this character is performed when a <distinguishedName> is encoded in
1216 a <NameAndOptionalUID>.
1219 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
1221 The LDAP definition for the Name and Optional UID syntax is:
1223 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
1225 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
1232 1.4. Common ABNF Productions
1235 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
1237 SQUOTE = %x27 ; single quote ("'")
1242 * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
1243 * be escaped except when at the beginning of a value, the
1244 * definition of Name and Optional UID appears to be flawed,
1245 * because there is no clear means to determine whether the
1246 * UID part is present or not.
1250 * cn=Someone,dc=example,dc=com#'1'B
1252 * could be either a NameAndOptionalUID with trailing UID, i.e.
1254 * DN = "cn=Someone,dc=example,dc=com"
1257 * or a NameAndOptionalUID with no trailing UID, and the AVA
1258 * in the last RDN made of
1260 * attributeType = dc
1261 * attributeValue = com#'1'B
1263 * in fact "com#'1'B" is a valid IA5 string.
1265 * As a consequence, current slapd code takes the presence of
1266 * #<valid BitString> at the end of the string representation
1267 * of a NameAndOptionalUID to mean this is indeed a BitString.
1268 * This is quite arbitrary - it has changed the past and might
1269 * change in the future.
1279 struct berval dn, uid;
1281 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
1283 ber_dupbv( &dn, in );
1284 if( !dn.bv_val ) return LDAP_OTHER;
1286 /* if there's a "#", try bitStringValidate()... */
1287 uid.bv_val = strrchr( dn.bv_val, '#' );
1288 if ( !BER_BVISNULL( &uid ) ) {
1290 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1292 rc = bitStringValidate( NULL, &uid );
1293 if ( rc == LDAP_SUCCESS ) {
1294 /* in case of success, trim the UID,
1295 * otherwise treat it as part of the DN */
1296 dn.bv_len -= uid.bv_len + 1;
1297 uid.bv_val[-1] = '\0';
1301 rc = dnValidate( NULL, &dn );
1303 ber_memfree( dn.bv_val );
1314 assert( val != NULL );
1315 assert( out != NULL );
1318 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1320 if( BER_BVISEMPTY( val ) ) {
1321 ber_dupbv_x( out, val, ctx );
1323 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1324 return LDAP_INVALID_SYNTAX;
1328 struct berval dnval = *val;
1329 struct berval uidval = BER_BVNULL;
1331 uidval.bv_val = strrchr( val->bv_val, '#' );
1332 if ( !BER_BVISNULL( &uidval ) ) {
1334 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1336 rc = bitStringValidate( NULL, &uidval );
1338 if ( rc == LDAP_SUCCESS ) {
1339 ber_dupbv_x( &dnval, val, ctx );
1341 dnval.bv_len -= ++uidval.bv_len;
1342 dnval.bv_val[dnval.bv_len] = '\0';
1345 BER_BVZERO( &uidval );
1349 rc = dnPretty( syntax, &dnval, out, ctx );
1350 if ( dnval.bv_val != val->bv_val ) {
1351 slap_sl_free( dnval.bv_val, ctx );
1353 if( rc != LDAP_SUCCESS ) {
1357 if( !BER_BVISNULL( &uidval ) ) {
1360 tmp = slap_sl_realloc( out->bv_val, out->bv_len
1361 + uidval.bv_len + 1,
1364 ber_memfree_x( out->bv_val, ctx );
1368 memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
1369 out->bv_len += uidval.bv_len;
1370 out->bv_val[out->bv_len] = '\0';
1374 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1376 return LDAP_SUCCESS;
1380 uniqueMemberNormalize(
1385 struct berval *normalized,
1391 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1393 ber_dupbv_x( &out, val, ctx );
1394 if ( BER_BVISEMPTY( &out ) ) {
1398 struct berval uid = BER_BVNULL;
1400 uid.bv_val = strrchr( out.bv_val, '#' );
1401 if ( !BER_BVISNULL( &uid ) ) {
1403 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1405 rc = bitStringValidate( NULL, &uid );
1406 if ( rc == LDAP_SUCCESS ) {
1407 uid.bv_val[-1] = '\0';
1408 out.bv_len -= uid.bv_len + 1;
1414 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1416 if( rc != LDAP_SUCCESS ) {
1417 slap_sl_free( out.bv_val, ctx );
1418 return LDAP_INVALID_SYNTAX;
1421 if( !BER_BVISNULL( &uid ) ) {
1424 tmp = ch_realloc( normalized->bv_val,
1425 normalized->bv_len + uid.bv_len
1426 + STRLENOF("#") + 1 );
1427 if ( tmp == NULL ) {
1428 ber_memfree_x( normalized->bv_val, ctx );
1432 normalized->bv_val = tmp;
1434 /* insert the separator */
1435 normalized->bv_val[normalized->bv_len++] = '#';
1437 /* append the UID */
1438 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1439 uid.bv_val, uid.bv_len );
1440 normalized->bv_len += uid.bv_len;
1443 normalized->bv_val[normalized->bv_len] = '\0';
1446 slap_sl_free( out.bv_val, ctx );
1449 return LDAP_SUCCESS;
1458 struct berval *value,
1459 void *assertedValue )
1462 struct berval *asserted = (struct berval *) assertedValue;
1463 struct berval assertedDN = *asserted;
1464 struct berval assertedUID = BER_BVNULL;
1465 struct berval valueDN = *value;
1466 struct berval valueUID = BER_BVNULL;
1467 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1469 if ( !BER_BVISEMPTY( asserted ) ) {
1470 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1471 if ( !BER_BVISNULL( &assertedUID ) ) {
1472 assertedUID.bv_val++;
1473 assertedUID.bv_len = assertedDN.bv_len
1474 - ( assertedUID.bv_val - assertedDN.bv_val );
1476 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1477 assertedDN.bv_len -= assertedUID.bv_len + 1;
1480 BER_BVZERO( &assertedUID );
1485 if ( !BER_BVISEMPTY( value ) ) {
1487 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1488 if ( !BER_BVISNULL( &valueUID ) ) {
1490 valueUID.bv_len = valueDN.bv_len
1491 - ( valueUID.bv_val - valueDN.bv_val );
1493 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1494 valueDN.bv_len -= valueUID.bv_len + 1;
1497 BER_BVZERO( &valueUID );
1502 if( valueUID.bv_len && assertedUID.bv_len ) {
1504 d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len;
1506 *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1;
1507 return LDAP_SUCCESS;
1510 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1513 return LDAP_SUCCESS;
1516 } else if ( !approx && valueUID.bv_len ) {
1519 return LDAP_SUCCESS;
1521 } else if ( !approx && assertedUID.bv_len ) {
1524 return LDAP_SUCCESS;
1527 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1531 uniqueMemberIndexer(
1536 struct berval *prefix,
1544 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1545 /* just count them */
1549 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1551 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1552 struct berval assertedDN = values[i];
1553 struct berval assertedUID = BER_BVNULL;
1555 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1556 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1557 if ( !BER_BVISNULL( &assertedUID ) ) {
1558 assertedUID.bv_val++;
1559 assertedUID.bv_len = assertedDN.bv_len
1560 - ( assertedUID.bv_val - assertedDN.bv_val );
1562 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1563 assertedDN.bv_len -= assertedUID.bv_len + 1;
1566 BER_BVZERO( &assertedUID );
1571 dnvalues[i] = assertedDN;
1573 BER_BVZERO( &dnvalues[i] );
1575 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1576 dnvalues, keysp, ctx );
1578 slap_sl_free( dnvalues, ctx );
1588 struct berval *prefix,
1589 void * assertedValue,
1593 struct berval *asserted = (struct berval *) assertedValue;
1594 struct berval assertedDN = *asserted;
1595 struct berval assertedUID = BER_BVNULL;
1597 if ( !BER_BVISEMPTY( asserted ) ) {
1598 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1599 if ( !BER_BVISNULL( &assertedUID ) ) {
1600 assertedUID.bv_val++;
1601 assertedUID.bv_len = assertedDN.bv_len
1602 - ( assertedUID.bv_val - assertedDN.bv_val );
1604 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1605 assertedDN.bv_len -= assertedUID.bv_len + 1;
1608 BER_BVZERO( &assertedUID );
1613 return octetStringFilter( use, flags, syntax, mr, prefix,
1614 &assertedDN, keysp, ctx );
1619 * Handling boolean syntax and matching is quite rigid.
1620 * A more flexible approach would be to allow a variety
1621 * of strings to be normalized and prettied into TRUE
1629 /* very unforgiving validation, requires no normalization
1630 * before simplistic matching
1633 if( in->bv_len == 4 ) {
1634 if( bvmatch( in, &slap_true_bv ) ) {
1635 return LDAP_SUCCESS;
1637 } else if( in->bv_len == 5 ) {
1638 if( bvmatch( in, &slap_false_bv ) ) {
1639 return LDAP_SUCCESS;
1643 return LDAP_INVALID_SYNTAX;
1652 struct berval *value,
1653 void *assertedValue )
1655 /* simplistic matching allowed by rigid validation */
1656 struct berval *asserted = (struct berval *) assertedValue;
1657 *matchp = (int) asserted->bv_len - (int) value->bv_len;
1658 return LDAP_SUCCESS;
1661 /*-------------------------------------------------------------------
1662 LDAP/X.500 string syntax / matching rules have a few oddities. This
1663 comment attempts to detail how slapd(8) treats them.
1666 StringSyntax X.500 LDAP Matching/Comments
1667 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1668 PrintableString subset subset i/e + ignore insignificant spaces
1669 PrintableString subset subset i/e + ignore insignificant spaces
1670 NumericString subset subset ignore all spaces
1671 IA5String ASCII ASCII i/e + ignore insignificant spaces
1672 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1674 TelephoneNumber subset subset i + ignore all spaces and "-"
1676 See RFC 4518 for details.
1680 In X.500(93), a directory string can be either a PrintableString,
1681 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1682 In later versions, more CHOICEs were added. In all cases the string
1685 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1686 A directory string cannot be zero length.
1688 For matching, there are both case ignore and exact rules. Both
1689 also require that "insignificant" spaces be ignored.
1690 spaces before the first non-space are ignored;
1691 spaces after the last non-space are ignored;
1692 spaces after a space are ignored.
1693 Note: by these rules (and as clarified in X.520), a string of only
1694 spaces is to be treated as if held one space, not empty (which
1695 would be a syntax error).
1698 In ASN.1, numeric string is just a string of digits and spaces
1699 and could be empty. However, in X.500, all attribute values of
1700 numeric string carry a non-empty constraint. For example:
1702 internationalISDNNumber ATTRIBUTE ::= {
1703 WITH SYNTAX InternationalISDNNumber
1704 EQUALITY MATCHING RULE numericStringMatch
1705 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1706 ID id-at-internationalISDNNumber }
1707 InternationalISDNNumber ::=
1708 NumericString (SIZE(1..ub-international-isdn-number))
1710 Unforunately, some assertion values are don't carry the same
1711 constraint (but its unclear how such an assertion could ever
1712 be true). In LDAP, there is one syntax (numericString) not two
1713 (numericString with constraint, numericString without constraint).
1714 This should be treated as numericString with non-empty constraint.
1715 Note that while someone may have no ISDN number, there are no ISDN
1716 numbers which are zero length.
1718 In matching, spaces are ignored.
1721 In ASN.1, Printable string is just a string of printable characters
1722 and can be empty. In X.500, semantics much like NumericString (see
1723 serialNumber for a like example) excepting uses insignificant space
1724 handling instead of ignore all spaces. They must be non-empty.
1727 Basically same as PrintableString. There are no examples in X.500,
1728 but same logic applies. Empty strings are allowed.
1730 -------------------------------------------------------------------*/
1739 unsigned char *u = (unsigned char *)in->bv_val;
1741 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1742 /* directory strings cannot be empty */
1743 return LDAP_INVALID_SYNTAX;
1746 for( count = in->bv_len; count > 0; count -= len, u += len ) {
1747 /* get the length indicated by the first byte */
1748 len = LDAP_UTF8_CHARLEN2( u, len );
1750 /* very basic checks */
1753 if( (u[5] & 0xC0) != 0x80 ) {
1754 return LDAP_INVALID_SYNTAX;
1757 if( (u[4] & 0xC0) != 0x80 ) {
1758 return LDAP_INVALID_SYNTAX;
1761 if( (u[3] & 0xC0) != 0x80 ) {
1762 return LDAP_INVALID_SYNTAX;
1765 if( (u[2] & 0xC0 )!= 0x80 ) {
1766 return LDAP_INVALID_SYNTAX;
1769 if( (u[1] & 0xC0) != 0x80 ) {
1770 return LDAP_INVALID_SYNTAX;
1773 /* CHARLEN already validated it */
1776 return LDAP_INVALID_SYNTAX;
1779 /* make sure len corresponds with the offset
1780 to the next character */
1781 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1785 return LDAP_INVALID_SYNTAX;
1788 return LDAP_SUCCESS;
1792 UTF8StringNormalize(
1797 struct berval *normalized,
1800 struct berval tmp, nvalue;
1801 int flags, wasspace;
1804 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1806 if( BER_BVISNULL( val ) ) {
1807 /* assume we're dealing with a syntax (e.g., UTF8String)
1808 * which allows empty strings
1810 BER_BVZERO( normalized );
1811 return LDAP_SUCCESS;
1814 flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1815 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1816 flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1817 ? LDAP_UTF8_APPROX : 0;
1819 val = UTF8bvnormalize( val, &tmp, flags, ctx );
1820 /* out of memory or syntax error, the former is unlikely */
1822 return LDAP_INVALID_SYNTAX;
1825 /* collapse spaces (in place) */
1827 nvalue.bv_val = tmp.bv_val;
1829 /* trim leading spaces? */
1830 wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1831 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1833 for( i = 0; i < tmp.bv_len; i++) {
1834 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1835 if( wasspace++ == 0 ) {
1836 /* trim repeated spaces */
1837 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1841 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1845 if( !BER_BVISEMPTY( &nvalue ) ) {
1846 /* trim trailing space? */
1848 (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1849 ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1853 nvalue.bv_val[nvalue.bv_len] = '\0';
1856 /* string of all spaces is treated as one space */
1857 nvalue.bv_val[0] = ' ';
1858 nvalue.bv_val[1] = '\0';
1862 *normalized = nvalue;
1863 return LDAP_SUCCESS;
1867 directoryStringSubstringsMatch(
1872 struct berval *value,
1873 void *assertedValue )
1876 SubstringsAssertion *sub = assertedValue;
1877 struct berval left = *value;
1881 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1882 if ( sub->sa_initial.bv_len > left.bv_len ) {
1883 /* not enough left */
1888 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1889 sub->sa_initial.bv_len );
1895 left.bv_val += sub->sa_initial.bv_len;
1896 left.bv_len -= sub->sa_initial.bv_len;
1898 priorspace = ASCII_SPACE(
1899 sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1902 if ( sub->sa_any ) {
1903 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1907 if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1908 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1910 /* allow next space to match */
1917 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1921 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1922 /* not enough left */
1927 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1934 idx = p - left.bv_val;
1936 if ( idx >= left.bv_len ) {
1937 /* this shouldn't happen */
1944 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1945 /* not enough left */
1950 match = memcmp( left.bv_val,
1951 sub->sa_any[i].bv_val,
1952 sub->sa_any[i].bv_len );
1960 left.bv_val += sub->sa_any[i].bv_len;
1961 left.bv_len -= sub->sa_any[i].bv_len;
1963 priorspace = ASCII_SPACE(
1964 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
1968 if ( !BER_BVISNULL( &sub->sa_final ) ) {
1969 if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
1970 && ASCII_SPACE( sub->sa_final.bv_val[0] ))
1972 /* allow next space to match */
1977 if ( sub->sa_final.bv_len > left.bv_len ) {
1978 /* not enough left */
1983 match = memcmp( sub->sa_final.bv_val,
1984 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
1985 sub->sa_final.bv_len );
1994 return LDAP_SUCCESS;
1997 #if defined(SLAPD_APPROX_INITIALS)
1998 # define SLAPD_APPROX_DELIMITER "._ "
1999 # define SLAPD_APPROX_WORDLEN 2
2001 # define SLAPD_APPROX_DELIMITER " "
2002 # define SLAPD_APPROX_WORDLEN 1
2011 struct berval *value,
2012 void *assertedValue )
2014 struct berval *nval, *assertv;
2015 char *val, **values, **words, *c;
2016 int i, count, len, nextchunk=0, nextavail=0;
2018 /* Yes, this is necessary */
2019 nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
2020 if( nval == NULL ) {
2022 return LDAP_SUCCESS;
2025 /* Yes, this is necessary */
2026 assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
2027 NULL, LDAP_UTF8_APPROX, NULL );
2028 if( assertv == NULL ) {
2031 return LDAP_SUCCESS;
2034 /* Isolate how many words there are */
2035 for ( c = nval->bv_val, count = 1; *c; c++ ) {
2036 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
2037 if ( c == NULL ) break;
2042 /* Get a phonetic copy of each word */
2043 words = (char **)ch_malloc( count * sizeof(char *) );
2044 values = (char **)ch_malloc( count * sizeof(char *) );
2045 for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) {
2047 values[i] = phonetic(c);
2050 /* Work through the asserted value's words, to see if at least some
2051 * of the words are there, in the same order. */
2053 while ( (ber_len_t) nextchunk < assertv->bv_len ) {
2054 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
2059 #if defined(SLAPD_APPROX_INITIALS)
2060 else if( len == 1 ) {
2061 /* Single letter words need to at least match one word's initial */
2062 for( i=nextavail; i<count; i++ )
2063 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
2070 /* Isolate the next word in the asserted value and phonetic it */
2071 assertv->bv_val[nextchunk+len] = '\0';
2072 val = phonetic( assertv->bv_val + nextchunk );
2074 /* See if this phonetic chunk is in the remaining words of *value */
2075 for( i=nextavail; i<count; i++ ){
2076 if( !strcmp( val, values[i] ) ){
2084 /* This chunk in the asserted value was NOT within the *value. */
2090 /* Go on to the next word in the asserted value */
2094 /* If some of the words were seen, call it a match */
2095 if( nextavail > 0 ) {
2102 /* Cleanup allocs */
2103 ber_bvfree( assertv );
2104 for( i=0; i<count; i++ ) {
2105 ch_free( values[i] );
2111 return LDAP_SUCCESS;
2120 struct berval *prefix,
2126 int i,j, len, wordcount, keycount=0;
2127 struct berval *newkeys;
2128 BerVarray keys=NULL;
2130 for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
2131 struct berval val = BER_BVNULL;
2132 /* Yes, this is necessary */
2133 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
2134 assert( !BER_BVISNULL( &val ) );
2136 /* Isolate how many words there are. There will be a key for each */
2137 for( wordcount = 0, c = val.bv_val; *c; c++) {
2138 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2139 if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
2141 if (*c == '\0') break;
2145 /* Allocate/increase storage to account for new keys */
2146 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
2147 * sizeof(struct berval) );
2148 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
2149 if( keys ) ch_free( keys );
2152 /* Get a phonetic copy of each word */
2153 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
2155 if( len < SLAPD_APPROX_WORDLEN ) continue;
2156 ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
2161 ber_memfree( val.bv_val );
2163 BER_BVZERO( &keys[keycount] );
2166 return LDAP_SUCCESS;
2175 struct berval *prefix,
2176 void * assertedValue,
2185 /* Yes, this is necessary */
2186 val = UTF8bvnormalize( ((struct berval *)assertedValue),
2187 NULL, LDAP_UTF8_APPROX, NULL );
2188 if( val == NULL || BER_BVISNULL( val ) ) {
2189 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2190 BER_BVZERO( &keys[0] );
2193 return LDAP_SUCCESS;
2196 /* Isolate how many words there are. There will be a key for each */
2197 for( count = 0,c = val->bv_val; *c; c++) {
2198 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2199 if( len >= SLAPD_APPROX_WORDLEN ) count++;
2201 if (*c == '\0') break;
2205 /* Allocate storage for new keys */
2206 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2208 /* Get a phonetic copy of each word */
2209 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2211 if( len < SLAPD_APPROX_WORDLEN ) continue;
2212 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2218 BER_BVZERO( &keys[count] );
2221 return LDAP_SUCCESS;
2224 /* Remove all spaces and '-' characters */
2226 telephoneNumberNormalize(
2231 struct berval *normalized,
2236 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2238 /* validator should have refused an empty string */
2239 assert( !BER_BVISEMPTY( val ) );
2241 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2243 for( p = val->bv_val; *p; p++ ) {
2244 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
2250 normalized->bv_len = q - normalized->bv_val;
2252 if( BER_BVISEMPTY( normalized ) ) {
2253 slap_sl_free( normalized->bv_val, ctx );
2254 BER_BVZERO( normalized );
2255 return LDAP_INVALID_SYNTAX;
2258 return LDAP_SUCCESS;
2262 postalAddressValidate(
2266 struct berval bv = *in;
2269 for ( c = 0; c < in->bv_len; c++ ) {
2270 if ( in->bv_val[c] == '\\' ) {
2272 if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2273 && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2275 return LDAP_INVALID_SYNTAX;
2280 if ( in->bv_val[c] == '$' ) {
2281 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2282 if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2283 return LDAP_INVALID_SYNTAX;
2285 bv.bv_val = &in->bv_val[c] + 1;
2289 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2290 return UTF8StringValidate( NULL, &bv );
2294 postalAddressNormalize(
2299 struct berval *normalized,
2302 BerVarray lines = NULL, nlines = NULL;
2304 int rc = LDAP_SUCCESS;
2305 MatchingRule *xmr = NULL;
2308 if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2309 xmr = slap_schema.si_mr_caseIgnoreMatch;
2312 xmr = slap_schema.si_mr_caseExactMatch;
2315 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2316 if ( val->bv_val[c] == '$' ) {
2321 lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2322 nlines = &lines[l + 2];
2324 lines[0].bv_val = val->bv_val;
2325 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2326 if ( val->bv_val[c] == '$' ) {
2327 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2329 lines[l].bv_val = &val->bv_val[c + 1];
2332 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2334 normalized->bv_len = l;
2336 for ( l = 0; !BER_BVISNULL( &lines[l] ); l++ ) {
2337 /* NOTE: we directly normalize each line,
2338 * without unescaping the values, since the special
2339 * values '\24' ('$') and '\5C' ('\') are not affected
2340 * by normalization */
2341 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2342 if ( rc != LDAP_SUCCESS ) {
2343 rc = LDAP_INVALID_SYNTAX;
2347 normalized->bv_len += nlines[l].bv_len;
2350 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2352 p = normalized->bv_val;
2353 for ( l = 0; !BER_BVISNULL( &nlines[l] ); l++ ) {
2354 p = lutil_strbvcopy( p, &nlines[l] );
2359 assert( p == &normalized->bv_val[normalized->bv_len] );
2362 if ( nlines != NULL ) {
2363 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2364 slap_sl_free( nlines[l].bv_val, ctx );
2367 slap_sl_free( lines, ctx );
2378 struct berval val = *in;
2380 if( BER_BVISEMPTY( &val ) ) {
2381 /* disallow empty strings */
2382 return LDAP_INVALID_SYNTAX;
2385 while( OID_LEADCHAR( val.bv_val[0] ) ) {
2386 if ( val.bv_len == 1 ) {
2387 return LDAP_SUCCESS;
2390 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2397 while ( OID_LEADCHAR( val.bv_val[0] )) {
2401 if ( val.bv_len == 0 ) {
2402 return LDAP_SUCCESS;
2406 if( !OID_SEPARATOR( val.bv_val[0] )) {
2414 return LDAP_INVALID_SYNTAX;
2423 struct berval val = *in;
2425 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2427 if ( val.bv_val[0] == '-' ) {
2431 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2432 return LDAP_INVALID_SYNTAX;
2435 if( val.bv_val[0] == '0' ) { /* "-0" */
2436 return LDAP_INVALID_SYNTAX;
2439 } else if ( val.bv_val[0] == '0' ) {
2440 if( val.bv_len > 1 ) { /* "0<more>" */
2441 return LDAP_INVALID_SYNTAX;
2444 return LDAP_SUCCESS;
2447 for( i=0; i < val.bv_len; i++ ) {
2448 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2449 return LDAP_INVALID_SYNTAX;
2453 return LDAP_SUCCESS;
2462 struct berval *value,
2463 void *assertedValue )
2465 struct berval *asserted = (struct berval *) assertedValue;
2466 int vsign = 1, asign = 1; /* default sign = '+' */
2471 if( v.bv_val[0] == '-' ) {
2477 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2480 if( a.bv_val[0] == '-' ) {
2486 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2488 match = vsign - asign;
2490 match = ( v.bv_len != a.bv_len
2491 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2492 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2493 if( vsign < 0 ) match = -match;
2496 /* Ordering rule used in extensible match filter? */
2497 if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2498 match = (match >= 0);
2501 return LDAP_SUCCESS;
2504 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2505 #define INDEX_INTLEN_CHOP 7
2506 #define INDEX_INTLEN_CHOPBYTES 3
2515 /* Integer index key format, designed for memcmp to collate correctly:
2516 * if too large: one's complement sign*<approx exponent=chopped bytes>,
2517 * two's complement value (sign-extended or chopped as needed),
2518 * however in first byte above, the top <number of exponent-bytes + 1>
2519 * bits are the inverse sign and next bit is the sign as delimiter.
2521 ber_slen_t k = index_intlen_strlen;
2523 unsigned signmask = ~0x7fU;
2524 unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2525 struct berval val = *in, itmp = *tmp;
2527 if ( val.bv_val[0] != '-' ) {
2532 /* Chop least significant digits, increase length instead */
2533 if ( val.bv_len > (ber_len_t) k ) {
2534 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2535 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2536 chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
2539 if ( lutil_str2bin( &val, &itmp, ctx )) {
2540 return LDAP_INVALID_SYNTAX;
2543 /* Omit leading sign byte */
2544 if ( itmp.bv_val[0] == neg ) {
2549 k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2551 assert( chop == 0 );
2552 memset( key->bv_val, neg, k ); /* sign-extend */
2553 } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2554 /* Got exponent -k, or no room for 2 sign bits */
2555 lenp = lenbuf + sizeof(lenbuf);
2556 chop = - (ber_len_t) k;
2558 *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2560 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2561 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2562 * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2563 k = (lenbuf + sizeof(lenbuf)) - lenp;
2564 if ( k > (ber_slen_t) index_intlen )
2566 memcpy( key->bv_val, lenp, k );
2567 itmp.bv_len = index_intlen - k;
2569 memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2570 key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2574 /* Index generation function: Ordered index */
2581 struct berval *prefix,
2591 unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2593 /* count the values and find max needed length */
2595 for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2596 if ( vlen < values[i].bv_len )
2597 vlen = values[i].bv_len;
2599 if ( vlen > maxstrlen )
2602 /* we should have at least one value at this point */
2605 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2606 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2607 keys[i].bv_len = index_intlen;
2608 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2611 keys[i].bv_val = NULL;
2613 if ( vlen > sizeof(ibuf) ) {
2614 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2618 itmp.bv_len = sizeof(ibuf);
2620 for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2621 if ( itmp.bv_val != ibuf ) {
2622 itmp.bv_len = values[i].bv_len;
2623 if ( itmp.bv_len <= sizeof(ibuf) )
2624 itmp.bv_len = sizeof(ibuf);
2625 else if ( itmp.bv_len > maxstrlen )
2626 itmp.bv_len = maxstrlen;
2628 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2634 if ( itmp.bv_val != ibuf ) {
2635 slap_sl_free( itmp.bv_val, ctx );
2640 /* Index generation function: Ordered index */
2647 struct berval *prefix,
2648 void * assertedValue,
2655 struct berval *value;
2658 value = (struct berval *) assertedValue;
2660 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2662 keys[0].bv_len = index_intlen;
2663 keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2665 keys[1].bv_val = NULL;
2667 iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2668 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2669 if ( iv.bv_len > (int) sizeof(ibuf) ) {
2670 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2673 iv.bv_len = sizeof(ibuf);
2676 rc = integerVal2Key( value, keys, &iv, ctx );
2680 if ( iv.bv_val != ibuf ) {
2681 slap_sl_free( iv.bv_val, ctx );
2687 countryStringValidate(
2689 struct berval *val )
2691 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2693 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2694 return LDAP_INVALID_SYNTAX;
2696 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2697 return LDAP_INVALID_SYNTAX;
2700 return LDAP_SUCCESS;
2704 printableStringValidate(
2706 struct berval *val )
2710 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2712 for(i=0; i < val->bv_len; i++) {
2713 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2714 return LDAP_INVALID_SYNTAX;
2718 return LDAP_SUCCESS;
2722 printablesStringValidate(
2724 struct berval *val )
2728 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2730 for(i=0,len=0; i < val->bv_len; i++) {
2731 int c = val->bv_val[i];
2735 return LDAP_INVALID_SYNTAX;
2739 } else if ( SLAP_PRINTABLE(c) ) {
2742 return LDAP_INVALID_SYNTAX;
2747 return LDAP_INVALID_SYNTAX;
2750 return LDAP_SUCCESS;
2756 struct berval *val )
2760 for(i=0; i < val->bv_len; i++) {
2761 if( !LDAP_ASCII(val->bv_val[i]) ) {
2762 return LDAP_INVALID_SYNTAX;
2766 return LDAP_SUCCESS;
2775 struct berval *normalized,
2779 int casefold = !SLAP_MR_ASSOCIATED( mr,
2780 slap_schema.si_mr_caseExactIA5Match );
2782 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2786 /* Ignore initial whitespace */
2787 while ( ASCII_SPACE( *p ) ) p++;
2789 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2790 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2791 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2792 normalized->bv_val[normalized->bv_len] = '\0';
2794 p = q = normalized->bv_val;
2797 if ( ASCII_SPACE( *p ) ) {
2800 /* Ignore the extra whitespace */
2801 while ( ASCII_SPACE( *p ) ) {
2805 } else if ( casefold ) {
2806 /* Most IA5 rules require casefolding */
2807 *q++ = TOLOWER(*p); p++;
2814 assert( normalized->bv_val <= p );
2818 * If the string ended in space, backup the pointer one
2819 * position. One is enough because the above loop collapsed
2820 * all whitespace to a single space.
2822 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2824 /* null terminate */
2827 normalized->bv_len = q - normalized->bv_val;
2829 return LDAP_SUCCESS;
2838 if( in->bv_len != 36 ) {
2839 return LDAP_INVALID_SYNTAX;
2842 for( i=0; i<36; i++ ) {
2848 if( in->bv_val[i] != '-' ) {
2849 return LDAP_INVALID_SYNTAX;
2853 if( !ASCII_HEX( in->bv_val[i]) ) {
2854 return LDAP_INVALID_SYNTAX;
2859 return LDAP_SUCCESS;
2870 int rc=LDAP_INVALID_SYNTAX;
2872 assert( in != NULL );
2873 assert( out != NULL );
2875 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2878 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2880 for( i=0; i<36; i++ ) {
2886 if( in->bv_val[i] != '-' ) {
2889 out->bv_val[i] = '-';
2893 if( !ASCII_HEX( in->bv_val[i]) ) {
2896 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2901 out->bv_val[ out->bv_len ] = '\0';
2905 slap_sl_free( out->bv_val, ctx );
2918 struct berval *normalized,
2921 unsigned char octet = '\0';
2925 if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2926 /* NOTE: must be a normalized UUID */
2927 assert( val->bv_len == 16 );
2929 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2930 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2931 val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2932 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2934 return LDAP_SUCCESS;
2937 normalized->bv_len = 16;
2938 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2940 for( i=0, j=0; i<36; i++ ) {
2941 unsigned char nibble;
2942 if( val->bv_val[i] == '-' ) {
2945 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2946 nibble = val->bv_val[i] - '0';
2948 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2949 nibble = val->bv_val[i] - ('a'-10);
2951 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2952 nibble = val->bv_val[i] - ('A'-10);
2955 slap_sl_free( normalized->bv_val, ctx );
2956 BER_BVZERO( normalized );
2957 return LDAP_INVALID_SYNTAX;
2962 normalized->bv_val[j>>1] = octet;
2964 octet = nibble << 4;
2969 normalized->bv_val[normalized->bv_len] = 0;
2970 return LDAP_SUCCESS;
2976 numericStringValidate(
2982 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2984 for(i=0; i < in->bv_len; i++) {
2985 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
2986 return LDAP_INVALID_SYNTAX;
2990 return LDAP_SUCCESS;
2994 numericStringNormalize(
2999 struct berval *normalized,
3002 /* removal all spaces */
3005 assert( !BER_BVISEMPTY( val ) );
3007 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3010 q = normalized->bv_val;
3013 if ( ASCII_SPACE( *p ) ) {
3014 /* Ignore whitespace */
3021 /* we should have copied no more than is in val */
3022 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3024 /* null terminate */
3027 normalized->bv_len = q - normalized->bv_val;
3029 if( BER_BVISEMPTY( normalized ) ) {
3030 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3031 normalized->bv_val[0] = ' ';
3032 normalized->bv_val[1] = '\0';
3033 normalized->bv_len = 1;
3036 return LDAP_SUCCESS;
3040 * Integer conversion macros that will use the largest available
3043 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3044 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
3045 # define SLAP_LONG long long
3047 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
3048 # define SLAP_LONG long
3049 #endif /* HAVE_STRTOLL ... */
3057 struct berval *value,
3058 void *assertedValue )
3060 SLAP_LONG lValue, lAssertedValue;
3063 /* safe to assume integers are NUL terminated? */
3064 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3065 if( errno == ERANGE )
3067 return LDAP_CONSTRAINT_VIOLATION;
3070 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3072 if( errno == ERANGE )
3074 return LDAP_CONSTRAINT_VIOLATION;
3077 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3078 return LDAP_SUCCESS;
3087 struct berval *value,
3088 void *assertedValue )
3090 SLAP_LONG lValue, lAssertedValue;
3093 /* safe to assume integers are NUL terminated? */
3094 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3095 if( errno == ERANGE )
3097 return LDAP_CONSTRAINT_VIOLATION;
3100 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3102 if( errno == ERANGE )
3104 return LDAP_CONSTRAINT_VIOLATION;
3107 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3108 return LDAP_SUCCESS;
3112 checkNum( struct berval *in, struct berval *out )
3114 /* parse serialNumber */
3115 ber_len_t neg = 0, extra = 0;
3118 out->bv_val = in->bv_val;
3121 if ( out->bv_val[0] == '-' ) {
3126 if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3127 first = out->bv_val[2];
3130 out->bv_len += STRLENOF("0x");
3131 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3132 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3135 } else if ( out->bv_val[0] == '\'' ) {
3136 first = out->bv_val[1];
3139 out->bv_len += STRLENOF("'");
3141 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3142 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3144 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3147 out->bv_len += STRLENOF("'H");
3150 first = out->bv_val[0];
3151 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3152 if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3156 if ( !( out->bv_len > neg ) ) {
3160 if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3168 serialNumberAndIssuerCheck(
3176 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3178 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3179 /* Parse old format */
3180 is->bv_val = ber_bvchr( in, '$' );
3181 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3183 sn->bv_val = in->bv_val;
3184 sn->bv_len = is->bv_val - in->bv_val;
3187 is->bv_len = in->bv_len - (sn->bv_len + 1);
3189 /* eat leading zeros */
3190 for( n=0; n < (sn->bv_len-1); n++ ) {
3191 if( sn->bv_val[n] != '0' ) break;
3196 for( n=0; n < sn->bv_len; n++ ) {
3197 if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3201 /* Parse GSER format */
3206 HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3210 struct berval x = *in;
3216 /* eat leading spaces */
3217 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3221 /* should be at issuer or serialNumber NamedValue */
3222 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3223 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3226 x.bv_val += STRLENOF("issuer");
3227 x.bv_len -= STRLENOF("issuer");
3229 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3233 /* eat leading spaces */
3234 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3238 /* For backward compatibility, this part is optional */
3239 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3240 x.bv_val += STRLENOF("rdnSequence:");
3241 x.bv_len -= STRLENOF("rdnSequence:");
3244 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3248 is->bv_val = x.bv_val;
3251 for ( ; is->bv_len < x.bv_len; ) {
3252 if ( is->bv_val[is->bv_len] != '"' ) {
3256 if ( is->bv_val[is->bv_len+1] == '"' ) {
3263 x.bv_val += is->bv_len + 1;
3264 x.bv_len -= is->bv_len + 1;
3266 have |= HAVE_ISSUER;
3268 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3270 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3272 /* parse serialNumber */
3273 x.bv_val += STRLENOF("serialNumber");
3274 x.bv_len -= STRLENOF("serialNumber");
3276 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3280 /* eat leading spaces */
3281 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3285 if ( checkNum( &x, sn ) ) {
3286 return LDAP_INVALID_SYNTAX;
3289 x.bv_val += sn->bv_len;
3290 x.bv_len -= sn->bv_len;
3295 return LDAP_INVALID_SYNTAX;
3298 /* eat leading spaces */
3299 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3303 if ( have == HAVE_ALL ) {
3307 if ( x.bv_val[0] != ',' ) {
3308 return LDAP_INVALID_SYNTAX;
3315 /* should have no characters left... */
3316 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3318 if ( numdquotes == 0 ) {
3319 ber_dupbv_x( &ni, is, ctx );
3324 ni.bv_len = is->bv_len - numdquotes;
3325 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3326 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3327 if ( is->bv_val[src] == '"' ) {
3330 ni.bv_val[dst] = is->bv_val[src];
3332 ni.bv_val[dst] = '\0';
3342 serialNumberAndIssuerValidate(
3347 struct berval sn, i;
3349 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3352 rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3357 /* validate DN -- doesn't handle double dquote */
3358 rc = dnValidate( NULL, &i );
3360 rc = LDAP_INVALID_SYNTAX;
3363 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3364 slap_sl_free( i.bv_val, NULL );
3367 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3368 in->bv_val, rc, 0 );
3375 serialNumberAndIssuerPretty(
3382 struct berval sn, i, ni = BER_BVNULL;
3385 assert( in != NULL );
3386 assert( out != NULL );
3390 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3393 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3398 rc = dnPretty( syntax, &i, &ni, ctx );
3400 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3401 slap_sl_free( i.bv_val, ctx );
3405 rc = LDAP_INVALID_SYNTAX;
3409 /* make room from sn + "$" */
3410 out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3411 + sn.bv_len + ni.bv_len;
3412 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3414 if ( out->bv_val == NULL ) {
3421 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3422 p = lutil_strbvcopy( p, &sn );
3423 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3424 p = lutil_strbvcopy( p, &ni );
3425 p = lutil_strcopy( p, /*{*/ "\" }" );
3427 assert( p == &out->bv_val[out->bv_len] );
3430 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3431 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3433 slap_sl_free( ni.bv_val, ctx );
3435 return LDAP_SUCCESS;
3445 /* Use hex format. '123456789abcdef'H */
3446 unsigned char *ptr, zero = '\0';
3449 ber_len_t i, len, nlen;
3451 assert( in != NULL );
3452 assert( !BER_BVISNULL( in ) );
3453 assert( out != NULL );
3454 assert( !BER_BVISNULL( out ) );
3456 ptr = (unsigned char *)in->bv_val;
3459 /* Check for minimal encodings */
3461 if ( ptr[0] & 0x80 ) {
3462 if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3466 } else if ( ptr[0] == 0 ) {
3467 if ( !( ptr[1] & 0x80 ) ) {
3474 } else if ( len == 0 ) {
3475 /* FIXME: this should not be possible,
3476 * since a value of zero would have length 1 */
3481 first = !( ptr[0] & 0xf0U );
3482 nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3483 if ( nlen >= out->bv_len ) {
3484 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3490 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3494 for ( ; i < len; i++ ) {
3495 sprintf( sptr, "%02X", ptr[i] );
3502 assert( sptr == &out->bv_val[nlen] );
3509 #define SLAP_SN_BUFLEN (64)
3512 * This routine is called by certificateExactNormalize when
3513 * certificateExactNormalize receives a search string instead of
3514 * a certificate. This routine checks if the search value is valid
3515 * and then returns the normalized value
3518 serialNumberAndIssuerNormalize(
3526 struct berval sn, sn2, sn3, i, ni;
3527 char sbuf2[SLAP_SN_BUFLEN];
3528 char sbuf3[SLAP_SN_BUFLEN];
3532 assert( in != NULL );
3533 assert( out != NULL );
3535 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3538 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3543 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3545 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3546 slap_sl_free( i.bv_val, ctx );
3550 return LDAP_INVALID_SYNTAX;
3553 /* Convert sn to canonical hex */
3555 if ( sn.bv_len > sizeof( sbuf2 ) ) {
3556 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3558 sn2.bv_len = sn.bv_len;
3559 if ( lutil_str2bin( &sn, &sn2, ctx )) {
3560 rc = LDAP_INVALID_SYNTAX;
3565 sn3.bv_len = sizeof(sbuf3);
3566 if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
3567 rc = LDAP_INVALID_SYNTAX;
3571 out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3572 + sn3.bv_len + ni.bv_len;
3573 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3575 if ( out->bv_val == NULL ) {
3583 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3584 p = lutil_strbvcopy( p, &sn3 );
3585 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3586 p = lutil_strbvcopy( p, &ni );
3587 p = lutil_strcopy( p, /*{*/ "\" }" );
3589 assert( p == &out->bv_val[out->bv_len] );
3592 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3593 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3595 if ( sn2.bv_val != sbuf2 ) {
3596 slap_sl_free( sn2.bv_val, ctx );
3599 if ( sn3.bv_val != sbuf3 ) {
3600 slap_sl_free( sn3.bv_val, ctx );
3603 slap_sl_free( ni.bv_val, ctx );
3609 certificateExactNormalize(
3614 struct berval *normalized,
3617 BerElementBuffer berbuf;
3618 BerElement *ber = (BerElement *)&berbuf;
3622 char serialbuf2[SLAP_SN_BUFLEN];
3623 struct berval sn, sn2 = BER_BVNULL;
3624 struct berval issuer_dn = BER_BVNULL, bvdn;
3626 int rc = LDAP_INVALID_SYNTAX;
3628 assert( val != NULL );
3630 Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3631 val->bv_val, val->bv_len, 0 );
3633 if ( BER_BVISEMPTY( val ) ) goto done;
3635 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3636 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3639 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3641 ber_init2( ber, val, LBER_USE_DER );
3642 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3643 tag = ber_skip_tag( ber, &len ); /* Sequence */
3644 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3645 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3646 tag = ber_skip_tag( ber, &len );
3647 tag = ber_get_int( ber, &i ); /* version */
3650 /* NOTE: move the test here from certificateValidate,
3651 * so that we can validate certs with serial longer
3652 * than sizeof(ber_int_t) */
3653 tag = ber_skip_tag( ber, &len ); /* serial */
3655 sn.bv_val = (char *)ber->ber_ptr;
3656 sn2.bv_val = serialbuf2;
3657 sn2.bv_len = sizeof(serialbuf2);
3658 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3659 rc = LDAP_INVALID_SYNTAX;
3662 ber_skip_data( ber, len );
3664 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3665 ber_skip_data( ber, len );
3666 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3667 len = ber_ptrlen( ber );
3668 bvdn.bv_val = val->bv_val + len;
3669 bvdn.bv_len = val->bv_len - len;
3671 rc = dnX509normalize( &bvdn, &issuer_dn );
3672 if ( rc != LDAP_SUCCESS ) goto done;
3674 normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3675 + sn2.bv_len + issuer_dn.bv_len;
3676 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3678 p = normalized->bv_val;
3680 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3681 p = lutil_strbvcopy( p, &sn2 );
3682 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3683 p = lutil_strbvcopy( p, &issuer_dn );
3684 p = lutil_strcopy( p, /*{*/ "\" }" );
3689 Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3690 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3692 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3693 if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3698 /* X.509 PKI certificateList stuff */
3700 checkTime( struct berval *in, struct berval *out )
3704 char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3707 assert( in != NULL );
3708 assert( !BER_BVISNULL( in ) );
3709 assert( !BER_BVISEMPTY( in ) );
3711 if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3715 if ( out != NULL ) {
3716 assert( !BER_BVISNULL( out ) );
3717 assert( out->bv_len >= sizeof( buf ) );
3718 bv.bv_val = out->bv_val;
3724 for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3725 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3728 if ( in->bv_val[i] != 'Z' ) {
3733 if ( i != in->bv_len ) {
3737 if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3738 lutil_strncopy( bv.bv_val, in->bv_val, i );
3741 } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3742 char *p = bv.bv_val;
3743 if ( in->bv_val[0] < '7' ) {
3744 p = lutil_strcopy( p, "20" );
3747 p = lutil_strcopy( p, "19" );
3749 lutil_strncopy( p, in->bv_val, i );
3756 rc = generalizedTimeValidate( NULL, &bv );
3757 if ( rc == LDAP_SUCCESS && out != NULL ) {
3758 if ( out->bv_len > bv.bv_len ) {
3759 out->bv_val[ bv.bv_len ] = '\0';
3761 out->bv_len = bv.bv_len;
3764 return rc != LDAP_SUCCESS;
3768 issuerAndThisUpdateCheck(
3775 struct berval x = *in;
3776 struct berval ni = BER_BVNULL;
3777 /* Parse GSER format */
3781 HAVE_THISUPDATE = 0x2,
3782 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3786 if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3788 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3789 return LDAP_INVALID_SYNTAX;
3793 x.bv_len -= STRLENOF("{}");
3796 /* eat leading spaces */
3797 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3801 /* should be at issuer or thisUpdate */
3802 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3803 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3806 x.bv_val += STRLENOF("issuer");
3807 x.bv_len -= STRLENOF("issuer");
3809 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3813 /* eat leading spaces */
3814 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3818 /* For backward compatibility, this part is optional */
3819 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3820 return LDAP_INVALID_SYNTAX;
3822 x.bv_val += STRLENOF("rdnSequence:");
3823 x.bv_len -= STRLENOF("rdnSequence:");
3825 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3829 is->bv_val = x.bv_val;
3832 for ( ; is->bv_len < x.bv_len; ) {
3833 if ( is->bv_val[is->bv_len] != '"' ) {
3837 if ( is->bv_val[is->bv_len+1] == '"' ) {
3844 x.bv_val += is->bv_len + 1;
3845 x.bv_len -= is->bv_len + 1;
3847 have |= HAVE_ISSUER;
3849 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3851 if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3853 /* parse thisUpdate */
3854 x.bv_val += STRLENOF("thisUpdate");
3855 x.bv_len -= STRLENOF("thisUpdate");
3857 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3861 /* eat leading spaces */
3862 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3866 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3870 tu->bv_val = x.bv_val;
3873 for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3874 if ( tu->bv_val[tu->bv_len] == '"' ) {
3878 x.bv_val += tu->bv_len + 1;
3879 x.bv_len -= tu->bv_len + 1;
3881 have |= HAVE_THISUPDATE;
3884 return LDAP_INVALID_SYNTAX;
3887 /* eat leading spaces */
3888 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3892 if ( have == HAVE_ALL ) {
3896 if ( x.bv_val[0] != ',' ) {
3897 return LDAP_INVALID_SYNTAX;
3904 /* should have no characters left... */
3905 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3907 if ( numdquotes == 0 ) {
3908 ber_dupbv_x( &ni, is, ctx );
3913 ni.bv_len = is->bv_len - numdquotes;
3914 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3915 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3916 if ( is->bv_val[src] == '"' ) {
3919 ni.bv_val[dst] = is->bv_val[src];
3921 ni.bv_val[dst] = '\0';
3930 issuerAndThisUpdateValidate(
3935 struct berval i, tu;
3937 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3940 rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3945 /* validate DN -- doesn't handle double dquote */
3946 rc = dnValidate( NULL, &i );
3948 rc = LDAP_INVALID_SYNTAX;
3950 } else if ( checkTime( &tu, NULL ) ) {
3951 rc = LDAP_INVALID_SYNTAX;
3954 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3955 slap_sl_free( i.bv_val, NULL );
3958 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3959 in->bv_val, rc, 0 );
3966 issuerAndThisUpdatePretty(
3973 struct berval i, tu, ni = BER_BVNULL;
3976 assert( in != NULL );
3977 assert( out != NULL );
3981 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3984 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
3989 rc = dnPretty( syntax, &i, &ni, ctx );
3991 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3992 slap_sl_free( i.bv_val, ctx );
3995 if ( rc || checkTime( &tu, NULL ) ) {
3996 rc = LDAP_INVALID_SYNTAX;
4001 out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
4002 + ni.bv_len + tu.bv_len;
4003 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4005 if ( out->bv_val == NULL ) {
4012 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4013 p = lutil_strbvcopy( p, &ni );
4014 p = lutil_strcopy( p, "\", thisUpdate \"" );
4015 p = lutil_strbvcopy( p, &tu );
4016 p = lutil_strcopy( p, /*{*/ "\" }" );
4018 assert( p == &out->bv_val[out->bv_len] );
4021 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4022 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4024 slap_sl_free( ni.bv_val, ctx );
4030 issuerAndThisUpdateNormalize(
4038 struct berval i, ni, tu, tu2;
4039 char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4043 assert( in != NULL );
4044 assert( out != NULL );
4046 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4049 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4054 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4056 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4057 slap_sl_free( i.bv_val, ctx );
4061 tu2.bv_len = sizeof( sbuf );
4062 if ( rc || checkTime( &tu, &tu2 ) ) {
4063 return LDAP_INVALID_SYNTAX;
4066 out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4067 + ni.bv_len + tu2.bv_len;
4068 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4070 if ( out->bv_val == NULL ) {
4078 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4079 p = lutil_strbvcopy( p, &ni );
4080 p = lutil_strcopy( p, "\", thisUpdate \"" );
4081 p = lutil_strbvcopy( p, &tu2 );
4082 p = lutil_strcopy( p, /*{*/ "\" }" );
4084 assert( p == &out->bv_val[out->bv_len] );
4087 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4088 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4090 slap_sl_free( ni.bv_val, ctx );
4096 certificateListExactNormalize(
4101 struct berval *normalized,
4104 BerElementBuffer berbuf;
4105 BerElement *ber = (BerElement *)&berbuf;
4109 struct berval issuer_dn = BER_BVNULL, bvdn,
4111 char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4112 int rc = LDAP_INVALID_SYNTAX;
4114 assert( val != NULL );
4116 Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4117 val->bv_val, val->bv_len, 0 );
4119 if ( BER_BVISEMPTY( val ) ) goto done;
4121 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4122 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4125 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4127 ber_init2( ber, val, LBER_USE_DER );
4128 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
4129 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4130 tag = ber_skip_tag( ber, &len ); /* Sequence */
4131 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4132 tag = ber_peek_tag( ber, &len );
4133 /* Optional version */
4134 if ( tag == LBER_INTEGER ) {
4135 tag = ber_get_int( ber, &version );
4136 assert( tag == LBER_INTEGER );
4137 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4139 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
4140 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4141 ber_skip_data( ber, len );
4143 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
4144 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4145 len = ber_ptrlen( ber );
4146 bvdn.bv_val = val->bv_val + len;
4147 bvdn.bv_len = val->bv_len - len;
4148 tag = ber_skip_tag( ber, &len );
4149 ber_skip_data( ber, len );
4151 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
4152 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4153 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4154 bvtu.bv_val = (char *)ber->ber_ptr;
4157 rc = dnX509normalize( &bvdn, &issuer_dn );
4158 if ( rc != LDAP_SUCCESS ) goto done;
4160 thisUpdate.bv_val = tubuf;
4161 thisUpdate.bv_len = sizeof(tubuf);
4162 if ( checkTime( &bvtu, &thisUpdate ) ) {
4163 rc = LDAP_INVALID_SYNTAX;
4167 normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4168 + issuer_dn.bv_len + thisUpdate.bv_len;
4169 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4171 p = normalized->bv_val;
4173 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4174 p = lutil_strbvcopy( p, &issuer_dn );
4175 p = lutil_strcopy( p, "\", thisUpdate \"" );
4176 p = lutil_strbvcopy( p, &thisUpdate );
4177 p = lutil_strcopy( p, /*{*/ "\" }" );
4182 Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4183 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4185 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4190 /* X.509 PMI serialNumberAndIssuerSerialCheck
4192 AttributeCertificateExactAssertion ::= SEQUENCE {
4193 serialNumber CertificateSerialNumber,
4194 issuer AttCertIssuer }
4196 CertificateSerialNumber ::= INTEGER
4198 AttCertIssuer ::= [0] SEQUENCE {
4199 issuerName GeneralNames OPTIONAL,
4200 baseCertificateID [0] IssuerSerial OPTIONAL,
4201 objectDigestInfo [1] ObjectDigestInfo OPTIONAL }
4202 -- At least one component shall be present
4204 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4206 GeneralName ::= CHOICE {
4207 otherName [0] INSTANCE OF OTHER-NAME,
4208 rfc822Name [1] IA5String,
4209 dNSName [2] IA5String,
4210 x400Address [3] ORAddress,
4211 directoryName [4] Name,
4212 ediPartyName [5] EDIPartyName,
4213 uniformResourceIdentifier [6] IA5String,
4214 iPAddress [7] OCTET STRING,
4215 registeredID [8] OBJECT IDENTIFIER }
4217 IssuerSerial ::= SEQUENCE {
4218 issuer GeneralNames,
4219 serial CertificateSerialNumber,
4220 issuerUID UniqueIdentifier OPTIONAL }
4222 ObjectDigestInfo ::= SEQUENCE {
4223 digestedObjectType ENUMERATED {
4226 otherObjectTypes (2) },
4227 otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
4228 digestAlgorithm AlgorithmIdentifier,
4229 objectDigest BIT STRING }
4231 * The way I interpret it, an assertion should look like
4233 { serialNumber 'dd'H,
4234 issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4235 baseCertificateID { serial '1d'H,
4236 issuer { directoryName:rdnSequence:"cn=zzz" },
4237 issuerUID <value> -- optional
4239 objectDigestInfo { ... } -- optional
4243 * with issuerName, baseCertificateID and objectDigestInfo optional,
4244 * at least one present; the way it's currently implemented, it is
4246 { serialNumber 'dd'H,
4247 issuer { baseCertificateID { serial '1d'H,
4248 issuer { directoryName:rdnSequence:"cn=zzz" }
4253 * with all the above parts mandatory.
4256 serialNumberAndIssuerSerialCheck(
4260 struct berval *i_sn, /* contain serial of baseCertificateID */
4263 /* Parse GSER format */
4268 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4269 } have = HAVE_NONE, have2 = HAVE_NONE;
4271 struct berval x = *in;
4274 if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4277 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4284 /* eat leading spaces */
4285 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4289 /* should be at issuer or serialNumber NamedValue */
4290 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4291 if ( have & HAVE_ISSUER ) {
4292 return LDAP_INVALID_SYNTAX;
4295 /* parse IssuerSerial */
4296 x.bv_val += STRLENOF("issuer");
4297 x.bv_len -= STRLENOF("issuer");
4299 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4303 /* eat leading spaces */
4304 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4308 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4312 /* eat leading spaces */
4313 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4317 if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4318 return LDAP_INVALID_SYNTAX;
4320 x.bv_val += STRLENOF("baseCertificateID ");
4321 x.bv_len -= STRLENOF("baseCertificateID ");
4323 /* eat leading spaces */
4324 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4328 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4333 /* eat leading spaces */
4334 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4338 /* parse issuer of baseCertificateID */
4339 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4340 if ( have2 & HAVE_ISSUER ) {
4341 return LDAP_INVALID_SYNTAX;
4344 x.bv_val += STRLENOF("issuer ");
4345 x.bv_len -= STRLENOF("issuer ");
4347 /* eat leading spaces */
4348 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4352 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4356 /* eat leading spaces */
4357 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4361 if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4362 return LDAP_INVALID_SYNTAX;
4364 x.bv_val += STRLENOF("directoryName:rdnSequence:");
4365 x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4367 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4371 is->bv_val = x.bv_val;
4374 for ( ; is->bv_len < x.bv_len; ) {
4375 if ( is->bv_val[is->bv_len] != '"' ) {
4379 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4386 x.bv_val += is->bv_len + 1;
4387 x.bv_len -= is->bv_len + 1;
4389 /* eat leading spaces */
4390 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4394 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4398 have2 |= HAVE_ISSUER;
4400 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4401 if ( have2 & HAVE_SN ) {
4402 return LDAP_INVALID_SYNTAX;
4405 x.bv_val += STRLENOF("serial ");
4406 x.bv_len -= STRLENOF("serial ");
4408 /* eat leading spaces */
4409 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4413 if ( checkNum( &x, i_sn ) ) {
4414 return LDAP_INVALID_SYNTAX;
4417 x.bv_val += i_sn->bv_len;
4418 x.bv_len -= i_sn->bv_len;
4423 return LDAP_INVALID_SYNTAX;
4426 /* eat leading spaces */
4427 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4431 if ( have2 == HAVE_ALL ) {
4435 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4440 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4444 /* eat leading spaces */
4445 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4449 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4453 have |= HAVE_ISSUER;
4455 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4456 if ( have & HAVE_SN ) {
4457 return LDAP_INVALID_SYNTAX;
4460 /* parse serialNumber */
4461 x.bv_val += STRLENOF("serialNumber");
4462 x.bv_len -= STRLENOF("serialNumber");
4464 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4468 /* eat leading spaces */
4469 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4473 if ( checkNum( &x, sn ) ) {
4474 return LDAP_INVALID_SYNTAX;
4477 x.bv_val += sn->bv_len;
4478 x.bv_len -= sn->bv_len;
4483 return LDAP_INVALID_SYNTAX;
4487 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4491 if ( have == HAVE_ALL ) {
4495 if ( x.bv_val[0] != ',' ) {
4496 return LDAP_INVALID_SYNTAX;
4502 /* should have no characters left... */
4503 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4505 if ( numdquotes == 0 ) {
4506 ber_dupbv_x( &ni, is, ctx );
4511 ni.bv_len = is->bv_len - numdquotes;
4512 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4513 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4514 if ( is->bv_val[src] == '"' ) {
4517 ni.bv_val[dst] = is->bv_val[src];
4519 ni.bv_val[dst] = '\0';
4524 /* need to handle double dquotes here */
4528 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4530 serialNumberAndIssuerSerialValidate(
4535 struct berval sn, i, i_sn;
4537 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4540 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4545 /* validate DN -- doesn't handle double dquote */
4546 rc = dnValidate( NULL, &i );
4548 rc = LDAP_INVALID_SYNTAX;
4551 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4552 slap_sl_free( i.bv_val, NULL );
4556 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4557 in->bv_val, rc, 0 );
4562 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4564 serialNumberAndIssuerSerialPretty(
4570 struct berval sn, i, i_sn, ni = BER_BVNULL;
4574 assert( in != NULL );
4575 assert( out != NULL );
4577 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4580 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4585 rc = dnPretty( syntax, &i, &ni, ctx );
4587 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4588 slap_sl_free( i.bv_val, ctx );
4592 rc = LDAP_INVALID_SYNTAX;
4596 /* make room from sn + "$" */
4597 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4598 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4599 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4601 if ( out->bv_val == NULL ) {
4608 p = lutil_strcopy( p, "{ serialNumber " );
4609 p = lutil_strbvcopy( p, &sn );
4610 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4611 p = lutil_strbvcopy( p, &ni );
4612 p = lutil_strcopy( p, "\" }, serial " );
4613 p = lutil_strbvcopy( p, &i_sn );
4614 p = lutil_strcopy( p, " } } }" );
4616 assert( p == &out->bv_val[out->bv_len] );
4619 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4620 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4622 slap_sl_free( ni.bv_val, ctx );
4627 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4629 * This routine is called by attributeCertificateExactNormalize
4630 * when attributeCertificateExactNormalize receives a search
4631 * string instead of a attribute certificate. This routine
4632 * checks if the search value is valid and then returns the
4636 serialNumberAndIssuerSerialNormalize(
4644 struct berval i, ni = BER_BVNULL,
4645 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4646 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4647 char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4648 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4652 assert( in != NULL );
4653 assert( out != NULL );
4655 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4658 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4663 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4665 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4666 slap_sl_free( i.bv_val, ctx );
4670 rc = LDAP_INVALID_SYNTAX;
4674 /* Convert sn to canonical hex */
4676 sn2.bv_len = sn.bv_len;
4677 if ( sn.bv_len > sizeof( sbuf2 ) ) {
4678 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4680 if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4681 rc = LDAP_INVALID_SYNTAX;
4685 /* Convert i_sn to canonical hex */
4686 i_sn2.bv_val = i_sbuf2;
4687 i_sn2.bv_len = i_sn.bv_len;
4688 if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4689 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4691 if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4692 rc = LDAP_INVALID_SYNTAX;
4697 sn3.bv_len = sizeof(sbuf3);
4698 if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4699 rc = LDAP_INVALID_SYNTAX;
4703 i_sn3.bv_val = i_sbuf3;
4704 i_sn3.bv_len = sizeof(i_sbuf3);
4705 if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4706 rc = LDAP_INVALID_SYNTAX;
4710 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4711 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4712 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4714 if ( out->bv_val == NULL ) {
4722 p = lutil_strcopy( p, "{ serialNumber " );
4723 p = lutil_strbvcopy( p, &sn3 );
4724 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4725 p = lutil_strbvcopy( p, &ni );
4726 p = lutil_strcopy( p, "\" }, serial " );
4727 p = lutil_strbvcopy( p, &i_sn3 );
4728 p = lutil_strcopy( p, " } } }" );
4730 assert( p == &out->bv_val[out->bv_len] );
4733 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4734 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4736 if ( sn2.bv_val != sbuf2 ) {
4737 slap_sl_free( sn2.bv_val, ctx );
4740 if ( i_sn2.bv_val != i_sbuf2 ) {
4741 slap_sl_free( i_sn2.bv_val, ctx );
4744 if ( sn3.bv_val != sbuf3 ) {
4745 slap_sl_free( sn3.bv_val, ctx );
4748 if ( i_sn3.bv_val != i_sbuf3 ) {
4749 slap_sl_free( i_sn3.bv_val, ctx );
4752 slap_sl_free( ni.bv_val, ctx );
4757 /* X.509 PMI attributeCertificateExactNormalize */
4759 attributeCertificateExactNormalize(
4764 struct berval *normalized,
4767 BerElementBuffer berbuf;
4768 BerElement *ber = (BerElement *)&berbuf;
4771 char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4772 struct berval sn, i_sn, sn2, i_sn2;
4773 struct berval issuer_dn = BER_BVNULL, bvdn;
4775 int rc = LDAP_INVALID_SYNTAX;
4777 if ( BER_BVISEMPTY( val ) ) {
4781 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4782 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4785 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4787 ber_init2( ber, val, LBER_USE_DER );
4788 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
4789 tag = ber_skip_tag( ber, &len ); /* Sequence */
4790 tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */
4791 ber_skip_data( ber, len );
4792 tag = ber_skip_tag( ber, &len ); /* Holder Sequence */
4793 ber_skip_data( ber, len );
4796 tag = ber_skip_tag( ber, &len ); /* Sequence */
4797 /* issuerName (GeneralNames sequence; optional)? */
4798 tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */
4799 tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */
4800 tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */
4801 if ( tag != SLAP_X509_GN_DIRECTORYNAME ) {
4802 rc = LDAP_INVALID_SYNTAX;
4805 tag = ber_peek_tag( ber, &len ); /* sequence of RDN */
4806 len = ber_ptrlen( ber );
4807 bvdn.bv_val = val->bv_val + len;
4808 bvdn.bv_len = val->bv_len - len;
4809 rc = dnX509normalize( &bvdn, &issuer_dn );
4810 if ( rc != LDAP_SUCCESS ) goto done;
4812 tag = ber_skip_tag( ber, &len ); /* sequence of RDN */
4813 ber_skip_data( ber, len );
4814 tag = ber_skip_tag( ber, &len ); /* serial number */
4815 if ( tag != LBER_INTEGER ) {
4816 rc = LDAP_INVALID_SYNTAX;
4819 i_sn.bv_val = (char *)ber->ber_ptr;
4821 i_sn2.bv_val = issuer_serialbuf;
4822 i_sn2.bv_len = sizeof(issuer_serialbuf);
4823 if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4824 rc = LDAP_INVALID_SYNTAX;
4827 ber_skip_data( ber, len );
4829 /* issuerUID (bitstring; optional)? */
4830 /* objectDigestInfo (sequence; optional)? */
4832 tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */
4833 ber_skip_data( ber, len );
4834 tag = ber_skip_tag( ber, &len ); /* serial number */
4835 if ( tag != LBER_INTEGER ) {
4836 rc = LDAP_INVALID_SYNTAX;
4839 sn.bv_val = (char *)ber->ber_ptr;
4841 sn2.bv_val = serialbuf;
4842 sn2.bv_len = sizeof(serialbuf);
4843 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4844 rc = LDAP_INVALID_SYNTAX;
4847 ber_skip_data( ber, len );
4849 normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" )
4850 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4851 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4853 p = normalized->bv_val;
4855 p = lutil_strcopy( p, "{ serialNumber " );
4856 p = lutil_strbvcopy( p, &sn2 );
4857 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4858 p = lutil_strbvcopy( p, &issuer_dn );
4859 p = lutil_strcopy( p, "\" }, serial " );
4860 p = lutil_strbvcopy( p, &i_sn2 );
4861 p = lutil_strcopy( p, " } } }" );
4863 Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4864 normalized->bv_val, NULL, NULL );
4869 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4870 if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4871 if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4884 assert( in != NULL );
4885 assert( !BER_BVISNULL( in ) );
4887 for ( i = 0; i < in->bv_len; i++ ) {
4888 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4889 return LDAP_INVALID_SYNTAX;
4893 return LDAP_SUCCESS;
4896 /* Normalize a SID as used inside a CSN:
4897 * three-digit numeric string */
4904 struct berval *normalized,
4909 assert( val != NULL );
4910 assert( normalized != NULL );
4912 ber_dupbv_x( normalized, val, ctx );
4914 for ( i = 0; i < normalized->bv_len; i++ ) {
4915 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4916 ber_memfree_x( normalized->bv_val, ctx );
4917 BER_BVZERO( normalized );
4918 return LDAP_INVALID_SYNTAX;
4921 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4924 return LDAP_SUCCESS;
4932 assert( in != NULL );
4933 assert( !BER_BVISNULL( in ) );
4935 if ( in->bv_len != 3 ) {
4936 return LDAP_INVALID_SYNTAX;
4939 return hexValidate( NULL, in );
4942 /* Normalize a SID as used inside a CSN:
4943 * three-digit numeric string */
4950 struct berval *normalized,
4953 if ( val->bv_len != 3 ) {
4954 return LDAP_INVALID_SYNTAX;
4957 return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4967 return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4970 /* Normalize a SID as used inside a CSN, either as-is
4971 * (assertion value) or extracted from the CSN
4972 * (attribute value) */
4979 struct berval *normalized,
4987 if ( BER_BVISEMPTY( val ) ) {
4988 return LDAP_INVALID_SYNTAX;
4991 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4992 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
4995 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4997 ptr = ber_bvchr( val, '#' );
4998 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
4999 return LDAP_INVALID_SYNTAX;
5002 bv.bv_val = ptr + 1;
5003 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5005 ptr = ber_bvchr( &bv, '#' );
5006 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5007 return LDAP_INVALID_SYNTAX;
5010 bv.bv_val = ptr + 1;
5011 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5013 ptr = ber_bvchr( &bv, '#' );
5014 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5015 return LDAP_INVALID_SYNTAX;
5018 bv.bv_len = ptr - bv.bv_val;
5020 if ( bv.bv_len == 2 ) {
5021 /* OpenLDAP 2.3 SID */
5023 buf[ 1 ] = bv.bv_val[ 0 ];
5024 buf[ 2 ] = bv.bv_val[ 1 ];
5031 return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5043 assert( in != NULL );
5044 assert( !BER_BVISNULL( in ) );
5046 if ( BER_BVISEMPTY( in ) ) {
5047 return LDAP_INVALID_SYNTAX;
5052 ptr = ber_bvchr( &bv, '#' );
5053 if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5054 return LDAP_INVALID_SYNTAX;
5057 bv.bv_len = ptr - bv.bv_val;
5058 if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5059 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5061 return LDAP_INVALID_SYNTAX;
5064 rc = generalizedTimeValidate( NULL, &bv );
5065 if ( rc != LDAP_SUCCESS ) {
5069 bv.bv_val = ptr + 1;
5070 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5072 ptr = ber_bvchr( &bv, '#' );
5073 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5074 return LDAP_INVALID_SYNTAX;
5077 bv.bv_len = ptr - bv.bv_val;
5078 if ( bv.bv_len != 6 ) {
5079 return LDAP_INVALID_SYNTAX;
5082 rc = hexValidate( NULL, &bv );
5083 if ( rc != LDAP_SUCCESS ) {
5087 bv.bv_val = ptr + 1;
5088 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5090 ptr = ber_bvchr( &bv, '#' );
5091 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5092 return LDAP_INVALID_SYNTAX;
5095 bv.bv_len = ptr - bv.bv_val;
5096 if ( bv.bv_len == 2 ) {
5097 /* tolerate old 2-digit replica-id */
5098 rc = hexValidate( NULL, &bv );
5101 rc = sidValidate( NULL, &bv );
5103 if ( rc != LDAP_SUCCESS ) {
5107 bv.bv_val = ptr + 1;
5108 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5110 if ( bv.bv_len != 6 ) {
5111 return LDAP_INVALID_SYNTAX;
5114 return hexValidate( NULL, &bv );
5117 /* Normalize a CSN in OpenLDAP 2.1 format */
5124 struct berval *normalized,
5127 struct berval gt, cnt, sid, mod;
5129 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5133 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5134 assert( !BER_BVISEMPTY( val ) );
5138 ptr = ber_bvchr( >, '#' );
5139 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5140 return LDAP_INVALID_SYNTAX;
5143 gt.bv_len = ptr - gt.bv_val;
5144 if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5145 return LDAP_INVALID_SYNTAX;
5148 if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5149 return LDAP_INVALID_SYNTAX;
5152 cnt.bv_val = ptr + 1;
5153 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5155 ptr = ber_bvchr( &cnt, '#' );
5156 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5157 return LDAP_INVALID_SYNTAX;
5160 cnt.bv_len = ptr - cnt.bv_val;
5161 if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5162 return LDAP_INVALID_SYNTAX;
5165 if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5166 return LDAP_INVALID_SYNTAX;
5169 cnt.bv_val += STRLENOF( "0x" );
5170 cnt.bv_len -= STRLENOF( "0x" );
5172 sid.bv_val = ptr + 1;
5173 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5175 ptr = ber_bvchr( &sid, '#' );
5176 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5177 return LDAP_INVALID_SYNTAX;
5180 sid.bv_len = ptr - sid.bv_val;
5181 if ( sid.bv_len != STRLENOF( "0" ) ) {
5182 return LDAP_INVALID_SYNTAX;
5185 mod.bv_val = ptr + 1;
5186 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5187 if ( mod.bv_len != STRLENOF( "0000" ) ) {
5188 return LDAP_INVALID_SYNTAX;
5191 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5195 ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5196 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5198 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5200 ptr = lutil_strcopy( ptr, ".000000Z#00" );
5201 ptr = lutil_strbvcopy( ptr, &cnt );
5205 *ptr++ = sid.bv_val[ 0 ];
5209 for ( i = 0; i < mod.bv_len; i++ ) {
5210 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5214 assert( ptr == &bv.bv_val[bv.bv_len] );
5216 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5217 return LDAP_INVALID_SYNTAX;
5220 ber_dupbv_x( normalized, &bv, ctx );
5222 return LDAP_SUCCESS;
5225 /* Normalize a CSN in OpenLDAP 2.3 format */
5232 struct berval *normalized,
5235 struct berval gt, cnt, sid, mod;
5237 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5241 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5242 assert( !BER_BVISEMPTY( val ) );
5246 ptr = ber_bvchr( >, '#' );
5247 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5248 return LDAP_INVALID_SYNTAX;
5251 gt.bv_len = ptr - gt.bv_val;
5252 if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5253 return LDAP_INVALID_SYNTAX;
5256 cnt.bv_val = ptr + 1;
5257 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5259 ptr = ber_bvchr( &cnt, '#' );
5260 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5261 return LDAP_INVALID_SYNTAX;
5264 cnt.bv_len = ptr - cnt.bv_val;
5265 if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5266 return LDAP_INVALID_SYNTAX;
5269 sid.bv_val = ptr + 1;
5270 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5272 ptr = ber_bvchr( &sid, '#' );
5273 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5274 return LDAP_INVALID_SYNTAX;
5277 sid.bv_len = ptr - sid.bv_val;
5278 if ( sid.bv_len != STRLENOF( "00" ) ) {
5279 return LDAP_INVALID_SYNTAX;
5282 mod.bv_val = ptr + 1;
5283 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5284 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5285 return LDAP_INVALID_SYNTAX;
5288 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5292 ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5293 ptr = lutil_strcopy( ptr, ".000000Z#" );
5294 ptr = lutil_strbvcopy( ptr, &cnt );
5297 for ( i = 0; i < sid.bv_len; i++ ) {
5298 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5301 for ( i = 0; i < mod.bv_len; i++ ) {
5302 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5306 assert( ptr == &bv.bv_val[bv.bv_len] );
5307 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5308 return LDAP_INVALID_SYNTAX;
5311 ber_dupbv_x( normalized, &bv, ctx );
5313 return LDAP_SUCCESS;
5316 /* Normalize a CSN */
5323 struct berval *normalized,
5326 struct berval cnt, sid, mod;
5330 assert( val != NULL );
5331 assert( normalized != NULL );
5333 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5335 if ( BER_BVISEMPTY( val ) ) {
5336 return LDAP_INVALID_SYNTAX;
5339 if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5340 /* Openldap <= 2.3 */
5342 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5345 if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5348 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5351 if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5352 return LDAP_INVALID_SYNTAX;
5355 ptr = ber_bvchr( val, '#' );
5356 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5357 return LDAP_INVALID_SYNTAX;
5360 if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5361 return LDAP_INVALID_SYNTAX;
5364 cnt.bv_val = ptr + 1;
5365 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5367 ptr = ber_bvchr( &cnt, '#' );
5368 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5369 return LDAP_INVALID_SYNTAX;
5372 if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5373 return LDAP_INVALID_SYNTAX;
5376 sid.bv_val = ptr + 1;
5377 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5379 ptr = ber_bvchr( &sid, '#' );
5380 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5381 return LDAP_INVALID_SYNTAX;
5384 sid.bv_len = ptr - sid.bv_val;
5385 if ( sid.bv_len != STRLENOF( "000" ) ) {
5386 return LDAP_INVALID_SYNTAX;
5389 mod.bv_val = ptr + 1;
5390 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5392 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5393 return LDAP_INVALID_SYNTAX;
5396 ber_dupbv_x( normalized, val, ctx );
5398 for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5399 i < normalized->bv_len; i++ )
5401 /* assume it's already validated that's all hex digits */
5402 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5405 return LDAP_SUCCESS;
5415 return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5418 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5419 /* slight optimization - does not need the start parameter */
5420 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5425 check_time_syntax (struct berval *val,
5428 struct berval *fraction)
5431 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5432 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
5433 * GeneralizedTime supports leap seconds, UTCTime does not.
5435 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5436 static const int mdays[2][12] = {
5437 /* non-leap years */
5438 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5440 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5443 int part, c, c1, c2, tzoffset, leapyear = 0;
5446 e = p + val->bv_len;
5448 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5449 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5451 for (part = start; part < 7 && p < e; part++) {
5453 if (!ASCII_DIGIT(c1)) {
5458 return LDAP_INVALID_SYNTAX;
5461 if (!ASCII_DIGIT(c)) {
5462 return LDAP_INVALID_SYNTAX;
5464 c += c1 * 10 - '0' * 11;
5465 if ((part | 1) == 3) {
5468 return LDAP_INVALID_SYNTAX;
5471 if (c >= ceiling[part]) {
5472 if (! (c == 60 && part == 6 && start == 0))
5473 return LDAP_INVALID_SYNTAX;
5477 if (part < 5 + start) {
5478 return LDAP_INVALID_SYNTAX;
5480 for (; part < 9; part++) {
5484 /* leapyear check for the Gregorian calendar (year>1581) */
5485 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5489 if (parts[3] >= mdays[leapyear][parts[2]]) {
5490 return LDAP_INVALID_SYNTAX;
5494 fraction->bv_val = p;
5495 fraction->bv_len = 0;
5496 if (p < e && (*p == '.' || *p == ',')) {
5498 while (++p < e && ASCII_DIGIT(*p)) {
5501 if (p - fraction->bv_val == 1) {
5502 return LDAP_INVALID_SYNTAX;
5504 for (end_num = p; end_num[-1] == '0'; --end_num) {
5507 c = end_num - fraction->bv_val;
5508 if (c != 1) fraction->bv_len = c;
5514 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5520 return LDAP_INVALID_SYNTAX;
5526 for (part = 7; part < 9 && p < e; part++) {
5528 if (!ASCII_DIGIT(c1)) {
5533 return LDAP_INVALID_SYNTAX;
5536 if (!ASCII_DIGIT(c2)) {
5537 return LDAP_INVALID_SYNTAX;
5539 parts[part] = c1 * 10 + c2 - '0' * 11;
5540 if (parts[part] >= ceiling[part]) {
5541 return LDAP_INVALID_SYNTAX;
5544 if (part < 8 + start) {
5545 return LDAP_INVALID_SYNTAX;
5548 if (tzoffset == '-') {
5549 /* negative offset to UTC, ie west of Greenwich */
5550 parts[4] += parts[7];
5551 parts[5] += parts[8];
5552 /* offset is just hhmm, no seconds */
5553 for (part = 6; --part >= 0; ) {
5557 c = mdays[leapyear][parts[2]];
5559 if (parts[part] >= c) {
5561 return LDAP_INVALID_SYNTAX;
5566 } else if (part != 5) {
5571 /* positive offset to UTC, ie east of Greenwich */
5572 parts[4] -= parts[7];
5573 parts[5] -= parts[8];
5574 for (part = 6; --part >= 0; ) {
5575 if (parts[part] < 0) {
5577 return LDAP_INVALID_SYNTAX;
5582 /* make first arg to % non-negative */
5583 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5588 } else if (part != 5) {
5595 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5598 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5605 struct berval *normalized )
5609 rc = check_time_syntax(val, 1, parts, NULL);
5610 if (rc != LDAP_SUCCESS) {
5614 normalized->bv_val = ch_malloc( 14 );
5615 if ( normalized->bv_val == NULL ) {
5616 return LBER_ERROR_MEMORY;
5619 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5620 parts[1], parts[2] + 1, parts[3] + 1,
5621 parts[4], parts[5], parts[6] );
5622 normalized->bv_len = 13;
5624 return LDAP_SUCCESS;
5634 return check_time_syntax(in, 1, parts, NULL);
5637 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5640 generalizedTimeValidate(
5645 struct berval fraction;
5646 return check_time_syntax(in, 0, parts, &fraction);
5650 generalizedTimeNormalize(
5655 struct berval *normalized,
5660 struct berval fraction;
5662 rc = check_time_syntax(val, 0, parts, &fraction);
5663 if (rc != LDAP_SUCCESS) {
5667 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5668 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5669 if ( BER_BVISNULL( normalized ) ) {
5670 return LBER_ERROR_MEMORY;
5673 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5674 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5675 parts[4], parts[5], parts[6] );
5676 if ( !BER_BVISEMPTY( &fraction ) ) {
5677 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5678 fraction.bv_val, fraction.bv_len );
5679 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5681 strcpy( normalized->bv_val + len-1, "Z" );
5682 normalized->bv_len = len;
5684 return LDAP_SUCCESS;
5688 generalizedTimeOrderingMatch(
5693 struct berval *value,
5694 void *assertedValue )
5696 struct berval *asserted = (struct berval *) assertedValue;
5697 ber_len_t v_len = value->bv_len;
5698 ber_len_t av_len = asserted->bv_len;
5700 /* ignore trailing 'Z' when comparing */
5701 int match = memcmp( value->bv_val, asserted->bv_val,
5702 (v_len < av_len ? v_len : av_len) - 1 );
5703 if ( match == 0 ) match = v_len - av_len;
5705 /* If used in extensible match filter, match if value < asserted */
5706 if ( flags & SLAP_MR_EXT )
5707 match = (match >= 0);
5710 return LDAP_SUCCESS;
5713 /* Index generation function: Ordered index */
5714 int generalizedTimeIndexer(
5719 struct berval *prefix,
5727 BerValue bvtmp; /* 40 bit index */
5729 struct lutil_timet tt;
5731 bvtmp.bv_len = sizeof(tmp);
5733 for( i=0; values[i].bv_val != NULL; i++ ) {
5734 /* just count them */
5737 /* we should have at least one value at this point */
5740 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5742 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5743 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5744 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5745 /* Use 40 bits of time for key */
5746 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5747 lutil_tm2time( &tm, &tt );
5748 tmp[0] = tt.tt_gsec & 0xff;
5749 tmp[4] = tt.tt_sec & 0xff;
5751 tmp[3] = tt.tt_sec & 0xff;
5753 tmp[2] = tt.tt_sec & 0xff;
5755 tmp[1] = tt.tt_sec & 0xff;
5757 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5761 keys[j].bv_val = NULL;
5766 return LDAP_SUCCESS;
5769 /* Index generation function: Ordered index */
5770 int generalizedTimeFilter(
5775 struct berval *prefix,
5776 void * assertedValue,
5782 BerValue bvtmp; /* 40 bit index */
5783 BerValue *value = (BerValue *) assertedValue;
5785 struct lutil_timet tt;
5787 bvtmp.bv_len = sizeof(tmp);
5789 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5790 /* Use 40 bits of time for key */
5791 if ( value->bv_val && value->bv_len >= 10 &&
5792 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5794 lutil_tm2time( &tm, &tt );
5795 tmp[0] = tt.tt_gsec & 0xff;
5796 tmp[4] = tt.tt_sec & 0xff;
5798 tmp[3] = tt.tt_sec & 0xff;
5800 tmp[2] = tt.tt_sec & 0xff;
5802 tmp[1] = tt.tt_sec & 0xff;
5804 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5805 ber_dupbv_x(keys, &bvtmp, ctx );
5806 keys[1].bv_val = NULL;
5814 return LDAP_SUCCESS;
5818 deliveryMethodValidate(
5820 struct berval *val )
5823 #define LENOF(s) (sizeof(s)-1)
5824 struct berval tmp = *val;
5826 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5827 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5828 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5831 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5833 switch( tmp.bv_val[0] ) {
5836 if(( tmp.bv_len >= LENOF("any") ) &&
5837 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5839 tmp.bv_len -= LENOF("any");
5840 tmp.bv_val += LENOF("any");
5843 return LDAP_INVALID_SYNTAX;
5847 if(( tmp.bv_len >= LENOF("mhs") ) &&
5848 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5850 tmp.bv_len -= LENOF("mhs");
5851 tmp.bv_val += LENOF("mhs");
5854 return LDAP_INVALID_SYNTAX;
5858 if(( tmp.bv_len >= LENOF("physical") ) &&
5859 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5861 tmp.bv_len -= LENOF("physical");
5862 tmp.bv_val += LENOF("physical");
5865 return LDAP_INVALID_SYNTAX;
5868 case 'T': /* telex or teletex or telephone */
5869 if(( tmp.bv_len >= LENOF("telex") ) &&
5870 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5872 tmp.bv_len -= LENOF("telex");
5873 tmp.bv_val += LENOF("telex");
5876 if(( tmp.bv_len >= LENOF("teletex") ) &&
5877 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5879 tmp.bv_len -= LENOF("teletex");
5880 tmp.bv_val += LENOF("teletex");
5883 if(( tmp.bv_len >= LENOF("telephone") ) &&
5884 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5886 tmp.bv_len -= LENOF("telephone");
5887 tmp.bv_val += LENOF("telephone");
5890 return LDAP_INVALID_SYNTAX;
5893 case 'G': /* g3fax or g4fax */
5894 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5895 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5896 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5898 tmp.bv_len -= LENOF("g3fax");
5899 tmp.bv_val += LENOF("g3fax");
5902 return LDAP_INVALID_SYNTAX;
5906 if(( tmp.bv_len >= LENOF("ia5") ) &&
5907 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5909 tmp.bv_len -= LENOF("ia5");
5910 tmp.bv_val += LENOF("ia5");
5913 return LDAP_INVALID_SYNTAX;
5917 if(( tmp.bv_len >= LENOF("videotex") ) &&
5918 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5920 tmp.bv_len -= LENOF("videotex");
5921 tmp.bv_val += LENOF("videotex");
5924 return LDAP_INVALID_SYNTAX;
5927 return LDAP_INVALID_SYNTAX;
5930 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
5932 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5936 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
5940 return LDAP_INVALID_SYNTAX;
5942 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5951 nisNetgroupTripleValidate(
5953 struct berval *val )
5958 if ( BER_BVISEMPTY( val ) ) {
5959 return LDAP_INVALID_SYNTAX;
5962 p = (char *)val->bv_val;
5963 e = p + val->bv_len;
5965 if ( *p != '(' /*')'*/ ) {
5966 return LDAP_INVALID_SYNTAX;
5969 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5973 return LDAP_INVALID_SYNTAX;
5976 } else if ( !AD_CHAR( *p ) ) {
5977 return LDAP_INVALID_SYNTAX;
5981 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5982 return LDAP_INVALID_SYNTAX;
5988 return LDAP_INVALID_SYNTAX;
5991 return LDAP_SUCCESS;
5995 bootParameterValidate(
5997 struct berval *val )
6001 if ( BER_BVISEMPTY( val ) ) {
6002 return LDAP_INVALID_SYNTAX;
6005 p = (char *)val->bv_val;
6006 e = p + val->bv_len;
6009 for (; ( p < e ) && ( *p != '=' ); p++ ) {
6010 if ( !AD_CHAR( *p ) ) {
6011 return LDAP_INVALID_SYNTAX;
6016 return LDAP_INVALID_SYNTAX;
6020 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6021 if ( !AD_CHAR( *p ) ) {
6022 return LDAP_INVALID_SYNTAX;
6027 return LDAP_INVALID_SYNTAX;
6031 for ( p++; p < e; p++ ) {
6032 if ( !SLAP_PRINTABLE( *p ) ) {
6033 return LDAP_INVALID_SYNTAX;
6037 return LDAP_SUCCESS;
6041 firstComponentNormalize(
6046 struct berval *normalized,
6053 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6054 ber_dupbv_x( normalized, val, ctx );
6055 return LDAP_SUCCESS;
6058 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6060 if( ! ( val->bv_val[0] == '(' /*')'*/
6061 && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6062 && ! ( val->bv_val[0] == '{' /*'}'*/
6063 && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6065 return LDAP_INVALID_SYNTAX;
6068 /* trim leading white space */
6070 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6076 /* grab next word */
6077 comp.bv_val = &val->bv_val[len];
6078 len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6079 for( comp.bv_len = 0;
6080 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6086 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6087 rc = numericoidValidate( NULL, &comp );
6088 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6089 rc = integerValidate( NULL, &comp );
6091 rc = LDAP_INVALID_SYNTAX;
6095 if( rc == LDAP_SUCCESS ) {
6096 ber_dupbv_x( normalized, &comp, ctx );
6102 static char *country_gen_syn[] = {
6103 "1.3.6.1.4.1.1466.115.121.1.15", /* Directory String */
6104 "1.3.6.1.4.1.1466.115.121.1.26", /* IA5 String */
6105 "1.3.6.1.4.1.1466.115.121.1.44", /* Printable String */
6109 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6110 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6112 static slap_syntax_defs_rec syntax_defs[] = {
6113 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6114 X_BINARY X_NOT_H_R ")",
6115 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6116 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6117 0, NULL, NULL, NULL},
6118 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6119 0, NULL, NULL, NULL},
6120 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6122 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6123 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6125 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6126 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6127 0, NULL, bitStringValidate, NULL },
6128 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6129 0, NULL, booleanValidate, NULL},
6130 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6131 X_BINARY X_NOT_H_R ")",
6132 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6133 NULL, certificateValidate, NULL},
6134 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6135 X_BINARY X_NOT_H_R ")",
6136 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6137 NULL, certificateListValidate, NULL},
6138 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6139 X_BINARY X_NOT_H_R ")",
6140 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6141 NULL, sequenceValidate, NULL},
6142 {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6143 X_BINARY X_NOT_H_R ")",
6144 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6145 NULL, attributeCertificateValidate, NULL},
6146 #if 0 /* need to go __after__ printableString */
6147 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6148 0, "1.3.6.1.4.1.1466.115.121.1.44",
6149 countryStringValidate, NULL},
6151 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6152 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6153 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6154 0, NULL, rdnValidate, rdnPretty},
6155 #ifdef LDAP_COMP_MATCH
6156 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6157 0, NULL, allComponentsValidate, NULL},
6158 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6159 0, NULL, componentFilterValidate, NULL},
6161 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6162 0, NULL, NULL, NULL},
6163 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6164 0, NULL, deliveryMethodValidate, NULL},
6165 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6166 0, NULL, UTF8StringValidate, NULL},
6167 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6168 0, NULL, NULL, NULL},
6169 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6170 0, NULL, NULL, NULL},
6171 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6172 0, NULL, NULL, NULL},
6173 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6174 0, NULL, NULL, NULL},
6175 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6176 0, NULL, NULL, NULL},
6177 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6178 0, NULL, printablesStringValidate, NULL},
6179 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6180 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6181 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6182 0, NULL, generalizedTimeValidate, NULL},
6183 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6184 0, NULL, NULL, NULL},
6185 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6186 0, NULL, IA5StringValidate, NULL},
6187 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6188 0, NULL, integerValidate, NULL},
6189 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6190 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6191 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6192 0, NULL, NULL, NULL},
6193 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6194 0, NULL, NULL, NULL},
6195 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6196 0, NULL, NULL, NULL},
6197 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6198 0, NULL, NULL, NULL},
6199 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6200 0, NULL, NULL, NULL},
6201 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6202 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6203 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6204 0, NULL, NULL, NULL},
6205 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6206 0, NULL, numericStringValidate, NULL},
6207 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6208 0, NULL, NULL, NULL},
6209 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6210 0, NULL, numericoidValidate, NULL},
6211 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6212 0, NULL, IA5StringValidate, NULL},
6213 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6214 0, NULL, blobValidate, NULL},
6215 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6216 0, NULL, postalAddressValidate, NULL},
6217 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6218 0, NULL, NULL, NULL},
6219 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6220 0, NULL, NULL, NULL},
6221 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6222 0, NULL, printableStringValidate, NULL},
6223 /* moved here because now depends on Directory String, IA5 String
6224 * and Printable String */
6225 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6226 0, country_gen_syn, countryStringValidate, NULL},
6227 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6228 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6229 0, NULL, subtreeSpecificationValidate, NULL},
6230 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6231 X_BINARY X_NOT_H_R ")",
6232 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6233 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6234 0, NULL, printableStringValidate, NULL},
6235 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6236 0, NULL, NULL, NULL},
6237 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6238 0, NULL, printablesStringValidate, NULL},
6239 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6240 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6241 0, NULL, utcTimeValidate, NULL},
6243 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6244 0, NULL, NULL, NULL},
6245 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6246 0, NULL, NULL, NULL},
6247 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6248 0, NULL, NULL, NULL},
6249 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6250 0, NULL, NULL, NULL},
6251 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6252 0, NULL, NULL, NULL},
6254 /* RFC 2307 NIS Syntaxes */
6255 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
6256 0, NULL, nisNetgroupTripleValidate, NULL},
6257 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
6258 0, NULL, bootParameterValidate, NULL},
6260 /* draft-zeilenga-ldap-x509 */
6261 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6262 SLAP_SYNTAX_HIDE, NULL,
6263 serialNumberAndIssuerValidate,
6264 serialNumberAndIssuerPretty},
6265 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6266 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6267 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6268 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6269 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6270 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6271 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6272 SLAP_SYNTAX_HIDE, NULL,
6273 issuerAndThisUpdateValidate,
6274 issuerAndThisUpdatePretty},
6275 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6276 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6277 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6278 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6279 {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6280 SLAP_SYNTAX_HIDE, NULL,
6281 serialNumberAndIssuerSerialValidate,
6282 serialNumberAndIssuerSerialPretty},
6283 {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6284 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6286 #ifdef SLAPD_AUTHPASSWD
6287 /* needs updating */
6288 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6289 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6292 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6293 0, NULL, UUIDValidate, UUIDPretty},
6295 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6296 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6298 {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6299 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6301 /* OpenLDAP Void Syntax */
6302 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6303 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6305 /* FIXME: OID is unused, but not registered yet */
6306 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6307 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6309 {NULL, 0, NULL, NULL, NULL}
6312 char *csnSIDMatchSyntaxes[] = {
6313 "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6316 char *certificateExactMatchSyntaxes[] = {
6317 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6320 char *certificateListExactMatchSyntaxes[] = {
6321 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6324 char *attributeCertificateExactMatchSyntaxes[] = {
6325 attributeCertificateSyntaxOID /* attributeCertificate */,
6329 #ifdef LDAP_COMP_MATCH
6330 char *componentFilterMatchSyntaxes[] = {
6331 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6332 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6333 attributeCertificateSyntaxOID /* attributeCertificate */,
6338 char *directoryStringSyntaxes[] = {
6339 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6342 char *integerFirstComponentMatchSyntaxes[] = {
6343 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6344 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6347 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6348 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6349 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
6350 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6351 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6352 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6353 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6354 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6355 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6360 * Other matching rules in X.520 that we do not use (yet):
6362 * 2.5.13.25 uTCTimeMatch
6363 * 2.5.13.26 uTCTimeOrderingMatch
6364 * 2.5.13.31* directoryStringFirstComponentMatch
6365 * 2.5.13.32* wordMatch
6366 * 2.5.13.33* keywordMatch
6367 * 2.5.13.36+ certificatePairExactMatch
6368 * 2.5.13.37+ certificatePairMatch
6369 * 2.5.13.40+ algorithmIdentifierMatch
6370 * 2.5.13.41* storedPrefixMatch
6371 * 2.5.13.42 attributeCertificateMatch
6372 * 2.5.13.43 readerAndKeyIDMatch
6373 * 2.5.13.44 attributeIntegrityMatch
6375 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6376 * (+) described in draft-zeilenga-ldap-x509
6378 static slap_mrule_defs_rec mrule_defs[] = {
6380 * EQUALITY matching rules must be listed after associated APPROX
6381 * matching rules. So, we list all APPROX matching rules first.
6383 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6384 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6385 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6386 NULL, NULL, directoryStringApproxMatch,
6387 directoryStringApproxIndexer, directoryStringApproxFilter,
6390 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6391 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6392 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6393 NULL, NULL, IA5StringApproxMatch,
6394 IA5StringApproxIndexer, IA5StringApproxFilter,
6398 * Other matching rules
6401 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6402 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6403 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6404 NULL, NULL, octetStringMatch,
6405 octetStringIndexer, octetStringFilter,
6408 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6409 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6410 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6411 NULL, dnNormalize, dnMatch,
6412 octetStringIndexer, octetStringFilter,
6415 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6416 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6417 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6418 NULL, dnNormalize, dnRelativeMatch,
6422 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
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.10 NAME 'dnSubordinateMatch' "
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.11 NAME 'dnSuperiorMatch' "
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.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6444 "SYNTAX 1.2.36.79672281.1.5.0 )",
6445 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6446 NULL, rdnNormalize, rdnMatch,
6447 octetStringIndexer, octetStringFilter,
6450 #ifdef LDAP_COMP_MATCH
6451 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6452 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6453 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6454 NULL, NULL , componentFilterMatch,
6455 octetStringIndexer, octetStringFilter,
6458 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6459 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6460 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6461 NULL, NULL , allComponentsMatch,
6462 octetStringIndexer, octetStringFilter,
6465 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6466 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6467 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6468 NULL, NULL , directoryComponentsMatch,
6469 octetStringIndexer, octetStringFilter,
6473 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6474 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6475 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6476 NULL, UTF8StringNormalize, octetStringMatch,
6477 octetStringIndexer, octetStringFilter,
6478 directoryStringApproxMatchOID },
6480 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6481 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6482 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6483 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6485 "caseIgnoreMatch" },
6487 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6488 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6489 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6490 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6491 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6492 "caseIgnoreMatch" },
6494 {"( 2.5.13.5 NAME 'caseExactMatch' "
6495 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6496 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6497 NULL, UTF8StringNormalize, octetStringMatch,
6498 octetStringIndexer, octetStringFilter,
6499 directoryStringApproxMatchOID },
6501 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6502 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6503 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6504 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6508 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6509 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6510 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6511 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6512 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6515 {"( 2.5.13.8 NAME 'numericStringMatch' "
6516 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6517 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6518 NULL, numericStringNormalize, octetStringMatch,
6519 octetStringIndexer, octetStringFilter,
6522 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6523 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6524 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6525 NULL, numericStringNormalize, octetStringOrderingMatch,
6527 "numericStringMatch" },
6529 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6530 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6531 SLAP_MR_SUBSTR, NULL,
6532 NULL, numericStringNormalize, octetStringSubstringsMatch,
6533 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6534 "numericStringMatch" },
6536 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6537 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6538 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6539 NULL, postalAddressNormalize, octetStringMatch,
6540 octetStringIndexer, octetStringFilter,
6543 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6544 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6545 SLAP_MR_SUBSTR, NULL,
6546 NULL, NULL, NULL, NULL, NULL,
6547 "caseIgnoreListMatch" },
6549 {"( 2.5.13.13 NAME 'booleanMatch' "
6550 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6551 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6552 NULL, NULL, booleanMatch,
6553 octetStringIndexer, octetStringFilter,
6556 {"( 2.5.13.14 NAME 'integerMatch' "
6557 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6558 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6559 NULL, NULL, integerMatch,
6560 integerIndexer, integerFilter,
6563 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6564 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6565 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6566 NULL, NULL, integerMatch,
6570 {"( 2.5.13.16 NAME 'bitStringMatch' "
6571 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6572 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6573 NULL, NULL, octetStringMatch,
6574 octetStringIndexer, octetStringFilter,
6577 {"( 2.5.13.17 NAME 'octetStringMatch' "
6578 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6579 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6580 NULL, NULL, octetStringMatch,
6581 octetStringIndexer, octetStringFilter,
6584 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6585 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6586 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6587 NULL, NULL, octetStringOrderingMatch,
6589 "octetStringMatch" },
6591 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6592 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6593 SLAP_MR_SUBSTR, NULL,
6594 NULL, NULL, octetStringSubstringsMatch,
6595 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6596 "octetStringMatch" },
6598 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6599 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6600 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6602 telephoneNumberNormalize, octetStringMatch,
6603 octetStringIndexer, octetStringFilter,
6606 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6607 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6608 SLAP_MR_SUBSTR, NULL,
6609 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6610 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6611 "telephoneNumberMatch" },
6613 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6614 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6615 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6616 NULL, NULL, NULL, NULL, NULL, NULL },
6618 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6619 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6620 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6621 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6622 uniqueMemberIndexer, uniqueMemberFilter,
6625 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6626 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6627 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6628 NULL, NULL, NULL, NULL, NULL, NULL },
6630 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6631 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6632 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6633 NULL, generalizedTimeNormalize, octetStringMatch,
6634 generalizedTimeIndexer, generalizedTimeFilter,
6637 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6638 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6639 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6640 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6642 "generalizedTimeMatch" },
6644 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6645 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6646 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6647 integerFirstComponentMatchSyntaxes,
6648 NULL, firstComponentNormalize, integerMatch,
6649 octetStringIndexer, octetStringFilter,
6652 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6653 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6654 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6655 objectIdentifierFirstComponentMatchSyntaxes,
6656 NULL, firstComponentNormalize, octetStringMatch,
6657 octetStringIndexer, octetStringFilter,
6660 {"( 2.5.13.34 NAME 'certificateExactMatch' "
6661 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6662 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6663 NULL, certificateExactNormalize, octetStringMatch,
6664 octetStringIndexer, octetStringFilter,
6667 {"( 2.5.13.35 NAME 'certificateMatch' "
6668 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6669 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6670 NULL, NULL, NULL, NULL, NULL,
6673 {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6674 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6675 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6676 NULL, certificateListExactNormalize, octetStringMatch,
6677 octetStringIndexer, octetStringFilter,
6680 {"( 2.5.13.39 NAME 'certificateListMatch' "
6681 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6682 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6683 NULL, NULL, NULL, NULL, NULL,
6686 {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6687 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6688 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6689 NULL, attributeCertificateExactNormalize, octetStringMatch,
6690 octetStringIndexer, octetStringFilter,
6693 {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6694 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6695 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6696 NULL, NULL, NULL, NULL, NULL,
6699 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6700 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6701 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6702 NULL, IA5StringNormalize, octetStringMatch,
6703 octetStringIndexer, octetStringFilter,
6704 IA5StringApproxMatchOID },
6706 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
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.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6714 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6715 SLAP_MR_SUBSTR, NULL,
6716 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6717 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6718 "caseIgnoreIA5Match" },
6720 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
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 "caseExactIA5Match" },
6727 #ifdef SLAPD_AUTHPASSWD
6728 /* needs updating */
6729 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6730 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6731 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6732 NULL, NULL, authPasswordMatch,
6737 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6738 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6740 NULL, NULL, integerBitAndMatch,
6744 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6745 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6747 NULL, NULL, integerBitOrMatch,
6751 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6752 "SYNTAX 1.3.6.1.1.16.1 )",
6753 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6754 NULL, UUIDNormalize, octetStringMatch,
6755 octetStringIndexer, octetStringFilter,
6758 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6759 "SYNTAX 1.3.6.1.1.16.1 )",
6760 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_MUTATION_NORMALIZER, NULL,
6761 NULL, UUIDNormalize, octetStringOrderingMatch,
6762 octetStringIndexer, octetStringFilter,
6765 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6766 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6767 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6768 NULL, csnNormalize, csnMatch,
6769 csnIndexer, csnFilter,
6772 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6773 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6774 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6775 NULL, csnNormalize, csnOrderingMatch,
6779 {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6780 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6781 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6782 NULL, csnSidNormalize, octetStringMatch,
6783 octetStringIndexer, octetStringFilter,
6786 /* FIXME: OID is unused, but not registered yet */
6787 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6788 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6789 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6790 NULL, authzNormalize, authzMatch,
6794 {NULL, SLAP_MR_NONE, NULL,
6795 NULL, NULL, NULL, NULL, NULL,
6800 slap_schema_init( void )
6805 /* we should only be called once (from main) */
6806 assert( schema_init_done == 0 );
6808 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6809 res = register_syntax( &syntax_defs[i] );
6812 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6813 syntax_defs[i].sd_desc );
6818 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6819 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6820 mrule_defs[i].mrd_compat_syntaxes == NULL )
6823 "slap_schema_init: Ignoring unusable matching rule %s\n",
6824 mrule_defs[i].mrd_desc );
6828 res = register_matching_rule( &mrule_defs[i] );
6832 "slap_schema_init: Error registering matching rule %s\n",
6833 mrule_defs[i].mrd_desc );
6838 res = slap_schema_load();
6839 schema_init_done = 1;
6844 schema_destroy( void )
6853 if( schema_init_done ) {
6854 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6855 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );