1 /* schema_init.c - init builtin schema */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2015 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
18 * Syntaxes - implementation notes:
20 * Validate function(syntax, value):
21 * Called before the other functions here to check if the value
22 * is valid according to the syntax.
24 * Pretty function(syntax, input value, output prettified...):
25 * If it exists, maps different notations of the same value to a
26 * unique representation which can be stored in the directory and
27 * possibly be passed to the Match/Indexer/Filter() functions.
29 * E.g. DN "2.5.4.3 = foo\,bar, o = BAZ" -> "cn=foo\2Cbar,o=BAZ",
30 * but unlike DN normalization, "BAZ" is not mapped to "baz".
34 * Matching rules - implementation notes:
36 * Matching rules match an attribute value (often from the directory)
37 * against an asserted value (e.g. from a filter).
39 * Invoked with validated and commonly pretty/normalized arguments, thus
40 * a number of matching rules can simply use the octetString functions.
42 * Normalize function(...input value, output normalized...):
43 * If it exists, maps matching values to a unique representation
44 * which is passed to the Match/Indexer/Filter() functions.
46 * Different matching rules can normalize values of the same syntax
47 * differently. E.g. caseIgnore rules normalize to lowercase,
48 * caseExact rules do not.
50 * Match function(*output matchp, ...value, asserted value):
51 * On success, set *matchp. 0 means match. For ORDERING/most EQUALITY,
52 * less/greater than 0 means value less/greater than asserted. However:
54 * In extensible match filters, ORDERING rules match if value<asserted.
56 * EQUALITY rules may order values differently than ORDERING rules for
57 * speed, since EQUALITY ordering is only used for SLAP_AT_SORTED_VAL.
58 * Some EQUALITY rules do not order values (ITS#6722).
60 * Indexer function(...attribute values, *output keysp,...):
61 * Generates index keys for the attribute values. Backends can store
62 * them in an index, a {key->entry ID set} mapping, for the attribute.
64 * A search can look up the DN/scope and asserted values in the
65 * indexes, if any, to narrow down the number of entires to check
66 * against the search criteria.
68 * Filter function(...asserted value, *output keysp,...):
69 * Generates index key(s) for the asserted value, to be looked up in
70 * the index from the Indexer function. *keysp is an array because
71 * substring matching rules can generate multiple lookup keys.
74 * A key is usually a hash of match type, attribute value and schema
75 * info, because one index can contain keys for many filtering types.
77 * Some indexes instead have EQUALITY keys ordered so that if
78 * key(val1) < key(val2), then val1 < val2 by the ORDERING rule.
79 * That way the ORDERING rule can use the EQUALITY index.
82 * This chops the attribute values up in small chunks and indexes all
83 * possible chunks of certain sizes. Substring filtering looks up
84 * SOME of the asserted value's chunks, and the caller uses the
85 * intersection of the resulting entry ID sets.
86 * See the index_substr_* keywords in slapd.conf(5).
98 #include <ac/string.h>
99 #include <ac/socket.h>
102 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
104 #include "ldap_utf8.h"
107 #include "lutil_hash.h"
108 #define HASH_BYTES LUTIL_HASH_BYTES
109 #define HASH_CONTEXT lutil_HASH_CTX
110 #define HASH_Init(c) lutil_HASHInit(c)
111 #define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
112 #define HASH_Final(d,c) lutil_HASHFinal(d,c)
114 /* approx matching rules */
115 #define directoryStringApproxMatchOID "1.3.6.1.4.1.4203.666.4.4"
116 #define directoryStringApproxMatch approxMatch
117 #define directoryStringApproxIndexer approxIndexer
118 #define directoryStringApproxFilter approxFilter
119 #define IA5StringApproxMatchOID "1.3.6.1.4.1.4203.666.4.5"
120 #define IA5StringApproxMatch approxMatch
121 #define IA5StringApproxIndexer approxIndexer
122 #define IA5StringApproxFilter approxFilter
124 /* Change Sequence Number (CSN) - much of this will change */
125 #define csnMatch octetStringMatch
126 #define csnOrderingMatch octetStringOrderingMatch
127 #define csnIndexer generalizedTimeIndexer
128 #define csnFilter generalizedTimeFilter
130 #define authzMatch octetStringMatch
132 /* X.509 PMI ldapSyntaxes */
133 /* FIXME: need to create temporary OIDs under OpenLDAP's arc;
134 * these are currently hijacked
136 * 1.3.6.1.4.1.4203.666 OpenLDAP
137 * 1.3.6.1.4.1.4203.666.11 self-contained works
138 * 1.3.6.1.4.1.4203.666.11.10 X.509 PMI
139 * 1.3.6.1.4.1.4203.666.11.10.2 X.509 PMI ldapSyntaxes
140 * 1.3.6.1.4.1.4203.666.11.10.2.1 AttributeCertificate (supported)
141 * 1.3.6.1.4.1.4203.666.11.10.2.2 AttributeCertificateExactAssertion (supported)
142 * 1.3.6.1.4.1.4203.666.11.10.2.3 AttributeCertificateAssertion (not supported)
143 * 1.3.6.1.4.1.4203.666.11.10.2.4 AttCertPath (X-SUBST'ed right now in pmi.schema)
144 * 1.3.6.1.4.1.4203.666.11.10.2.5 PolicySyntax (X-SUBST'ed right now in pmi.schema)
145 * 1.3.6.1.4.1.4203.666.11.10.2.6 RoleSyntax (X-SUBST'ed right now in pmi.schema)
147 #if 0 /* from <draft-ietf-pkix-ldap-schema-02.txt> (expired) */
148 #define attributeCertificateSyntaxOID "1.2.826.0.1.3344810.7.5"
149 #define attributeCertificateExactAssertionSyntaxOID "1.2.826.0.1.3344810.7.6"
150 #define attributeCertificateAssertionSyntaxOID "1.2.826.0.1.3344810.7.7"
151 #else /* from OpenLDAP's experimental oid arc */
152 #define X509_PMI_SyntaxOID "1.3.6.1.4.1.4203.666.11.10.2"
153 #define attributeCertificateSyntaxOID X509_PMI_SyntaxOID ".1"
154 #define attributeCertificateExactAssertionSyntaxOID X509_PMI_SyntaxOID ".2"
155 #define attributeCertificateAssertionSyntaxOID X509_PMI_SyntaxOID ".3"
158 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
159 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
160 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
161 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
163 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
164 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
165 SLAP_INDEX_INTLEN_DEFAULT );
167 ldap_pvt_thread_mutex_t ad_index_mutex;
168 ldap_pvt_thread_mutex_t ad_undef_mutex;
169 ldap_pvt_thread_mutex_t oc_undef_mutex;
172 generalizedTimeValidate(
176 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
181 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
188 /* no value allowed */
189 return LDAP_INVALID_SYNTAX;
197 /* any value allowed */
201 #define berValidate blobValidate
208 if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
209 if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
214 /* X.509 related stuff */
223 SLAP_TAG_UTCTIME = 0x17U,
224 SLAP_TAG_GENERALIZEDTIME = 0x18U
228 #define SLAP_X509_OPTION (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
231 SLAP_X509_OPT_C_VERSION = SLAP_X509_OPTION + 0,
232 SLAP_X509_OPT_C_ISSUERUNIQUEID = LBER_CLASS_CONTEXT + 1,
233 SLAP_X509_OPT_C_SUBJECTUNIQUEID = LBER_CLASS_CONTEXT + 2,
234 SLAP_X509_OPT_C_EXTENSIONS = SLAP_X509_OPTION + 3
238 SLAP_X509_OPT_CL_CRLEXTENSIONS = SLAP_X509_OPTION + 0
242 GeneralName ::= CHOICE {
243 otherName [0] INSTANCE OF OTHER-NAME,
244 rfc822Name [1] IA5String,
245 dNSName [2] IA5String,
246 x400Address [3] ORAddress,
247 directoryName [4] Name,
248 ediPartyName [5] EDIPartyName,
249 uniformResourceIdentifier [6] IA5String,
250 iPAddress [7] OCTET STRING,
251 registeredID [8] OBJECT IDENTIFIER }
254 SLAP_X509_GN_OTHERNAME = SLAP_X509_OPTION + 0,
255 SLAP_X509_GN_RFC822NAME = SLAP_X509_OPTION + 1,
256 SLAP_X509_GN_DNSNAME = SLAP_X509_OPTION + 2,
257 SLAP_X509_GN_X400ADDRESS = SLAP_X509_OPTION + 3,
258 SLAP_X509_GN_DIRECTORYNAME = SLAP_X509_OPTION + 4,
259 SLAP_X509_GN_EDIPARTYNAME = SLAP_X509_OPTION + 5,
260 SLAP_X509_GN_URI = SLAP_X509_OPTION + 6,
261 SLAP_X509_GN_IPADDRESS = SLAP_X509_OPTION + 7,
262 SLAP_X509_GN_REGISTEREDID = SLAP_X509_OPTION + 8
265 /* X.509 PMI related stuff */
272 SLAP_X509AC_ISSUER = SLAP_X509_OPTION + 0
275 /* X.509 certificate validation */
277 certificateValidate( Syntax *syntax, struct berval *in )
279 BerElementBuffer berbuf;
280 BerElement *ber = (BerElement *)&berbuf;
283 ber_int_t version = SLAP_X509_V1;
285 ber_init2( ber, in, LBER_USE_DER );
286 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
287 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
288 tag = ber_skip_tag( ber, &len ); /* Sequence */
289 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
290 tag = ber_peek_tag( ber, &len );
291 /* Optional version */
292 if ( tag == SLAP_X509_OPT_C_VERSION ) {
293 tag = ber_skip_tag( ber, &len );
294 tag = ber_get_int( ber, &version );
295 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
297 /* NOTE: don't try to parse Serial, because it might be longer
298 * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
299 tag = ber_skip_tag( ber, &len ); /* Serial */
300 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
301 ber_skip_data( ber, len );
302 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
303 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
304 ber_skip_data( ber, len );
305 tag = ber_skip_tag( ber, &len ); /* Issuer DN */
306 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
307 ber_skip_data( ber, len );
308 tag = ber_skip_tag( ber, &len ); /* Validity */
309 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
310 ber_skip_data( ber, len );
311 tag = ber_skip_tag( ber, &len ); /* Subject DN */
312 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
313 ber_skip_data( ber, len );
314 tag = ber_skip_tag( ber, &len ); /* Subject PublicKeyInfo */
315 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
316 ber_skip_data( ber, len );
317 tag = ber_skip_tag( ber, &len );
318 if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) { /* issuerUniqueID */
319 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
320 ber_skip_data( ber, len );
321 tag = ber_skip_tag( ber, &len );
323 if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
324 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
325 ber_skip_data( ber, len );
326 tag = ber_skip_tag( ber, &len );
328 if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) { /* Extensions */
329 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
330 tag = ber_skip_tag( ber, &len );
331 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
332 ber_skip_data( ber, len );
333 tag = ber_skip_tag( ber, &len );
335 /* signatureAlgorithm */
336 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
337 ber_skip_data( ber, len );
338 tag = ber_skip_tag( ber, &len );
340 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
341 ber_skip_data( ber, len );
342 tag = ber_skip_tag( ber, &len );
343 /* Must be at end now */
344 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
348 /* X.509 certificate list validation */
350 checkTime( struct berval *in, struct berval *out );
353 certificateListValidate( Syntax *syntax, struct berval *in )
355 BerElementBuffer berbuf;
356 BerElement *ber = (BerElement *)&berbuf;
358 ber_len_t len, wrapper_len;
361 ber_int_t version = SLAP_X509_V1;
362 struct berval bvdn, bvtu;
364 ber_init2( ber, in, LBER_USE_DER );
365 tag = ber_skip_tag( ber, &wrapper_len ); /* Signed wrapper */
366 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
367 wrapper_start = ber->ber_ptr;
368 tag = ber_skip_tag( ber, &len ); /* Sequence */
369 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
370 tag = ber_peek_tag( ber, &len );
371 /* Optional version */
372 if ( tag == LBER_INTEGER ) {
373 tag = ber_get_int( ber, &version );
374 assert( tag == LBER_INTEGER );
375 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
377 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
378 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
379 ber_skip_data( ber, len );
380 tag = ber_peek_tag( ber, &len ); /* Issuer DN */
381 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
382 len = ber_ptrlen( ber );
383 bvdn.bv_val = in->bv_val + len;
384 bvdn.bv_len = in->bv_len - len;
385 tag = ber_skip_tag( ber, &len );
386 ber_skip_data( ber, len );
387 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
388 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
389 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
390 bvtu.bv_val = (char *)ber->ber_ptr;
392 ber_skip_data( ber, len );
393 /* Optional nextUpdate */
394 tag = ber_skip_tag( ber, &len );
395 if ( tag == SLAP_TAG_UTCTIME || tag == SLAP_TAG_GENERALIZEDTIME ) {
396 ber_skip_data( ber, len );
397 tag = ber_skip_tag( ber, &len );
399 /* revokedCertificates - Sequence of Sequence, Optional */
400 if ( tag == LBER_SEQUENCE ) {
403 stag = ber_peek_tag( ber, &seqlen );
404 if ( stag == LBER_SEQUENCE || !len ) {
405 /* RFC5280 requires non-empty, but X.509(2005) allows empty. */
407 ber_skip_data( ber, len );
408 tag = ber_skip_tag( ber, &len );
411 /* Optional Extensions - Sequence of Sequence */
412 if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
414 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
415 tag = ber_peek_tag( ber, &seqlen );
416 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
417 ber_skip_data( ber, len );
418 tag = ber_skip_tag( ber, &len );
420 /* signatureAlgorithm */
421 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
422 ber_skip_data( ber, len );
423 tag = ber_skip_tag( ber, &len );
425 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
426 ber_skip_data( ber, len );
427 if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1;
428 tag = ber_skip_tag( ber, &len );
429 /* Must be at end now */
430 /* NOTE: OpenSSL tolerates CL with garbage past the end */
431 if ( len || tag != LBER_DEFAULT ) {
432 struct berval issuer_dn = BER_BVNULL, thisUpdate;
433 char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
436 if ( ! wrapper_ok ) {
437 return LDAP_INVALID_SYNTAX;
440 rc = dnX509normalize( &bvdn, &issuer_dn );
441 if ( rc != LDAP_SUCCESS ) {
442 rc = LDAP_INVALID_SYNTAX;
446 thisUpdate.bv_val = tubuf;
447 thisUpdate.bv_len = sizeof(tubuf);
448 if ( checkTime( &bvtu, &thisUpdate ) ) {
449 rc = LDAP_INVALID_SYNTAX;
453 Debug( LDAP_DEBUG_ANY,
454 "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n",
455 issuer_dn.bv_val, thisUpdate.bv_val, 0 );
458 if ( ! BER_BVISNULL( &issuer_dn ) ) {
459 ber_memfree( issuer_dn.bv_val );
468 /* X.509 PMI Attribute Certificate Validate */
470 attributeCertificateValidate( Syntax *syntax, struct berval *in )
472 BerElementBuffer berbuf;
473 BerElement *ber = (BerElement *)&berbuf;
479 ber_init2( ber, in, LBER_USE_DER );
481 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
482 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
484 tag = ber_skip_tag( ber, &len ); /* Sequence */
485 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
487 tag = ber_peek_tag( ber, &len ); /* Version */
488 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
489 tag = ber_get_int( ber, &version ); /* X.509 only allows v2 */
490 if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX;
492 tag = ber_skip_tag( ber, &len ); /* Holder */
493 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
494 ber_skip_data( ber, len );
496 tag = ber_skip_tag( ber, &len ); /* Issuer */
497 if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX;
498 ber_skip_data( ber, len );
500 tag = ber_skip_tag( ber, &len ); /* Signature */
501 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
502 ber_skip_data( ber, len );
504 tag = ber_skip_tag( ber, &len ); /* Serial number */
505 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
506 ber_skip_data( ber, len );
508 tag = ber_skip_tag( ber, &len ); /* AttCertValidityPeriod */
509 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
510 ber_skip_data( ber, len );
512 tag = ber_skip_tag( ber, &len ); /* Attributes */
513 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
514 ber_skip_data( ber, len );
516 tag = ber_peek_tag( ber, &len );
518 if ( tag == LBER_BITSTRING ) { /* issuerUniqueID */
519 tag = ber_skip_tag( ber, &len );
520 ber_skip_data( ber, len );
521 tag = ber_peek_tag( ber, &len );
524 if ( tag == LBER_SEQUENCE ) { /* extensions or signatureAlgorithm */
525 tag = ber_skip_tag( ber, &len );
526 ber_skip_data( ber, len );
528 tag = ber_peek_tag( ber, &len );
531 if ( tag == LBER_SEQUENCE ) { /* signatureAlgorithm */
532 tag = ber_skip_tag( ber, &len );
533 ber_skip_data( ber, len );
535 tag = ber_peek_tag( ber, &len );
538 if ( tag == LBER_BITSTRING ) { /* Signature */
539 tag = ber_skip_tag( ber, &len );
540 ber_skip_data( ber, len );
542 tag = ber_peek_tag( ber, &len );
545 /* Must be at end now */
546 if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX;
557 struct berval *value,
558 void *assertedValue )
560 struct berval *asserted = (struct berval *) assertedValue;
561 ber_slen_t d = (ber_slen_t) value->bv_len - (ber_slen_t) asserted->bv_len;
563 /* For speed, order first by length, then by contents */
564 *matchp = d ? (sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1)
565 : memcmp( value->bv_val, asserted->bv_val, value->bv_len );
571 octetStringOrderingMatch(
576 struct berval *value,
577 void *assertedValue )
579 struct berval *asserted = (struct berval *) assertedValue;
580 ber_len_t v_len = value->bv_len;
581 ber_len_t av_len = asserted->bv_len;
583 int match = memcmp( value->bv_val, asserted->bv_val,
584 (v_len < av_len ? v_len : av_len) );
587 match = sizeof(v_len) == sizeof(int)
588 ? (int) v_len - (int) av_len
589 : v_len < av_len ? -1 : v_len > av_len;
591 /* If used in extensible match filter, match if value < asserted */
592 if ( flags & SLAP_MR_EXT )
593 match = (match >= 0);
599 /* Initialize HASHcontext from match type and schema info */
602 HASH_CONTEXT *HASHcontext,
603 struct berval *prefix,
608 HASH_Init(HASHcontext);
609 if(prefix && prefix->bv_len > 0) {
610 HASH_Update(HASHcontext,
611 (unsigned char *)prefix->bv_val, prefix->bv_len);
613 if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
614 HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
615 HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
619 /* Set HASHdigest from HASHcontext and value:len */
622 HASH_CONTEXT *HASHcontext,
623 unsigned char *HASHdigest,
624 unsigned char *value,
627 HASH_CONTEXT ctx = *HASHcontext;
628 HASH_Update( &ctx, value, len );
629 HASH_Final( HASHdigest, &ctx );
632 /* Index generation function: Attribute values -> index hash keys */
633 int octetStringIndexer(
638 struct berval *prefix,
646 HASH_CONTEXT HASHcontext;
647 unsigned char HASHdigest[HASH_BYTES];
648 struct berval digest;
649 digest.bv_val = (char *)HASHdigest;
650 digest.bv_len = sizeof(HASHdigest);
652 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
653 /* just count them */
656 /* we should have at least one value at this point */
659 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
661 slen = syntax->ssyn_oidlen;
662 mlen = mr->smr_oidlen;
664 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
665 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
666 hashIter( &HASHcontext, HASHdigest,
667 (unsigned char *)values[i].bv_val, values[i].bv_len );
668 ber_dupbv_x( &keys[i], &digest, ctx );
671 BER_BVZERO( &keys[i] );
678 /* Index generation function: Asserted value -> index hash key */
679 int octetStringFilter(
684 struct berval *prefix,
685 void * assertedValue,
691 HASH_CONTEXT HASHcontext;
692 unsigned char HASHdigest[HASH_BYTES];
693 struct berval *value = (struct berval *) assertedValue;
694 struct berval digest;
695 digest.bv_val = (char *)HASHdigest;
696 digest.bv_len = sizeof(HASHdigest);
698 slen = syntax->ssyn_oidlen;
699 mlen = mr->smr_oidlen;
701 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
703 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
704 hashIter( &HASHcontext, HASHdigest,
705 (unsigned char *)value->bv_val, value->bv_len );
707 ber_dupbv_x( keys, &digest, ctx );
708 BER_BVZERO( &keys[1] );
716 octetStringSubstringsMatch(
721 struct berval *value,
722 void *assertedValue )
725 SubstringsAssertion *sub = assertedValue;
726 struct berval left = *value;
730 /* Add up asserted input length */
731 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
732 inlen += sub->sa_initial.bv_len;
735 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
736 inlen += sub->sa_any[i].bv_len;
739 if ( !BER_BVISNULL( &sub->sa_final ) ) {
740 inlen += sub->sa_final.bv_len;
743 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
744 if ( inlen > left.bv_len ) {
749 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
750 sub->sa_initial.bv_len );
756 left.bv_val += sub->sa_initial.bv_len;
757 left.bv_len -= sub->sa_initial.bv_len;
758 inlen -= sub->sa_initial.bv_len;
761 if ( !BER_BVISNULL( &sub->sa_final ) ) {
762 if ( inlen > left.bv_len ) {
767 match = memcmp( sub->sa_final.bv_val,
768 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
769 sub->sa_final.bv_len );
775 left.bv_len -= sub->sa_final.bv_len;
776 inlen -= sub->sa_final.bv_len;
780 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
785 if ( inlen > left.bv_len ) {
786 /* not enough length */
791 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
795 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
802 idx = p - left.bv_val;
804 if ( idx >= left.bv_len ) {
805 /* this shouldn't happen */
812 if ( sub->sa_any[i].bv_len > left.bv_len ) {
813 /* not enough left */
818 match = memcmp( left.bv_val,
819 sub->sa_any[i].bv_val,
820 sub->sa_any[i].bv_len );
828 left.bv_val += sub->sa_any[i].bv_len;
829 left.bv_len -= sub->sa_any[i].bv_len;
830 inlen -= sub->sa_any[i].bv_len;
839 /* Substring index generation function: Attribute values -> index hash keys */
841 octetStringSubstringsIndexer(
846 struct berval *prefix,
855 HASH_CONTEXT HCany, HCini, HCfin;
856 unsigned char HASHdigest[HASH_BYTES];
857 struct berval digest;
858 digest.bv_val = (char *)HASHdigest;
859 digest.bv_len = sizeof(HASHdigest);
863 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
864 /* count number of indices to generate */
865 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
866 if( values[i].bv_len >= index_substr_if_maxlen ) {
867 nkeys += index_substr_if_maxlen -
868 (index_substr_if_minlen - 1);
869 } else if( values[i].bv_len >= index_substr_if_minlen ) {
870 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
874 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
875 if( values[i].bv_len >= index_substr_any_len ) {
876 nkeys += values[i].bv_len - (index_substr_any_len - 1);
880 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
881 if( values[i].bv_len >= index_substr_if_maxlen ) {
882 nkeys += index_substr_if_maxlen -
883 (index_substr_if_minlen - 1);
884 } else if( values[i].bv_len >= index_substr_if_minlen ) {
885 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
891 /* no keys to generate */
896 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
898 slen = syntax->ssyn_oidlen;
899 mlen = mr->smr_oidlen;
901 if ( flags & SLAP_INDEX_SUBSTR_ANY )
902 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
903 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
904 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
905 if( flags & SLAP_INDEX_SUBSTR_FINAL )
906 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
909 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
912 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
913 ( values[i].bv_len >= index_substr_any_len ) )
915 max = values[i].bv_len - (index_substr_any_len - 1);
917 for( j=0; j<max; j++ ) {
918 hashIter( &HCany, HASHdigest,
919 (unsigned char *)&values[i].bv_val[j],
920 index_substr_any_len );
921 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
925 /* skip if too short */
926 if( values[i].bv_len < index_substr_if_minlen ) continue;
928 max = index_substr_if_maxlen < values[i].bv_len
929 ? index_substr_if_maxlen : values[i].bv_len;
931 for( j=index_substr_if_minlen; j<=max; j++ ) {
933 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
934 hashIter( &HCini, HASHdigest,
935 (unsigned char *)values[i].bv_val, j );
936 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
939 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
940 hashIter( &HCfin, HASHdigest,
941 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
942 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
949 BER_BVZERO( &keys[nkeys] );
959 /* Substring index generation function: Assertion value -> index hash keys */
961 octetStringSubstringsFilter (
966 struct berval *prefix,
967 void * assertedValue,
971 SubstringsAssertion *sa;
974 size_t slen, mlen, klen;
976 HASH_CONTEXT HASHcontext;
977 unsigned char HASHdigest[HASH_BYTES];
978 struct berval *value;
979 struct berval digest;
981 sa = (SubstringsAssertion *) assertedValue;
983 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
984 !BER_BVISNULL( &sa->sa_initial ) &&
985 sa->sa_initial.bv_len >= index_substr_if_minlen )
988 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
989 ( flags & SLAP_INDEX_SUBSTR_ANY ))
991 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
995 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
997 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
998 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
999 /* don't bother accounting with stepping */
1000 nkeys += sa->sa_any[i].bv_len -
1001 ( index_substr_any_len - 1 );
1006 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1007 !BER_BVISNULL( &sa->sa_final ) &&
1008 sa->sa_final.bv_len >= index_substr_if_minlen )
1011 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
1012 ( flags & SLAP_INDEX_SUBSTR_ANY ))
1014 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1020 return LDAP_SUCCESS;
1023 digest.bv_val = (char *)HASHdigest;
1024 digest.bv_len = sizeof(HASHdigest);
1026 slen = syntax->ssyn_oidlen;
1027 mlen = mr->smr_oidlen;
1029 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
1032 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1033 !BER_BVISNULL( &sa->sa_initial ) &&
1034 sa->sa_initial.bv_len >= index_substr_if_minlen )
1036 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1037 value = &sa->sa_initial;
1039 klen = index_substr_if_maxlen < value->bv_len
1040 ? index_substr_if_maxlen : value->bv_len;
1042 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1043 hashIter( &HASHcontext, HASHdigest,
1044 (unsigned char *)value->bv_val, klen );
1045 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1047 /* If initial is too long and we have subany indexed, use it
1048 * to match the excess...
1050 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1053 pre = SLAP_INDEX_SUBSTR_PREFIX;
1054 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1055 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
1057 hashIter( &HASHcontext, HASHdigest,
1058 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1059 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1064 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1066 pre = SLAP_INDEX_SUBSTR_PREFIX;
1067 klen = index_substr_any_len;
1069 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1070 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
1074 value = &sa->sa_any[i];
1076 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1078 j <= value->bv_len - index_substr_any_len;
1079 j += index_substr_any_step )
1081 hashIter( &HASHcontext, HASHdigest,
1082 (unsigned char *)&value->bv_val[j], klen );
1083 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1088 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1089 !BER_BVISNULL( &sa->sa_final ) &&
1090 sa->sa_final.bv_len >= index_substr_if_minlen )
1092 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1093 value = &sa->sa_final;
1095 klen = index_substr_if_maxlen < value->bv_len
1096 ? index_substr_if_maxlen : value->bv_len;
1098 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1099 hashIter( &HASHcontext, HASHdigest,
1100 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
1101 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1103 /* If final is too long and we have subany indexed, use it
1104 * to match the excess...
1106 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1109 pre = SLAP_INDEX_SUBSTR_PREFIX;
1110 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1111 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
1113 hashIter( &HASHcontext, HASHdigest,
1114 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1115 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1121 BER_BVZERO( &keys[nkeys] );
1128 return LDAP_SUCCESS;
1138 /* very unforgiving validation, requires no normalization
1139 * before simplistic matching
1141 if( in->bv_len < 3 ) {
1142 return LDAP_INVALID_SYNTAX;
1145 /* RFC 4517 Section 3.3.2 Bit String:
1146 * BitString = SQUOTE *binary-digit SQUOTE "B"
1147 * binary-digit = "0" / "1"
1149 * where SQUOTE [RFC4512] is
1150 * SQUOTE = %x27 ; single quote ("'")
1152 * Example: '0101111101'B
1155 if( in->bv_val[0] != '\'' ||
1156 in->bv_val[in->bv_len - 2] != '\'' ||
1157 in->bv_val[in->bv_len - 1] != 'B' )
1159 return LDAP_INVALID_SYNTAX;
1162 for( i = in->bv_len - 3; i > 0; i-- ) {
1163 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
1164 return LDAP_INVALID_SYNTAX;
1168 return LDAP_SUCCESS;
1172 * Syntaxes from RFC 4517
1177 A value of the Bit String syntax is a sequence of binary digits. The
1178 LDAP-specific encoding of a value of this syntax is defined by the
1181 BitString = SQUOTE *binary-digit SQUOTE "B"
1183 binary-digit = "0" / "1"
1185 The <SQUOTE> rule is defined in [MODELS].
1190 The LDAP definition for the Bit String syntax is:
1192 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
1194 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
1198 3.3.21. Name and Optional UID
1200 A value of the Name and Optional UID syntax is the distinguished name
1201 [MODELS] of an entity optionally accompanied by a unique identifier
1202 that serves to differentiate the entity from others with an identical
1205 The LDAP-specific encoding of a value of this syntax is defined by
1208 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
1210 The <BitString> rule is defined in Section 3.3.2. The
1211 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
1212 defined in [MODELS].
1214 Note that although the '#' character may occur in the string
1215 representation of a distinguished name, no additional escaping of
1216 this character is performed when a <distinguishedName> is encoded in
1217 a <NameAndOptionalUID>.
1220 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
1222 The LDAP definition for the Name and Optional UID syntax is:
1224 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
1226 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
1233 1.4. Common ABNF Productions
1236 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
1238 SQUOTE = %x27 ; single quote ("'")
1243 * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
1244 * be escaped except when at the beginning of a value, the
1245 * definition of Name and Optional UID appears to be flawed,
1246 * because there is no clear means to determine whether the
1247 * UID part is present or not.
1251 * cn=Someone,dc=example,dc=com#'1'B
1253 * could be either a NameAndOptionalUID with trailing UID, i.e.
1255 * DN = "cn=Someone,dc=example,dc=com"
1258 * or a NameAndOptionalUID with no trailing UID, and the AVA
1259 * in the last RDN made of
1261 * attributeType = dc
1262 * attributeValue = com#'1'B
1264 * in fact "com#'1'B" is a valid IA5 string.
1266 * As a consequence, current slapd code takes the presence of
1267 * #<valid BitString> at the end of the string representation
1268 * of a NameAndOptionalUID to mean this is indeed a BitString.
1269 * This is quite arbitrary - it has changed the past and might
1270 * change in the future.
1280 struct berval dn, uid;
1282 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
1284 ber_dupbv( &dn, in );
1285 if( !dn.bv_val ) return LDAP_OTHER;
1287 /* if there's a "#", try bitStringValidate()... */
1288 uid.bv_val = strrchr( dn.bv_val, '#' );
1289 if ( !BER_BVISNULL( &uid ) ) {
1291 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1293 rc = bitStringValidate( NULL, &uid );
1294 if ( rc == LDAP_SUCCESS ) {
1295 /* in case of success, trim the UID,
1296 * otherwise treat it as part of the DN */
1297 dn.bv_len -= uid.bv_len + 1;
1298 uid.bv_val[-1] = '\0';
1302 rc = dnValidate( NULL, &dn );
1304 ber_memfree( dn.bv_val );
1315 assert( val != NULL );
1316 assert( out != NULL );
1319 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1321 if( BER_BVISEMPTY( val ) ) {
1322 ber_dupbv_x( out, val, ctx );
1324 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1325 return LDAP_INVALID_SYNTAX;
1329 struct berval dnval = *val;
1330 struct berval uidval = BER_BVNULL;
1332 uidval.bv_val = strrchr( val->bv_val, '#' );
1333 if ( !BER_BVISNULL( &uidval ) ) {
1335 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1337 rc = bitStringValidate( NULL, &uidval );
1339 if ( rc == LDAP_SUCCESS ) {
1340 ber_dupbv_x( &dnval, val, ctx );
1342 dnval.bv_len -= ++uidval.bv_len;
1343 dnval.bv_val[dnval.bv_len] = '\0';
1346 BER_BVZERO( &uidval );
1350 rc = dnPretty( syntax, &dnval, out, ctx );
1351 if ( dnval.bv_val != val->bv_val ) {
1352 slap_sl_free( dnval.bv_val, ctx );
1354 if( rc != LDAP_SUCCESS ) {
1358 if( !BER_BVISNULL( &uidval ) ) {
1361 tmp = slap_sl_realloc( out->bv_val, out->bv_len
1362 + uidval.bv_len + 1,
1365 ber_memfree_x( out->bv_val, ctx );
1369 memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
1370 out->bv_len += uidval.bv_len;
1371 out->bv_val[out->bv_len] = '\0';
1375 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1377 return LDAP_SUCCESS;
1381 uniqueMemberNormalize(
1386 struct berval *normalized,
1392 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1394 ber_dupbv_x( &out, val, ctx );
1395 if ( BER_BVISEMPTY( &out ) ) {
1399 struct berval uid = BER_BVNULL;
1401 uid.bv_val = strrchr( out.bv_val, '#' );
1402 if ( !BER_BVISNULL( &uid ) ) {
1404 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1406 rc = bitStringValidate( NULL, &uid );
1407 if ( rc == LDAP_SUCCESS ) {
1408 uid.bv_val[-1] = '\0';
1409 out.bv_len -= uid.bv_len + 1;
1415 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1417 if( rc != LDAP_SUCCESS ) {
1418 slap_sl_free( out.bv_val, ctx );
1419 return LDAP_INVALID_SYNTAX;
1422 if( !BER_BVISNULL( &uid ) ) {
1425 tmp = ch_realloc( normalized->bv_val,
1426 normalized->bv_len + uid.bv_len
1427 + STRLENOF("#") + 1 );
1428 if ( tmp == NULL ) {
1429 ber_memfree_x( normalized->bv_val, ctx );
1433 normalized->bv_val = tmp;
1435 /* insert the separator */
1436 normalized->bv_val[normalized->bv_len++] = '#';
1438 /* append the UID */
1439 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1440 uid.bv_val, uid.bv_len );
1441 normalized->bv_len += uid.bv_len;
1444 normalized->bv_val[normalized->bv_len] = '\0';
1447 slap_sl_free( out.bv_val, ctx );
1450 return LDAP_SUCCESS;
1459 struct berval *value,
1460 void *assertedValue )
1463 struct berval *asserted = (struct berval *) assertedValue;
1464 struct berval assertedDN = *asserted;
1465 struct berval assertedUID = BER_BVNULL;
1466 struct berval valueDN = *value;
1467 struct berval valueUID = BER_BVNULL;
1468 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1470 if ( !BER_BVISEMPTY( asserted ) ) {
1471 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1472 if ( !BER_BVISNULL( &assertedUID ) ) {
1473 assertedUID.bv_val++;
1474 assertedUID.bv_len = assertedDN.bv_len
1475 - ( assertedUID.bv_val - assertedDN.bv_val );
1477 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1478 assertedDN.bv_len -= assertedUID.bv_len + 1;
1481 BER_BVZERO( &assertedUID );
1486 if ( !BER_BVISEMPTY( value ) ) {
1488 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1489 if ( !BER_BVISNULL( &valueUID ) ) {
1491 valueUID.bv_len = valueDN.bv_len
1492 - ( valueUID.bv_val - valueDN.bv_val );
1494 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1495 valueDN.bv_len -= valueUID.bv_len + 1;
1498 BER_BVZERO( &valueUID );
1503 if( valueUID.bv_len && assertedUID.bv_len ) {
1505 d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len;
1507 *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1;
1508 return LDAP_SUCCESS;
1511 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1514 return LDAP_SUCCESS;
1517 } else if ( !approx && valueUID.bv_len ) {
1520 return LDAP_SUCCESS;
1522 } else if ( !approx && assertedUID.bv_len ) {
1525 return LDAP_SUCCESS;
1528 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1532 uniqueMemberIndexer(
1537 struct berval *prefix,
1545 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1546 /* just count them */
1550 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1552 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1553 struct berval assertedDN = values[i];
1554 struct berval assertedUID = BER_BVNULL;
1556 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1557 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1558 if ( !BER_BVISNULL( &assertedUID ) ) {
1559 assertedUID.bv_val++;
1560 assertedUID.bv_len = assertedDN.bv_len
1561 - ( assertedUID.bv_val - assertedDN.bv_val );
1563 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1564 assertedDN.bv_len -= assertedUID.bv_len + 1;
1567 BER_BVZERO( &assertedUID );
1572 dnvalues[i] = assertedDN;
1574 BER_BVZERO( &dnvalues[i] );
1576 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1577 dnvalues, keysp, ctx );
1579 slap_sl_free( dnvalues, ctx );
1589 struct berval *prefix,
1590 void * assertedValue,
1594 struct berval *asserted = (struct berval *) assertedValue;
1595 struct berval assertedDN = *asserted;
1596 struct berval assertedUID = BER_BVNULL;
1598 if ( !BER_BVISEMPTY( asserted ) ) {
1599 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1600 if ( !BER_BVISNULL( &assertedUID ) ) {
1601 assertedUID.bv_val++;
1602 assertedUID.bv_len = assertedDN.bv_len
1603 - ( assertedUID.bv_val - assertedDN.bv_val );
1605 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1606 assertedDN.bv_len -= assertedUID.bv_len + 1;
1609 BER_BVZERO( &assertedUID );
1614 return octetStringFilter( use, flags, syntax, mr, prefix,
1615 &assertedDN, keysp, ctx );
1620 * Handling boolean syntax and matching is quite rigid.
1621 * A more flexible approach would be to allow a variety
1622 * of strings to be normalized and prettied into TRUE
1630 /* very unforgiving validation, requires no normalization
1631 * before simplistic matching
1634 if( in->bv_len == 4 ) {
1635 if( bvmatch( in, &slap_true_bv ) ) {
1636 return LDAP_SUCCESS;
1638 } else if( in->bv_len == 5 ) {
1639 if( bvmatch( in, &slap_false_bv ) ) {
1640 return LDAP_SUCCESS;
1644 return LDAP_INVALID_SYNTAX;
1653 struct berval *value,
1654 void *assertedValue )
1656 /* simplistic matching allowed by rigid validation */
1657 struct berval *asserted = (struct berval *) assertedValue;
1658 *matchp = (int) asserted->bv_len - (int) value->bv_len;
1659 return LDAP_SUCCESS;
1662 /*-------------------------------------------------------------------
1663 LDAP/X.500 string syntax / matching rules have a few oddities. This
1664 comment attempts to detail how slapd(8) treats them.
1667 StringSyntax X.500 LDAP Matching/Comments
1668 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1669 PrintableString subset subset i/e + ignore insignificant spaces
1670 PrintableString subset subset i/e + ignore insignificant spaces
1671 NumericString subset subset ignore all spaces
1672 IA5String ASCII ASCII i/e + ignore insignificant spaces
1673 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1675 TelephoneNumber subset subset i + ignore all spaces and "-"
1677 See RFC 4518 for details.
1681 In X.500(93), a directory string can be either a PrintableString,
1682 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1683 In later versions, more CHOICEs were added. In all cases the string
1686 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1687 A directory string cannot be zero length.
1689 For matching, there are both case ignore and exact rules. Both
1690 also require that "insignificant" spaces be ignored.
1691 spaces before the first non-space are ignored;
1692 spaces after the last non-space are ignored;
1693 spaces after a space are ignored.
1694 Note: by these rules (and as clarified in X.520), a string of only
1695 spaces is to be treated as if held one space, not empty (which
1696 would be a syntax error).
1699 In ASN.1, numeric string is just a string of digits and spaces
1700 and could be empty. However, in X.500, all attribute values of
1701 numeric string carry a non-empty constraint. For example:
1703 internationalISDNNumber ATTRIBUTE ::= {
1704 WITH SYNTAX InternationalISDNNumber
1705 EQUALITY MATCHING RULE numericStringMatch
1706 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1707 ID id-at-internationalISDNNumber }
1708 InternationalISDNNumber ::=
1709 NumericString (SIZE(1..ub-international-isdn-number))
1711 Unforunately, some assertion values are don't carry the same
1712 constraint (but its unclear how such an assertion could ever
1713 be true). In LDAP, there is one syntax (numericString) not two
1714 (numericString with constraint, numericString without constraint).
1715 This should be treated as numericString with non-empty constraint.
1716 Note that while someone may have no ISDN number, there are no ISDN
1717 numbers which are zero length.
1719 In matching, spaces are ignored.
1722 In ASN.1, Printable string is just a string of printable characters
1723 and can be empty. In X.500, semantics much like NumericString (see
1724 serialNumber for a like example) excepting uses insignificant space
1725 handling instead of ignore all spaces. They must be non-empty.
1728 Basically same as PrintableString. There are no examples in X.500,
1729 but same logic applies. Empty strings are allowed.
1731 -------------------------------------------------------------------*/
1739 unsigned char *u = (unsigned char *)in->bv_val, *end = in->bv_val + in->bv_len;
1741 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1742 /* directory strings cannot be empty */
1743 return LDAP_INVALID_SYNTAX;
1746 for( ; u < end; 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';
1855 } else if ( tmp.bv_len ) {
1856 /* string of all spaces is treated as one space */
1857 nvalue.bv_val[0] = ' ';
1858 nvalue.bv_val[1] = '\0';
1860 } /* should never be entered with 0-length val */
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] );
2157 if( keys[keycount].bv_len ) {
2160 ch_free( keys[keycount].bv_val );
2165 ber_memfree( val.bv_val );
2167 BER_BVZERO( &keys[keycount] );
2170 return LDAP_SUCCESS;
2179 struct berval *prefix,
2180 void * assertedValue,
2189 /* Yes, this is necessary */
2190 val = UTF8bvnormalize( ((struct berval *)assertedValue),
2191 NULL, LDAP_UTF8_APPROX, NULL );
2192 if( val == NULL || BER_BVISNULL( val ) ) {
2193 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2194 BER_BVZERO( &keys[0] );
2197 return LDAP_SUCCESS;
2200 /* Isolate how many words there are. There will be a key for each */
2201 for( count = 0,c = val->bv_val; *c; c++) {
2202 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2203 if( len >= SLAPD_APPROX_WORDLEN ) count++;
2205 if (*c == '\0') break;
2209 /* Allocate storage for new keys */
2210 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2212 /* Get a phonetic copy of each word */
2213 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2215 if( len < SLAPD_APPROX_WORDLEN ) continue;
2216 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2222 BER_BVZERO( &keys[count] );
2225 return LDAP_SUCCESS;
2228 /* Remove all spaces and '-' characters */
2230 telephoneNumberNormalize(
2235 struct berval *normalized,
2240 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2242 /* validator should have refused an empty string */
2243 assert( !BER_BVISEMPTY( val ) );
2245 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2247 for( p = val->bv_val; *p; p++ ) {
2248 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
2254 normalized->bv_len = q - normalized->bv_val;
2256 if( BER_BVISEMPTY( normalized ) ) {
2257 slap_sl_free( normalized->bv_val, ctx );
2258 BER_BVZERO( normalized );
2259 return LDAP_INVALID_SYNTAX;
2262 return LDAP_SUCCESS;
2266 postalAddressValidate(
2270 struct berval bv = *in;
2273 for ( c = 0; c < in->bv_len; c++ ) {
2274 if ( in->bv_val[c] == '\\' ) {
2276 if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2277 && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2279 return LDAP_INVALID_SYNTAX;
2284 if ( in->bv_val[c] == '$' ) {
2285 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2286 if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2287 return LDAP_INVALID_SYNTAX;
2289 bv.bv_val = &in->bv_val[c] + 1;
2293 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2294 return UTF8StringValidate( NULL, &bv );
2298 postalAddressNormalize(
2303 struct berval *normalized,
2306 BerVarray lines = NULL, nlines = NULL;
2308 int rc = LDAP_SUCCESS;
2309 MatchingRule *xmr = NULL;
2312 if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2313 xmr = slap_schema.si_mr_caseIgnoreMatch;
2316 xmr = slap_schema.si_mr_caseExactMatch;
2319 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2320 if ( val->bv_val[c] == '$' ) {
2325 lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2326 nlines = &lines[l + 2];
2328 lines[0].bv_val = val->bv_val;
2329 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2330 if ( val->bv_val[c] == '$' ) {
2331 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2333 lines[l].bv_val = &val->bv_val[c + 1];
2336 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2338 normalized->bv_len = c = l;
2340 for ( l = 0; l <= c; l++ ) {
2341 /* NOTE: we directly normalize each line,
2342 * without unescaping the values, since the special
2343 * values '\24' ('$') and '\5C' ('\') are not affected
2344 * by normalization */
2345 if ( !lines[l].bv_len ) {
2346 nlines[l].bv_len = 0;
2347 nlines[l].bv_val = NULL;
2350 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2351 if ( rc != LDAP_SUCCESS ) {
2352 rc = LDAP_INVALID_SYNTAX;
2356 normalized->bv_len += nlines[l].bv_len;
2359 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2361 p = normalized->bv_val;
2362 for ( l = 0; l <= c ; l++ ) {
2363 p = lutil_strbvcopy( p, &nlines[l] );
2368 assert( p == &normalized->bv_val[normalized->bv_len] );
2371 if ( nlines != NULL ) {
2372 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2373 slap_sl_free( nlines[l].bv_val, ctx );
2376 slap_sl_free( lines, ctx );
2387 struct berval val = *in;
2389 if( BER_BVISEMPTY( &val ) ) {
2390 /* disallow empty strings */
2391 return LDAP_INVALID_SYNTAX;
2394 while( OID_LEADCHAR( val.bv_val[0] ) ) {
2395 if ( val.bv_len == 1 ) {
2396 return LDAP_SUCCESS;
2399 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2406 while ( OID_LEADCHAR( val.bv_val[0] )) {
2410 if ( val.bv_len == 0 ) {
2411 return LDAP_SUCCESS;
2415 if( !OID_SEPARATOR( val.bv_val[0] )) {
2423 return LDAP_INVALID_SYNTAX;
2432 struct berval val = *in;
2434 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2436 if ( val.bv_val[0] == '-' ) {
2440 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2441 return LDAP_INVALID_SYNTAX;
2444 if( val.bv_val[0] == '0' ) { /* "-0" */
2445 return LDAP_INVALID_SYNTAX;
2448 } else if ( val.bv_val[0] == '0' ) {
2449 if( val.bv_len > 1 ) { /* "0<more>" */
2450 return LDAP_INVALID_SYNTAX;
2453 return LDAP_SUCCESS;
2456 for( i=0; i < val.bv_len; i++ ) {
2457 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2458 return LDAP_INVALID_SYNTAX;
2462 return LDAP_SUCCESS;
2471 struct berval *value,
2472 void *assertedValue )
2474 struct berval *asserted = (struct berval *) assertedValue;
2475 int vsign = 1, asign = 1; /* default sign = '+' */
2480 if( v.bv_val[0] == '-' ) {
2486 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2489 if( a.bv_val[0] == '-' ) {
2495 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2497 match = vsign - asign;
2499 match = ( v.bv_len != a.bv_len
2500 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2501 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2502 if( vsign < 0 ) match = -match;
2505 /* Ordering rule used in extensible match filter? */
2506 if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2507 match = (match >= 0);
2510 return LDAP_SUCCESS;
2513 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2514 #define INDEX_INTLEN_CHOP 7
2515 #define INDEX_INTLEN_CHOPBYTES 3
2524 /* Integer index key format, designed for memcmp to collate correctly:
2525 * if too large: one's complement sign*<approx exponent=chopped bytes>,
2526 * two's complement value (sign-extended or chopped as needed),
2527 * however in first byte above, the top <number of exponent-bytes + 1>
2528 * bits are the inverse sign and next bit is the sign as delimiter.
2530 ber_slen_t k = index_intlen_strlen;
2532 unsigned signmask = ~0x7fU;
2533 unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2534 struct berval val = *in, itmp = *tmp;
2536 if ( val.bv_val[0] != '-' ) {
2541 /* Chop least significant digits, increase length instead */
2542 if ( val.bv_len > (ber_len_t) k ) {
2543 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2544 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2545 chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
2548 if ( lutil_str2bin( &val, &itmp, ctx )) {
2549 return LDAP_INVALID_SYNTAX;
2552 /* Omit leading sign byte */
2553 if ( itmp.bv_val[0] == neg ) {
2558 k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2560 assert( chop == 0 );
2561 memset( key->bv_val, neg, k ); /* sign-extend */
2562 } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2563 /* Got exponent -k, or no room for 2 sign bits */
2564 lenp = lenbuf + sizeof(lenbuf);
2565 chop = - (ber_len_t) k;
2567 *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2569 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2570 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2571 * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2572 k = (lenbuf + sizeof(lenbuf)) - lenp;
2573 if ( k > (ber_slen_t) index_intlen )
2575 memcpy( key->bv_val, lenp, k );
2576 itmp.bv_len = index_intlen - k;
2578 memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2579 key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2583 /* Index generation function: Ordered index */
2590 struct berval *prefix,
2600 unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2602 /* count the values and find max needed length */
2604 for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2605 if ( vlen < values[i].bv_len )
2606 vlen = values[i].bv_len;
2608 if ( vlen > maxstrlen )
2611 /* we should have at least one value at this point */
2614 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2615 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2616 keys[i].bv_len = index_intlen;
2617 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2620 keys[i].bv_val = NULL;
2622 if ( vlen > sizeof(ibuf) ) {
2623 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2627 itmp.bv_len = sizeof(ibuf);
2629 for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2630 if ( itmp.bv_val != ibuf ) {
2631 itmp.bv_len = values[i].bv_len;
2632 if ( itmp.bv_len <= sizeof(ibuf) )
2633 itmp.bv_len = sizeof(ibuf);
2634 else if ( itmp.bv_len > maxstrlen )
2635 itmp.bv_len = maxstrlen;
2637 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2639 slap_sl_free( keys, ctx );
2645 if ( itmp.bv_val != ibuf ) {
2646 slap_sl_free( itmp.bv_val, ctx );
2651 /* Index generation function: Ordered index */
2658 struct berval *prefix,
2659 void * assertedValue,
2666 struct berval *value;
2669 value = (struct berval *) assertedValue;
2671 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2673 keys[0].bv_len = index_intlen;
2674 keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2676 keys[1].bv_val = NULL;
2678 iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2679 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2680 if ( iv.bv_len > (int) sizeof(ibuf) ) {
2681 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2684 iv.bv_len = sizeof(ibuf);
2687 rc = integerVal2Key( value, keys, &iv, ctx );
2689 if ( iv.bv_val != ibuf ) {
2690 slap_sl_free( iv.bv_val, ctx );
2696 slap_sl_free( keys, ctx );
2702 countryStringValidate(
2704 struct berval *val )
2706 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2708 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2709 return LDAP_INVALID_SYNTAX;
2711 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2712 return LDAP_INVALID_SYNTAX;
2715 return LDAP_SUCCESS;
2719 printableStringValidate(
2721 struct berval *val )
2725 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2727 for(i=0; i < val->bv_len; i++) {
2728 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2729 return LDAP_INVALID_SYNTAX;
2733 return LDAP_SUCCESS;
2737 printablesStringValidate(
2739 struct berval *val )
2743 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2745 for(i=0,len=0; i < val->bv_len; i++) {
2746 int c = val->bv_val[i];
2750 return LDAP_INVALID_SYNTAX;
2754 } else if ( SLAP_PRINTABLE(c) ) {
2757 return LDAP_INVALID_SYNTAX;
2762 return LDAP_INVALID_SYNTAX;
2765 return LDAP_SUCCESS;
2771 struct berval *val )
2775 for(i=0; i < val->bv_len; i++) {
2776 if( !LDAP_ASCII(val->bv_val[i]) ) {
2777 return LDAP_INVALID_SYNTAX;
2781 return LDAP_SUCCESS;
2790 struct berval *normalized,
2794 int casefold = !SLAP_MR_ASSOCIATED( mr,
2795 slap_schema.si_mr_caseExactIA5Match );
2797 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2801 /* Ignore initial whitespace */
2802 while ( ASCII_SPACE( *p ) ) p++;
2804 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2805 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2806 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2807 normalized->bv_val[normalized->bv_len] = '\0';
2809 p = q = normalized->bv_val;
2812 if ( ASCII_SPACE( *p ) ) {
2815 /* Ignore the extra whitespace */
2816 while ( ASCII_SPACE( *p ) ) {
2820 } else if ( casefold ) {
2821 /* Most IA5 rules require casefolding */
2822 *q++ = TOLOWER(*p); p++;
2829 assert( normalized->bv_val <= p );
2833 * If the string ended in space, backup the pointer one
2834 * position. One is enough because the above loop collapsed
2835 * all whitespace to a single space.
2837 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2839 /* null terminate */
2842 normalized->bv_len = q - normalized->bv_val;
2844 return LDAP_SUCCESS;
2853 if( in->bv_len != 36 ) {
2854 return LDAP_INVALID_SYNTAX;
2857 for( i=0; i<36; i++ ) {
2863 if( in->bv_val[i] != '-' ) {
2864 return LDAP_INVALID_SYNTAX;
2868 if( !ASCII_HEX( in->bv_val[i]) ) {
2869 return LDAP_INVALID_SYNTAX;
2874 return LDAP_SUCCESS;
2885 int rc=LDAP_INVALID_SYNTAX;
2887 assert( in != NULL );
2888 assert( out != NULL );
2890 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2893 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2895 for( i=0; i<36; i++ ) {
2901 if( in->bv_val[i] != '-' ) {
2904 out->bv_val[i] = '-';
2908 if( !ASCII_HEX( in->bv_val[i]) ) {
2911 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2916 out->bv_val[ out->bv_len ] = '\0';
2920 slap_sl_free( out->bv_val, ctx );
2933 struct berval *normalized,
2936 unsigned char octet = '\0';
2940 if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
2941 /* NOTE: must be a normalized UUID */
2942 assert( val->bv_len == 16 );
2944 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
2945 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
2946 val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
2947 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
2949 return LDAP_SUCCESS;
2952 normalized->bv_len = 16;
2953 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2955 for( i=0, j=0; i<36; i++ ) {
2956 unsigned char nibble;
2957 if( val->bv_val[i] == '-' ) {
2960 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
2961 nibble = val->bv_val[i] - '0';
2963 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
2964 nibble = val->bv_val[i] - ('a'-10);
2966 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
2967 nibble = val->bv_val[i] - ('A'-10);
2970 slap_sl_free( normalized->bv_val, ctx );
2971 BER_BVZERO( normalized );
2972 return LDAP_INVALID_SYNTAX;
2977 normalized->bv_val[j>>1] = octet;
2979 octet = nibble << 4;
2984 normalized->bv_val[normalized->bv_len] = 0;
2985 return LDAP_SUCCESS;
2991 numericStringValidate(
2997 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
2999 for(i=0; i < in->bv_len; i++) {
3000 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
3001 return LDAP_INVALID_SYNTAX;
3005 return LDAP_SUCCESS;
3009 numericStringNormalize(
3014 struct berval *normalized,
3017 /* removal all spaces */
3020 assert( !BER_BVISEMPTY( val ) );
3022 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3025 q = normalized->bv_val;
3028 if ( ASCII_SPACE( *p ) ) {
3029 /* Ignore whitespace */
3036 /* we should have copied no more than is in val */
3037 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3039 /* null terminate */
3042 normalized->bv_len = q - normalized->bv_val;
3044 if( BER_BVISEMPTY( normalized ) ) {
3045 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3046 normalized->bv_val[0] = ' ';
3047 normalized->bv_val[1] = '\0';
3048 normalized->bv_len = 1;
3051 return LDAP_SUCCESS;
3055 * Integer conversion macros that will use the largest available
3058 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3059 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
3060 # define SLAP_LONG long long
3062 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
3063 # define SLAP_LONG long
3064 #endif /* HAVE_STRTOLL ... */
3072 struct berval *value,
3073 void *assertedValue )
3075 SLAP_LONG lValue, lAssertedValue;
3078 /* safe to assume integers are NUL terminated? */
3079 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3080 if( errno == ERANGE )
3082 return LDAP_CONSTRAINT_VIOLATION;
3085 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3087 if( errno == ERANGE )
3089 return LDAP_CONSTRAINT_VIOLATION;
3092 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3093 return LDAP_SUCCESS;
3102 struct berval *value,
3103 void *assertedValue )
3105 SLAP_LONG lValue, lAssertedValue;
3108 /* safe to assume integers are NUL terminated? */
3109 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3110 if( errno == ERANGE )
3112 return LDAP_CONSTRAINT_VIOLATION;
3115 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3117 if( errno == ERANGE )
3119 return LDAP_CONSTRAINT_VIOLATION;
3122 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3123 return LDAP_SUCCESS;
3127 checkNum( struct berval *in, struct berval *out )
3129 /* parse serialNumber */
3130 ber_len_t neg = 0, extra = 0;
3133 out->bv_val = in->bv_val;
3136 if ( out->bv_val[0] == '-' ) {
3141 if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3142 first = out->bv_val[2];
3145 out->bv_len += STRLENOF("0x");
3146 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3147 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3150 } else if ( out->bv_val[0] == '\'' ) {
3151 first = out->bv_val[1];
3154 out->bv_len += STRLENOF("'");
3156 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3157 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3159 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3162 out->bv_len += STRLENOF("'H");
3165 first = out->bv_val[0];
3166 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3167 if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3171 if ( !( out->bv_len > neg ) ) {
3175 if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3183 serialNumberAndIssuerCheck(
3191 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3193 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3194 /* Parse old format */
3195 is->bv_val = ber_bvchr( in, '$' );
3196 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3198 sn->bv_val = in->bv_val;
3199 sn->bv_len = is->bv_val - in->bv_val;
3202 is->bv_len = in->bv_len - (sn->bv_len + 1);
3204 /* eat leading zeros */
3205 for( n=0; n < (sn->bv_len-1); n++ ) {
3206 if( sn->bv_val[n] != '0' ) break;
3211 for( n=0; n < sn->bv_len; n++ ) {
3212 if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3216 /* Parse GSER format */
3221 HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3225 struct berval x = *in;
3231 /* eat leading spaces */
3232 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3236 /* should be at issuer or serialNumber NamedValue */
3237 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3238 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3241 x.bv_val += STRLENOF("issuer");
3242 x.bv_len -= STRLENOF("issuer");
3244 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3248 /* eat leading spaces */
3249 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3253 /* For backward compatibility, this part is optional */
3254 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3255 x.bv_val += STRLENOF("rdnSequence:");
3256 x.bv_len -= STRLENOF("rdnSequence:");
3259 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3263 is->bv_val = x.bv_val;
3266 for ( ; is->bv_len < x.bv_len; ) {
3267 if ( is->bv_val[is->bv_len] != '"' ) {
3271 if ( is->bv_val[is->bv_len+1] == '"' ) {
3279 x.bv_val += is->bv_len + 1;
3280 x.bv_len -= is->bv_len + 1;
3282 have |= HAVE_ISSUER;
3284 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3286 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3288 /* parse serialNumber */
3289 x.bv_val += STRLENOF("serialNumber");
3290 x.bv_len -= STRLENOF("serialNumber");
3292 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3296 /* eat leading spaces */
3297 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3301 if ( checkNum( &x, sn ) ) {
3302 return LDAP_INVALID_SYNTAX;
3305 x.bv_val += sn->bv_len;
3306 x.bv_len -= sn->bv_len;
3311 return LDAP_INVALID_SYNTAX;
3314 /* eat leading spaces */
3315 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3319 if ( have == HAVE_ALL ) {
3323 if ( x.bv_val[0] != ',' ) {
3324 return LDAP_INVALID_SYNTAX;
3331 /* should have no characters left... */
3332 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3334 if ( numdquotes == 0 ) {
3335 ber_dupbv_x( &ni, is, ctx );
3340 ni.bv_len = is->bv_len - numdquotes;
3341 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3342 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3343 if ( is->bv_val[src] == '"' ) {
3346 ni.bv_val[dst] = is->bv_val[src];
3348 ni.bv_val[dst] = '\0';
3358 serialNumberAndIssuerValidate(
3363 struct berval sn, i;
3365 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3368 rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3373 /* validate DN -- doesn't handle double dquote */
3374 rc = dnValidate( NULL, &i );
3376 rc = LDAP_INVALID_SYNTAX;
3379 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3380 slap_sl_free( i.bv_val, NULL );
3383 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3384 in->bv_val, rc, 0 );
3391 serialNumberAndIssuerPretty(
3398 struct berval sn, i, ni = BER_BVNULL;
3401 assert( in != NULL );
3402 assert( out != NULL );
3406 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3409 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3414 rc = dnPretty( syntax, &i, &ni, ctx );
3416 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3417 slap_sl_free( i.bv_val, ctx );
3421 rc = LDAP_INVALID_SYNTAX;
3425 /* make room from sn + "$" */
3426 out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3427 + sn.bv_len + ni.bv_len;
3428 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3430 if ( out->bv_val == NULL ) {
3437 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3438 p = lutil_strbvcopy( p, &sn );
3439 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3440 p = lutil_strbvcopy( p, &ni );
3441 p = lutil_strcopy( p, /*{*/ "\" }" );
3443 assert( p == &out->bv_val[out->bv_len] );
3446 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3447 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3449 slap_sl_free( ni.bv_val, ctx );
3451 return LDAP_SUCCESS;
3461 /* Use hex format. '123456789abcdef'H */
3462 unsigned char *ptr, zero = '\0';
3465 ber_len_t i, len, nlen;
3467 assert( in != NULL );
3468 assert( !BER_BVISNULL( in ) );
3469 assert( out != NULL );
3470 assert( !BER_BVISNULL( out ) );
3472 ptr = (unsigned char *)in->bv_val;
3475 /* Check for minimal encodings */
3477 if ( ptr[0] & 0x80 ) {
3478 if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3482 } else if ( ptr[0] == 0 ) {
3483 if ( !( ptr[1] & 0x80 ) ) {
3490 } else if ( len == 0 ) {
3491 /* FIXME: this should not be possible,
3492 * since a value of zero would have length 1 */
3497 first = !( ptr[0] & 0xf0U );
3498 nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3499 if ( nlen >= out->bv_len ) {
3500 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3506 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3510 for ( ; i < len; i++ ) {
3511 sprintf( sptr, "%02X", ptr[i] );
3518 assert( sptr == &out->bv_val[nlen] );
3525 #define SLAP_SN_BUFLEN (64)
3528 * This routine is called by certificateExactNormalize when
3529 * certificateExactNormalize receives a search string instead of
3530 * a certificate. This routine checks if the search value is valid
3531 * and then returns the normalized value
3534 serialNumberAndIssuerNormalize(
3542 struct berval sn, sn2, sn3, i, ni;
3543 char sbuf2[SLAP_SN_BUFLEN];
3544 char sbuf3[SLAP_SN_BUFLEN];
3548 assert( in != NULL );
3549 assert( out != NULL );
3551 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3554 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3559 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3561 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3562 slap_sl_free( i.bv_val, ctx );
3566 return LDAP_INVALID_SYNTAX;
3569 /* Convert sn to canonical hex */
3571 if ( sn.bv_len > sizeof( sbuf2 ) ) {
3572 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3574 sn2.bv_len = sn.bv_len;
3576 sn3.bv_len = sizeof(sbuf3);
3577 if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
3578 rc = LDAP_INVALID_SYNTAX;
3582 out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3583 + sn3.bv_len + ni.bv_len;
3584 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3585 if ( out->bv_val == NULL ) {
3593 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3594 p = lutil_strbvcopy( p, &sn3 );
3595 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3596 p = lutil_strbvcopy( p, &ni );
3597 p = lutil_strcopy( p, /*{*/ "\" }" );
3599 assert( p == &out->bv_val[out->bv_len] );
3602 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3603 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3605 if ( sn2.bv_val != sbuf2 ) {
3606 slap_sl_free( sn2.bv_val, ctx );
3609 if ( sn3.bv_val != sbuf3 ) {
3610 slap_sl_free( sn3.bv_val, ctx );
3613 slap_sl_free( ni.bv_val, ctx );
3619 certificateExactNormalize(
3624 struct berval *normalized,
3627 BerElementBuffer berbuf;
3628 BerElement *ber = (BerElement *)&berbuf;
3632 char serialbuf2[SLAP_SN_BUFLEN];
3633 struct berval sn, sn2 = BER_BVNULL;
3634 struct berval issuer_dn = BER_BVNULL, bvdn;
3636 int rc = LDAP_INVALID_SYNTAX;
3638 assert( val != NULL );
3640 Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3641 val->bv_val, val->bv_len, 0 );
3643 if ( BER_BVISEMPTY( val ) ) goto done;
3645 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3646 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3649 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3651 ber_init2( ber, val, LBER_USE_DER );
3652 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3653 tag = ber_skip_tag( ber, &len ); /* Sequence */
3654 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3655 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3656 tag = ber_skip_tag( ber, &len );
3657 tag = ber_get_int( ber, &i ); /* version */
3660 /* NOTE: move the test here from certificateValidate,
3661 * so that we can validate certs with serial longer
3662 * than sizeof(ber_int_t) */
3663 tag = ber_skip_tag( ber, &len ); /* serial */
3665 sn.bv_val = (char *)ber->ber_ptr;
3666 sn2.bv_val = serialbuf2;
3667 sn2.bv_len = sizeof(serialbuf2);
3668 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3669 rc = LDAP_INVALID_SYNTAX;
3672 ber_skip_data( ber, len );
3674 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3675 ber_skip_data( ber, len );
3676 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3678 len = ber_ptrlen( ber );
3679 bvdn.bv_val = val->bv_val + len;
3680 bvdn.bv_len = val->bv_len - len;
3682 rc = dnX509normalize( &bvdn, &issuer_dn );
3683 if ( rc != LDAP_SUCCESS ) goto done;
3686 normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3687 + sn2.bv_len + issuer_dn.bv_len;
3688 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3690 p = normalized->bv_val;
3692 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3693 p = lutil_strbvcopy( p, &sn2 );
3694 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3695 p = lutil_strbvcopy( p, &issuer_dn );
3696 p = lutil_strcopy( p, /*{*/ "\" }" );
3701 Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3702 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3704 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3705 if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3710 /* X.509 PKI certificateList stuff */
3712 checkTime( struct berval *in, struct berval *out )
3716 char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3719 assert( in != NULL );
3720 assert( !BER_BVISNULL( in ) );
3721 assert( !BER_BVISEMPTY( in ) );
3723 if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3727 if ( out != NULL ) {
3728 assert( !BER_BVISNULL( out ) );
3729 assert( out->bv_len >= sizeof( buf ) );
3730 bv.bv_val = out->bv_val;
3736 for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3737 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3740 if ( in->bv_val[i] != 'Z' ) {
3745 if ( i != in->bv_len ) {
3749 if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3750 lutil_strncopy( bv.bv_val, in->bv_val, i );
3753 } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3754 char *p = bv.bv_val;
3755 if ( in->bv_val[0] < '7' ) {
3756 p = lutil_strcopy( p, "20" );
3759 p = lutil_strcopy( p, "19" );
3761 lutil_strncopy( p, in->bv_val, i );
3768 rc = generalizedTimeValidate( NULL, &bv );
3769 if ( rc == LDAP_SUCCESS && out != NULL ) {
3770 if ( out->bv_len > bv.bv_len ) {
3771 out->bv_val[ bv.bv_len ] = '\0';
3773 out->bv_len = bv.bv_len;
3776 return rc != LDAP_SUCCESS;
3780 issuerAndThisUpdateCheck(
3787 struct berval x = *in;
3788 struct berval ni = BER_BVNULL;
3789 /* Parse GSER format */
3793 HAVE_THISUPDATE = 0x2,
3794 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3798 if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3800 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3801 return LDAP_INVALID_SYNTAX;
3805 x.bv_len -= STRLENOF("{}");
3808 /* eat leading spaces */
3809 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3813 /* should be at issuer or thisUpdate */
3814 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3815 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3818 x.bv_val += STRLENOF("issuer");
3819 x.bv_len -= STRLENOF("issuer");
3821 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3825 /* eat leading spaces */
3826 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3830 /* For backward compatibility, this part is optional */
3831 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3832 return LDAP_INVALID_SYNTAX;
3834 x.bv_val += STRLENOF("rdnSequence:");
3835 x.bv_len -= STRLENOF("rdnSequence:");
3837 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3841 is->bv_val = x.bv_val;
3844 for ( ; is->bv_len < x.bv_len; ) {
3845 if ( is->bv_val[is->bv_len] != '"' ) {
3849 if ( is->bv_val[is->bv_len+1] == '"' ) {
3857 x.bv_val += is->bv_len + 1;
3858 x.bv_len -= is->bv_len + 1;
3860 have |= HAVE_ISSUER;
3862 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3864 if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3866 /* parse thisUpdate */
3867 x.bv_val += STRLENOF("thisUpdate");
3868 x.bv_len -= STRLENOF("thisUpdate");
3870 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3874 /* eat leading spaces */
3875 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3879 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3883 tu->bv_val = x.bv_val;
3886 for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3887 if ( tu->bv_val[tu->bv_len] == '"' ) {
3891 x.bv_val += tu->bv_len + 1;
3892 x.bv_len -= tu->bv_len + 1;
3894 have |= HAVE_THISUPDATE;
3897 return LDAP_INVALID_SYNTAX;
3900 /* eat leading spaces */
3901 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3905 if ( have == HAVE_ALL ) {
3909 if ( x.bv_val[0] != ',' ) {
3910 return LDAP_INVALID_SYNTAX;
3917 /* should have no characters left... */
3918 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3920 if ( numdquotes == 0 ) {
3921 ber_dupbv_x( &ni, is, ctx );
3926 ni.bv_len = is->bv_len - numdquotes;
3927 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3928 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3929 if ( is->bv_val[src] == '"' ) {
3932 ni.bv_val[dst] = is->bv_val[src];
3934 ni.bv_val[dst] = '\0';
3943 issuerAndThisUpdateValidate(
3948 struct berval i, tu;
3950 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
3953 rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
3958 /* validate DN -- doesn't handle double dquote */
3959 rc = dnValidate( NULL, &i );
3961 rc = LDAP_INVALID_SYNTAX;
3963 } else if ( checkTime( &tu, NULL ) ) {
3964 rc = LDAP_INVALID_SYNTAX;
3967 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3968 slap_sl_free( i.bv_val, NULL );
3971 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
3972 in->bv_val, rc, 0 );
3979 issuerAndThisUpdatePretty(
3986 struct berval i, tu, ni = BER_BVNULL;
3989 assert( in != NULL );
3990 assert( out != NULL );
3994 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
3997 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4002 rc = dnPretty( syntax, &i, &ni, ctx );
4004 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4005 slap_sl_free( i.bv_val, ctx );
4008 if ( rc || checkTime( &tu, NULL ) ) {
4009 rc = LDAP_INVALID_SYNTAX;
4014 out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
4015 + ni.bv_len + tu.bv_len;
4016 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4018 if ( out->bv_val == NULL ) {
4025 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4026 p = lutil_strbvcopy( p, &ni );
4027 p = lutil_strcopy( p, "\", thisUpdate \"" );
4028 p = lutil_strbvcopy( p, &tu );
4029 p = lutil_strcopy( p, /*{*/ "\" }" );
4031 assert( p == &out->bv_val[out->bv_len] );
4034 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4035 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4037 slap_sl_free( ni.bv_val, ctx );
4043 issuerAndThisUpdateNormalize(
4051 struct berval i, ni, tu, tu2;
4052 char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4056 assert( in != NULL );
4057 assert( out != NULL );
4059 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4062 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4067 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4069 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4070 slap_sl_free( i.bv_val, ctx );
4074 tu2.bv_len = sizeof( sbuf );
4075 if ( rc || checkTime( &tu, &tu2 ) ) {
4076 return LDAP_INVALID_SYNTAX;
4079 out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4080 + ni.bv_len + tu2.bv_len;
4081 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4083 if ( out->bv_val == NULL ) {
4091 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4092 p = lutil_strbvcopy( p, &ni );
4093 p = lutil_strcopy( p, "\", thisUpdate \"" );
4094 p = lutil_strbvcopy( p, &tu2 );
4095 p = lutil_strcopy( p, /*{*/ "\" }" );
4097 assert( p == &out->bv_val[out->bv_len] );
4100 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4101 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4103 slap_sl_free( ni.bv_val, ctx );
4109 certificateListExactNormalize(
4114 struct berval *normalized,
4117 BerElementBuffer berbuf;
4118 BerElement *ber = (BerElement *)&berbuf;
4122 struct berval issuer_dn = BER_BVNULL, bvdn,
4124 char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4125 int rc = LDAP_INVALID_SYNTAX;
4127 assert( val != NULL );
4129 Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4130 val->bv_val, val->bv_len, 0 );
4132 if ( BER_BVISEMPTY( val ) ) goto done;
4134 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4135 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4138 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4140 ber_init2( ber, val, LBER_USE_DER );
4141 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
4142 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4143 tag = ber_skip_tag( ber, &len ); /* Sequence */
4144 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4145 tag = ber_peek_tag( ber, &len );
4146 /* Optional version */
4147 if ( tag == LBER_INTEGER ) {
4148 tag = ber_get_int( ber, &version );
4149 assert( tag == LBER_INTEGER );
4150 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4152 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
4153 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4154 ber_skip_data( ber, len );
4156 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
4157 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4158 len = ber_ptrlen( ber );
4159 bvdn.bv_val = val->bv_val + len;
4160 bvdn.bv_len = val->bv_len - len;
4161 tag = ber_skip_tag( ber, &len );
4162 ber_skip_data( ber, len );
4164 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
4165 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4166 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4167 bvtu.bv_val = (char *)ber->ber_ptr;
4170 rc = dnX509normalize( &bvdn, &issuer_dn );
4171 if ( rc != LDAP_SUCCESS ) goto done;
4173 thisUpdate.bv_val = tubuf;
4174 thisUpdate.bv_len = sizeof(tubuf);
4175 if ( checkTime( &bvtu, &thisUpdate ) ) {
4176 rc = LDAP_INVALID_SYNTAX;
4180 normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4181 + issuer_dn.bv_len + thisUpdate.bv_len;
4182 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4184 p = normalized->bv_val;
4186 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4187 p = lutil_strbvcopy( p, &issuer_dn );
4188 p = lutil_strcopy( p, "\", thisUpdate \"" );
4189 p = lutil_strbvcopy( p, &thisUpdate );
4190 p = lutil_strcopy( p, /*{*/ "\" }" );
4195 Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4196 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4198 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4203 /* X.509 PMI serialNumberAndIssuerSerialCheck
4205 AttributeCertificateExactAssertion ::= SEQUENCE {
4206 serialNumber CertificateSerialNumber,
4207 issuer AttCertIssuer }
4209 CertificateSerialNumber ::= INTEGER
4211 AttCertIssuer ::= [0] SEQUENCE {
4212 issuerName GeneralNames OPTIONAL,
4213 baseCertificateID [0] IssuerSerial OPTIONAL,
4214 objectDigestInfo [1] ObjectDigestInfo OPTIONAL }
4215 -- At least one component shall be present
4217 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4219 GeneralName ::= CHOICE {
4220 otherName [0] INSTANCE OF OTHER-NAME,
4221 rfc822Name [1] IA5String,
4222 dNSName [2] IA5String,
4223 x400Address [3] ORAddress,
4224 directoryName [4] Name,
4225 ediPartyName [5] EDIPartyName,
4226 uniformResourceIdentifier [6] IA5String,
4227 iPAddress [7] OCTET STRING,
4228 registeredID [8] OBJECT IDENTIFIER }
4230 IssuerSerial ::= SEQUENCE {
4231 issuer GeneralNames,
4232 serial CertificateSerialNumber,
4233 issuerUID UniqueIdentifier OPTIONAL }
4235 ObjectDigestInfo ::= SEQUENCE {
4236 digestedObjectType ENUMERATED {
4239 otherObjectTypes (2) },
4240 otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
4241 digestAlgorithm AlgorithmIdentifier,
4242 objectDigest BIT STRING }
4244 * The way I interpret it, an assertion should look like
4246 { serialNumber 'dd'H,
4247 issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4248 baseCertificateID { serial '1d'H,
4249 issuer { directoryName:rdnSequence:"cn=zzz" },
4250 issuerUID <value> -- optional
4252 objectDigestInfo { ... } -- optional
4256 * with issuerName, baseCertificateID and objectDigestInfo optional,
4257 * at least one present; the way it's currently implemented, it is
4259 { serialNumber 'dd'H,
4260 issuer { baseCertificateID { serial '1d'H,
4261 issuer { directoryName:rdnSequence:"cn=zzz" }
4266 * with all the above parts mandatory.
4269 serialNumberAndIssuerSerialCheck(
4273 struct berval *i_sn, /* contain serial of baseCertificateID */
4276 /* Parse GSER format */
4281 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4282 } have = HAVE_NONE, have2 = HAVE_NONE;
4284 struct berval x = *in;
4287 if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4290 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4297 /* eat leading spaces */
4298 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4302 /* should be at issuer or serialNumber NamedValue */
4303 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4304 if ( have & HAVE_ISSUER ) {
4305 return LDAP_INVALID_SYNTAX;
4308 /* parse IssuerSerial */
4309 x.bv_val += STRLENOF("issuer");
4310 x.bv_len -= STRLENOF("issuer");
4312 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4316 /* eat leading spaces */
4317 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4321 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4325 /* eat leading spaces */
4326 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4330 if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4331 return LDAP_INVALID_SYNTAX;
4333 x.bv_val += STRLENOF("baseCertificateID ");
4334 x.bv_len -= STRLENOF("baseCertificateID ");
4336 /* eat leading spaces */
4337 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4341 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4346 /* eat leading spaces */
4347 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4351 /* parse issuer of baseCertificateID */
4352 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4353 if ( have2 & HAVE_ISSUER ) {
4354 return LDAP_INVALID_SYNTAX;
4357 x.bv_val += STRLENOF("issuer ");
4358 x.bv_len -= STRLENOF("issuer ");
4360 /* eat leading spaces */
4361 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4365 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4369 /* eat leading spaces */
4370 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4374 if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4375 return LDAP_INVALID_SYNTAX;
4377 x.bv_val += STRLENOF("directoryName:rdnSequence:");
4378 x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4380 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4384 is->bv_val = x.bv_val;
4387 for ( ; is->bv_len < x.bv_len; ) {
4388 if ( is->bv_val[is->bv_len] != '"' ) {
4392 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4400 x.bv_val += is->bv_len + 1;
4401 x.bv_len -= is->bv_len + 1;
4403 /* eat leading spaces */
4404 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4408 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4412 have2 |= HAVE_ISSUER;
4414 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4415 if ( have2 & HAVE_SN ) {
4416 return LDAP_INVALID_SYNTAX;
4419 x.bv_val += STRLENOF("serial ");
4420 x.bv_len -= STRLENOF("serial ");
4422 /* eat leading spaces */
4423 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4427 if ( checkNum( &x, i_sn ) ) {
4428 return LDAP_INVALID_SYNTAX;
4431 x.bv_val += i_sn->bv_len;
4432 x.bv_len -= i_sn->bv_len;
4437 return LDAP_INVALID_SYNTAX;
4440 /* eat leading spaces */
4441 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4445 if ( have2 == HAVE_ALL ) {
4449 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4454 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4458 /* eat leading spaces */
4459 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4463 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4467 have |= HAVE_ISSUER;
4469 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4470 if ( have & HAVE_SN ) {
4471 return LDAP_INVALID_SYNTAX;
4474 /* parse serialNumber */
4475 x.bv_val += STRLENOF("serialNumber");
4476 x.bv_len -= STRLENOF("serialNumber");
4478 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4482 /* eat leading spaces */
4483 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4487 if ( checkNum( &x, sn ) ) {
4488 return LDAP_INVALID_SYNTAX;
4491 x.bv_val += sn->bv_len;
4492 x.bv_len -= sn->bv_len;
4497 return LDAP_INVALID_SYNTAX;
4501 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4505 if ( have == HAVE_ALL ) {
4509 if ( x.bv_val[0] != ',' ) {
4510 return LDAP_INVALID_SYNTAX;
4516 /* should have no characters left... */
4517 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4519 if ( numdquotes == 0 ) {
4520 ber_dupbv_x( &ni, is, ctx );
4525 ni.bv_len = is->bv_len - numdquotes;
4526 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4527 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4528 if ( is->bv_val[src] == '"' ) {
4531 ni.bv_val[dst] = is->bv_val[src];
4533 ni.bv_val[dst] = '\0';
4538 /* need to handle double dquotes here */
4542 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4544 serialNumberAndIssuerSerialValidate(
4549 struct berval sn, i, i_sn;
4551 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4554 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4559 /* validate DN -- doesn't handle double dquote */
4560 rc = dnValidate( NULL, &i );
4562 rc = LDAP_INVALID_SYNTAX;
4565 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4566 slap_sl_free( i.bv_val, NULL );
4570 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4571 in->bv_val, rc, 0 );
4576 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4578 serialNumberAndIssuerSerialPretty(
4584 struct berval sn, i, i_sn, ni = BER_BVNULL;
4588 assert( in != NULL );
4589 assert( out != NULL );
4591 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4594 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4599 rc = dnPretty( syntax, &i, &ni, ctx );
4601 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4602 slap_sl_free( i.bv_val, ctx );
4606 rc = LDAP_INVALID_SYNTAX;
4610 /* make room from sn + "$" */
4611 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4612 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4613 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4615 if ( out->bv_val == NULL ) {
4622 p = lutil_strcopy( p, "{ serialNumber " );
4623 p = lutil_strbvcopy( p, &sn );
4624 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4625 p = lutil_strbvcopy( p, &ni );
4626 p = lutil_strcopy( p, "\" }, serial " );
4627 p = lutil_strbvcopy( p, &i_sn );
4628 p = lutil_strcopy( p, " } } }" );
4630 assert( p == &out->bv_val[out->bv_len] );
4633 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4634 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4636 slap_sl_free( ni.bv_val, ctx );
4641 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4643 * This routine is called by attributeCertificateExactNormalize
4644 * when attributeCertificateExactNormalize receives a search
4645 * string instead of a attribute certificate. This routine
4646 * checks if the search value is valid and then returns the
4650 serialNumberAndIssuerSerialNormalize(
4658 struct berval i, ni = BER_BVNULL,
4659 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4660 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4661 char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4662 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4666 assert( in != NULL );
4667 assert( out != NULL );
4669 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4672 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4677 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4679 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4680 slap_sl_free( i.bv_val, ctx );
4684 rc = LDAP_INVALID_SYNTAX;
4688 /* Convert sn to canonical hex */
4690 sn2.bv_len = sn.bv_len;
4691 if ( sn.bv_len > sizeof( sbuf2 ) ) {
4692 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4694 if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4695 rc = LDAP_INVALID_SYNTAX;
4699 /* Convert i_sn to canonical hex */
4700 i_sn2.bv_val = i_sbuf2;
4701 i_sn2.bv_len = i_sn.bv_len;
4702 if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4703 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4705 if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4706 rc = LDAP_INVALID_SYNTAX;
4711 sn3.bv_len = sizeof(sbuf3);
4712 if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4713 rc = LDAP_INVALID_SYNTAX;
4717 i_sn3.bv_val = i_sbuf3;
4718 i_sn3.bv_len = sizeof(i_sbuf3);
4719 if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4720 rc = LDAP_INVALID_SYNTAX;
4724 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4725 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4726 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4728 if ( out->bv_val == NULL ) {
4736 p = lutil_strcopy( p, "{ serialNumber " );
4737 p = lutil_strbvcopy( p, &sn3 );
4738 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4739 p = lutil_strbvcopy( p, &ni );
4740 p = lutil_strcopy( p, "\" }, serial " );
4741 p = lutil_strbvcopy( p, &i_sn3 );
4742 p = lutil_strcopy( p, " } } }" );
4744 assert( p == &out->bv_val[out->bv_len] );
4747 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4748 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4750 if ( sn2.bv_val != sbuf2 ) {
4751 slap_sl_free( sn2.bv_val, ctx );
4754 if ( i_sn2.bv_val != i_sbuf2 ) {
4755 slap_sl_free( i_sn2.bv_val, ctx );
4758 if ( sn3.bv_val != sbuf3 ) {
4759 slap_sl_free( sn3.bv_val, ctx );
4762 if ( i_sn3.bv_val != i_sbuf3 ) {
4763 slap_sl_free( i_sn3.bv_val, ctx );
4766 slap_sl_free( ni.bv_val, ctx );
4771 /* X.509 PMI attributeCertificateExactNormalize */
4773 attributeCertificateExactNormalize(
4778 struct berval *normalized,
4781 BerElementBuffer berbuf;
4782 BerElement *ber = (BerElement *)&berbuf;
4785 char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4786 struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4787 struct berval issuer_dn = BER_BVNULL, bvdn;
4789 int rc = LDAP_INVALID_SYNTAX;
4791 if ( BER_BVISEMPTY( val ) ) {
4795 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4796 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4799 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4801 ber_init2( ber, val, LBER_USE_DER );
4802 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
4803 tag = ber_skip_tag( ber, &len ); /* Sequence */
4804 tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */
4805 ber_skip_data( ber, len );
4806 tag = ber_skip_tag( ber, &len ); /* Holder Sequence */
4807 ber_skip_data( ber, len );
4810 tag = ber_skip_tag( ber, &len ); /* Sequence */
4811 /* issuerName (GeneralNames sequence; optional)? */
4812 tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */
4813 tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */
4814 tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */
4815 if ( tag != SLAP_X509_GN_DIRECTORYNAME ) {
4816 return LDAP_INVALID_SYNTAX;
4818 tag = ber_peek_tag( ber, &len ); /* sequence of RDN */
4819 len = ber_ptrlen( ber );
4820 bvdn.bv_val = val->bv_val + len;
4821 bvdn.bv_len = val->bv_len - len;
4822 rc = dnX509normalize( &bvdn, &issuer_dn );
4823 if ( rc != LDAP_SUCCESS ) goto done;
4825 tag = ber_skip_tag( ber, &len ); /* sequence of RDN */
4826 ber_skip_data( ber, len );
4827 tag = ber_skip_tag( ber, &len ); /* serial number */
4828 if ( tag != LBER_INTEGER ) {
4829 rc = LDAP_INVALID_SYNTAX;
4832 i_sn.bv_val = (char *)ber->ber_ptr;
4834 i_sn2.bv_val = issuer_serialbuf;
4835 i_sn2.bv_len = sizeof(issuer_serialbuf);
4836 if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4837 rc = LDAP_INVALID_SYNTAX;
4840 ber_skip_data( ber, len );
4842 /* issuerUID (bitstring; optional)? */
4843 /* objectDigestInfo (sequence; optional)? */
4845 tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */
4846 ber_skip_data( ber, len );
4847 tag = ber_skip_tag( ber, &len ); /* serial number */
4848 if ( tag != LBER_INTEGER ) {
4849 rc = LDAP_INVALID_SYNTAX;
4852 sn.bv_val = (char *)ber->ber_ptr;
4854 sn2.bv_val = serialbuf;
4855 sn2.bv_len = sizeof(serialbuf);
4856 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4857 rc = LDAP_INVALID_SYNTAX;
4860 ber_skip_data( ber, len );
4862 normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" )
4863 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4864 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4866 p = normalized->bv_val;
4868 p = lutil_strcopy( p, "{ serialNumber " );
4869 p = lutil_strbvcopy( p, &sn2 );
4870 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4871 p = lutil_strbvcopy( p, &issuer_dn );
4872 p = lutil_strcopy( p, "\" }, serial " );
4873 p = lutil_strbvcopy( p, &i_sn2 );
4874 p = lutil_strcopy( p, " } } }" );
4876 Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4877 normalized->bv_val, NULL, NULL );
4882 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4883 if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4884 if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4897 assert( in != NULL );
4898 assert( !BER_BVISNULL( in ) );
4900 for ( i = 0; i < in->bv_len; i++ ) {
4901 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4902 return LDAP_INVALID_SYNTAX;
4906 return LDAP_SUCCESS;
4909 /* Normalize a SID as used inside a CSN:
4910 * three-digit numeric string */
4917 struct berval *normalized,
4922 assert( val != NULL );
4923 assert( normalized != NULL );
4925 ber_dupbv_x( normalized, val, ctx );
4927 for ( i = 0; i < normalized->bv_len; i++ ) {
4928 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4929 ber_memfree_x( normalized->bv_val, ctx );
4930 BER_BVZERO( normalized );
4931 return LDAP_INVALID_SYNTAX;
4934 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
4937 return LDAP_SUCCESS;
4945 assert( in != NULL );
4946 assert( !BER_BVISNULL( in ) );
4948 if ( in->bv_len != 3 ) {
4949 return LDAP_INVALID_SYNTAX;
4952 return hexValidate( NULL, in );
4955 /* Normalize a SID as used inside a CSN:
4956 * three-digit numeric string */
4963 struct berval *normalized,
4966 if ( val->bv_len != 3 ) {
4967 return LDAP_INVALID_SYNTAX;
4970 return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
4980 return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
4983 /* Normalize a SID as used inside a CSN, either as-is
4984 * (assertion value) or extracted from the CSN
4985 * (attribute value) */
4992 struct berval *normalized,
5000 if ( BER_BVISEMPTY( val ) ) {
5001 return LDAP_INVALID_SYNTAX;
5004 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
5005 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
5008 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
5010 ptr = ber_bvchr( val, '#' );
5011 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5012 return LDAP_INVALID_SYNTAX;
5015 bv.bv_val = ptr + 1;
5016 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5018 ptr = ber_bvchr( &bv, '#' );
5019 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5020 return LDAP_INVALID_SYNTAX;
5023 bv.bv_val = ptr + 1;
5024 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5026 ptr = ber_bvchr( &bv, '#' );
5027 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5028 return LDAP_INVALID_SYNTAX;
5031 bv.bv_len = ptr - bv.bv_val;
5033 if ( bv.bv_len == 2 ) {
5034 /* OpenLDAP 2.3 SID */
5036 buf[ 1 ] = bv.bv_val[ 0 ];
5037 buf[ 2 ] = bv.bv_val[ 1 ];
5044 return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5056 assert( in != NULL );
5057 assert( !BER_BVISNULL( in ) );
5059 if ( BER_BVISEMPTY( in ) ) {
5060 return LDAP_INVALID_SYNTAX;
5065 ptr = ber_bvchr( &bv, '#' );
5066 if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5067 return LDAP_INVALID_SYNTAX;
5070 bv.bv_len = ptr - bv.bv_val;
5071 if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5072 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5074 return LDAP_INVALID_SYNTAX;
5077 rc = generalizedTimeValidate( NULL, &bv );
5078 if ( rc != LDAP_SUCCESS ) {
5082 bv.bv_val = ptr + 1;
5083 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5085 ptr = ber_bvchr( &bv, '#' );
5086 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5087 return LDAP_INVALID_SYNTAX;
5090 bv.bv_len = ptr - bv.bv_val;
5091 if ( bv.bv_len != 6 ) {
5092 return LDAP_INVALID_SYNTAX;
5095 rc = hexValidate( NULL, &bv );
5096 if ( rc != LDAP_SUCCESS ) {
5100 bv.bv_val = ptr + 1;
5101 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5103 ptr = ber_bvchr( &bv, '#' );
5104 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5105 return LDAP_INVALID_SYNTAX;
5108 bv.bv_len = ptr - bv.bv_val;
5109 if ( bv.bv_len == 2 ) {
5110 /* tolerate old 2-digit replica-id */
5111 rc = hexValidate( NULL, &bv );
5114 rc = sidValidate( NULL, &bv );
5116 if ( rc != LDAP_SUCCESS ) {
5120 bv.bv_val = ptr + 1;
5121 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5123 if ( bv.bv_len != 6 ) {
5124 return LDAP_INVALID_SYNTAX;
5127 return hexValidate( NULL, &bv );
5130 /* Normalize a CSN in OpenLDAP 2.1 format */
5137 struct berval *normalized,
5140 struct berval gt, cnt, sid, mod;
5142 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5146 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5147 assert( !BER_BVISEMPTY( val ) );
5151 ptr = ber_bvchr( >, '#' );
5152 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5153 return LDAP_INVALID_SYNTAX;
5156 gt.bv_len = ptr - gt.bv_val;
5157 if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5158 return LDAP_INVALID_SYNTAX;
5161 if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5162 return LDAP_INVALID_SYNTAX;
5165 cnt.bv_val = ptr + 1;
5166 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5168 ptr = ber_bvchr( &cnt, '#' );
5169 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5170 return LDAP_INVALID_SYNTAX;
5173 cnt.bv_len = ptr - cnt.bv_val;
5174 if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5175 return LDAP_INVALID_SYNTAX;
5178 if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5179 return LDAP_INVALID_SYNTAX;
5182 cnt.bv_val += STRLENOF( "0x" );
5183 cnt.bv_len -= STRLENOF( "0x" );
5185 sid.bv_val = ptr + 1;
5186 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5188 ptr = ber_bvchr( &sid, '#' );
5189 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5190 return LDAP_INVALID_SYNTAX;
5193 sid.bv_len = ptr - sid.bv_val;
5194 if ( sid.bv_len != STRLENOF( "0" ) ) {
5195 return LDAP_INVALID_SYNTAX;
5198 mod.bv_val = ptr + 1;
5199 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5200 if ( mod.bv_len != STRLENOF( "0000" ) ) {
5201 return LDAP_INVALID_SYNTAX;
5204 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5208 ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5209 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5211 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5213 ptr = lutil_strcopy( ptr, ".000000Z#00" );
5214 ptr = lutil_strbvcopy( ptr, &cnt );
5218 *ptr++ = sid.bv_val[ 0 ];
5222 for ( i = 0; i < mod.bv_len; i++ ) {
5223 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5227 assert( ptr == &bv.bv_val[bv.bv_len] );
5229 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5230 return LDAP_INVALID_SYNTAX;
5233 ber_dupbv_x( normalized, &bv, ctx );
5235 return LDAP_SUCCESS;
5238 /* Normalize a CSN in OpenLDAP 2.3 format */
5245 struct berval *normalized,
5248 struct berval gt, cnt, sid, mod;
5250 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5254 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5255 assert( !BER_BVISEMPTY( val ) );
5259 ptr = ber_bvchr( >, '#' );
5260 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5261 return LDAP_INVALID_SYNTAX;
5264 gt.bv_len = ptr - gt.bv_val;
5265 if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5266 return LDAP_INVALID_SYNTAX;
5269 cnt.bv_val = ptr + 1;
5270 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5272 ptr = ber_bvchr( &cnt, '#' );
5273 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5274 return LDAP_INVALID_SYNTAX;
5277 cnt.bv_len = ptr - cnt.bv_val;
5278 if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5279 return LDAP_INVALID_SYNTAX;
5282 sid.bv_val = ptr + 1;
5283 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5285 ptr = ber_bvchr( &sid, '#' );
5286 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5287 return LDAP_INVALID_SYNTAX;
5290 sid.bv_len = ptr - sid.bv_val;
5291 if ( sid.bv_len != STRLENOF( "00" ) ) {
5292 return LDAP_INVALID_SYNTAX;
5295 mod.bv_val = ptr + 1;
5296 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5297 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5298 return LDAP_INVALID_SYNTAX;
5301 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5305 ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5306 ptr = lutil_strcopy( ptr, ".000000Z#" );
5307 ptr = lutil_strbvcopy( ptr, &cnt );
5310 for ( i = 0; i < sid.bv_len; i++ ) {
5311 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5314 for ( i = 0; i < mod.bv_len; i++ ) {
5315 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5319 assert( ptr == &bv.bv_val[bv.bv_len] );
5320 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5321 return LDAP_INVALID_SYNTAX;
5324 ber_dupbv_x( normalized, &bv, ctx );
5326 return LDAP_SUCCESS;
5329 /* Normalize a CSN */
5336 struct berval *normalized,
5339 struct berval cnt, sid, mod;
5343 assert( val != NULL );
5344 assert( normalized != NULL );
5346 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5348 if ( BER_BVISEMPTY( val ) ) {
5349 return LDAP_INVALID_SYNTAX;
5352 if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5353 /* Openldap <= 2.3 */
5355 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5358 if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5361 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5364 if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5365 return LDAP_INVALID_SYNTAX;
5368 ptr = ber_bvchr( val, '#' );
5369 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5370 return LDAP_INVALID_SYNTAX;
5373 if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5374 return LDAP_INVALID_SYNTAX;
5377 cnt.bv_val = ptr + 1;
5378 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5380 ptr = ber_bvchr( &cnt, '#' );
5381 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5382 return LDAP_INVALID_SYNTAX;
5385 if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5386 return LDAP_INVALID_SYNTAX;
5389 sid.bv_val = ptr + 1;
5390 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5392 ptr = ber_bvchr( &sid, '#' );
5393 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5394 return LDAP_INVALID_SYNTAX;
5397 sid.bv_len = ptr - sid.bv_val;
5398 if ( sid.bv_len != STRLENOF( "000" ) ) {
5399 return LDAP_INVALID_SYNTAX;
5402 mod.bv_val = ptr + 1;
5403 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5405 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5406 return LDAP_INVALID_SYNTAX;
5409 ber_dupbv_x( normalized, val, ctx );
5411 for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5412 i < normalized->bv_len; i++ )
5414 /* assume it's already validated that's all hex digits */
5415 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5418 return LDAP_SUCCESS;
5428 return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5431 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5432 /* slight optimization - does not need the start parameter */
5433 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5438 check_time_syntax (struct berval *val,
5441 struct berval *fraction)
5444 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5445 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
5446 * GeneralizedTime supports leap seconds, UTCTime does not.
5448 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5449 static const int mdays[2][12] = {
5450 /* non-leap years */
5451 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5453 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5456 int part, c, c1, c2, tzoffset, leapyear = 0;
5459 e = p + val->bv_len;
5461 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5462 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5464 for (part = start; part < 7 && p < e; part++) {
5466 if (!ASCII_DIGIT(c1)) {
5471 return LDAP_INVALID_SYNTAX;
5474 if (!ASCII_DIGIT(c)) {
5475 return LDAP_INVALID_SYNTAX;
5477 c += c1 * 10 - '0' * 11;
5478 if ((part | 1) == 3) {
5481 return LDAP_INVALID_SYNTAX;
5484 if (c >= ceiling[part]) {
5485 if (! (c == 60 && part == 6 && start == 0))
5486 return LDAP_INVALID_SYNTAX;
5490 if (part < 5 + start) {
5491 return LDAP_INVALID_SYNTAX;
5493 for (; part < 9; part++) {
5497 /* leapyear check for the Gregorian calendar (year>1581) */
5498 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5502 if (parts[3] >= mdays[leapyear][parts[2]]) {
5503 return LDAP_INVALID_SYNTAX;
5507 fraction->bv_val = p;
5508 fraction->bv_len = 0;
5509 if (p < e && (*p == '.' || *p == ',')) {
5511 while (++p < e && ASCII_DIGIT(*p)) {
5514 if (p - fraction->bv_val == 1) {
5515 return LDAP_INVALID_SYNTAX;
5517 for (end_num = p; end_num[-1] == '0'; --end_num) {
5520 c = end_num - fraction->bv_val;
5521 if (c != 1) fraction->bv_len = c;
5527 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5533 return LDAP_INVALID_SYNTAX;
5539 for (part = 7; part < 9 && p < e; part++) {
5541 if (!ASCII_DIGIT(c1)) {
5546 return LDAP_INVALID_SYNTAX;
5549 if (!ASCII_DIGIT(c2)) {
5550 return LDAP_INVALID_SYNTAX;
5552 parts[part] = c1 * 10 + c2 - '0' * 11;
5553 if (parts[part] >= ceiling[part]) {
5554 return LDAP_INVALID_SYNTAX;
5557 if (part < 8 + start) {
5558 return LDAP_INVALID_SYNTAX;
5561 if (tzoffset == '-') {
5562 /* negative offset to UTC, ie west of Greenwich */
5563 parts[4] += parts[7];
5564 parts[5] += parts[8];
5565 /* offset is just hhmm, no seconds */
5566 for (part = 6; --part >= 0; ) {
5570 c = mdays[leapyear][parts[2]];
5572 if (parts[part] >= c) {
5574 return LDAP_INVALID_SYNTAX;
5579 } else if (part != 5) {
5584 /* positive offset to UTC, ie east of Greenwich */
5585 parts[4] -= parts[7];
5586 parts[5] -= parts[8];
5587 for (part = 6; --part >= 0; ) {
5588 if (parts[part] < 0) {
5590 return LDAP_INVALID_SYNTAX;
5595 /* make first arg to % non-negative */
5596 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5601 } else if (part != 5) {
5608 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5611 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5618 struct berval *normalized )
5622 rc = check_time_syntax(val, 1, parts, NULL);
5623 if (rc != LDAP_SUCCESS) {
5627 normalized->bv_val = ch_malloc( 14 );
5628 if ( normalized->bv_val == NULL ) {
5629 return LBER_ERROR_MEMORY;
5632 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5633 parts[1], parts[2] + 1, parts[3] + 1,
5634 parts[4], parts[5], parts[6] );
5635 normalized->bv_len = 13;
5637 return LDAP_SUCCESS;
5647 return check_time_syntax(in, 1, parts, NULL);
5650 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5653 generalizedTimeValidate(
5658 struct berval fraction;
5659 return check_time_syntax(in, 0, parts, &fraction);
5663 generalizedTimeNormalize(
5668 struct berval *normalized,
5673 struct berval fraction;
5675 rc = check_time_syntax(val, 0, parts, &fraction);
5676 if (rc != LDAP_SUCCESS) {
5680 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5681 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5682 if ( BER_BVISNULL( normalized ) ) {
5683 return LBER_ERROR_MEMORY;
5686 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5687 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5688 parts[4], parts[5], parts[6] );
5689 if ( !BER_BVISEMPTY( &fraction ) ) {
5690 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5691 fraction.bv_val, fraction.bv_len );
5692 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5694 strcpy( normalized->bv_val + len-1, "Z" );
5695 normalized->bv_len = len;
5697 return LDAP_SUCCESS;
5701 generalizedTimeOrderingMatch(
5706 struct berval *value,
5707 void *assertedValue )
5709 struct berval *asserted = (struct berval *) assertedValue;
5710 ber_len_t v_len = value->bv_len;
5711 ber_len_t av_len = asserted->bv_len;
5713 /* ignore trailing 'Z' when comparing */
5714 int match = memcmp( value->bv_val, asserted->bv_val,
5715 (v_len < av_len ? v_len : av_len) - 1 );
5716 if ( match == 0 ) match = v_len - av_len;
5718 /* If used in extensible match filter, match if value < asserted */
5719 if ( flags & SLAP_MR_EXT )
5720 match = (match >= 0);
5723 return LDAP_SUCCESS;
5726 /* Index generation function: Ordered index */
5727 int generalizedTimeIndexer(
5732 struct berval *prefix,
5740 BerValue bvtmp; /* 40 bit index */
5742 struct lutil_timet tt;
5744 bvtmp.bv_len = sizeof(tmp);
5746 for( i=0; values[i].bv_val != NULL; i++ ) {
5747 /* just count them */
5750 /* we should have at least one value at this point */
5753 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5755 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5756 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5757 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5758 /* Use 40 bits of time for key */
5759 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5760 lutil_tm2time( &tm, &tt );
5761 tmp[0] = tt.tt_gsec & 0xff;
5762 tmp[4] = tt.tt_sec & 0xff;
5764 tmp[3] = tt.tt_sec & 0xff;
5766 tmp[2] = tt.tt_sec & 0xff;
5768 tmp[1] = tt.tt_sec & 0xff;
5770 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5774 keys[j].bv_val = NULL;
5779 return LDAP_SUCCESS;
5782 /* Index generation function: Ordered index */
5783 int generalizedTimeFilter(
5788 struct berval *prefix,
5789 void * assertedValue,
5795 BerValue bvtmp; /* 40 bit index */
5796 BerValue *value = (BerValue *) assertedValue;
5798 struct lutil_timet tt;
5800 bvtmp.bv_len = sizeof(tmp);
5802 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5803 /* Use 40 bits of time for key */
5804 if ( value->bv_val && value->bv_len >= 10 &&
5805 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5807 lutil_tm2time( &tm, &tt );
5808 tmp[0] = tt.tt_gsec & 0xff;
5809 tmp[4] = tt.tt_sec & 0xff;
5811 tmp[3] = tt.tt_sec & 0xff;
5813 tmp[2] = tt.tt_sec & 0xff;
5815 tmp[1] = tt.tt_sec & 0xff;
5817 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5818 ber_dupbv_x(keys, &bvtmp, ctx );
5819 keys[1].bv_val = NULL;
5827 return LDAP_SUCCESS;
5831 deliveryMethodValidate(
5833 struct berval *val )
5836 #define LENOF(s) (sizeof(s)-1)
5837 struct berval tmp = *val;
5839 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5840 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5841 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5844 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5846 switch( tmp.bv_val[0] ) {
5849 if(( tmp.bv_len >= LENOF("any") ) &&
5850 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5852 tmp.bv_len -= LENOF("any");
5853 tmp.bv_val += LENOF("any");
5856 return LDAP_INVALID_SYNTAX;
5860 if(( tmp.bv_len >= LENOF("mhs") ) &&
5861 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5863 tmp.bv_len -= LENOF("mhs");
5864 tmp.bv_val += LENOF("mhs");
5867 return LDAP_INVALID_SYNTAX;
5871 if(( tmp.bv_len >= LENOF("physical") ) &&
5872 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5874 tmp.bv_len -= LENOF("physical");
5875 tmp.bv_val += LENOF("physical");
5878 return LDAP_INVALID_SYNTAX;
5881 case 'T': /* telex or teletex or telephone */
5882 if(( tmp.bv_len >= LENOF("telex") ) &&
5883 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5885 tmp.bv_len -= LENOF("telex");
5886 tmp.bv_val += LENOF("telex");
5889 if(( tmp.bv_len >= LENOF("teletex") ) &&
5890 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5892 tmp.bv_len -= LENOF("teletex");
5893 tmp.bv_val += LENOF("teletex");
5896 if(( tmp.bv_len >= LENOF("telephone") ) &&
5897 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5899 tmp.bv_len -= LENOF("telephone");
5900 tmp.bv_val += LENOF("telephone");
5903 return LDAP_INVALID_SYNTAX;
5906 case 'G': /* g3fax or g4fax */
5907 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5908 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5909 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5911 tmp.bv_len -= LENOF("g3fax");
5912 tmp.bv_val += LENOF("g3fax");
5915 return LDAP_INVALID_SYNTAX;
5919 if(( tmp.bv_len >= LENOF("ia5") ) &&
5920 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5922 tmp.bv_len -= LENOF("ia5");
5923 tmp.bv_val += LENOF("ia5");
5926 return LDAP_INVALID_SYNTAX;
5930 if(( tmp.bv_len >= LENOF("videotex") ) &&
5931 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5933 tmp.bv_len -= LENOF("videotex");
5934 tmp.bv_val += LENOF("videotex");
5937 return LDAP_INVALID_SYNTAX;
5940 return LDAP_INVALID_SYNTAX;
5943 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
5945 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5949 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
5953 return LDAP_INVALID_SYNTAX;
5955 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
5964 nisNetgroupTripleValidate(
5966 struct berval *val )
5971 if ( BER_BVISEMPTY( val ) ) {
5972 return LDAP_INVALID_SYNTAX;
5975 p = (char *)val->bv_val;
5976 e = p + val->bv_len;
5978 if ( *p != '(' /*')'*/ ) {
5979 return LDAP_INVALID_SYNTAX;
5982 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
5986 return LDAP_INVALID_SYNTAX;
5989 } else if ( !AD_CHAR( *p ) ) {
5990 return LDAP_INVALID_SYNTAX;
5994 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
5995 return LDAP_INVALID_SYNTAX;
6001 return LDAP_INVALID_SYNTAX;
6004 return LDAP_SUCCESS;
6008 bootParameterValidate(
6010 struct berval *val )
6014 if ( BER_BVISEMPTY( val ) ) {
6015 return LDAP_INVALID_SYNTAX;
6018 p = (char *)val->bv_val;
6019 e = p + val->bv_len;
6022 for (; ( p < e ) && ( *p != '=' ); p++ ) {
6023 if ( !AD_CHAR( *p ) ) {
6024 return LDAP_INVALID_SYNTAX;
6029 return LDAP_INVALID_SYNTAX;
6033 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6034 if ( !AD_CHAR( *p ) ) {
6035 return LDAP_INVALID_SYNTAX;
6040 return LDAP_INVALID_SYNTAX;
6044 for ( p++; p < e; p++ ) {
6045 if ( !SLAP_PRINTABLE( *p ) ) {
6046 return LDAP_INVALID_SYNTAX;
6050 return LDAP_SUCCESS;
6054 firstComponentNormalize(
6059 struct berval *normalized,
6066 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6067 ber_dupbv_x( normalized, val, ctx );
6068 return LDAP_SUCCESS;
6071 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6073 if( ! ( val->bv_val[0] == '(' /*')'*/
6074 && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6075 && ! ( val->bv_val[0] == '{' /*'}'*/
6076 && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6078 return LDAP_INVALID_SYNTAX;
6081 /* trim leading white space */
6083 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6089 /* grab next word */
6090 comp.bv_val = &val->bv_val[len];
6091 len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6092 for( comp.bv_len = 0;
6093 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6099 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6100 rc = numericoidValidate( NULL, &comp );
6101 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6102 rc = integerValidate( NULL, &comp );
6104 rc = LDAP_INVALID_SYNTAX;
6108 if( rc == LDAP_SUCCESS ) {
6109 ber_dupbv_x( normalized, &comp, ctx );
6115 static char *country_gen_syn[] = {
6116 "1.3.6.1.4.1.1466.115.121.1.15", /* Directory String */
6117 "1.3.6.1.4.1.1466.115.121.1.26", /* IA5 String */
6118 "1.3.6.1.4.1.1466.115.121.1.44", /* Printable String */
6122 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6123 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6125 static slap_syntax_defs_rec syntax_defs[] = {
6126 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6127 X_BINARY X_NOT_H_R ")",
6128 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6129 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6130 0, NULL, NULL, NULL},
6131 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6132 0, NULL, NULL, NULL},
6133 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6135 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6136 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6138 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6139 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6140 0, NULL, bitStringValidate, NULL },
6141 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6142 0, NULL, booleanValidate, NULL},
6143 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6144 X_BINARY X_NOT_H_R ")",
6145 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6146 NULL, certificateValidate, NULL},
6147 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6148 X_BINARY X_NOT_H_R ")",
6149 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6150 NULL, certificateListValidate, NULL},
6151 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6152 X_BINARY X_NOT_H_R ")",
6153 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6154 NULL, sequenceValidate, NULL},
6155 {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6156 X_BINARY X_NOT_H_R ")",
6157 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6158 NULL, attributeCertificateValidate, NULL},
6159 #if 0 /* need to go __after__ printableString */
6160 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6161 0, "1.3.6.1.4.1.1466.115.121.1.44",
6162 countryStringValidate, NULL},
6164 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6165 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6166 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6167 0, NULL, rdnValidate, rdnPretty},
6168 #ifdef LDAP_COMP_MATCH
6169 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6170 0, NULL, allComponentsValidate, NULL},
6171 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6172 0, NULL, componentFilterValidate, NULL},
6174 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6175 0, NULL, NULL, NULL},
6176 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6177 0, NULL, deliveryMethodValidate, NULL},
6178 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6179 0, NULL, UTF8StringValidate, NULL},
6180 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6181 0, NULL, NULL, NULL},
6182 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6183 0, NULL, NULL, NULL},
6184 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6185 0, NULL, NULL, NULL},
6186 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6187 0, NULL, NULL, NULL},
6188 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6189 0, NULL, NULL, NULL},
6190 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6191 0, NULL, printablesStringValidate, NULL},
6192 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6193 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6194 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6195 0, NULL, generalizedTimeValidate, NULL},
6196 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6197 0, NULL, NULL, NULL},
6198 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6199 0, NULL, IA5StringValidate, NULL},
6200 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6201 0, NULL, integerValidate, NULL},
6202 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6203 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6204 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6205 0, NULL, NULL, NULL},
6206 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6207 0, NULL, NULL, NULL},
6208 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6209 0, NULL, NULL, NULL},
6210 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6211 0, NULL, NULL, NULL},
6212 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6213 0, NULL, NULL, NULL},
6214 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6215 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6216 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6217 0, NULL, NULL, NULL},
6218 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6219 0, NULL, numericStringValidate, NULL},
6220 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6221 0, NULL, NULL, NULL},
6222 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6223 0, NULL, numericoidValidate, NULL},
6224 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6225 0, NULL, IA5StringValidate, NULL},
6226 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6227 0, NULL, blobValidate, NULL},
6228 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6229 0, NULL, postalAddressValidate, NULL},
6230 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6231 0, NULL, NULL, NULL},
6232 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6233 0, NULL, NULL, NULL},
6234 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6235 0, NULL, printableStringValidate, NULL},
6236 /* moved here because now depends on Directory String, IA5 String
6237 * and Printable String */
6238 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6239 0, country_gen_syn, countryStringValidate, NULL},
6240 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6241 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6242 0, NULL, subtreeSpecificationValidate, NULL},
6243 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6244 X_BINARY X_NOT_H_R ")",
6245 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6246 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6247 0, NULL, printableStringValidate, NULL},
6248 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6249 0, NULL, NULL, NULL},
6250 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6251 0, NULL, printablesStringValidate, NULL},
6252 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6253 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6254 0, NULL, utcTimeValidate, NULL},
6256 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6257 0, NULL, NULL, NULL},
6258 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6259 0, NULL, NULL, NULL},
6260 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6261 0, NULL, NULL, NULL},
6262 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6263 0, NULL, NULL, NULL},
6264 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6265 0, NULL, NULL, NULL},
6267 /* RFC 2307 NIS Syntaxes */
6268 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
6269 0, NULL, nisNetgroupTripleValidate, NULL},
6270 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
6271 0, NULL, bootParameterValidate, NULL},
6273 /* draft-zeilenga-ldap-x509 */
6274 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6275 SLAP_SYNTAX_HIDE, NULL,
6276 serialNumberAndIssuerValidate,
6277 serialNumberAndIssuerPretty},
6278 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6279 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6280 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6281 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6282 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6283 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6284 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6285 SLAP_SYNTAX_HIDE, NULL,
6286 issuerAndThisUpdateValidate,
6287 issuerAndThisUpdatePretty},
6288 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6289 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6290 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6291 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6292 {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6293 SLAP_SYNTAX_HIDE, NULL,
6294 serialNumberAndIssuerSerialValidate,
6295 serialNumberAndIssuerSerialPretty},
6296 {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6297 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6299 #ifdef SLAPD_AUTHPASSWD
6300 /* needs updating */
6301 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6302 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6305 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6306 0, NULL, UUIDValidate, UUIDPretty},
6308 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6309 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6311 {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6312 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6314 /* OpenLDAP Void Syntax */
6315 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6316 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6318 /* FIXME: OID is unused, but not registered yet */
6319 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6320 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6322 {NULL, 0, NULL, NULL, NULL}
6325 char *csnSIDMatchSyntaxes[] = {
6326 "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6329 char *certificateExactMatchSyntaxes[] = {
6330 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6333 char *certificateListExactMatchSyntaxes[] = {
6334 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6337 char *attributeCertificateExactMatchSyntaxes[] = {
6338 attributeCertificateSyntaxOID /* attributeCertificate */,
6342 #ifdef LDAP_COMP_MATCH
6343 char *componentFilterMatchSyntaxes[] = {
6344 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6345 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6346 attributeCertificateSyntaxOID /* attributeCertificate */,
6351 char *directoryStringSyntaxes[] = {
6352 "1.3.6.1.4.1.1466.115.121.1.11" /* countryString */,
6353 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6354 "1.3.6.1.4.1.1466.115.121.1.50" /* telephoneNumber */,
6357 char *integerFirstComponentMatchSyntaxes[] = {
6358 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6359 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6362 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6363 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6364 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
6365 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6366 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6367 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6368 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6369 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6370 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6375 * Other matching rules in X.520 that we do not use (yet):
6377 * 2.5.13.25 uTCTimeMatch
6378 * 2.5.13.26 uTCTimeOrderingMatch
6379 * 2.5.13.31* directoryStringFirstComponentMatch
6380 * 2.5.13.32* wordMatch
6381 * 2.5.13.33* keywordMatch
6382 * 2.5.13.36+ certificatePairExactMatch
6383 * 2.5.13.37+ certificatePairMatch
6384 * 2.5.13.40+ algorithmIdentifierMatch
6385 * 2.5.13.41* storedPrefixMatch
6386 * 2.5.13.42 attributeCertificateMatch
6387 * 2.5.13.43 readerAndKeyIDMatch
6388 * 2.5.13.44 attributeIntegrityMatch
6390 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6391 * (+) described in draft-zeilenga-ldap-x509
6393 static slap_mrule_defs_rec mrule_defs[] = {
6395 * EQUALITY matching rules must be listed after associated APPROX
6396 * matching rules. So, we list all APPROX matching rules first.
6398 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6399 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6400 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6401 NULL, NULL, directoryStringApproxMatch,
6402 directoryStringApproxIndexer, directoryStringApproxFilter,
6405 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6406 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6407 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6408 NULL, NULL, IA5StringApproxMatch,
6409 IA5StringApproxIndexer, IA5StringApproxFilter,
6413 * Other matching rules
6416 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6417 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6418 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6419 NULL, NULL, octetStringMatch,
6420 octetStringIndexer, octetStringFilter,
6423 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6424 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6425 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6426 NULL, dnNormalize, dnMatch,
6427 octetStringIndexer, octetStringFilter,
6430 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6431 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6432 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6433 NULL, dnNormalize, dnRelativeMatch,
6437 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6438 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6439 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6440 NULL, dnNormalize, dnRelativeMatch,
6444 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6445 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6446 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6447 NULL, dnNormalize, dnRelativeMatch,
6451 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6452 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6453 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6454 NULL, dnNormalize, dnRelativeMatch,
6458 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6459 "SYNTAX 1.2.36.79672281.1.5.0 )",
6460 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6461 NULL, rdnNormalize, rdnMatch,
6462 octetStringIndexer, octetStringFilter,
6465 #ifdef LDAP_COMP_MATCH
6466 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6467 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6468 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6469 NULL, NULL , componentFilterMatch,
6470 octetStringIndexer, octetStringFilter,
6473 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6474 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6475 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6476 NULL, NULL , allComponentsMatch,
6477 octetStringIndexer, octetStringFilter,
6480 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6481 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6482 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6483 NULL, NULL , directoryComponentsMatch,
6484 octetStringIndexer, octetStringFilter,
6488 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6489 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6490 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6491 NULL, UTF8StringNormalize, octetStringMatch,
6492 octetStringIndexer, octetStringFilter,
6493 directoryStringApproxMatchOID },
6495 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6496 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6497 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6498 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6500 "caseIgnoreMatch" },
6502 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6503 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6504 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6505 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6506 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6507 "caseIgnoreMatch" },
6509 {"( 2.5.13.5 NAME 'caseExactMatch' "
6510 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6511 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6512 NULL, UTF8StringNormalize, octetStringMatch,
6513 octetStringIndexer, octetStringFilter,
6514 directoryStringApproxMatchOID },
6516 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6517 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6518 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6519 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6523 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6524 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6525 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6526 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6527 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6530 {"( 2.5.13.8 NAME 'numericStringMatch' "
6531 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6532 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6533 NULL, numericStringNormalize, octetStringMatch,
6534 octetStringIndexer, octetStringFilter,
6537 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6538 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6539 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6540 NULL, numericStringNormalize, octetStringOrderingMatch,
6542 "numericStringMatch" },
6544 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6545 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6546 SLAP_MR_SUBSTR, NULL,
6547 NULL, numericStringNormalize, octetStringSubstringsMatch,
6548 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6549 "numericStringMatch" },
6551 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6552 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6553 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6554 NULL, postalAddressNormalize, octetStringMatch,
6555 octetStringIndexer, octetStringFilter,
6558 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6559 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6560 SLAP_MR_SUBSTR, NULL,
6561 NULL, NULL, NULL, NULL, NULL,
6562 "caseIgnoreListMatch" },
6564 {"( 2.5.13.13 NAME 'booleanMatch' "
6565 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6566 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6567 NULL, NULL, booleanMatch,
6568 octetStringIndexer, octetStringFilter,
6571 {"( 2.5.13.14 NAME 'integerMatch' "
6572 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6573 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6574 NULL, NULL, integerMatch,
6575 integerIndexer, integerFilter,
6578 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6579 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6580 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6581 NULL, NULL, integerMatch,
6585 {"( 2.5.13.16 NAME 'bitStringMatch' "
6586 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6587 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6588 NULL, NULL, octetStringMatch,
6589 octetStringIndexer, octetStringFilter,
6592 {"( 2.5.13.17 NAME 'octetStringMatch' "
6593 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6594 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6595 NULL, NULL, octetStringMatch,
6596 octetStringIndexer, octetStringFilter,
6599 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6600 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6601 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6602 NULL, NULL, octetStringOrderingMatch,
6604 "octetStringMatch" },
6606 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6607 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6608 SLAP_MR_SUBSTR, NULL,
6609 NULL, NULL, octetStringSubstringsMatch,
6610 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6611 "octetStringMatch" },
6613 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6614 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6615 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6617 telephoneNumberNormalize, octetStringMatch,
6618 octetStringIndexer, octetStringFilter,
6621 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6622 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6623 SLAP_MR_SUBSTR, NULL,
6624 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6625 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6626 "telephoneNumberMatch" },
6628 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6629 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6630 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6631 NULL, NULL, NULL, NULL, NULL, NULL },
6633 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6634 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6635 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6636 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6637 uniqueMemberIndexer, uniqueMemberFilter,
6640 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6641 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6642 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6643 NULL, NULL, NULL, NULL, NULL, NULL },
6645 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6646 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6647 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6648 NULL, generalizedTimeNormalize, octetStringMatch,
6649 generalizedTimeIndexer, generalizedTimeFilter,
6652 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6653 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6654 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6655 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6657 "generalizedTimeMatch" },
6659 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6660 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6661 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6662 integerFirstComponentMatchSyntaxes,
6663 NULL, firstComponentNormalize, integerMatch,
6664 octetStringIndexer, octetStringFilter,
6667 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6668 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6669 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6670 objectIdentifierFirstComponentMatchSyntaxes,
6671 NULL, firstComponentNormalize, octetStringMatch,
6672 octetStringIndexer, octetStringFilter,
6675 {"( 2.5.13.34 NAME 'certificateExactMatch' "
6676 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6677 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6678 NULL, certificateExactNormalize, octetStringMatch,
6679 octetStringIndexer, octetStringFilter,
6682 {"( 2.5.13.35 NAME 'certificateMatch' "
6683 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6684 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6685 NULL, NULL, NULL, NULL, NULL,
6688 {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6689 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6690 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6691 NULL, certificateListExactNormalize, octetStringMatch,
6692 octetStringIndexer, octetStringFilter,
6695 {"( 2.5.13.39 NAME 'certificateListMatch' "
6696 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6697 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6698 NULL, NULL, NULL, NULL, NULL,
6701 {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6702 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6703 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6704 NULL, attributeCertificateExactNormalize, octetStringMatch,
6705 octetStringIndexer, octetStringFilter,
6708 {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6709 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6710 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6711 NULL, NULL, NULL, NULL, NULL,
6714 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6715 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6716 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6717 NULL, IA5StringNormalize, octetStringMatch,
6718 octetStringIndexer, octetStringFilter,
6719 IA5StringApproxMatchOID },
6721 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6722 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6723 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6724 NULL, IA5StringNormalize, octetStringMatch,
6725 octetStringIndexer, octetStringFilter,
6726 IA5StringApproxMatchOID },
6728 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6729 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6730 SLAP_MR_SUBSTR, NULL,
6731 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6732 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6733 "caseIgnoreIA5Match" },
6735 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6736 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6737 SLAP_MR_SUBSTR, NULL,
6738 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6739 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6740 "caseExactIA5Match" },
6742 #ifdef SLAPD_AUTHPASSWD
6743 /* needs updating */
6744 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6745 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6746 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6747 NULL, NULL, authPasswordMatch,
6752 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6753 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6755 NULL, NULL, integerBitAndMatch,
6759 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6760 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6762 NULL, NULL, integerBitOrMatch,
6766 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6767 "SYNTAX 1.3.6.1.1.16.1 )",
6768 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6769 NULL, UUIDNormalize, octetStringMatch,
6770 octetStringIndexer, octetStringFilter,
6773 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6774 "SYNTAX 1.3.6.1.1.16.1 )",
6775 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6776 NULL, UUIDNormalize, octetStringOrderingMatch,
6777 octetStringIndexer, octetStringFilter,
6780 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6781 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6782 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6783 NULL, csnNormalize, csnMatch,
6784 csnIndexer, csnFilter,
6787 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6788 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6789 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6790 NULL, csnNormalize, csnOrderingMatch,
6794 {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6795 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6796 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6797 NULL, csnSidNormalize, octetStringMatch,
6798 octetStringIndexer, octetStringFilter,
6801 /* FIXME: OID is unused, but not registered yet */
6802 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6803 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6804 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6805 NULL, authzNormalize, authzMatch,
6809 {NULL, SLAP_MR_NONE, NULL,
6810 NULL, NULL, NULL, NULL, NULL,
6815 slap_schema_init( void )
6820 /* we should only be called once (from main) */
6821 assert( schema_init_done == 0 );
6823 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6824 res = register_syntax( &syntax_defs[i] );
6827 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6828 syntax_defs[i].sd_desc );
6833 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6834 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6835 mrule_defs[i].mrd_compat_syntaxes == NULL )
6838 "slap_schema_init: Ignoring unusable matching rule %s\n",
6839 mrule_defs[i].mrd_desc );
6843 res = register_matching_rule( &mrule_defs[i] );
6847 "slap_schema_init: Error registering matching rule %s\n",
6848 mrule_defs[i].mrd_desc );
6853 res = slap_schema_load();
6854 schema_init_done = 1;
6859 schema_destroy( void )
6868 if( schema_init_done ) {
6869 ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6870 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6871 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );