1 /* schema_init.c - init builtin schema */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 1998-2017 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"
109 #ifdef LUTIL_HASH64_BYTES
110 #define HASH_BYTES LUTIL_HASH64_BYTES
111 #define HASH_LEN hashlen
112 static void (*hashinit)(lutil_HASH_CTX *ctx) = lutil_HASHInit;
113 static void (*hashupdate)(lutil_HASH_CTX *ctx,unsigned char const *buf, ber_len_t len) = lutil_HASHUpdate;
114 static void (*hashfinal)(unsigned char digest[HASH_BYTES], lutil_HASH_CTX *ctx) = lutil_HASHFinal;
115 static int hashlen = LUTIL_HASH_BYTES;
116 #define HASH_Init(c) hashinit(c)
117 #define HASH_Update(c,buf,len) hashupdate(c,buf,len)
118 #define HASH_Final(d,c) hashfinal(d,c)
120 /* Toggle between 32 and 64 bit hashing, default to 32 for compatibility
121 -1 to query, returns 1 if 64 bit, 0 if 32.
122 0/1 to set 32/64, returns 0 on success, -1 on failure */
123 int slap_hash64( int onoff )
126 return hashlen == LUTIL_HASH64_BYTES;
127 } else if ( onoff ) {
128 hashinit = lutil_HASH64Init;
129 hashupdate = lutil_HASH64Update;
130 hashfinal = lutil_HASH64Final;
131 hashlen = LUTIL_HASH64_BYTES;
133 hashinit = lutil_HASHInit;
134 hashupdate = lutil_HASHUpdate;
135 hashfinal = lutil_HASHFinal;
136 hashlen = LUTIL_HASH_BYTES;
142 #define HASH_BYTES LUTIL_HASH_BYTES
143 #define HASH_LEN HASH_BYTES
144 #define HASH_Init(c) lutil_HASHInit(c)
145 #define HASH_Update(c,buf,len) lutil_HASHUpdate(c,buf,len)
146 #define HASH_Final(d,c) lutil_HASHFinal(d,c)
148 int slap_has64( int onoff )
153 return onoff ? -1 : 0;
157 #define HASH_CONTEXT lutil_HASH_CTX
159 /* approx matching rules */
160 #define directoryStringApproxMatchOID "1.3.6.1.4.1.4203.666.4.4"
161 #define directoryStringApproxMatch approxMatch
162 #define directoryStringApproxIndexer approxIndexer
163 #define directoryStringApproxFilter approxFilter
164 #define IA5StringApproxMatchOID "1.3.6.1.4.1.4203.666.4.5"
165 #define IA5StringApproxMatch approxMatch
166 #define IA5StringApproxIndexer approxIndexer
167 #define IA5StringApproxFilter approxFilter
169 /* Change Sequence Number (CSN) - much of this will change */
170 #define csnMatch octetStringMatch
171 #define csnOrderingMatch octetStringOrderingMatch
172 #define csnIndexer generalizedTimeIndexer
173 #define csnFilter generalizedTimeFilter
175 #define authzMatch octetStringMatch
177 /* X.509 PMI ldapSyntaxes */
178 /* FIXME: need to create temporary OIDs under OpenLDAP's arc;
179 * these are currently hijacked
181 * 1.3.6.1.4.1.4203.666 OpenLDAP
182 * 1.3.6.1.4.1.4203.666.11 self-contained works
183 * 1.3.6.1.4.1.4203.666.11.10 X.509 PMI
184 * 1.3.6.1.4.1.4203.666.11.10.2 X.509 PMI ldapSyntaxes
185 * 1.3.6.1.4.1.4203.666.11.10.2.1 AttributeCertificate (supported)
186 * 1.3.6.1.4.1.4203.666.11.10.2.2 AttributeCertificateExactAssertion (supported)
187 * 1.3.6.1.4.1.4203.666.11.10.2.3 AttributeCertificateAssertion (not supported)
188 * 1.3.6.1.4.1.4203.666.11.10.2.4 AttCertPath (X-SUBST'ed right now in pmi.schema)
189 * 1.3.6.1.4.1.4203.666.11.10.2.5 PolicySyntax (X-SUBST'ed right now in pmi.schema)
190 * 1.3.6.1.4.1.4203.666.11.10.2.6 RoleSyntax (X-SUBST'ed right now in pmi.schema)
192 #if 0 /* from <draft-ietf-pkix-ldap-schema-02.txt> (expired) */
193 #define attributeCertificateSyntaxOID "1.2.826.0.1.3344810.7.5"
194 #define attributeCertificateExactAssertionSyntaxOID "1.2.826.0.1.3344810.7.6"
195 #define attributeCertificateAssertionSyntaxOID "1.2.826.0.1.3344810.7.7"
196 #else /* from OpenLDAP's experimental oid arc */
197 #define X509_PMI_SyntaxOID "1.3.6.1.4.1.4203.666.11.10.2"
198 #define attributeCertificateSyntaxOID X509_PMI_SyntaxOID ".1"
199 #define attributeCertificateExactAssertionSyntaxOID X509_PMI_SyntaxOID ".2"
200 #define attributeCertificateAssertionSyntaxOID X509_PMI_SyntaxOID ".3"
203 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
204 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
205 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
206 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
208 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
209 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
210 SLAP_INDEX_INTLEN_DEFAULT );
212 ldap_pvt_thread_mutex_t ad_index_mutex;
213 ldap_pvt_thread_mutex_t ad_undef_mutex;
214 ldap_pvt_thread_mutex_t oc_undef_mutex;
217 generalizedTimeValidate(
221 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
226 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
233 /* no value allowed */
234 return LDAP_INVALID_SYNTAX;
242 /* any value allowed */
246 #define berValidate blobValidate
253 if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
254 if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
259 /* X.509 related stuff */
268 SLAP_TAG_UTCTIME = 0x17U,
269 SLAP_TAG_GENERALIZEDTIME = 0x18U
273 #define SLAP_X509_OPTION (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
276 SLAP_X509_OPT_C_VERSION = SLAP_X509_OPTION + 0,
277 SLAP_X509_OPT_C_ISSUERUNIQUEID = LBER_CLASS_CONTEXT + 1,
278 SLAP_X509_OPT_C_SUBJECTUNIQUEID = LBER_CLASS_CONTEXT + 2,
279 SLAP_X509_OPT_C_EXTENSIONS = SLAP_X509_OPTION + 3
283 SLAP_X509_OPT_CL_CRLEXTENSIONS = SLAP_X509_OPTION + 0
287 GeneralName ::= CHOICE {
288 otherName [0] INSTANCE OF OTHER-NAME,
289 rfc822Name [1] IA5String,
290 dNSName [2] IA5String,
291 x400Address [3] ORAddress,
292 directoryName [4] Name,
293 ediPartyName [5] EDIPartyName,
294 uniformResourceIdentifier [6] IA5String,
295 iPAddress [7] OCTET STRING,
296 registeredID [8] OBJECT IDENTIFIER }
299 SLAP_X509_GN_OTHERNAME = SLAP_X509_OPTION + 0,
300 SLAP_X509_GN_RFC822NAME = SLAP_X509_OPTION + 1,
301 SLAP_X509_GN_DNSNAME = SLAP_X509_OPTION + 2,
302 SLAP_X509_GN_X400ADDRESS = SLAP_X509_OPTION + 3,
303 SLAP_X509_GN_DIRECTORYNAME = SLAP_X509_OPTION + 4,
304 SLAP_X509_GN_EDIPARTYNAME = SLAP_X509_OPTION + 5,
305 SLAP_X509_GN_URI = SLAP_X509_OPTION + 6,
306 SLAP_X509_GN_IPADDRESS = SLAP_X509_OPTION + 7,
307 SLAP_X509_GN_REGISTEREDID = SLAP_X509_OPTION + 8
310 /* X.509 PMI related stuff */
317 SLAP_X509AC_ISSUER = SLAP_X509_OPTION + 0
320 /* X.509 certificate validation */
322 certificateValidate( Syntax *syntax, struct berval *in )
324 BerElementBuffer berbuf;
325 BerElement *ber = (BerElement *)&berbuf;
328 ber_int_t version = SLAP_X509_V1;
330 ber_init2( ber, in, LBER_USE_DER );
331 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
332 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
333 tag = ber_skip_tag( ber, &len ); /* Sequence */
334 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
335 tag = ber_peek_tag( ber, &len );
336 /* Optional version */
337 if ( tag == SLAP_X509_OPT_C_VERSION ) {
338 tag = ber_skip_tag( ber, &len );
339 tag = ber_get_int( ber, &version );
340 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
342 /* NOTE: don't try to parse Serial, because it might be longer
343 * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
344 tag = ber_skip_tag( ber, &len ); /* Serial */
345 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
346 ber_skip_data( ber, len );
347 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
348 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
349 ber_skip_data( ber, len );
350 tag = ber_skip_tag( ber, &len ); /* Issuer DN */
351 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
352 ber_skip_data( ber, len );
353 tag = ber_skip_tag( ber, &len ); /* Validity */
354 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
355 ber_skip_data( ber, len );
356 tag = ber_skip_tag( ber, &len ); /* Subject DN */
357 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
358 ber_skip_data( ber, len );
359 tag = ber_skip_tag( ber, &len ); /* Subject PublicKeyInfo */
360 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
361 ber_skip_data( ber, len );
362 tag = ber_skip_tag( ber, &len );
363 if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) { /* issuerUniqueID */
364 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
365 ber_skip_data( ber, len );
366 tag = ber_skip_tag( ber, &len );
368 if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) { /* subjectUniqueID */
369 if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
370 ber_skip_data( ber, len );
371 tag = ber_skip_tag( ber, &len );
373 if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) { /* Extensions */
374 if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
375 tag = ber_skip_tag( ber, &len );
376 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
377 ber_skip_data( ber, len );
378 tag = ber_skip_tag( ber, &len );
380 /* signatureAlgorithm */
381 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
382 ber_skip_data( ber, len );
383 tag = ber_skip_tag( ber, &len );
385 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
386 ber_skip_data( ber, len );
387 tag = ber_skip_tag( ber, &len );
388 /* Must be at end now */
389 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
393 /* X.509 certificate list validation */
395 checkTime( struct berval *in, struct berval *out );
398 certificateListValidate( Syntax *syntax, struct berval *in )
400 BerElementBuffer berbuf;
401 BerElement *ber = (BerElement *)&berbuf;
403 ber_len_t len, wrapper_len;
406 ber_int_t version = SLAP_X509_V1;
407 struct berval bvdn, bvtu;
409 ber_init2( ber, in, LBER_USE_DER );
410 tag = ber_skip_tag( ber, &wrapper_len ); /* Signed wrapper */
411 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
412 wrapper_start = ber->ber_ptr;
413 tag = ber_skip_tag( ber, &len ); /* Sequence */
414 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
415 tag = ber_peek_tag( ber, &len );
416 /* Optional version */
417 if ( tag == LBER_INTEGER ) {
418 tag = ber_get_int( ber, &version );
419 assert( tag == LBER_INTEGER );
420 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
422 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
423 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
424 ber_skip_data( ber, len );
425 tag = ber_peek_tag( ber, &len ); /* Issuer DN */
426 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
427 len = ber_ptrlen( ber );
428 bvdn.bv_val = in->bv_val + len;
429 bvdn.bv_len = in->bv_len - len;
430 tag = ber_skip_tag( ber, &len );
431 ber_skip_data( ber, len );
432 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
433 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
434 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
435 bvtu.bv_val = (char *)ber->ber_ptr;
437 ber_skip_data( ber, len );
438 /* Optional nextUpdate */
439 tag = ber_skip_tag( ber, &len );
440 if ( tag == SLAP_TAG_UTCTIME || tag == SLAP_TAG_GENERALIZEDTIME ) {
441 ber_skip_data( ber, len );
442 tag = ber_skip_tag( ber, &len );
444 /* revokedCertificates - Sequence of Sequence, Optional */
445 if ( tag == LBER_SEQUENCE ) {
448 stag = ber_peek_tag( ber, &seqlen );
449 if ( stag == LBER_SEQUENCE || !len ) {
450 /* RFC5280 requires non-empty, but X.509(2005) allows empty. */
452 ber_skip_data( ber, len );
453 tag = ber_skip_tag( ber, &len );
456 /* Optional Extensions - Sequence of Sequence */
457 if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
459 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
460 tag = ber_peek_tag( ber, &seqlen );
461 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
462 ber_skip_data( ber, len );
463 tag = ber_skip_tag( ber, &len );
465 /* signatureAlgorithm */
466 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
467 ber_skip_data( ber, len );
468 tag = ber_skip_tag( ber, &len );
470 if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
471 ber_skip_data( ber, len );
472 if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1;
473 tag = ber_skip_tag( ber, &len );
474 /* Must be at end now */
475 /* NOTE: OpenSSL tolerates CL with garbage past the end */
476 if ( len || tag != LBER_DEFAULT ) {
477 struct berval issuer_dn = BER_BVNULL, thisUpdate;
478 char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
481 if ( ! wrapper_ok ) {
482 return LDAP_INVALID_SYNTAX;
485 rc = dnX509normalize( &bvdn, &issuer_dn );
486 if ( rc != LDAP_SUCCESS ) {
487 rc = LDAP_INVALID_SYNTAX;
491 thisUpdate.bv_val = tubuf;
492 thisUpdate.bv_len = sizeof(tubuf);
493 if ( checkTime( &bvtu, &thisUpdate ) ) {
494 rc = LDAP_INVALID_SYNTAX;
498 Debug( LDAP_DEBUG_ANY,
499 "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n",
500 issuer_dn.bv_val, thisUpdate.bv_val, 0 );
503 if ( ! BER_BVISNULL( &issuer_dn ) ) {
504 ber_memfree( issuer_dn.bv_val );
513 /* X.509 PMI Attribute Certificate Validate */
515 attributeCertificateValidate( Syntax *syntax, struct berval *in )
517 BerElementBuffer berbuf;
518 BerElement *ber = (BerElement *)&berbuf;
524 ber_init2( ber, in, LBER_USE_DER );
526 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
527 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
529 tag = ber_skip_tag( ber, &len ); /* Sequence */
530 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
532 tag = ber_peek_tag( ber, &len ); /* Version */
533 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
534 tag = ber_get_int( ber, &version ); /* X.509 only allows v2 */
535 if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX;
537 tag = ber_skip_tag( ber, &len ); /* Holder */
538 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
539 ber_skip_data( ber, len );
541 tag = ber_skip_tag( ber, &len ); /* Issuer */
542 if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX;
543 ber_skip_data( ber, len );
545 tag = ber_skip_tag( ber, &len ); /* Signature */
546 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
547 ber_skip_data( ber, len );
549 tag = ber_skip_tag( ber, &len ); /* Serial number */
550 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
551 ber_skip_data( ber, len );
553 tag = ber_skip_tag( ber, &len ); /* AttCertValidityPeriod */
554 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
555 ber_skip_data( ber, len );
557 tag = ber_skip_tag( ber, &len ); /* Attributes */
558 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
559 ber_skip_data( ber, len );
561 tag = ber_peek_tag( ber, &len );
563 if ( tag == LBER_BITSTRING ) { /* issuerUniqueID */
564 tag = ber_skip_tag( ber, &len );
565 ber_skip_data( ber, len );
566 tag = ber_peek_tag( ber, &len );
569 if ( tag == LBER_SEQUENCE ) { /* extensions or signatureAlgorithm */
570 tag = ber_skip_tag( ber, &len );
571 ber_skip_data( ber, len );
573 tag = ber_peek_tag( ber, &len );
576 if ( tag == LBER_SEQUENCE ) { /* signatureAlgorithm */
577 tag = ber_skip_tag( ber, &len );
578 ber_skip_data( ber, len );
580 tag = ber_peek_tag( ber, &len );
583 if ( tag == LBER_BITSTRING ) { /* Signature */
584 tag = ber_skip_tag( ber, &len );
585 ber_skip_data( ber, len );
587 tag = ber_peek_tag( ber, &len );
590 /* Must be at end now */
591 if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX;
596 /* accept an OpenSSL-compatible private key */
602 BerElementBuffer berbuf;
603 BerElement *ber = (BerElement *)&berbuf;
608 ber_init2( ber, val, LBER_USE_DER );
609 tag = ber_skip_tag( ber, &len ); /* Sequence */
610 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
611 tag = ber_peek_tag( ber, &len );
612 if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
613 tag = ber_get_int( ber, &version );
614 /* the rest varies for RSA, DSA, EC, PKCS#8 */
624 struct berval *value,
625 void *assertedValue )
627 struct berval *asserted = (struct berval *) assertedValue;
628 ber_slen_t d = (ber_slen_t) value->bv_len - (ber_slen_t) asserted->bv_len;
630 /* For speed, order first by length, then by contents */
631 *matchp = d ? (sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1)
632 : memcmp( value->bv_val, asserted->bv_val, value->bv_len );
638 octetStringOrderingMatch(
643 struct berval *value,
644 void *assertedValue )
646 struct berval *asserted = (struct berval *) assertedValue;
647 ber_len_t v_len = value->bv_len;
648 ber_len_t av_len = asserted->bv_len;
650 int match = memcmp( value->bv_val, asserted->bv_val,
651 (v_len < av_len ? v_len : av_len) );
654 match = sizeof(v_len) == sizeof(int)
655 ? (int) v_len - (int) av_len
656 : v_len < av_len ? -1 : v_len > av_len;
658 /* If used in extensible match filter, match if value < asserted */
659 if ( flags & SLAP_MR_EXT )
660 match = (match >= 0);
666 /* Initialize HASHcontext from match type and schema info */
669 HASH_CONTEXT *HASHcontext,
670 struct berval *prefix,
675 HASH_Init(HASHcontext);
676 if(prefix && prefix->bv_len > 0) {
677 HASH_Update(HASHcontext,
678 (unsigned char *)prefix->bv_val, prefix->bv_len);
680 if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
681 HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
682 HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
686 /* Set HASHdigest from HASHcontext and value:len */
689 HASH_CONTEXT *HASHcontext,
690 unsigned char *HASHdigest,
691 unsigned char *value,
694 HASH_CONTEXT ctx = *HASHcontext;
695 HASH_Update( &ctx, value, len );
696 HASH_Final( HASHdigest, &ctx );
699 /* Index generation function: Attribute values -> index hash keys */
700 int octetStringIndexer(
705 struct berval *prefix,
713 HASH_CONTEXT HASHcontext;
714 unsigned char HASHdigest[HASH_BYTES];
715 struct berval digest;
716 digest.bv_val = (char *)HASHdigest;
717 digest.bv_len = HASH_LEN;
719 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
720 /* just count them */
723 /* we should have at least one value at this point */
726 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
728 slen = syntax->ssyn_oidlen;
729 mlen = mr->smr_oidlen;
731 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
732 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
733 hashIter( &HASHcontext, HASHdigest,
734 (unsigned char *)values[i].bv_val, values[i].bv_len );
735 ber_dupbv_x( &keys[i], &digest, ctx );
738 BER_BVZERO( &keys[i] );
745 /* Index generation function: Asserted value -> index hash key */
746 int octetStringFilter(
751 struct berval *prefix,
752 void * assertedValue,
758 HASH_CONTEXT HASHcontext;
759 unsigned char HASHdigest[HASH_BYTES];
760 struct berval *value = (struct berval *) assertedValue;
761 struct berval digest;
762 digest.bv_val = (char *)HASHdigest;
763 digest.bv_len = HASH_LEN;
765 slen = syntax->ssyn_oidlen;
766 mlen = mr->smr_oidlen;
768 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
770 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
771 hashIter( &HASHcontext, HASHdigest,
772 (unsigned char *)value->bv_val, value->bv_len );
774 ber_dupbv_x( keys, &digest, ctx );
775 BER_BVZERO( &keys[1] );
783 octetStringSubstringsMatch(
788 struct berval *value,
789 void *assertedValue )
792 SubstringsAssertion *sub = assertedValue;
793 struct berval left = *value;
797 /* Add up asserted input length */
798 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
799 inlen += sub->sa_initial.bv_len;
802 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
803 inlen += sub->sa_any[i].bv_len;
806 if ( !BER_BVISNULL( &sub->sa_final ) ) {
807 inlen += sub->sa_final.bv_len;
810 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
811 if ( inlen > left.bv_len ) {
816 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
817 sub->sa_initial.bv_len );
823 left.bv_val += sub->sa_initial.bv_len;
824 left.bv_len -= sub->sa_initial.bv_len;
825 inlen -= sub->sa_initial.bv_len;
828 if ( !BER_BVISNULL( &sub->sa_final ) ) {
829 if ( inlen > left.bv_len ) {
834 match = memcmp( sub->sa_final.bv_val,
835 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
836 sub->sa_final.bv_len );
842 left.bv_len -= sub->sa_final.bv_len;
843 inlen -= sub->sa_final.bv_len;
847 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
852 if ( inlen > left.bv_len ) {
853 /* not enough length */
858 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
862 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
869 idx = p - left.bv_val;
871 if ( idx >= left.bv_len ) {
872 /* this shouldn't happen */
879 if ( sub->sa_any[i].bv_len > left.bv_len ) {
880 /* not enough left */
885 match = memcmp( left.bv_val,
886 sub->sa_any[i].bv_val,
887 sub->sa_any[i].bv_len );
895 left.bv_val += sub->sa_any[i].bv_len;
896 left.bv_len -= sub->sa_any[i].bv_len;
897 inlen -= sub->sa_any[i].bv_len;
906 /* Substring index generation function: Attribute values -> index hash keys */
908 octetStringSubstringsIndexer(
913 struct berval *prefix,
922 HASH_CONTEXT HCany, HCini, HCfin;
923 unsigned char HASHdigest[HASH_BYTES];
924 struct berval digest;
925 digest.bv_val = (char *)HASHdigest;
926 digest.bv_len = HASH_LEN;
930 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
931 /* count number of indices to generate */
932 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
933 if( values[i].bv_len >= index_substr_if_maxlen ) {
934 nkeys += index_substr_if_maxlen -
935 (index_substr_if_minlen - 1);
936 } else if( values[i].bv_len >= index_substr_if_minlen ) {
937 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
941 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
942 if( values[i].bv_len >= index_substr_any_len ) {
943 nkeys += values[i].bv_len - (index_substr_any_len - 1);
947 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
948 if( values[i].bv_len >= index_substr_if_maxlen ) {
949 nkeys += index_substr_if_maxlen -
950 (index_substr_if_minlen - 1);
951 } else if( values[i].bv_len >= index_substr_if_minlen ) {
952 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
958 /* no keys to generate */
963 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
965 slen = syntax->ssyn_oidlen;
966 mlen = mr->smr_oidlen;
968 if ( flags & SLAP_INDEX_SUBSTR_ANY )
969 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
970 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
971 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
972 if( flags & SLAP_INDEX_SUBSTR_FINAL )
973 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
976 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
979 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
980 ( values[i].bv_len >= index_substr_any_len ) )
982 max = values[i].bv_len - (index_substr_any_len - 1);
984 for( j=0; j<max; j++ ) {
985 hashIter( &HCany, HASHdigest,
986 (unsigned char *)&values[i].bv_val[j],
987 index_substr_any_len );
988 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
992 /* skip if too short */
993 if( values[i].bv_len < index_substr_if_minlen ) continue;
995 max = index_substr_if_maxlen < values[i].bv_len
996 ? index_substr_if_maxlen : values[i].bv_len;
998 for( j=index_substr_if_minlen; j<=max; j++ ) {
1000 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1001 hashIter( &HCini, HASHdigest,
1002 (unsigned char *)values[i].bv_val, j );
1003 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1006 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1007 hashIter( &HCfin, HASHdigest,
1008 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
1009 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1016 BER_BVZERO( &keys[nkeys] );
1023 return LDAP_SUCCESS;
1026 /* Substring index generation function: Assertion value -> index hash keys */
1028 octetStringSubstringsFilter (
1033 struct berval *prefix,
1034 void * assertedValue,
1038 SubstringsAssertion *sa;
1040 ber_len_t nkeys = 0;
1041 size_t slen, mlen, klen;
1043 HASH_CONTEXT HASHcontext;
1044 unsigned char HASHdigest[HASH_BYTES];
1045 struct berval *value;
1046 struct berval digest;
1048 sa = (SubstringsAssertion *) assertedValue;
1050 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1051 !BER_BVISNULL( &sa->sa_initial ) &&
1052 sa->sa_initial.bv_len >= index_substr_if_minlen )
1055 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
1056 ( flags & SLAP_INDEX_SUBSTR_ANY ))
1058 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1062 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1064 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1065 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
1066 /* don't bother accounting with stepping */
1067 nkeys += sa->sa_any[i].bv_len -
1068 ( index_substr_any_len - 1 );
1073 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1074 !BER_BVISNULL( &sa->sa_final ) &&
1075 sa->sa_final.bv_len >= index_substr_if_minlen )
1078 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
1079 ( flags & SLAP_INDEX_SUBSTR_ANY ))
1081 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1087 return LDAP_SUCCESS;
1090 digest.bv_val = (char *)HASHdigest;
1091 digest.bv_len = HASH_LEN;
1093 slen = syntax->ssyn_oidlen;
1094 mlen = mr->smr_oidlen;
1096 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
1099 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1100 !BER_BVISNULL( &sa->sa_initial ) &&
1101 sa->sa_initial.bv_len >= index_substr_if_minlen )
1103 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1104 value = &sa->sa_initial;
1106 klen = index_substr_if_maxlen < value->bv_len
1107 ? index_substr_if_maxlen : value->bv_len;
1109 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1110 hashIter( &HASHcontext, HASHdigest,
1111 (unsigned char *)value->bv_val, klen );
1112 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1114 /* If initial is too long and we have subany indexed, use it
1115 * to match the excess...
1117 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1120 pre = SLAP_INDEX_SUBSTR_PREFIX;
1121 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1122 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
1124 hashIter( &HASHcontext, HASHdigest,
1125 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1126 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1131 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1133 pre = SLAP_INDEX_SUBSTR_PREFIX;
1134 klen = index_substr_any_len;
1136 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1137 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
1141 value = &sa->sa_any[i];
1143 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1145 j <= value->bv_len - index_substr_any_len;
1146 j += index_substr_any_step )
1148 hashIter( &HASHcontext, HASHdigest,
1149 (unsigned char *)&value->bv_val[j], klen );
1150 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1155 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1156 !BER_BVISNULL( &sa->sa_final ) &&
1157 sa->sa_final.bv_len >= index_substr_if_minlen )
1159 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1160 value = &sa->sa_final;
1162 klen = index_substr_if_maxlen < value->bv_len
1163 ? index_substr_if_maxlen : value->bv_len;
1165 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1166 hashIter( &HASHcontext, HASHdigest,
1167 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
1168 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1170 /* If final is too long and we have subany indexed, use it
1171 * to match the excess...
1173 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1176 pre = SLAP_INDEX_SUBSTR_PREFIX;
1177 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1178 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
1180 hashIter( &HASHcontext, HASHdigest,
1181 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1182 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1188 BER_BVZERO( &keys[nkeys] );
1195 return LDAP_SUCCESS;
1205 /* very unforgiving validation, requires no normalization
1206 * before simplistic matching
1208 if( in->bv_len < 3 ) {
1209 return LDAP_INVALID_SYNTAX;
1212 /* RFC 4517 Section 3.3.2 Bit String:
1213 * BitString = SQUOTE *binary-digit SQUOTE "B"
1214 * binary-digit = "0" / "1"
1216 * where SQUOTE [RFC4512] is
1217 * SQUOTE = %x27 ; single quote ("'")
1219 * Example: '0101111101'B
1222 if( in->bv_val[0] != '\'' ||
1223 in->bv_val[in->bv_len - 2] != '\'' ||
1224 in->bv_val[in->bv_len - 1] != 'B' )
1226 return LDAP_INVALID_SYNTAX;
1229 for( i = in->bv_len - 3; i > 0; i-- ) {
1230 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
1231 return LDAP_INVALID_SYNTAX;
1235 return LDAP_SUCCESS;
1239 * Syntaxes from RFC 4517
1244 A value of the Bit String syntax is a sequence of binary digits. The
1245 LDAP-specific encoding of a value of this syntax is defined by the
1248 BitString = SQUOTE *binary-digit SQUOTE "B"
1250 binary-digit = "0" / "1"
1252 The <SQUOTE> rule is defined in [MODELS].
1257 The LDAP definition for the Bit String syntax is:
1259 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
1261 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
1265 3.3.21. Name and Optional UID
1267 A value of the Name and Optional UID syntax is the distinguished name
1268 [MODELS] of an entity optionally accompanied by a unique identifier
1269 that serves to differentiate the entity from others with an identical
1272 The LDAP-specific encoding of a value of this syntax is defined by
1275 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
1277 The <BitString> rule is defined in Section 3.3.2. The
1278 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
1279 defined in [MODELS].
1281 Note that although the '#' character may occur in the string
1282 representation of a distinguished name, no additional escaping of
1283 this character is performed when a <distinguishedName> is encoded in
1284 a <NameAndOptionalUID>.
1287 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
1289 The LDAP definition for the Name and Optional UID syntax is:
1291 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
1293 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
1300 1.4. Common ABNF Productions
1303 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
1305 SQUOTE = %x27 ; single quote ("'")
1310 * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
1311 * be escaped except when at the beginning of a value, the
1312 * definition of Name and Optional UID appears to be flawed,
1313 * because there is no clear means to determine whether the
1314 * UID part is present or not.
1318 * cn=Someone,dc=example,dc=com#'1'B
1320 * could be either a NameAndOptionalUID with trailing UID, i.e.
1322 * DN = "cn=Someone,dc=example,dc=com"
1325 * or a NameAndOptionalUID with no trailing UID, and the AVA
1326 * in the last RDN made of
1328 * attributeType = dc
1329 * attributeValue = com#'1'B
1331 * in fact "com#'1'B" is a valid IA5 string.
1333 * As a consequence, current slapd code takes the presence of
1334 * #<valid BitString> at the end of the string representation
1335 * of a NameAndOptionalUID to mean this is indeed a BitString.
1336 * This is quite arbitrary - it has changed the past and might
1337 * change in the future.
1347 struct berval dn, uid;
1349 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
1351 ber_dupbv( &dn, in );
1352 if( !dn.bv_val ) return LDAP_OTHER;
1354 /* if there's a "#", try bitStringValidate()... */
1355 uid.bv_val = strrchr( dn.bv_val, '#' );
1356 if ( !BER_BVISNULL( &uid ) ) {
1358 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1360 rc = bitStringValidate( NULL, &uid );
1361 if ( rc == LDAP_SUCCESS ) {
1362 /* in case of success, trim the UID,
1363 * otherwise treat it as part of the DN */
1364 dn.bv_len -= uid.bv_len + 1;
1365 uid.bv_val[-1] = '\0';
1369 rc = dnValidate( NULL, &dn );
1371 ber_memfree( dn.bv_val );
1382 assert( val != NULL );
1383 assert( out != NULL );
1386 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1388 if( BER_BVISEMPTY( val ) ) {
1389 ber_dupbv_x( out, val, ctx );
1391 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1392 return LDAP_INVALID_SYNTAX;
1396 struct berval dnval = *val;
1397 struct berval uidval = BER_BVNULL;
1399 uidval.bv_val = strrchr( val->bv_val, '#' );
1400 if ( !BER_BVISNULL( &uidval ) ) {
1402 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1404 rc = bitStringValidate( NULL, &uidval );
1406 if ( rc == LDAP_SUCCESS ) {
1407 ber_dupbv_x( &dnval, val, ctx );
1409 dnval.bv_len -= ++uidval.bv_len;
1410 dnval.bv_val[dnval.bv_len] = '\0';
1413 BER_BVZERO( &uidval );
1417 rc = dnPretty( syntax, &dnval, out, ctx );
1418 if ( dnval.bv_val != val->bv_val ) {
1419 slap_sl_free( dnval.bv_val, ctx );
1421 if( rc != LDAP_SUCCESS ) {
1425 if( !BER_BVISNULL( &uidval ) ) {
1428 tmp = slap_sl_realloc( out->bv_val, out->bv_len
1429 + uidval.bv_len + 1,
1432 ber_memfree_x( out->bv_val, ctx );
1436 memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
1437 out->bv_len += uidval.bv_len;
1438 out->bv_val[out->bv_len] = '\0';
1442 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1444 return LDAP_SUCCESS;
1448 uniqueMemberNormalize(
1453 struct berval *normalized,
1459 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1461 ber_dupbv_x( &out, val, ctx );
1462 if ( BER_BVISEMPTY( &out ) ) {
1466 struct berval uid = BER_BVNULL;
1468 uid.bv_val = strrchr( out.bv_val, '#' );
1469 if ( !BER_BVISNULL( &uid ) ) {
1471 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1473 rc = bitStringValidate( NULL, &uid );
1474 if ( rc == LDAP_SUCCESS ) {
1475 uid.bv_val[-1] = '\0';
1476 out.bv_len -= uid.bv_len + 1;
1482 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1484 if( rc != LDAP_SUCCESS ) {
1485 slap_sl_free( out.bv_val, ctx );
1486 return LDAP_INVALID_SYNTAX;
1489 if( !BER_BVISNULL( &uid ) ) {
1492 tmp = ch_realloc( normalized->bv_val,
1493 normalized->bv_len + uid.bv_len
1494 + STRLENOF("#") + 1 );
1495 if ( tmp == NULL ) {
1496 ber_memfree_x( normalized->bv_val, ctx );
1500 normalized->bv_val = tmp;
1502 /* insert the separator */
1503 normalized->bv_val[normalized->bv_len++] = '#';
1505 /* append the UID */
1506 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1507 uid.bv_val, uid.bv_len );
1508 normalized->bv_len += uid.bv_len;
1511 normalized->bv_val[normalized->bv_len] = '\0';
1514 slap_sl_free( out.bv_val, ctx );
1517 return LDAP_SUCCESS;
1526 struct berval *value,
1527 void *assertedValue )
1530 struct berval *asserted = (struct berval *) assertedValue;
1531 struct berval assertedDN = *asserted;
1532 struct berval assertedUID = BER_BVNULL;
1533 struct berval valueDN = *value;
1534 struct berval valueUID = BER_BVNULL;
1535 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1537 if ( !BER_BVISEMPTY( asserted ) ) {
1538 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1539 if ( !BER_BVISNULL( &assertedUID ) ) {
1540 assertedUID.bv_val++;
1541 assertedUID.bv_len = assertedDN.bv_len
1542 - ( assertedUID.bv_val - assertedDN.bv_val );
1544 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1545 assertedDN.bv_len -= assertedUID.bv_len + 1;
1548 BER_BVZERO( &assertedUID );
1553 if ( !BER_BVISEMPTY( value ) ) {
1555 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1556 if ( !BER_BVISNULL( &valueUID ) ) {
1558 valueUID.bv_len = valueDN.bv_len
1559 - ( valueUID.bv_val - valueDN.bv_val );
1561 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1562 valueDN.bv_len -= valueUID.bv_len + 1;
1565 BER_BVZERO( &valueUID );
1570 if( valueUID.bv_len && assertedUID.bv_len ) {
1572 d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len;
1574 *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1;
1575 return LDAP_SUCCESS;
1578 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1581 return LDAP_SUCCESS;
1584 } else if ( !approx && valueUID.bv_len ) {
1587 return LDAP_SUCCESS;
1589 } else if ( !approx && assertedUID.bv_len ) {
1592 return LDAP_SUCCESS;
1595 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1599 uniqueMemberIndexer(
1604 struct berval *prefix,
1612 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1613 /* just count them */
1617 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1619 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1620 struct berval assertedDN = values[i];
1621 struct berval assertedUID = BER_BVNULL;
1623 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1624 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1625 if ( !BER_BVISNULL( &assertedUID ) ) {
1626 assertedUID.bv_val++;
1627 assertedUID.bv_len = assertedDN.bv_len
1628 - ( assertedUID.bv_val - assertedDN.bv_val );
1630 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1631 assertedDN.bv_len -= assertedUID.bv_len + 1;
1634 BER_BVZERO( &assertedUID );
1639 dnvalues[i] = assertedDN;
1641 BER_BVZERO( &dnvalues[i] );
1643 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1644 dnvalues, keysp, ctx );
1646 slap_sl_free( dnvalues, ctx );
1656 struct berval *prefix,
1657 void * assertedValue,
1661 struct berval *asserted = (struct berval *) assertedValue;
1662 struct berval assertedDN = *asserted;
1663 struct berval assertedUID = BER_BVNULL;
1665 if ( !BER_BVISEMPTY( asserted ) ) {
1666 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1667 if ( !BER_BVISNULL( &assertedUID ) ) {
1668 assertedUID.bv_val++;
1669 assertedUID.bv_len = assertedDN.bv_len
1670 - ( assertedUID.bv_val - assertedDN.bv_val );
1672 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1673 assertedDN.bv_len -= assertedUID.bv_len + 1;
1676 BER_BVZERO( &assertedUID );
1681 return octetStringFilter( use, flags, syntax, mr, prefix,
1682 &assertedDN, keysp, ctx );
1687 * Handling boolean syntax and matching is quite rigid.
1688 * A more flexible approach would be to allow a variety
1689 * of strings to be normalized and prettied into TRUE
1697 /* very unforgiving validation, requires no normalization
1698 * before simplistic matching
1701 if( in->bv_len == 4 ) {
1702 if( bvmatch( in, &slap_true_bv ) ) {
1703 return LDAP_SUCCESS;
1705 } else if( in->bv_len == 5 ) {
1706 if( bvmatch( in, &slap_false_bv ) ) {
1707 return LDAP_SUCCESS;
1711 return LDAP_INVALID_SYNTAX;
1720 struct berval *value,
1721 void *assertedValue )
1723 /* simplistic matching allowed by rigid validation */
1724 struct berval *asserted = (struct berval *) assertedValue;
1725 *matchp = (int) asserted->bv_len - (int) value->bv_len;
1726 return LDAP_SUCCESS;
1729 /*-------------------------------------------------------------------
1730 LDAP/X.500 string syntax / matching rules have a few oddities. This
1731 comment attempts to detail how slapd(8) treats them.
1734 StringSyntax X.500 LDAP Matching/Comments
1735 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1736 PrintableString subset subset i/e + ignore insignificant spaces
1737 PrintableString subset subset i/e + ignore insignificant spaces
1738 NumericString subset subset ignore all spaces
1739 IA5String ASCII ASCII i/e + ignore insignificant spaces
1740 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1742 TelephoneNumber subset subset i + ignore all spaces and "-"
1744 See RFC 4518 for details.
1748 In X.500(93), a directory string can be either a PrintableString,
1749 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1750 In later versions, more CHOICEs were added. In all cases the string
1753 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1754 A directory string cannot be zero length.
1756 For matching, there are both case ignore and exact rules. Both
1757 also require that "insignificant" spaces be ignored.
1758 spaces before the first non-space are ignored;
1759 spaces after the last non-space are ignored;
1760 spaces after a space are ignored.
1761 Note: by these rules (and as clarified in X.520), a string of only
1762 spaces is to be treated as if held one space, not empty (which
1763 would be a syntax error).
1766 In ASN.1, numeric string is just a string of digits and spaces
1767 and could be empty. However, in X.500, all attribute values of
1768 numeric string carry a non-empty constraint. For example:
1770 internationalISDNNumber ATTRIBUTE ::= {
1771 WITH SYNTAX InternationalISDNNumber
1772 EQUALITY MATCHING RULE numericStringMatch
1773 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1774 ID id-at-internationalISDNNumber }
1775 InternationalISDNNumber ::=
1776 NumericString (SIZE(1..ub-international-isdn-number))
1778 Unforunately, some assertion values are don't carry the same
1779 constraint (but its unclear how such an assertion could ever
1780 be true). In LDAP, there is one syntax (numericString) not two
1781 (numericString with constraint, numericString without constraint).
1782 This should be treated as numericString with non-empty constraint.
1783 Note that while someone may have no ISDN number, there are no ISDN
1784 numbers which are zero length.
1786 In matching, spaces are ignored.
1789 In ASN.1, Printable string is just a string of printable characters
1790 and can be empty. In X.500, semantics much like NumericString (see
1791 serialNumber for a like example) excepting uses insignificant space
1792 handling instead of ignore all spaces. They must be non-empty.
1795 Basically same as PrintableString. There are no examples in X.500,
1796 but same logic applies. Empty strings are allowed.
1798 -------------------------------------------------------------------*/
1806 unsigned char *u = (unsigned char *)in->bv_val, *end = in->bv_val + in->bv_len;
1808 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1809 /* directory strings cannot be empty */
1810 return LDAP_INVALID_SYNTAX;
1813 for( ; u < end; u += len ) {
1814 /* get the length indicated by the first byte */
1815 len = LDAP_UTF8_CHARLEN2( u, len );
1817 /* very basic checks */
1820 if( (u[5] & 0xC0) != 0x80 ) {
1821 return LDAP_INVALID_SYNTAX;
1824 if( (u[4] & 0xC0) != 0x80 ) {
1825 return LDAP_INVALID_SYNTAX;
1828 if( (u[3] & 0xC0) != 0x80 ) {
1829 return LDAP_INVALID_SYNTAX;
1832 if( (u[2] & 0xC0 )!= 0x80 ) {
1833 return LDAP_INVALID_SYNTAX;
1836 if( (u[1] & 0xC0) != 0x80 ) {
1837 return LDAP_INVALID_SYNTAX;
1840 /* CHARLEN already validated it */
1843 return LDAP_INVALID_SYNTAX;
1846 /* make sure len corresponds with the offset
1847 to the next character */
1848 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1852 return LDAP_INVALID_SYNTAX;
1855 return LDAP_SUCCESS;
1859 UTF8StringNormalize(
1864 struct berval *normalized,
1867 struct berval tmp, nvalue;
1868 int flags, wasspace;
1871 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1873 if( BER_BVISNULL( val ) ) {
1874 /* assume we're dealing with a syntax (e.g., UTF8String)
1875 * which allows empty strings
1877 BER_BVZERO( normalized );
1878 return LDAP_SUCCESS;
1881 flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1882 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1883 flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1884 ? LDAP_UTF8_APPROX : 0;
1886 val = UTF8bvnormalize( val, &tmp, flags, ctx );
1887 /* out of memory or syntax error, the former is unlikely */
1889 return LDAP_INVALID_SYNTAX;
1892 /* collapse spaces (in place) */
1894 nvalue.bv_val = tmp.bv_val;
1896 /* trim leading spaces? */
1897 wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1898 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1900 for( i = 0; i < tmp.bv_len; i++) {
1901 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1902 if( wasspace++ == 0 ) {
1903 /* trim repeated spaces */
1904 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1908 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1912 if( !BER_BVISEMPTY( &nvalue ) ) {
1913 /* trim trailing space? */
1915 (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1916 ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1920 nvalue.bv_val[nvalue.bv_len] = '\0';
1922 } else if ( tmp.bv_len ) {
1923 /* string of all spaces is treated as one space */
1924 nvalue.bv_val[0] = ' ';
1925 nvalue.bv_val[1] = '\0';
1927 } /* should never be entered with 0-length val */
1929 *normalized = nvalue;
1930 return LDAP_SUCCESS;
1934 directoryStringSubstringsMatch(
1939 struct berval *value,
1940 void *assertedValue )
1943 SubstringsAssertion *sub = assertedValue;
1944 struct berval left = *value;
1948 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1949 if ( sub->sa_initial.bv_len > left.bv_len ) {
1950 /* not enough left */
1955 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1956 sub->sa_initial.bv_len );
1962 left.bv_val += sub->sa_initial.bv_len;
1963 left.bv_len -= sub->sa_initial.bv_len;
1965 priorspace = ASCII_SPACE(
1966 sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1969 if ( sub->sa_any ) {
1970 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1974 if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1975 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1977 /* allow next space to match */
1984 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1988 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1989 /* not enough left */
1994 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
2001 idx = p - left.bv_val;
2003 if ( idx >= left.bv_len ) {
2004 /* this shouldn't happen */
2011 if ( sub->sa_any[i].bv_len > left.bv_len ) {
2012 /* not enough left */
2017 match = memcmp( left.bv_val,
2018 sub->sa_any[i].bv_val,
2019 sub->sa_any[i].bv_len );
2027 left.bv_val += sub->sa_any[i].bv_len;
2028 left.bv_len -= sub->sa_any[i].bv_len;
2030 priorspace = ASCII_SPACE(
2031 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
2035 if ( !BER_BVISNULL( &sub->sa_final ) ) {
2036 if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
2037 && ASCII_SPACE( sub->sa_final.bv_val[0] ))
2039 /* allow next space to match */
2044 if ( sub->sa_final.bv_len > left.bv_len ) {
2045 /* not enough left */
2050 match = memcmp( sub->sa_final.bv_val,
2051 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
2052 sub->sa_final.bv_len );
2061 return LDAP_SUCCESS;
2064 #if defined(SLAPD_APPROX_INITIALS)
2065 # define SLAPD_APPROX_DELIMITER "._ "
2066 # define SLAPD_APPROX_WORDLEN 2
2068 # define SLAPD_APPROX_DELIMITER " "
2069 # define SLAPD_APPROX_WORDLEN 1
2078 struct berval *value,
2079 void *assertedValue )
2081 struct berval *nval, *assertv;
2082 char *val, **values, **words, *c;
2083 int i, count, len, nextchunk=0, nextavail=0;
2085 /* Yes, this is necessary */
2086 nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
2087 if( nval == NULL ) {
2089 return LDAP_SUCCESS;
2092 /* Yes, this is necessary */
2093 assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
2094 NULL, LDAP_UTF8_APPROX, NULL );
2095 if( assertv == NULL ) {
2098 return LDAP_SUCCESS;
2101 /* Isolate how many words there are */
2102 for ( c = nval->bv_val, count = 1; *c; c++ ) {
2103 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
2104 if ( c == NULL ) break;
2109 /* Get a phonetic copy of each word */
2110 words = (char **)ch_malloc( count * sizeof(char *) );
2111 values = (char **)ch_malloc( count * sizeof(char *) );
2112 for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) {
2114 values[i] = phonetic(c);
2117 /* Work through the asserted value's words, to see if at least some
2118 * of the words are there, in the same order. */
2120 while ( (ber_len_t) nextchunk < assertv->bv_len ) {
2121 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
2126 #if defined(SLAPD_APPROX_INITIALS)
2127 else if( len == 1 ) {
2128 /* Single letter words need to at least match one word's initial */
2129 for( i=nextavail; i<count; i++ )
2130 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
2137 /* Isolate the next word in the asserted value and phonetic it */
2138 assertv->bv_val[nextchunk+len] = '\0';
2139 val = phonetic( assertv->bv_val + nextchunk );
2141 /* See if this phonetic chunk is in the remaining words of *value */
2142 for( i=nextavail; i<count; i++ ){
2143 if( !strcmp( val, values[i] ) ){
2151 /* This chunk in the asserted value was NOT within the *value. */
2157 /* Go on to the next word in the asserted value */
2161 /* If some of the words were seen, call it a match */
2162 if( nextavail > 0 ) {
2169 /* Cleanup allocs */
2170 ber_bvfree( assertv );
2171 for( i=0; i<count; i++ ) {
2172 ch_free( values[i] );
2178 return LDAP_SUCCESS;
2187 struct berval *prefix,
2193 int i,j, len, wordcount, keycount=0;
2194 struct berval *newkeys;
2195 BerVarray keys=NULL;
2197 for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
2198 struct berval val = BER_BVNULL;
2199 /* Yes, this is necessary */
2200 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
2201 assert( !BER_BVISNULL( &val ) );
2203 /* Isolate how many words there are. There will be a key for each */
2204 for( wordcount = 0, c = val.bv_val; *c; c++) {
2205 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2206 if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
2208 if (*c == '\0') break;
2212 /* Allocate/increase storage to account for new keys */
2213 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
2214 * sizeof(struct berval) );
2215 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
2216 if( keys ) ch_free( keys );
2219 /* Get a phonetic copy of each word */
2220 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
2222 if( len < SLAPD_APPROX_WORDLEN ) continue;
2223 ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
2224 if( keys[keycount].bv_len ) {
2227 ch_free( keys[keycount].bv_val );
2232 ber_memfree( val.bv_val );
2234 BER_BVZERO( &keys[keycount] );
2237 return LDAP_SUCCESS;
2246 struct berval *prefix,
2247 void * assertedValue,
2256 /* Yes, this is necessary */
2257 val = UTF8bvnormalize( ((struct berval *)assertedValue),
2258 NULL, LDAP_UTF8_APPROX, NULL );
2259 if( val == NULL || BER_BVISNULL( val ) ) {
2260 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2261 BER_BVZERO( &keys[0] );
2264 return LDAP_SUCCESS;
2267 /* Isolate how many words there are. There will be a key for each */
2268 for( count = 0,c = val->bv_val; *c; c++) {
2269 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2270 if( len >= SLAPD_APPROX_WORDLEN ) count++;
2272 if (*c == '\0') break;
2276 /* Allocate storage for new keys */
2277 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2279 /* Get a phonetic copy of each word */
2280 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2282 if( len < SLAPD_APPROX_WORDLEN ) continue;
2283 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2289 BER_BVZERO( &keys[count] );
2292 return LDAP_SUCCESS;
2295 /* Remove all spaces and '-' characters */
2297 telephoneNumberNormalize(
2302 struct berval *normalized,
2307 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2309 /* validator should have refused an empty string */
2310 assert( !BER_BVISEMPTY( val ) );
2312 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2314 for( p = val->bv_val; *p; p++ ) {
2315 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
2321 normalized->bv_len = q - normalized->bv_val;
2323 if( BER_BVISEMPTY( normalized ) ) {
2324 slap_sl_free( normalized->bv_val, ctx );
2325 BER_BVZERO( normalized );
2326 return LDAP_INVALID_SYNTAX;
2329 return LDAP_SUCCESS;
2333 postalAddressValidate(
2337 struct berval bv = *in;
2340 for ( c = 0; c < in->bv_len; c++ ) {
2341 if ( in->bv_val[c] == '\\' ) {
2343 if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2344 && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2346 return LDAP_INVALID_SYNTAX;
2351 if ( in->bv_val[c] == '$' ) {
2352 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2353 if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2354 return LDAP_INVALID_SYNTAX;
2356 bv.bv_val = &in->bv_val[c] + 1;
2360 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2361 return UTF8StringValidate( NULL, &bv );
2365 postalAddressNormalize(
2370 struct berval *normalized,
2373 BerVarray lines = NULL, nlines = NULL;
2375 int rc = LDAP_SUCCESS;
2376 MatchingRule *xmr = NULL;
2379 if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2380 xmr = slap_schema.si_mr_caseIgnoreMatch;
2383 xmr = slap_schema.si_mr_caseExactMatch;
2386 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2387 if ( val->bv_val[c] == '$' ) {
2392 lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2393 nlines = &lines[l + 2];
2395 lines[0].bv_val = val->bv_val;
2396 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2397 if ( val->bv_val[c] == '$' ) {
2398 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2400 lines[l].bv_val = &val->bv_val[c + 1];
2403 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2405 normalized->bv_len = c = l;
2407 for ( l = 0; l <= c; l++ ) {
2408 /* NOTE: we directly normalize each line,
2409 * without unescaping the values, since the special
2410 * values '\24' ('$') and '\5C' ('\') are not affected
2411 * by normalization */
2412 if ( !lines[l].bv_len ) {
2413 nlines[l].bv_len = 0;
2414 nlines[l].bv_val = NULL;
2417 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2418 if ( rc != LDAP_SUCCESS ) {
2419 rc = LDAP_INVALID_SYNTAX;
2423 normalized->bv_len += nlines[l].bv_len;
2426 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2428 p = normalized->bv_val;
2429 for ( l = 0; l <= c ; l++ ) {
2430 p = lutil_strbvcopy( p, &nlines[l] );
2435 assert( p == &normalized->bv_val[normalized->bv_len] );
2438 if ( nlines != NULL ) {
2439 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2440 slap_sl_free( nlines[l].bv_val, ctx );
2443 slap_sl_free( lines, ctx );
2454 struct berval val = *in;
2456 if( BER_BVISEMPTY( &val ) ) {
2457 /* disallow empty strings */
2458 return LDAP_INVALID_SYNTAX;
2461 while( OID_LEADCHAR( val.bv_val[0] ) ) {
2462 if ( val.bv_len == 1 ) {
2463 return LDAP_SUCCESS;
2466 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2473 while ( OID_LEADCHAR( val.bv_val[0] )) {
2477 if ( val.bv_len == 0 ) {
2478 return LDAP_SUCCESS;
2482 if( !OID_SEPARATOR( val.bv_val[0] )) {
2490 return LDAP_INVALID_SYNTAX;
2499 struct berval val = *in;
2501 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2503 if ( val.bv_val[0] == '-' ) {
2507 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2508 return LDAP_INVALID_SYNTAX;
2511 if( val.bv_val[0] == '0' ) { /* "-0" */
2512 return LDAP_INVALID_SYNTAX;
2515 } else if ( val.bv_val[0] == '0' ) {
2516 if( val.bv_len > 1 ) { /* "0<more>" */
2517 return LDAP_INVALID_SYNTAX;
2520 return LDAP_SUCCESS;
2523 for( i=0; i < val.bv_len; i++ ) {
2524 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2525 return LDAP_INVALID_SYNTAX;
2529 return LDAP_SUCCESS;
2538 struct berval *value,
2539 void *assertedValue )
2541 struct berval *asserted = (struct berval *) assertedValue;
2542 int vsign = 1, asign = 1; /* default sign = '+' */
2547 if( v.bv_val[0] == '-' ) {
2553 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2556 if( a.bv_val[0] == '-' ) {
2562 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2564 match = vsign - asign;
2566 match = ( v.bv_len != a.bv_len
2567 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2568 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2569 if( vsign < 0 ) match = -match;
2572 /* Ordering rule used in extensible match filter? */
2573 if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2574 match = (match >= 0);
2577 return LDAP_SUCCESS;
2580 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2581 #define INDEX_INTLEN_CHOP 7
2582 #define INDEX_INTLEN_CHOPBYTES 3
2591 /* Integer index key format, designed for memcmp to collate correctly:
2592 * if too large: one's complement sign*<approx exponent=chopped bytes>,
2593 * two's complement value (sign-extended or chopped as needed),
2594 * however in first byte above, the top <number of exponent-bytes + 1>
2595 * bits are the inverse sign and next bit is the sign as delimiter.
2597 ber_slen_t k = index_intlen_strlen;
2599 unsigned signmask = ~0x7fU;
2600 unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2601 struct berval val = *in, itmp = *tmp;
2603 if ( val.bv_val[0] != '-' ) {
2608 /* Chop least significant digits, increase length instead */
2609 if ( val.bv_len > (ber_len_t) k ) {
2610 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2611 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2612 chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
2615 if ( lutil_str2bin( &val, &itmp, ctx )) {
2616 return LDAP_INVALID_SYNTAX;
2619 /* Omit leading sign byte */
2620 if ( itmp.bv_val[0] == neg ) {
2625 k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2627 assert( chop == 0 );
2628 memset( key->bv_val, neg, k ); /* sign-extend */
2629 } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2630 /* Got exponent -k, or no room for 2 sign bits */
2631 lenp = lenbuf + sizeof(lenbuf);
2632 chop = - (ber_len_t) k;
2634 *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2636 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2637 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2638 * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2639 k = (lenbuf + sizeof(lenbuf)) - lenp;
2640 if ( k > (ber_slen_t) index_intlen )
2642 memcpy( key->bv_val, lenp, k );
2643 itmp.bv_len = index_intlen - k;
2645 memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2646 key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2650 /* Index generation function: Ordered index */
2657 struct berval *prefix,
2667 unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2669 /* count the values and find max needed length */
2671 for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2672 if ( vlen < values[i].bv_len )
2673 vlen = values[i].bv_len;
2675 if ( vlen > maxstrlen )
2678 /* we should have at least one value at this point */
2681 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2682 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2683 keys[i].bv_len = index_intlen;
2684 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2687 keys[i].bv_val = NULL;
2689 if ( vlen > sizeof(ibuf) ) {
2690 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2694 itmp.bv_len = sizeof(ibuf);
2696 for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2697 if ( itmp.bv_val != ibuf ) {
2698 itmp.bv_len = values[i].bv_len;
2699 if ( itmp.bv_len <= sizeof(ibuf) )
2700 itmp.bv_len = sizeof(ibuf);
2701 else if ( itmp.bv_len > maxstrlen )
2702 itmp.bv_len = maxstrlen;
2704 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2706 slap_sl_free( keys, ctx );
2712 if ( itmp.bv_val != ibuf ) {
2713 slap_sl_free( itmp.bv_val, ctx );
2718 /* Index generation function: Ordered index */
2725 struct berval *prefix,
2726 void * assertedValue,
2733 struct berval *value;
2736 value = (struct berval *) assertedValue;
2738 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2740 keys[0].bv_len = index_intlen;
2741 keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2743 keys[1].bv_val = NULL;
2745 iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2746 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2747 if ( iv.bv_len > (int) sizeof(ibuf) ) {
2748 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2751 iv.bv_len = sizeof(ibuf);
2754 rc = integerVal2Key( value, keys, &iv, ctx );
2756 if ( iv.bv_val != ibuf ) {
2757 slap_sl_free( iv.bv_val, ctx );
2763 slap_sl_free( keys, ctx );
2769 countryStringValidate(
2771 struct berval *val )
2773 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2775 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2776 return LDAP_INVALID_SYNTAX;
2778 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2779 return LDAP_INVALID_SYNTAX;
2782 return LDAP_SUCCESS;
2786 printableStringValidate(
2788 struct berval *val )
2792 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2794 for(i=0; i < val->bv_len; i++) {
2795 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2796 return LDAP_INVALID_SYNTAX;
2800 return LDAP_SUCCESS;
2804 printablesStringValidate(
2806 struct berval *val )
2810 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2812 for(i=0,len=0; i < val->bv_len; i++) {
2813 int c = val->bv_val[i];
2817 return LDAP_INVALID_SYNTAX;
2821 } else if ( SLAP_PRINTABLE(c) ) {
2824 return LDAP_INVALID_SYNTAX;
2829 return LDAP_INVALID_SYNTAX;
2832 return LDAP_SUCCESS;
2838 struct berval *val )
2842 for(i=0; i < val->bv_len; i++) {
2843 if( !LDAP_ASCII(val->bv_val[i]) ) {
2844 return LDAP_INVALID_SYNTAX;
2848 return LDAP_SUCCESS;
2857 struct berval *normalized,
2861 int casefold = !SLAP_MR_ASSOCIATED( mr,
2862 slap_schema.si_mr_caseExactIA5Match );
2864 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2868 /* Ignore initial whitespace */
2869 while ( ASCII_SPACE( *p ) ) p++;
2871 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2872 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2873 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2874 normalized->bv_val[normalized->bv_len] = '\0';
2876 p = q = normalized->bv_val;
2879 if ( ASCII_SPACE( *p ) ) {
2882 /* Ignore the extra whitespace */
2883 while ( ASCII_SPACE( *p ) ) {
2887 } else if ( casefold ) {
2888 /* Most IA5 rules require casefolding */
2889 *q++ = TOLOWER(*p); p++;
2896 assert( normalized->bv_val <= p );
2900 * If the string ended in space, backup the pointer one
2901 * position. One is enough because the above loop collapsed
2902 * all whitespace to a single space.
2904 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2906 /* null terminate */
2909 normalized->bv_len = q - normalized->bv_val;
2911 return LDAP_SUCCESS;
2920 if( in->bv_len != 36 ) {
2921 return LDAP_INVALID_SYNTAX;
2924 for( i=0; i<36; i++ ) {
2930 if( in->bv_val[i] != '-' ) {
2931 return LDAP_INVALID_SYNTAX;
2935 if( !ASCII_HEX( in->bv_val[i]) ) {
2936 return LDAP_INVALID_SYNTAX;
2941 return LDAP_SUCCESS;
2952 int rc=LDAP_INVALID_SYNTAX;
2954 assert( in != NULL );
2955 assert( out != NULL );
2957 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2960 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2962 for( i=0; i<36; i++ ) {
2968 if( in->bv_val[i] != '-' ) {
2971 out->bv_val[i] = '-';
2975 if( !ASCII_HEX( in->bv_val[i]) ) {
2978 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2983 out->bv_val[ out->bv_len ] = '\0';
2987 slap_sl_free( out->bv_val, ctx );
3000 struct berval *normalized,
3003 unsigned char octet = '\0';
3007 if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
3008 /* NOTE: must be a normalized UUID */
3009 assert( val->bv_len == 16 );
3011 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
3012 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
3013 val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
3014 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
3016 return LDAP_SUCCESS;
3019 normalized->bv_len = 16;
3020 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
3022 for( i=0, j=0; i<36; i++ ) {
3023 unsigned char nibble;
3024 if( val->bv_val[i] == '-' ) {
3027 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
3028 nibble = val->bv_val[i] - '0';
3030 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
3031 nibble = val->bv_val[i] - ('a'-10);
3033 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
3034 nibble = val->bv_val[i] - ('A'-10);
3037 slap_sl_free( normalized->bv_val, ctx );
3038 BER_BVZERO( normalized );
3039 return LDAP_INVALID_SYNTAX;
3044 normalized->bv_val[j>>1] = octet;
3046 octet = nibble << 4;
3051 normalized->bv_val[normalized->bv_len] = 0;
3052 return LDAP_SUCCESS;
3058 numericStringValidate(
3064 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
3066 for(i=0; i < in->bv_len; i++) {
3067 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
3068 return LDAP_INVALID_SYNTAX;
3072 return LDAP_SUCCESS;
3076 numericStringNormalize(
3081 struct berval *normalized,
3084 /* removal all spaces */
3087 assert( !BER_BVISEMPTY( val ) );
3089 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3092 q = normalized->bv_val;
3095 if ( ASCII_SPACE( *p ) ) {
3096 /* Ignore whitespace */
3103 /* we should have copied no more than is in val */
3104 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3106 /* null terminate */
3109 normalized->bv_len = q - normalized->bv_val;
3111 if( BER_BVISEMPTY( normalized ) ) {
3112 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3113 normalized->bv_val[0] = ' ';
3114 normalized->bv_val[1] = '\0';
3115 normalized->bv_len = 1;
3118 return LDAP_SUCCESS;
3122 * Integer conversion macros that will use the largest available
3125 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3126 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
3127 # define SLAP_LONG long long
3129 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
3130 # define SLAP_LONG long
3131 #endif /* HAVE_STRTOLL ... */
3139 struct berval *value,
3140 void *assertedValue )
3142 SLAP_LONG lValue, lAssertedValue;
3145 /* safe to assume integers are NUL terminated? */
3146 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3147 if( errno == ERANGE )
3149 return LDAP_CONSTRAINT_VIOLATION;
3152 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3154 if( errno == ERANGE )
3156 return LDAP_CONSTRAINT_VIOLATION;
3159 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3160 return LDAP_SUCCESS;
3169 struct berval *value,
3170 void *assertedValue )
3172 SLAP_LONG lValue, lAssertedValue;
3175 /* safe to assume integers are NUL terminated? */
3176 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3177 if( errno == ERANGE )
3179 return LDAP_CONSTRAINT_VIOLATION;
3182 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3184 if( errno == ERANGE )
3186 return LDAP_CONSTRAINT_VIOLATION;
3189 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3190 return LDAP_SUCCESS;
3194 checkNum( struct berval *in, struct berval *out )
3196 /* parse serialNumber */
3197 ber_len_t neg = 0, extra = 0;
3200 out->bv_val = in->bv_val;
3203 if ( out->bv_val[0] == '-' ) {
3208 if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3209 first = out->bv_val[2];
3212 out->bv_len += STRLENOF("0x");
3213 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3214 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3217 } else if ( out->bv_val[0] == '\'' ) {
3218 first = out->bv_val[1];
3221 out->bv_len += STRLENOF("'");
3223 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3224 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3226 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3229 out->bv_len += STRLENOF("'H");
3232 first = out->bv_val[0];
3233 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3234 if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3238 if ( !( out->bv_len > neg ) ) {
3242 if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3250 serialNumberAndIssuerCheck(
3258 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3260 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3261 /* Parse old format */
3262 is->bv_val = ber_bvchr( in, '$' );
3263 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3265 sn->bv_val = in->bv_val;
3266 sn->bv_len = is->bv_val - in->bv_val;
3269 is->bv_len = in->bv_len - (sn->bv_len + 1);
3271 /* eat leading zeros */
3272 for( n=0; n < (sn->bv_len-1); n++ ) {
3273 if( sn->bv_val[n] != '0' ) break;
3278 for( n=0; n < sn->bv_len; n++ ) {
3279 if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3283 /* Parse GSER format */
3288 HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3292 struct berval x = *in;
3298 /* eat leading spaces */
3299 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3303 /* should be at issuer or serialNumber NamedValue */
3304 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3305 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3308 x.bv_val += STRLENOF("issuer");
3309 x.bv_len -= STRLENOF("issuer");
3311 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3315 /* eat leading spaces */
3316 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3320 /* For backward compatibility, this part is optional */
3321 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3322 x.bv_val += STRLENOF("rdnSequence:");
3323 x.bv_len -= STRLENOF("rdnSequence:");
3326 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3330 is->bv_val = x.bv_val;
3333 for ( ; is->bv_len < x.bv_len; ) {
3334 if ( is->bv_val[is->bv_len] != '"' ) {
3338 if ( is->bv_val[is->bv_len+1] == '"' ) {
3346 x.bv_val += is->bv_len + 1;
3347 x.bv_len -= is->bv_len + 1;
3349 have |= HAVE_ISSUER;
3351 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3353 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3355 /* parse serialNumber */
3356 x.bv_val += STRLENOF("serialNumber");
3357 x.bv_len -= STRLENOF("serialNumber");
3359 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3363 /* eat leading spaces */
3364 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3368 if ( checkNum( &x, sn ) ) {
3369 return LDAP_INVALID_SYNTAX;
3372 x.bv_val += sn->bv_len;
3373 x.bv_len -= sn->bv_len;
3378 return LDAP_INVALID_SYNTAX;
3381 /* eat leading spaces */
3382 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3386 if ( have == HAVE_ALL ) {
3390 if ( x.bv_val[0] != ',' ) {
3391 return LDAP_INVALID_SYNTAX;
3398 /* should have no characters left... */
3399 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3401 if ( numdquotes == 0 ) {
3402 ber_dupbv_x( &ni, is, ctx );
3407 ni.bv_len = is->bv_len - numdquotes;
3408 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3409 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3410 if ( is->bv_val[src] == '"' ) {
3413 ni.bv_val[dst] = is->bv_val[src];
3415 ni.bv_val[dst] = '\0';
3425 serialNumberAndIssuerValidate(
3430 struct berval sn, i;
3432 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3435 rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3440 /* validate DN -- doesn't handle double dquote */
3441 rc = dnValidate( NULL, &i );
3443 rc = LDAP_INVALID_SYNTAX;
3446 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3447 slap_sl_free( i.bv_val, NULL );
3450 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3451 in->bv_val, rc, 0 );
3458 serialNumberAndIssuerPretty(
3465 struct berval sn, i, ni = BER_BVNULL;
3468 assert( in != NULL );
3469 assert( out != NULL );
3473 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3476 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3481 rc = dnPretty( syntax, &i, &ni, ctx );
3483 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3484 slap_sl_free( i.bv_val, ctx );
3488 rc = LDAP_INVALID_SYNTAX;
3492 /* make room from sn + "$" */
3493 out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3494 + sn.bv_len + ni.bv_len;
3495 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3497 if ( out->bv_val == NULL ) {
3504 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3505 p = lutil_strbvcopy( p, &sn );
3506 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3507 p = lutil_strbvcopy( p, &ni );
3508 p = lutil_strcopy( p, /*{*/ "\" }" );
3510 assert( p == &out->bv_val[out->bv_len] );
3513 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3514 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3516 slap_sl_free( ni.bv_val, ctx );
3518 return LDAP_SUCCESS;
3528 /* Use hex format. '123456789abcdef'H */
3529 unsigned char *ptr, zero = '\0';
3532 ber_len_t i, len, nlen;
3534 assert( in != NULL );
3535 assert( !BER_BVISNULL( in ) );
3536 assert( out != NULL );
3537 assert( !BER_BVISNULL( out ) );
3539 ptr = (unsigned char *)in->bv_val;
3542 /* Check for minimal encodings */
3544 if ( ptr[0] & 0x80 ) {
3545 if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3549 } else if ( ptr[0] == 0 ) {
3550 if ( !( ptr[1] & 0x80 ) ) {
3557 } else if ( len == 0 ) {
3558 /* FIXME: this should not be possible,
3559 * since a value of zero would have length 1 */
3564 first = !( ptr[0] & 0xf0U );
3565 nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3566 if ( nlen >= out->bv_len ) {
3567 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3573 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3577 for ( ; i < len; i++ ) {
3578 sprintf( sptr, "%02X", ptr[i] );
3585 assert( sptr == &out->bv_val[nlen] );
3592 #define SLAP_SN_BUFLEN (64)
3595 * This routine is called by certificateExactNormalize when
3596 * certificateExactNormalize receives a search string instead of
3597 * a certificate. This routine checks if the search value is valid
3598 * and then returns the normalized value
3601 serialNumberAndIssuerNormalize(
3609 struct berval sn, sn2, sn3, i, ni;
3610 char sbuf2[SLAP_SN_BUFLEN];
3611 char sbuf3[SLAP_SN_BUFLEN];
3615 assert( in != NULL );
3616 assert( out != NULL );
3618 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3621 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3626 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3628 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3629 slap_sl_free( i.bv_val, ctx );
3633 return LDAP_INVALID_SYNTAX;
3636 /* Convert sn to canonical hex */
3638 if ( sn.bv_len > sizeof( sbuf2 ) ) {
3639 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3641 sn2.bv_len = sn.bv_len;
3643 sn3.bv_len = sizeof(sbuf3);
3644 if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
3645 rc = LDAP_INVALID_SYNTAX;
3649 out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3650 + sn3.bv_len + ni.bv_len;
3651 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3652 if ( out->bv_val == NULL ) {
3660 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3661 p = lutil_strbvcopy( p, &sn3 );
3662 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3663 p = lutil_strbvcopy( p, &ni );
3664 p = lutil_strcopy( p, /*{*/ "\" }" );
3666 assert( p == &out->bv_val[out->bv_len] );
3669 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3670 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3672 if ( sn2.bv_val != sbuf2 ) {
3673 slap_sl_free( sn2.bv_val, ctx );
3676 if ( sn3.bv_val != sbuf3 ) {
3677 slap_sl_free( sn3.bv_val, ctx );
3680 slap_sl_free( ni.bv_val, ctx );
3686 certificateExactNormalize(
3691 struct berval *normalized,
3694 BerElementBuffer berbuf;
3695 BerElement *ber = (BerElement *)&berbuf;
3699 char serialbuf2[SLAP_SN_BUFLEN];
3700 struct berval sn, sn2 = BER_BVNULL;
3701 struct berval issuer_dn = BER_BVNULL, bvdn;
3703 int rc = LDAP_INVALID_SYNTAX;
3705 assert( val != NULL );
3707 Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3708 val->bv_val, val->bv_len, 0 );
3710 if ( BER_BVISEMPTY( val ) ) goto done;
3712 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3713 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3716 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3718 ber_init2( ber, val, LBER_USE_DER );
3719 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3720 tag = ber_skip_tag( ber, &len ); /* Sequence */
3721 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3722 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3723 tag = ber_skip_tag( ber, &len );
3724 tag = ber_get_int( ber, &i ); /* version */
3727 /* NOTE: move the test here from certificateValidate,
3728 * so that we can validate certs with serial longer
3729 * than sizeof(ber_int_t) */
3730 tag = ber_skip_tag( ber, &len ); /* serial */
3732 sn.bv_val = (char *)ber->ber_ptr;
3733 sn2.bv_val = serialbuf2;
3734 sn2.bv_len = sizeof(serialbuf2);
3735 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3736 rc = LDAP_INVALID_SYNTAX;
3739 ber_skip_data( ber, len );
3741 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3742 ber_skip_data( ber, len );
3743 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3745 len = ber_ptrlen( ber );
3746 bvdn.bv_val = val->bv_val + len;
3747 bvdn.bv_len = val->bv_len - len;
3749 rc = dnX509normalize( &bvdn, &issuer_dn );
3750 if ( rc != LDAP_SUCCESS ) goto done;
3753 normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3754 + sn2.bv_len + issuer_dn.bv_len;
3755 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3757 p = normalized->bv_val;
3759 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3760 p = lutil_strbvcopy( p, &sn2 );
3761 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3762 p = lutil_strbvcopy( p, &issuer_dn );
3763 p = lutil_strcopy( p, /*{*/ "\" }" );
3768 Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3769 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3771 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3772 if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3777 /* X.509 PKI certificateList stuff */
3779 checkTime( struct berval *in, struct berval *out )
3783 char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3786 assert( in != NULL );
3787 assert( !BER_BVISNULL( in ) );
3788 assert( !BER_BVISEMPTY( in ) );
3790 if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3794 if ( out != NULL ) {
3795 assert( !BER_BVISNULL( out ) );
3796 assert( out->bv_len >= sizeof( buf ) );
3797 bv.bv_val = out->bv_val;
3803 for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3804 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3807 if ( in->bv_val[i] != 'Z' ) {
3812 if ( i != in->bv_len ) {
3816 if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3817 lutil_strncopy( bv.bv_val, in->bv_val, i );
3820 } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3821 char *p = bv.bv_val;
3822 if ( in->bv_val[0] < '7' ) {
3823 p = lutil_strcopy( p, "20" );
3826 p = lutil_strcopy( p, "19" );
3828 lutil_strncopy( p, in->bv_val, i );
3835 rc = generalizedTimeValidate( NULL, &bv );
3836 if ( rc == LDAP_SUCCESS && out != NULL ) {
3837 if ( out->bv_len > bv.bv_len ) {
3838 out->bv_val[ bv.bv_len ] = '\0';
3840 out->bv_len = bv.bv_len;
3843 return rc != LDAP_SUCCESS;
3847 issuerAndThisUpdateCheck(
3854 struct berval x = *in;
3855 struct berval ni = BER_BVNULL;
3856 /* Parse GSER format */
3860 HAVE_THISUPDATE = 0x2,
3861 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3865 if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3867 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3868 return LDAP_INVALID_SYNTAX;
3872 x.bv_len -= STRLENOF("{}");
3875 /* eat leading spaces */
3876 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3880 /* should be at issuer or thisUpdate */
3881 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3882 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3885 x.bv_val += STRLENOF("issuer");
3886 x.bv_len -= STRLENOF("issuer");
3888 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3892 /* eat leading spaces */
3893 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3897 /* For backward compatibility, this part is optional */
3898 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3899 return LDAP_INVALID_SYNTAX;
3901 x.bv_val += STRLENOF("rdnSequence:");
3902 x.bv_len -= STRLENOF("rdnSequence:");
3904 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3908 is->bv_val = x.bv_val;
3911 for ( ; is->bv_len < x.bv_len; ) {
3912 if ( is->bv_val[is->bv_len] != '"' ) {
3916 if ( is->bv_val[is->bv_len+1] == '"' ) {
3924 x.bv_val += is->bv_len + 1;
3925 x.bv_len -= is->bv_len + 1;
3927 have |= HAVE_ISSUER;
3929 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3931 if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3933 /* parse thisUpdate */
3934 x.bv_val += STRLENOF("thisUpdate");
3935 x.bv_len -= STRLENOF("thisUpdate");
3937 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3941 /* eat leading spaces */
3942 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3946 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3950 tu->bv_val = x.bv_val;
3953 for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3954 if ( tu->bv_val[tu->bv_len] == '"' ) {
3958 x.bv_val += tu->bv_len + 1;
3959 x.bv_len -= tu->bv_len + 1;
3961 have |= HAVE_THISUPDATE;
3964 return LDAP_INVALID_SYNTAX;
3967 /* eat leading spaces */
3968 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3972 if ( have == HAVE_ALL ) {
3976 if ( x.bv_val[0] != ',' ) {
3977 return LDAP_INVALID_SYNTAX;
3984 /* should have no characters left... */
3985 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3987 if ( numdquotes == 0 ) {
3988 ber_dupbv_x( &ni, is, ctx );
3993 ni.bv_len = is->bv_len - numdquotes;
3994 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3995 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3996 if ( is->bv_val[src] == '"' ) {
3999 ni.bv_val[dst] = is->bv_val[src];
4001 ni.bv_val[dst] = '\0';
4010 issuerAndThisUpdateValidate(
4015 struct berval i, tu;
4017 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
4020 rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
4025 /* validate DN -- doesn't handle double dquote */
4026 rc = dnValidate( NULL, &i );
4028 rc = LDAP_INVALID_SYNTAX;
4030 } else if ( checkTime( &tu, NULL ) ) {
4031 rc = LDAP_INVALID_SYNTAX;
4034 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4035 slap_sl_free( i.bv_val, NULL );
4038 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
4039 in->bv_val, rc, 0 );
4046 issuerAndThisUpdatePretty(
4053 struct berval i, tu, ni = BER_BVNULL;
4056 assert( in != NULL );
4057 assert( out != NULL );
4061 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
4064 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4069 rc = dnPretty( syntax, &i, &ni, ctx );
4071 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4072 slap_sl_free( i.bv_val, ctx );
4075 if ( rc || checkTime( &tu, NULL ) ) {
4076 rc = LDAP_INVALID_SYNTAX;
4081 out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
4082 + ni.bv_len + tu.bv_len;
4083 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4085 if ( out->bv_val == NULL ) {
4092 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4093 p = lutil_strbvcopy( p, &ni );
4094 p = lutil_strcopy( p, "\", thisUpdate \"" );
4095 p = lutil_strbvcopy( p, &tu );
4096 p = lutil_strcopy( p, /*{*/ "\" }" );
4098 assert( p == &out->bv_val[out->bv_len] );
4101 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4102 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4104 slap_sl_free( ni.bv_val, ctx );
4110 issuerAndThisUpdateNormalize(
4118 struct berval i, ni, tu, tu2;
4119 char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4123 assert( in != NULL );
4124 assert( out != NULL );
4126 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4129 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4134 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4136 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4137 slap_sl_free( i.bv_val, ctx );
4141 tu2.bv_len = sizeof( sbuf );
4142 if ( rc || checkTime( &tu, &tu2 ) ) {
4143 return LDAP_INVALID_SYNTAX;
4146 out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4147 + ni.bv_len + tu2.bv_len;
4148 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4150 if ( out->bv_val == NULL ) {
4158 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4159 p = lutil_strbvcopy( p, &ni );
4160 p = lutil_strcopy( p, "\", thisUpdate \"" );
4161 p = lutil_strbvcopy( p, &tu2 );
4162 p = lutil_strcopy( p, /*{*/ "\" }" );
4164 assert( p == &out->bv_val[out->bv_len] );
4167 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4168 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4170 slap_sl_free( ni.bv_val, ctx );
4176 certificateListExactNormalize(
4181 struct berval *normalized,
4184 BerElementBuffer berbuf;
4185 BerElement *ber = (BerElement *)&berbuf;
4189 struct berval issuer_dn = BER_BVNULL, bvdn,
4191 char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4192 int rc = LDAP_INVALID_SYNTAX;
4194 assert( val != NULL );
4196 Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4197 val->bv_val, val->bv_len, 0 );
4199 if ( BER_BVISEMPTY( val ) ) goto done;
4201 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4202 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4205 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4207 ber_init2( ber, val, LBER_USE_DER );
4208 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
4209 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4210 tag = ber_skip_tag( ber, &len ); /* Sequence */
4211 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4212 tag = ber_peek_tag( ber, &len );
4213 /* Optional version */
4214 if ( tag == LBER_INTEGER ) {
4215 tag = ber_get_int( ber, &version );
4216 assert( tag == LBER_INTEGER );
4217 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4219 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
4220 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4221 ber_skip_data( ber, len );
4223 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
4224 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4225 len = ber_ptrlen( ber );
4226 bvdn.bv_val = val->bv_val + len;
4227 bvdn.bv_len = val->bv_len - len;
4228 tag = ber_skip_tag( ber, &len );
4229 ber_skip_data( ber, len );
4231 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
4232 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4233 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4234 bvtu.bv_val = (char *)ber->ber_ptr;
4237 rc = dnX509normalize( &bvdn, &issuer_dn );
4238 if ( rc != LDAP_SUCCESS ) goto done;
4240 thisUpdate.bv_val = tubuf;
4241 thisUpdate.bv_len = sizeof(tubuf);
4242 if ( checkTime( &bvtu, &thisUpdate ) ) {
4243 rc = LDAP_INVALID_SYNTAX;
4247 normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4248 + issuer_dn.bv_len + thisUpdate.bv_len;
4249 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4251 p = normalized->bv_val;
4253 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4254 p = lutil_strbvcopy( p, &issuer_dn );
4255 p = lutil_strcopy( p, "\", thisUpdate \"" );
4256 p = lutil_strbvcopy( p, &thisUpdate );
4257 p = lutil_strcopy( p, /*{*/ "\" }" );
4262 Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4263 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4265 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4270 /* X.509 PMI serialNumberAndIssuerSerialCheck
4272 AttributeCertificateExactAssertion ::= SEQUENCE {
4273 serialNumber CertificateSerialNumber,
4274 issuer AttCertIssuer }
4276 CertificateSerialNumber ::= INTEGER
4278 AttCertIssuer ::= [0] SEQUENCE {
4279 issuerName GeneralNames OPTIONAL,
4280 baseCertificateID [0] IssuerSerial OPTIONAL,
4281 objectDigestInfo [1] ObjectDigestInfo OPTIONAL }
4282 -- At least one component shall be present
4284 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4286 GeneralName ::= CHOICE {
4287 otherName [0] INSTANCE OF OTHER-NAME,
4288 rfc822Name [1] IA5String,
4289 dNSName [2] IA5String,
4290 x400Address [3] ORAddress,
4291 directoryName [4] Name,
4292 ediPartyName [5] EDIPartyName,
4293 uniformResourceIdentifier [6] IA5String,
4294 iPAddress [7] OCTET STRING,
4295 registeredID [8] OBJECT IDENTIFIER }
4297 IssuerSerial ::= SEQUENCE {
4298 issuer GeneralNames,
4299 serial CertificateSerialNumber,
4300 issuerUID UniqueIdentifier OPTIONAL }
4302 ObjectDigestInfo ::= SEQUENCE {
4303 digestedObjectType ENUMERATED {
4306 otherObjectTypes (2) },
4307 otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
4308 digestAlgorithm AlgorithmIdentifier,
4309 objectDigest BIT STRING }
4311 * The way I interpret it, an assertion should look like
4313 { serialNumber 'dd'H,
4314 issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4315 baseCertificateID { serial '1d'H,
4316 issuer { directoryName:rdnSequence:"cn=zzz" },
4317 issuerUID <value> -- optional
4319 objectDigestInfo { ... } -- optional
4323 * with issuerName, baseCertificateID and objectDigestInfo optional,
4324 * at least one present; the way it's currently implemented, it is
4326 { serialNumber 'dd'H,
4327 issuer { baseCertificateID { serial '1d'H,
4328 issuer { directoryName:rdnSequence:"cn=zzz" }
4333 * with all the above parts mandatory.
4336 serialNumberAndIssuerSerialCheck(
4340 struct berval *i_sn, /* contain serial of baseCertificateID */
4343 /* Parse GSER format */
4348 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4349 } have = HAVE_NONE, have2 = HAVE_NONE;
4351 struct berval x = *in;
4354 if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4357 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4364 /* eat leading spaces */
4365 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4369 /* should be at issuer or serialNumber NamedValue */
4370 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4371 if ( have & HAVE_ISSUER ) {
4372 return LDAP_INVALID_SYNTAX;
4375 /* parse IssuerSerial */
4376 x.bv_val += STRLENOF("issuer");
4377 x.bv_len -= STRLENOF("issuer");
4379 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4383 /* eat leading spaces */
4384 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4388 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4392 /* eat leading spaces */
4393 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4397 if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4398 return LDAP_INVALID_SYNTAX;
4400 x.bv_val += STRLENOF("baseCertificateID ");
4401 x.bv_len -= STRLENOF("baseCertificateID ");
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;
4413 /* eat leading spaces */
4414 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4418 /* parse issuer of baseCertificateID */
4419 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4420 if ( have2 & HAVE_ISSUER ) {
4421 return LDAP_INVALID_SYNTAX;
4424 x.bv_val += STRLENOF("issuer ");
4425 x.bv_len -= STRLENOF("issuer ");
4427 /* eat leading spaces */
4428 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4432 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4436 /* eat leading spaces */
4437 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4441 if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4442 return LDAP_INVALID_SYNTAX;
4444 x.bv_val += STRLENOF("directoryName:rdnSequence:");
4445 x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4447 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4451 is->bv_val = x.bv_val;
4454 for ( ; is->bv_len < x.bv_len; ) {
4455 if ( is->bv_val[is->bv_len] != '"' ) {
4459 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4467 x.bv_val += is->bv_len + 1;
4468 x.bv_len -= is->bv_len + 1;
4470 /* eat leading spaces */
4471 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4475 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4479 have2 |= HAVE_ISSUER;
4481 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4482 if ( have2 & HAVE_SN ) {
4483 return LDAP_INVALID_SYNTAX;
4486 x.bv_val += STRLENOF("serial ");
4487 x.bv_len -= STRLENOF("serial ");
4489 /* eat leading spaces */
4490 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4494 if ( checkNum( &x, i_sn ) ) {
4495 return LDAP_INVALID_SYNTAX;
4498 x.bv_val += i_sn->bv_len;
4499 x.bv_len -= i_sn->bv_len;
4504 return LDAP_INVALID_SYNTAX;
4507 /* eat leading spaces */
4508 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4512 if ( have2 == HAVE_ALL ) {
4516 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4521 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4525 /* eat leading spaces */
4526 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4530 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4534 have |= HAVE_ISSUER;
4536 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4537 if ( have & HAVE_SN ) {
4538 return LDAP_INVALID_SYNTAX;
4541 /* parse serialNumber */
4542 x.bv_val += STRLENOF("serialNumber");
4543 x.bv_len -= STRLENOF("serialNumber");
4545 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4549 /* eat leading spaces */
4550 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4554 if ( checkNum( &x, sn ) ) {
4555 return LDAP_INVALID_SYNTAX;
4558 x.bv_val += sn->bv_len;
4559 x.bv_len -= sn->bv_len;
4564 return LDAP_INVALID_SYNTAX;
4568 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4572 if ( have == HAVE_ALL ) {
4576 if ( x.bv_val[0] != ',' ) {
4577 return LDAP_INVALID_SYNTAX;
4583 /* should have no characters left... */
4584 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4586 if ( numdquotes == 0 ) {
4587 ber_dupbv_x( &ni, is, ctx );
4592 ni.bv_len = is->bv_len - numdquotes;
4593 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4594 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4595 if ( is->bv_val[src] == '"' ) {
4598 ni.bv_val[dst] = is->bv_val[src];
4600 ni.bv_val[dst] = '\0';
4605 /* need to handle double dquotes here */
4609 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4611 serialNumberAndIssuerSerialValidate(
4616 struct berval sn, i, i_sn;
4618 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4621 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4626 /* validate DN -- doesn't handle double dquote */
4627 rc = dnValidate( NULL, &i );
4629 rc = LDAP_INVALID_SYNTAX;
4632 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4633 slap_sl_free( i.bv_val, NULL );
4637 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4638 in->bv_val, rc, 0 );
4643 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4645 serialNumberAndIssuerSerialPretty(
4651 struct berval sn, i, i_sn, ni = BER_BVNULL;
4655 assert( in != NULL );
4656 assert( out != NULL );
4658 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4661 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4666 rc = dnPretty( syntax, &i, &ni, ctx );
4668 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4669 slap_sl_free( i.bv_val, ctx );
4673 rc = LDAP_INVALID_SYNTAX;
4677 /* make room from sn + "$" */
4678 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4679 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4680 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4682 if ( out->bv_val == NULL ) {
4689 p = lutil_strcopy( p, "{ serialNumber " );
4690 p = lutil_strbvcopy( p, &sn );
4691 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4692 p = lutil_strbvcopy( p, &ni );
4693 p = lutil_strcopy( p, "\" }, serial " );
4694 p = lutil_strbvcopy( p, &i_sn );
4695 p = lutil_strcopy( p, " } } }" );
4697 assert( p == &out->bv_val[out->bv_len] );
4700 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4701 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4703 slap_sl_free( ni.bv_val, ctx );
4708 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4710 * This routine is called by attributeCertificateExactNormalize
4711 * when attributeCertificateExactNormalize receives a search
4712 * string instead of a attribute certificate. This routine
4713 * checks if the search value is valid and then returns the
4717 serialNumberAndIssuerSerialNormalize(
4725 struct berval i, ni = BER_BVNULL,
4726 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4727 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4728 char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4729 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4733 assert( in != NULL );
4734 assert( out != NULL );
4736 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4739 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4744 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4746 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4747 slap_sl_free( i.bv_val, ctx );
4751 rc = LDAP_INVALID_SYNTAX;
4755 /* Convert sn to canonical hex */
4757 sn2.bv_len = sn.bv_len;
4758 if ( sn.bv_len > sizeof( sbuf2 ) ) {
4759 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4761 if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4762 rc = LDAP_INVALID_SYNTAX;
4766 /* Convert i_sn to canonical hex */
4767 i_sn2.bv_val = i_sbuf2;
4768 i_sn2.bv_len = i_sn.bv_len;
4769 if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4770 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4772 if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4773 rc = LDAP_INVALID_SYNTAX;
4778 sn3.bv_len = sizeof(sbuf3);
4779 if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4780 rc = LDAP_INVALID_SYNTAX;
4784 i_sn3.bv_val = i_sbuf3;
4785 i_sn3.bv_len = sizeof(i_sbuf3);
4786 if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4787 rc = LDAP_INVALID_SYNTAX;
4791 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4792 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4793 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4795 if ( out->bv_val == NULL ) {
4803 p = lutil_strcopy( p, "{ serialNumber " );
4804 p = lutil_strbvcopy( p, &sn3 );
4805 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4806 p = lutil_strbvcopy( p, &ni );
4807 p = lutil_strcopy( p, "\" }, serial " );
4808 p = lutil_strbvcopy( p, &i_sn3 );
4809 p = lutil_strcopy( p, " } } }" );
4811 assert( p == &out->bv_val[out->bv_len] );
4814 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4815 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4817 if ( sn2.bv_val != sbuf2 ) {
4818 slap_sl_free( sn2.bv_val, ctx );
4821 if ( i_sn2.bv_val != i_sbuf2 ) {
4822 slap_sl_free( i_sn2.bv_val, ctx );
4825 if ( sn3.bv_val != sbuf3 ) {
4826 slap_sl_free( sn3.bv_val, ctx );
4829 if ( i_sn3.bv_val != i_sbuf3 ) {
4830 slap_sl_free( i_sn3.bv_val, ctx );
4833 slap_sl_free( ni.bv_val, ctx );
4838 /* X.509 PMI attributeCertificateExactNormalize */
4840 attributeCertificateExactNormalize(
4845 struct berval *normalized,
4848 BerElementBuffer berbuf;
4849 BerElement *ber = (BerElement *)&berbuf;
4852 char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4853 struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4854 struct berval issuer_dn = BER_BVNULL, bvdn;
4856 int rc = LDAP_INVALID_SYNTAX;
4858 if ( BER_BVISEMPTY( val ) ) {
4862 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4863 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4866 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4868 ber_init2( ber, val, LBER_USE_DER );
4869 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
4870 tag = ber_skip_tag( ber, &len ); /* Sequence */
4871 tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */
4872 ber_skip_data( ber, len );
4873 tag = ber_skip_tag( ber, &len ); /* Holder Sequence */
4874 ber_skip_data( ber, len );
4877 tag = ber_skip_tag( ber, &len ); /* Sequence */
4878 /* issuerName (GeneralNames sequence; optional)? */
4879 tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */
4880 tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */
4881 tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */
4882 if ( tag != SLAP_X509_GN_DIRECTORYNAME ) {
4883 return LDAP_INVALID_SYNTAX;
4885 tag = ber_peek_tag( ber, &len ); /* sequence of RDN */
4886 len = ber_ptrlen( ber );
4887 bvdn.bv_val = val->bv_val + len;
4888 bvdn.bv_len = val->bv_len - len;
4889 rc = dnX509normalize( &bvdn, &issuer_dn );
4890 if ( rc != LDAP_SUCCESS ) goto done;
4892 tag = ber_skip_tag( ber, &len ); /* sequence of RDN */
4893 ber_skip_data( ber, len );
4894 tag = ber_skip_tag( ber, &len ); /* serial number */
4895 if ( tag != LBER_INTEGER ) {
4896 rc = LDAP_INVALID_SYNTAX;
4899 i_sn.bv_val = (char *)ber->ber_ptr;
4901 i_sn2.bv_val = issuer_serialbuf;
4902 i_sn2.bv_len = sizeof(issuer_serialbuf);
4903 if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4904 rc = LDAP_INVALID_SYNTAX;
4907 ber_skip_data( ber, len );
4909 /* issuerUID (bitstring; optional)? */
4910 /* objectDigestInfo (sequence; optional)? */
4912 tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */
4913 ber_skip_data( ber, len );
4914 tag = ber_skip_tag( ber, &len ); /* serial number */
4915 if ( tag != LBER_INTEGER ) {
4916 rc = LDAP_INVALID_SYNTAX;
4919 sn.bv_val = (char *)ber->ber_ptr;
4921 sn2.bv_val = serialbuf;
4922 sn2.bv_len = sizeof(serialbuf);
4923 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4924 rc = LDAP_INVALID_SYNTAX;
4927 ber_skip_data( ber, len );
4929 normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" )
4930 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4931 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4933 p = normalized->bv_val;
4935 p = lutil_strcopy( p, "{ serialNumber " );
4936 p = lutil_strbvcopy( p, &sn2 );
4937 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4938 p = lutil_strbvcopy( p, &issuer_dn );
4939 p = lutil_strcopy( p, "\" }, serial " );
4940 p = lutil_strbvcopy( p, &i_sn2 );
4941 p = lutil_strcopy( p, " } } }" );
4943 Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4944 normalized->bv_val, NULL, NULL );
4949 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4950 if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4951 if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4964 assert( in != NULL );
4965 assert( !BER_BVISNULL( in ) );
4967 for ( i = 0; i < in->bv_len; i++ ) {
4968 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4969 return LDAP_INVALID_SYNTAX;
4973 return LDAP_SUCCESS;
4976 /* Normalize a SID as used inside a CSN:
4977 * three-digit numeric string */
4984 struct berval *normalized,
4989 assert( val != NULL );
4990 assert( normalized != NULL );
4992 ber_dupbv_x( normalized, val, ctx );
4994 for ( i = 0; i < normalized->bv_len; i++ ) {
4995 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4996 ber_memfree_x( normalized->bv_val, ctx );
4997 BER_BVZERO( normalized );
4998 return LDAP_INVALID_SYNTAX;
5001 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5004 return LDAP_SUCCESS;
5012 assert( in != NULL );
5013 assert( !BER_BVISNULL( in ) );
5015 if ( in->bv_len != 3 ) {
5016 return LDAP_INVALID_SYNTAX;
5019 return hexValidate( NULL, in );
5022 /* Normalize a SID as used inside a CSN:
5023 * three-digit numeric string */
5030 struct berval *normalized,
5033 if ( val->bv_len != 3 ) {
5034 return LDAP_INVALID_SYNTAX;
5037 return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
5047 return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5050 /* Normalize a SID as used inside a CSN, either as-is
5051 * (assertion value) or extracted from the CSN
5052 * (attribute value) */
5059 struct berval *normalized,
5067 if ( BER_BVISEMPTY( val ) ) {
5068 return LDAP_INVALID_SYNTAX;
5071 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
5072 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
5075 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
5077 ptr = ber_bvchr( val, '#' );
5078 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5079 return LDAP_INVALID_SYNTAX;
5082 bv.bv_val = ptr + 1;
5083 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5085 ptr = ber_bvchr( &bv, '#' );
5086 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5087 return LDAP_INVALID_SYNTAX;
5090 bv.bv_val = ptr + 1;
5091 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5093 ptr = ber_bvchr( &bv, '#' );
5094 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5095 return LDAP_INVALID_SYNTAX;
5098 bv.bv_len = ptr - bv.bv_val;
5100 if ( bv.bv_len == 2 ) {
5101 /* OpenLDAP 2.3 SID */
5103 buf[ 1 ] = bv.bv_val[ 0 ];
5104 buf[ 2 ] = bv.bv_val[ 1 ];
5111 return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5123 assert( in != NULL );
5124 assert( !BER_BVISNULL( in ) );
5126 if ( BER_BVISEMPTY( in ) ) {
5127 return LDAP_INVALID_SYNTAX;
5132 ptr = ber_bvchr( &bv, '#' );
5133 if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5134 return LDAP_INVALID_SYNTAX;
5137 bv.bv_len = ptr - bv.bv_val;
5138 if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5139 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5141 return LDAP_INVALID_SYNTAX;
5144 rc = generalizedTimeValidate( NULL, &bv );
5145 if ( rc != LDAP_SUCCESS ) {
5149 bv.bv_val = ptr + 1;
5150 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5152 ptr = ber_bvchr( &bv, '#' );
5153 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5154 return LDAP_INVALID_SYNTAX;
5157 bv.bv_len = ptr - bv.bv_val;
5158 if ( bv.bv_len != 6 ) {
5159 return LDAP_INVALID_SYNTAX;
5162 rc = hexValidate( NULL, &bv );
5163 if ( rc != LDAP_SUCCESS ) {
5167 bv.bv_val = ptr + 1;
5168 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5170 ptr = ber_bvchr( &bv, '#' );
5171 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5172 return LDAP_INVALID_SYNTAX;
5175 bv.bv_len = ptr - bv.bv_val;
5176 if ( bv.bv_len == 2 ) {
5177 /* tolerate old 2-digit replica-id */
5178 rc = hexValidate( NULL, &bv );
5181 rc = sidValidate( NULL, &bv );
5183 if ( rc != LDAP_SUCCESS ) {
5187 bv.bv_val = ptr + 1;
5188 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5190 if ( bv.bv_len != 6 ) {
5191 return LDAP_INVALID_SYNTAX;
5194 return hexValidate( NULL, &bv );
5197 /* Normalize a CSN in OpenLDAP 2.1 format */
5204 struct berval *normalized,
5207 struct berval gt, cnt, sid, mod;
5209 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5213 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5214 assert( !BER_BVISEMPTY( val ) );
5218 ptr = ber_bvchr( >, '#' );
5219 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5220 return LDAP_INVALID_SYNTAX;
5223 gt.bv_len = ptr - gt.bv_val;
5224 if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5225 return LDAP_INVALID_SYNTAX;
5228 if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5229 return LDAP_INVALID_SYNTAX;
5232 cnt.bv_val = ptr + 1;
5233 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5235 ptr = ber_bvchr( &cnt, '#' );
5236 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5237 return LDAP_INVALID_SYNTAX;
5240 cnt.bv_len = ptr - cnt.bv_val;
5241 if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5242 return LDAP_INVALID_SYNTAX;
5245 if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5246 return LDAP_INVALID_SYNTAX;
5249 cnt.bv_val += STRLENOF( "0x" );
5250 cnt.bv_len -= STRLENOF( "0x" );
5252 sid.bv_val = ptr + 1;
5253 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5255 ptr = ber_bvchr( &sid, '#' );
5256 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5257 return LDAP_INVALID_SYNTAX;
5260 sid.bv_len = ptr - sid.bv_val;
5261 if ( sid.bv_len != STRLENOF( "0" ) ) {
5262 return LDAP_INVALID_SYNTAX;
5265 mod.bv_val = ptr + 1;
5266 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5267 if ( mod.bv_len != STRLENOF( "0000" ) ) {
5268 return LDAP_INVALID_SYNTAX;
5271 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5275 ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5276 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5278 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5280 ptr = lutil_strcopy( ptr, ".000000Z#00" );
5281 ptr = lutil_strbvcopy( ptr, &cnt );
5285 *ptr++ = sid.bv_val[ 0 ];
5289 for ( i = 0; i < mod.bv_len; i++ ) {
5290 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5294 assert( ptr == &bv.bv_val[bv.bv_len] );
5296 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5297 return LDAP_INVALID_SYNTAX;
5300 ber_dupbv_x( normalized, &bv, ctx );
5302 return LDAP_SUCCESS;
5305 /* Normalize a CSN in OpenLDAP 2.3 format */
5312 struct berval *normalized,
5315 struct berval gt, cnt, sid, mod;
5317 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5321 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5322 assert( !BER_BVISEMPTY( val ) );
5326 ptr = ber_bvchr( >, '#' );
5327 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5328 return LDAP_INVALID_SYNTAX;
5331 gt.bv_len = ptr - gt.bv_val;
5332 if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5333 return LDAP_INVALID_SYNTAX;
5336 cnt.bv_val = ptr + 1;
5337 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5339 ptr = ber_bvchr( &cnt, '#' );
5340 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5341 return LDAP_INVALID_SYNTAX;
5344 cnt.bv_len = ptr - cnt.bv_val;
5345 if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5346 return LDAP_INVALID_SYNTAX;
5349 sid.bv_val = ptr + 1;
5350 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5352 ptr = ber_bvchr( &sid, '#' );
5353 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5354 return LDAP_INVALID_SYNTAX;
5357 sid.bv_len = ptr - sid.bv_val;
5358 if ( sid.bv_len != STRLENOF( "00" ) ) {
5359 return LDAP_INVALID_SYNTAX;
5362 mod.bv_val = ptr + 1;
5363 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5364 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5365 return LDAP_INVALID_SYNTAX;
5368 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5372 ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5373 ptr = lutil_strcopy( ptr, ".000000Z#" );
5374 ptr = lutil_strbvcopy( ptr, &cnt );
5377 for ( i = 0; i < sid.bv_len; i++ ) {
5378 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5381 for ( i = 0; i < mod.bv_len; i++ ) {
5382 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5386 assert( ptr == &bv.bv_val[bv.bv_len] );
5387 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5388 return LDAP_INVALID_SYNTAX;
5391 ber_dupbv_x( normalized, &bv, ctx );
5393 return LDAP_SUCCESS;
5396 /* Normalize a CSN */
5403 struct berval *normalized,
5406 struct berval cnt, sid, mod;
5410 assert( val != NULL );
5411 assert( normalized != NULL );
5413 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5415 if ( BER_BVISEMPTY( val ) ) {
5416 return LDAP_INVALID_SYNTAX;
5419 if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5420 /* Openldap <= 2.3 */
5422 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5425 if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5428 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5431 if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5432 return LDAP_INVALID_SYNTAX;
5435 ptr = ber_bvchr( val, '#' );
5436 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5437 return LDAP_INVALID_SYNTAX;
5440 if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5441 return LDAP_INVALID_SYNTAX;
5444 cnt.bv_val = ptr + 1;
5445 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5447 ptr = ber_bvchr( &cnt, '#' );
5448 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5449 return LDAP_INVALID_SYNTAX;
5452 if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5453 return LDAP_INVALID_SYNTAX;
5456 sid.bv_val = ptr + 1;
5457 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5459 ptr = ber_bvchr( &sid, '#' );
5460 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5461 return LDAP_INVALID_SYNTAX;
5464 sid.bv_len = ptr - sid.bv_val;
5465 if ( sid.bv_len != STRLENOF( "000" ) ) {
5466 return LDAP_INVALID_SYNTAX;
5469 mod.bv_val = ptr + 1;
5470 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5472 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5473 return LDAP_INVALID_SYNTAX;
5476 ber_dupbv_x( normalized, val, ctx );
5478 for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5479 i < normalized->bv_len; i++ )
5481 /* assume it's already validated that's all hex digits */
5482 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5485 return LDAP_SUCCESS;
5495 return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5498 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5499 /* slight optimization - does not need the start parameter */
5500 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5505 check_time_syntax (struct berval *val,
5508 struct berval *fraction)
5511 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5512 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
5513 * GeneralizedTime supports leap seconds, UTCTime does not.
5515 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5516 static const int mdays[2][12] = {
5517 /* non-leap years */
5518 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5520 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5523 int part, c, c1, c2, tzoffset, leapyear = 0;
5526 e = p + val->bv_len;
5528 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5529 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5531 for (part = start; part < 7 && p < e; part++) {
5533 if (!ASCII_DIGIT(c1)) {
5538 return LDAP_INVALID_SYNTAX;
5541 if (!ASCII_DIGIT(c)) {
5542 return LDAP_INVALID_SYNTAX;
5544 c += c1 * 10 - '0' * 11;
5545 if ((part | 1) == 3) {
5548 return LDAP_INVALID_SYNTAX;
5551 if (c >= ceiling[part]) {
5552 if (! (c == 60 && part == 6 && start == 0))
5553 return LDAP_INVALID_SYNTAX;
5557 if (part < 5 + start) {
5558 return LDAP_INVALID_SYNTAX;
5560 for (; part < 9; part++) {
5564 /* leapyear check for the Gregorian calendar (year>1581) */
5565 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5569 if (parts[3] >= mdays[leapyear][parts[2]]) {
5570 return LDAP_INVALID_SYNTAX;
5574 fraction->bv_val = p;
5575 fraction->bv_len = 0;
5576 if (p < e && (*p == '.' || *p == ',')) {
5578 while (++p < e && ASCII_DIGIT(*p)) {
5581 if (p - fraction->bv_val == 1) {
5582 return LDAP_INVALID_SYNTAX;
5584 for (end_num = p; end_num[-1] == '0'; --end_num) {
5587 c = end_num - fraction->bv_val;
5588 if (c != 1) fraction->bv_len = c;
5594 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5600 return LDAP_INVALID_SYNTAX;
5606 for (part = 7; part < 9 && p < e; part++) {
5608 if (!ASCII_DIGIT(c1)) {
5613 return LDAP_INVALID_SYNTAX;
5616 if (!ASCII_DIGIT(c2)) {
5617 return LDAP_INVALID_SYNTAX;
5619 parts[part] = c1 * 10 + c2 - '0' * 11;
5620 if (parts[part] >= ceiling[part]) {
5621 return LDAP_INVALID_SYNTAX;
5624 if (part < 8 + start) {
5625 return LDAP_INVALID_SYNTAX;
5628 if (tzoffset == '-') {
5629 /* negative offset to UTC, ie west of Greenwich */
5630 parts[4] += parts[7];
5631 parts[5] += parts[8];
5632 /* offset is just hhmm, no seconds */
5633 for (part = 6; --part >= 0; ) {
5637 c = mdays[leapyear][parts[2]];
5639 if (parts[part] >= c) {
5641 return LDAP_INVALID_SYNTAX;
5646 } else if (part != 5) {
5651 /* positive offset to UTC, ie east of Greenwich */
5652 parts[4] -= parts[7];
5653 parts[5] -= parts[8];
5654 for (part = 6; --part >= 0; ) {
5655 if (parts[part] < 0) {
5657 return LDAP_INVALID_SYNTAX;
5662 /* make first arg to % non-negative */
5663 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5668 } else if (part != 5) {
5675 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5678 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5685 struct berval *normalized )
5689 rc = check_time_syntax(val, 1, parts, NULL);
5690 if (rc != LDAP_SUCCESS) {
5694 normalized->bv_val = ch_malloc( 14 );
5695 if ( normalized->bv_val == NULL ) {
5696 return LBER_ERROR_MEMORY;
5699 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5700 parts[1], parts[2] + 1, parts[3] + 1,
5701 parts[4], parts[5], parts[6] );
5702 normalized->bv_len = 13;
5704 return LDAP_SUCCESS;
5714 return check_time_syntax(in, 1, parts, NULL);
5717 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5720 generalizedTimeValidate(
5725 struct berval fraction;
5726 return check_time_syntax(in, 0, parts, &fraction);
5730 generalizedTimeNormalize(
5735 struct berval *normalized,
5740 struct berval fraction;
5742 rc = check_time_syntax(val, 0, parts, &fraction);
5743 if (rc != LDAP_SUCCESS) {
5747 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5748 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5749 if ( BER_BVISNULL( normalized ) ) {
5750 return LBER_ERROR_MEMORY;
5753 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5754 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5755 parts[4], parts[5], parts[6] );
5756 if ( !BER_BVISEMPTY( &fraction ) ) {
5757 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5758 fraction.bv_val, fraction.bv_len );
5759 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5761 strcpy( normalized->bv_val + len-1, "Z" );
5762 normalized->bv_len = len;
5764 return LDAP_SUCCESS;
5768 generalizedTimeOrderingMatch(
5773 struct berval *value,
5774 void *assertedValue )
5776 struct berval *asserted = (struct berval *) assertedValue;
5777 ber_len_t v_len = value->bv_len;
5778 ber_len_t av_len = asserted->bv_len;
5780 /* ignore trailing 'Z' when comparing */
5781 int match = memcmp( value->bv_val, asserted->bv_val,
5782 (v_len < av_len ? v_len : av_len) - 1 );
5783 if ( match == 0 ) match = v_len - av_len;
5785 /* If used in extensible match filter, match if value < asserted */
5786 if ( flags & SLAP_MR_EXT )
5787 match = (match >= 0);
5790 return LDAP_SUCCESS;
5793 /* Index generation function: Ordered index */
5794 int generalizedTimeIndexer(
5799 struct berval *prefix,
5807 BerValue bvtmp; /* 40 bit index */
5809 struct lutil_timet tt;
5811 bvtmp.bv_len = sizeof(tmp);
5813 for( i=0; values[i].bv_val != NULL; i++ ) {
5814 /* just count them */
5817 /* we should have at least one value at this point */
5820 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5822 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5823 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5824 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5825 /* Use 40 bits of time for key */
5826 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5827 lutil_tm2time( &tm, &tt );
5828 tmp[0] = tt.tt_gsec & 0xff;
5829 tmp[4] = tt.tt_sec & 0xff;
5831 tmp[3] = tt.tt_sec & 0xff;
5833 tmp[2] = tt.tt_sec & 0xff;
5835 tmp[1] = tt.tt_sec & 0xff;
5837 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5841 keys[j].bv_val = NULL;
5846 return LDAP_SUCCESS;
5849 /* Index generation function: Ordered index */
5850 int generalizedTimeFilter(
5855 struct berval *prefix,
5856 void * assertedValue,
5862 BerValue bvtmp; /* 40 bit index */
5863 BerValue *value = (BerValue *) assertedValue;
5865 struct lutil_timet tt;
5867 bvtmp.bv_len = sizeof(tmp);
5869 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5870 /* Use 40 bits of time for key */
5871 if ( value->bv_val && value->bv_len >= 10 &&
5872 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5874 lutil_tm2time( &tm, &tt );
5875 tmp[0] = tt.tt_gsec & 0xff;
5876 tmp[4] = tt.tt_sec & 0xff;
5878 tmp[3] = tt.tt_sec & 0xff;
5880 tmp[2] = tt.tt_sec & 0xff;
5882 tmp[1] = tt.tt_sec & 0xff;
5884 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5885 ber_dupbv_x(keys, &bvtmp, ctx );
5886 keys[1].bv_val = NULL;
5894 return LDAP_SUCCESS;
5898 deliveryMethodValidate(
5900 struct berval *val )
5903 #define LENOF(s) (sizeof(s)-1)
5904 struct berval tmp = *val;
5906 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5907 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5908 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5911 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5913 switch( tmp.bv_val[0] ) {
5916 if(( tmp.bv_len >= LENOF("any") ) &&
5917 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5919 tmp.bv_len -= LENOF("any");
5920 tmp.bv_val += LENOF("any");
5923 return LDAP_INVALID_SYNTAX;
5927 if(( tmp.bv_len >= LENOF("mhs") ) &&
5928 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5930 tmp.bv_len -= LENOF("mhs");
5931 tmp.bv_val += LENOF("mhs");
5934 return LDAP_INVALID_SYNTAX;
5938 if(( tmp.bv_len >= LENOF("physical") ) &&
5939 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5941 tmp.bv_len -= LENOF("physical");
5942 tmp.bv_val += LENOF("physical");
5945 return LDAP_INVALID_SYNTAX;
5948 case 'T': /* telex or teletex or telephone */
5949 if(( tmp.bv_len >= LENOF("telex") ) &&
5950 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5952 tmp.bv_len -= LENOF("telex");
5953 tmp.bv_val += LENOF("telex");
5956 if(( tmp.bv_len >= LENOF("teletex") ) &&
5957 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5959 tmp.bv_len -= LENOF("teletex");
5960 tmp.bv_val += LENOF("teletex");
5963 if(( tmp.bv_len >= LENOF("telephone") ) &&
5964 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5966 tmp.bv_len -= LENOF("telephone");
5967 tmp.bv_val += LENOF("telephone");
5970 return LDAP_INVALID_SYNTAX;
5973 case 'G': /* g3fax or g4fax */
5974 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5975 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5976 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5978 tmp.bv_len -= LENOF("g3fax");
5979 tmp.bv_val += LENOF("g3fax");
5982 return LDAP_INVALID_SYNTAX;
5986 if(( tmp.bv_len >= LENOF("ia5") ) &&
5987 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5989 tmp.bv_len -= LENOF("ia5");
5990 tmp.bv_val += LENOF("ia5");
5993 return LDAP_INVALID_SYNTAX;
5997 if(( tmp.bv_len >= LENOF("videotex") ) &&
5998 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
6000 tmp.bv_len -= LENOF("videotex");
6001 tmp.bv_val += LENOF("videotex");
6004 return LDAP_INVALID_SYNTAX;
6007 return LDAP_INVALID_SYNTAX;
6010 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
6012 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
6016 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
6020 return LDAP_INVALID_SYNTAX;
6022 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
6031 nisNetgroupTripleValidate(
6033 struct berval *val )
6038 if ( BER_BVISEMPTY( val ) ) {
6039 return LDAP_INVALID_SYNTAX;
6042 p = (char *)val->bv_val;
6043 e = p + val->bv_len;
6045 if ( *p != '(' /*')'*/ ) {
6046 return LDAP_INVALID_SYNTAX;
6049 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
6053 return LDAP_INVALID_SYNTAX;
6056 } else if ( !AD_CHAR( *p ) ) {
6057 return LDAP_INVALID_SYNTAX;
6061 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
6062 return LDAP_INVALID_SYNTAX;
6068 return LDAP_INVALID_SYNTAX;
6071 return LDAP_SUCCESS;
6075 bootParameterValidate(
6077 struct berval *val )
6081 if ( BER_BVISEMPTY( val ) ) {
6082 return LDAP_INVALID_SYNTAX;
6085 p = (char *)val->bv_val;
6086 e = p + val->bv_len;
6089 for (; ( p < e ) && ( *p != '=' ); p++ ) {
6090 if ( !AD_CHAR( *p ) ) {
6091 return LDAP_INVALID_SYNTAX;
6096 return LDAP_INVALID_SYNTAX;
6100 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6101 if ( !AD_CHAR( *p ) ) {
6102 return LDAP_INVALID_SYNTAX;
6107 return LDAP_INVALID_SYNTAX;
6111 for ( p++; p < e; p++ ) {
6112 if ( !SLAP_PRINTABLE( *p ) ) {
6113 return LDAP_INVALID_SYNTAX;
6117 return LDAP_SUCCESS;
6121 firstComponentNormalize(
6126 struct berval *normalized,
6133 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6134 ber_dupbv_x( normalized, val, ctx );
6135 return LDAP_SUCCESS;
6138 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6140 if( ! ( val->bv_val[0] == '(' /*')'*/
6141 && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6142 && ! ( val->bv_val[0] == '{' /*'}'*/
6143 && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6145 return LDAP_INVALID_SYNTAX;
6148 /* trim leading white space */
6150 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6156 /* grab next word */
6157 comp.bv_val = &val->bv_val[len];
6158 len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6159 for( comp.bv_len = 0;
6160 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6166 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6167 rc = numericoidValidate( NULL, &comp );
6168 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6169 rc = integerValidate( NULL, &comp );
6171 rc = LDAP_INVALID_SYNTAX;
6175 if( rc == LDAP_SUCCESS ) {
6176 ber_dupbv_x( normalized, &comp, ctx );
6182 static char *country_gen_syn[] = {
6183 "1.3.6.1.4.1.1466.115.121.1.15", /* Directory String */
6184 "1.3.6.1.4.1.1466.115.121.1.26", /* IA5 String */
6185 "1.3.6.1.4.1.1466.115.121.1.44", /* Printable String */
6189 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6190 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6192 static slap_syntax_defs_rec syntax_defs[] = {
6193 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6194 X_BINARY X_NOT_H_R ")",
6195 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6196 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6197 0, NULL, NULL, NULL},
6198 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6199 0, NULL, NULL, NULL},
6200 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6202 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6203 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6205 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6206 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6207 0, NULL, bitStringValidate, NULL },
6208 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6209 0, NULL, booleanValidate, NULL},
6210 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6211 X_BINARY X_NOT_H_R ")",
6212 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6213 NULL, certificateValidate, NULL},
6214 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6215 X_BINARY X_NOT_H_R ")",
6216 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6217 NULL, certificateListValidate, NULL},
6218 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6219 X_BINARY X_NOT_H_R ")",
6220 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6221 NULL, sequenceValidate, NULL},
6222 {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6223 X_BINARY X_NOT_H_R ")",
6224 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6225 NULL, attributeCertificateValidate, NULL},
6226 #if 0 /* need to go __after__ printableString */
6227 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6228 0, "1.3.6.1.4.1.1466.115.121.1.44",
6229 countryStringValidate, NULL},
6231 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6232 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6233 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6234 0, NULL, rdnValidate, rdnPretty},
6235 #ifdef LDAP_COMP_MATCH
6236 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6237 0, NULL, allComponentsValidate, NULL},
6238 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6239 0, NULL, componentFilterValidate, NULL},
6241 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6242 0, NULL, NULL, NULL},
6243 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6244 0, NULL, deliveryMethodValidate, NULL},
6245 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6246 0, NULL, UTF8StringValidate, NULL},
6247 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6248 0, NULL, NULL, NULL},
6249 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6250 0, NULL, NULL, NULL},
6251 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6252 0, NULL, NULL, NULL},
6253 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6254 0, NULL, NULL, NULL},
6255 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6256 0, NULL, NULL, NULL},
6257 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6258 0, NULL, printablesStringValidate, NULL},
6259 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6260 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6261 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6262 0, NULL, generalizedTimeValidate, NULL},
6263 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6264 0, NULL, NULL, NULL},
6265 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6266 0, NULL, IA5StringValidate, NULL},
6267 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6268 0, NULL, integerValidate, NULL},
6269 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6270 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6271 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6272 0, NULL, NULL, NULL},
6273 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6274 0, NULL, NULL, NULL},
6275 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6276 0, NULL, NULL, NULL},
6277 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6278 0, NULL, NULL, NULL},
6279 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6280 0, NULL, NULL, NULL},
6281 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6282 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6283 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6284 0, NULL, NULL, NULL},
6285 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6286 0, NULL, numericStringValidate, NULL},
6287 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6288 0, NULL, NULL, NULL},
6289 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6290 0, NULL, numericoidValidate, NULL},
6291 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6292 0, NULL, IA5StringValidate, NULL},
6293 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6294 0, NULL, blobValidate, NULL},
6295 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6296 0, NULL, postalAddressValidate, NULL},
6297 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6298 0, NULL, NULL, NULL},
6299 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6300 0, NULL, NULL, NULL},
6301 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6302 0, NULL, printableStringValidate, NULL},
6303 /* moved here because now depends on Directory String, IA5 String
6304 * and Printable String */
6305 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6306 0, country_gen_syn, countryStringValidate, NULL},
6307 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6308 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6309 0, NULL, subtreeSpecificationValidate, NULL},
6310 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6311 X_BINARY X_NOT_H_R ")",
6312 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6313 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6314 0, NULL, printableStringValidate, NULL},
6315 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6316 0, NULL, NULL, NULL},
6317 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6318 0, NULL, printablesStringValidate, NULL},
6319 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6320 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6321 0, NULL, utcTimeValidate, NULL},
6323 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6324 0, NULL, NULL, NULL},
6325 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6326 0, NULL, NULL, NULL},
6327 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6328 0, NULL, NULL, NULL},
6329 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6330 0, NULL, NULL, NULL},
6331 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6332 0, NULL, NULL, NULL},
6334 /* RFC 2307 NIS Syntaxes */
6335 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
6336 0, NULL, nisNetgroupTripleValidate, NULL},
6337 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
6338 0, NULL, bootParameterValidate, NULL},
6340 /* draft-zeilenga-ldap-x509 */
6341 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6342 SLAP_SYNTAX_HIDE, NULL,
6343 serialNumberAndIssuerValidate,
6344 serialNumberAndIssuerPretty},
6345 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6346 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6347 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6348 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6349 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6350 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6351 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6352 SLAP_SYNTAX_HIDE, NULL,
6353 issuerAndThisUpdateValidate,
6354 issuerAndThisUpdatePretty},
6355 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6356 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6357 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6358 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6359 {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6360 SLAP_SYNTAX_HIDE, NULL,
6361 serialNumberAndIssuerSerialValidate,
6362 serialNumberAndIssuerSerialPretty},
6363 {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6364 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6366 #ifdef SLAPD_AUTHPASSWD
6367 /* needs updating */
6368 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6369 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6372 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6373 0, NULL, UUIDValidate, UUIDPretty},
6375 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6376 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6378 {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6379 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6381 /* OpenLDAP Void Syntax */
6382 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6383 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6385 /* FIXME: OID is unused, but not registered yet */
6386 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6387 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6389 /* OpenSSL-compatible Private Keys for X.509 certificates */
6390 {"( 1.3.6.1.4.1.4203.666.2.13 DESC 'OpenLDAP privateKey' )",
6391 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, privateKeyValidate, NULL},
6392 {NULL, 0, NULL, NULL, NULL}
6395 char *csnSIDMatchSyntaxes[] = {
6396 "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6399 char *certificateExactMatchSyntaxes[] = {
6400 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6403 char *certificateListExactMatchSyntaxes[] = {
6404 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6407 char *attributeCertificateExactMatchSyntaxes[] = {
6408 attributeCertificateSyntaxOID /* attributeCertificate */,
6412 #ifdef LDAP_COMP_MATCH
6413 char *componentFilterMatchSyntaxes[] = {
6414 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6415 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6416 attributeCertificateSyntaxOID /* attributeCertificate */,
6421 char *directoryStringSyntaxes[] = {
6422 "1.3.6.1.4.1.1466.115.121.1.11" /* countryString */,
6423 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6424 "1.3.6.1.4.1.1466.115.121.1.50" /* telephoneNumber */,
6427 char *integerFirstComponentMatchSyntaxes[] = {
6428 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6429 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6432 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6433 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6434 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
6435 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6436 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6437 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6438 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6439 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6440 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6445 * Other matching rules in X.520 that we do not use (yet):
6447 * 2.5.13.25 uTCTimeMatch
6448 * 2.5.13.26 uTCTimeOrderingMatch
6449 * 2.5.13.31* directoryStringFirstComponentMatch
6450 * 2.5.13.32* wordMatch
6451 * 2.5.13.33* keywordMatch
6452 * 2.5.13.36+ certificatePairExactMatch
6453 * 2.5.13.37+ certificatePairMatch
6454 * 2.5.13.40+ algorithmIdentifierMatch
6455 * 2.5.13.41* storedPrefixMatch
6456 * 2.5.13.42 attributeCertificateMatch
6457 * 2.5.13.43 readerAndKeyIDMatch
6458 * 2.5.13.44 attributeIntegrityMatch
6460 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6461 * (+) described in draft-zeilenga-ldap-x509
6463 static slap_mrule_defs_rec mrule_defs[] = {
6465 * EQUALITY matching rules must be listed after associated APPROX
6466 * matching rules. So, we list all APPROX matching rules first.
6468 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6469 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6470 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6471 NULL, NULL, directoryStringApproxMatch,
6472 directoryStringApproxIndexer, directoryStringApproxFilter,
6475 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6476 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6477 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6478 NULL, NULL, IA5StringApproxMatch,
6479 IA5StringApproxIndexer, IA5StringApproxFilter,
6483 * Other matching rules
6486 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6487 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6488 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6489 NULL, NULL, octetStringMatch,
6490 octetStringIndexer, octetStringFilter,
6493 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6494 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6495 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6496 NULL, dnNormalize, dnMatch,
6497 octetStringIndexer, octetStringFilter,
6500 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6501 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6502 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6503 NULL, dnNormalize, dnRelativeMatch,
6507 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6508 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6509 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6510 NULL, dnNormalize, dnRelativeMatch,
6514 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6515 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6516 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6517 NULL, dnNormalize, dnRelativeMatch,
6521 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6522 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6523 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6524 NULL, dnNormalize, dnRelativeMatch,
6528 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6529 "SYNTAX 1.2.36.79672281.1.5.0 )",
6530 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6531 NULL, rdnNormalize, rdnMatch,
6532 octetStringIndexer, octetStringFilter,
6535 #ifdef LDAP_COMP_MATCH
6536 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6537 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6538 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6539 NULL, NULL , componentFilterMatch,
6540 octetStringIndexer, octetStringFilter,
6543 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6544 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6545 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6546 NULL, NULL , allComponentsMatch,
6547 octetStringIndexer, octetStringFilter,
6550 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6551 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6552 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6553 NULL, NULL , directoryComponentsMatch,
6554 octetStringIndexer, octetStringFilter,
6558 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6559 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6560 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6561 NULL, UTF8StringNormalize, octetStringMatch,
6562 octetStringIndexer, octetStringFilter,
6563 directoryStringApproxMatchOID },
6565 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6566 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6567 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6568 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6570 "caseIgnoreMatch" },
6572 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6573 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6574 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6575 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6576 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6577 "caseIgnoreMatch" },
6579 {"( 2.5.13.5 NAME 'caseExactMatch' "
6580 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6581 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6582 NULL, UTF8StringNormalize, octetStringMatch,
6583 octetStringIndexer, octetStringFilter,
6584 directoryStringApproxMatchOID },
6586 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6587 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6588 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6589 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6593 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6594 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6595 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6596 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6597 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6600 {"( 2.5.13.8 NAME 'numericStringMatch' "
6601 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6602 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6603 NULL, numericStringNormalize, octetStringMatch,
6604 octetStringIndexer, octetStringFilter,
6607 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6608 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6609 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6610 NULL, numericStringNormalize, octetStringOrderingMatch,
6612 "numericStringMatch" },
6614 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6615 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6616 SLAP_MR_SUBSTR, NULL,
6617 NULL, numericStringNormalize, octetStringSubstringsMatch,
6618 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6619 "numericStringMatch" },
6621 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6622 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6623 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6624 NULL, postalAddressNormalize, octetStringMatch,
6625 octetStringIndexer, octetStringFilter,
6628 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6629 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6630 SLAP_MR_SUBSTR, NULL,
6631 NULL, NULL, NULL, NULL, NULL,
6632 "caseIgnoreListMatch" },
6634 {"( 2.5.13.13 NAME 'booleanMatch' "
6635 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6636 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6637 NULL, NULL, booleanMatch,
6638 octetStringIndexer, octetStringFilter,
6641 {"( 2.5.13.14 NAME 'integerMatch' "
6642 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6643 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6644 NULL, NULL, integerMatch,
6645 integerIndexer, integerFilter,
6648 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6649 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6650 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6651 NULL, NULL, integerMatch,
6655 {"( 2.5.13.16 NAME 'bitStringMatch' "
6656 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6657 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6658 NULL, NULL, octetStringMatch,
6659 octetStringIndexer, octetStringFilter,
6662 {"( 2.5.13.17 NAME 'octetStringMatch' "
6663 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6664 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6665 NULL, NULL, octetStringMatch,
6666 octetStringIndexer, octetStringFilter,
6669 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6670 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6671 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6672 NULL, NULL, octetStringOrderingMatch,
6674 "octetStringMatch" },
6676 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6677 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6678 SLAP_MR_SUBSTR, NULL,
6679 NULL, NULL, octetStringSubstringsMatch,
6680 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6681 "octetStringMatch" },
6683 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6684 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6685 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6687 telephoneNumberNormalize, octetStringMatch,
6688 octetStringIndexer, octetStringFilter,
6691 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6692 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6693 SLAP_MR_SUBSTR, NULL,
6694 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6695 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6696 "telephoneNumberMatch" },
6698 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6699 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6700 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6701 NULL, NULL, NULL, NULL, NULL, NULL },
6703 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6704 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6705 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6706 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6707 uniqueMemberIndexer, uniqueMemberFilter,
6710 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6711 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6712 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6713 NULL, NULL, NULL, NULL, NULL, NULL },
6715 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6716 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6717 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6718 NULL, generalizedTimeNormalize, octetStringMatch,
6719 generalizedTimeIndexer, generalizedTimeFilter,
6722 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6723 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6724 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6725 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6727 "generalizedTimeMatch" },
6729 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6730 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6731 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6732 integerFirstComponentMatchSyntaxes,
6733 NULL, firstComponentNormalize, integerMatch,
6734 octetStringIndexer, octetStringFilter,
6737 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6738 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6739 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6740 objectIdentifierFirstComponentMatchSyntaxes,
6741 NULL, firstComponentNormalize, octetStringMatch,
6742 octetStringIndexer, octetStringFilter,
6745 {"( 2.5.13.34 NAME 'certificateExactMatch' "
6746 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6747 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6748 NULL, certificateExactNormalize, octetStringMatch,
6749 octetStringIndexer, octetStringFilter,
6752 {"( 2.5.13.35 NAME 'certificateMatch' "
6753 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6754 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6755 NULL, NULL, NULL, NULL, NULL,
6758 {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6759 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6760 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6761 NULL, certificateListExactNormalize, octetStringMatch,
6762 octetStringIndexer, octetStringFilter,
6765 {"( 2.5.13.39 NAME 'certificateListMatch' "
6766 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6767 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6768 NULL, NULL, NULL, NULL, NULL,
6771 {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6772 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6773 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6774 NULL, attributeCertificateExactNormalize, octetStringMatch,
6775 octetStringIndexer, octetStringFilter,
6778 {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6779 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6780 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6781 NULL, NULL, NULL, NULL, NULL,
6784 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6785 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6786 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6787 NULL, IA5StringNormalize, octetStringMatch,
6788 octetStringIndexer, octetStringFilter,
6789 IA5StringApproxMatchOID },
6791 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6792 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6793 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6794 NULL, IA5StringNormalize, octetStringMatch,
6795 octetStringIndexer, octetStringFilter,
6796 IA5StringApproxMatchOID },
6798 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6799 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6800 SLAP_MR_SUBSTR, NULL,
6801 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6802 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6803 "caseIgnoreIA5Match" },
6805 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6806 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6807 SLAP_MR_SUBSTR, NULL,
6808 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6809 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6810 "caseExactIA5Match" },
6812 #ifdef SLAPD_AUTHPASSWD
6813 /* needs updating */
6814 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6815 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6816 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6817 NULL, NULL, authPasswordMatch,
6822 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6823 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6825 NULL, NULL, integerBitAndMatch,
6829 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6830 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6832 NULL, NULL, integerBitOrMatch,
6836 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6837 "SYNTAX 1.3.6.1.1.16.1 )",
6838 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6839 NULL, UUIDNormalize, octetStringMatch,
6840 octetStringIndexer, octetStringFilter,
6843 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6844 "SYNTAX 1.3.6.1.1.16.1 )",
6845 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6846 NULL, UUIDNormalize, octetStringOrderingMatch,
6847 octetStringIndexer, octetStringFilter,
6850 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6851 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6852 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6853 NULL, csnNormalize, csnMatch,
6854 csnIndexer, csnFilter,
6857 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6858 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6859 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6860 NULL, csnNormalize, csnOrderingMatch,
6864 {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6865 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6866 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6867 NULL, csnSidNormalize, octetStringMatch,
6868 octetStringIndexer, octetStringFilter,
6871 /* FIXME: OID is unused, but not registered yet */
6872 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6873 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6874 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6875 NULL, authzNormalize, authzMatch,
6879 {"( 1.3.6.1.4.1.4203.666.4.13 NAME 'privateKeyMatch' "
6880 "SYNTAX 1.3.6.1.4.1.4203.666.2.13 )", /* OpenLDAP privateKey */
6881 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6882 NULL, NULL, octetStringMatch,
6886 {NULL, SLAP_MR_NONE, NULL,
6887 NULL, NULL, NULL, NULL, NULL,
6892 slap_schema_init( void )
6897 /* we should only be called once (from main) */
6898 assert( schema_init_done == 0 );
6900 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6901 res = register_syntax( &syntax_defs[i] );
6904 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6905 syntax_defs[i].sd_desc );
6910 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6911 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6912 mrule_defs[i].mrd_compat_syntaxes == NULL )
6915 "slap_schema_init: Ignoring unusable matching rule %s\n",
6916 mrule_defs[i].mrd_desc );
6920 res = register_matching_rule( &mrule_defs[i] );
6924 "slap_schema_init: Error registering matching rule %s\n",
6925 mrule_defs[i].mrd_desc );
6930 res = slap_schema_load();
6931 schema_init_done = 1;
6936 schema_destroy( void )
6945 if( schema_init_done ) {
6946 ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6947 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6948 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );