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 a PKCS#8 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 tag = ber_skip_tag( ber, &len ); /* AlgorithmIdentifier */
615 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
616 ber_skip_data( ber, len );
617 tag = ber_skip_tag( ber, &len ); /* PrivateKey */
618 if ( tag != LBER_OCTETSTRING ) return LDAP_INVALID_SYNTAX;
619 ber_skip_data( ber, len );
620 tag = ber_skip_tag( ber, &len );
621 if ( tag == LBER_SET ) { /* Optional Attributes */
622 ber_skip_data( ber, len );
623 tag = ber_skip_tag( ber, &len );
626 /* Must be at end now */
627 if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
637 struct berval *value,
638 void *assertedValue )
640 struct berval *asserted = (struct berval *) assertedValue;
641 ber_slen_t d = (ber_slen_t) value->bv_len - (ber_slen_t) asserted->bv_len;
643 /* For speed, order first by length, then by contents */
644 *matchp = d ? (sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1)
645 : memcmp( value->bv_val, asserted->bv_val, value->bv_len );
651 octetStringOrderingMatch(
656 struct berval *value,
657 void *assertedValue )
659 struct berval *asserted = (struct berval *) assertedValue;
660 ber_len_t v_len = value->bv_len;
661 ber_len_t av_len = asserted->bv_len;
663 int match = memcmp( value->bv_val, asserted->bv_val,
664 (v_len < av_len ? v_len : av_len) );
667 match = sizeof(v_len) == sizeof(int)
668 ? (int) v_len - (int) av_len
669 : v_len < av_len ? -1 : v_len > av_len;
671 /* If used in extensible match filter, match if value < asserted */
672 if ( flags & SLAP_MR_EXT )
673 match = (match >= 0);
679 /* Initialize HASHcontext from match type and schema info */
682 HASH_CONTEXT *HASHcontext,
683 struct berval *prefix,
688 HASH_Init(HASHcontext);
689 if(prefix && prefix->bv_len > 0) {
690 HASH_Update(HASHcontext,
691 (unsigned char *)prefix->bv_val, prefix->bv_len);
693 if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
694 HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
695 HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
699 /* Set HASHdigest from HASHcontext and value:len */
702 HASH_CONTEXT *HASHcontext,
703 unsigned char *HASHdigest,
704 unsigned char *value,
707 HASH_CONTEXT ctx = *HASHcontext;
708 HASH_Update( &ctx, value, len );
709 HASH_Final( HASHdigest, &ctx );
712 /* Index generation function: Attribute values -> index hash keys */
713 int octetStringIndexer(
718 struct berval *prefix,
725 HASH_CONTEXT HASHcontext;
726 unsigned char HASHdigest[HASH_BYTES];
727 struct berval digest;
728 digest.bv_val = (char *)HASHdigest;
729 digest.bv_len = HASH_LEN;
731 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
732 /* just count them */
735 /* we should have at least one value at this point */
738 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
740 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
741 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
742 hashIter( &HASHcontext, HASHdigest,
743 (unsigned char *)values[i].bv_val, values[i].bv_len );
744 ber_dupbv_x( &keys[i], &digest, ctx );
747 BER_BVZERO( &keys[i] );
754 /* Index generation function: Asserted value -> index hash key */
755 int octetStringFilter(
760 struct berval *prefix,
761 void * assertedValue,
766 HASH_CONTEXT HASHcontext;
767 unsigned char HASHdigest[HASH_BYTES];
768 struct berval *value = (struct berval *) assertedValue;
769 struct berval digest;
770 digest.bv_val = (char *)HASHdigest;
771 digest.bv_len = HASH_LEN;
773 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
775 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
776 hashIter( &HASHcontext, HASHdigest,
777 (unsigned char *)value->bv_val, value->bv_len );
779 ber_dupbv_x( keys, &digest, ctx );
780 BER_BVZERO( &keys[1] );
788 octetStringSubstringsMatch(
793 struct berval *value,
794 void *assertedValue )
797 SubstringsAssertion *sub = assertedValue;
798 struct berval left = *value;
802 /* Add up asserted input length */
803 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
804 inlen += sub->sa_initial.bv_len;
807 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
808 inlen += sub->sa_any[i].bv_len;
811 if ( !BER_BVISNULL( &sub->sa_final ) ) {
812 inlen += sub->sa_final.bv_len;
815 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
816 if ( inlen > left.bv_len ) {
821 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
822 sub->sa_initial.bv_len );
828 left.bv_val += sub->sa_initial.bv_len;
829 left.bv_len -= sub->sa_initial.bv_len;
830 inlen -= sub->sa_initial.bv_len;
833 if ( !BER_BVISNULL( &sub->sa_final ) ) {
834 if ( inlen > left.bv_len ) {
839 match = memcmp( sub->sa_final.bv_val,
840 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
841 sub->sa_final.bv_len );
847 left.bv_len -= sub->sa_final.bv_len;
848 inlen -= sub->sa_final.bv_len;
852 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
857 if ( inlen > left.bv_len ) {
858 /* not enough length */
863 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
867 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
874 idx = p - left.bv_val;
876 if ( idx >= left.bv_len ) {
877 /* this shouldn't happen */
884 if ( sub->sa_any[i].bv_len > left.bv_len ) {
885 /* not enough left */
890 match = memcmp( left.bv_val,
891 sub->sa_any[i].bv_val,
892 sub->sa_any[i].bv_len );
900 left.bv_val += sub->sa_any[i].bv_len;
901 left.bv_len -= sub->sa_any[i].bv_len;
902 inlen -= sub->sa_any[i].bv_len;
911 /* Substring index generation function: Attribute values -> index hash keys */
913 octetStringSubstringsIndexer(
918 struct berval *prefix,
926 HASH_CONTEXT HCany, HCini, HCfin;
927 unsigned char HASHdigest[HASH_BYTES];
928 struct berval digest;
929 digest.bv_val = (char *)HASHdigest;
930 digest.bv_len = HASH_LEN;
934 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
935 /* count number of indices to generate */
936 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
937 if( values[i].bv_len >= index_substr_if_maxlen ) {
938 nkeys += index_substr_if_maxlen -
939 (index_substr_if_minlen - 1);
940 } else if( values[i].bv_len >= index_substr_if_minlen ) {
941 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
945 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
946 if( values[i].bv_len >= index_substr_any_len ) {
947 nkeys += values[i].bv_len - (index_substr_any_len - 1);
951 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
952 if( values[i].bv_len >= index_substr_if_maxlen ) {
953 nkeys += index_substr_if_maxlen -
954 (index_substr_if_minlen - 1);
955 } else if( values[i].bv_len >= index_substr_if_minlen ) {
956 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
962 /* no keys to generate */
967 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
969 if ( flags & SLAP_INDEX_SUBSTR_ANY )
970 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
971 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
972 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
973 if( flags & SLAP_INDEX_SUBSTR_FINAL )
974 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
977 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
980 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
981 ( values[i].bv_len >= index_substr_any_len ) )
983 max = values[i].bv_len - (index_substr_any_len - 1);
985 for( j=0; j<max; j++ ) {
986 hashIter( &HCany, HASHdigest,
987 (unsigned char *)&values[i].bv_val[j],
988 index_substr_any_len );
989 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
993 /* skip if too short */
994 if( values[i].bv_len < index_substr_if_minlen ) continue;
996 max = index_substr_if_maxlen < values[i].bv_len
997 ? index_substr_if_maxlen : values[i].bv_len;
999 for( j=index_substr_if_minlen; j<=max; j++ ) {
1001 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1002 hashIter( &HCini, HASHdigest,
1003 (unsigned char *)values[i].bv_val, j );
1004 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1007 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1008 hashIter( &HCfin, HASHdigest,
1009 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
1010 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1017 BER_BVZERO( &keys[nkeys] );
1024 return LDAP_SUCCESS;
1027 /* Substring index generation function: Assertion value -> index hash keys */
1029 octetStringSubstringsFilter (
1034 struct berval *prefix,
1035 void * assertedValue,
1039 SubstringsAssertion *sa;
1041 ber_len_t nkeys = 0;
1044 HASH_CONTEXT HASHcontext;
1045 unsigned char HASHdigest[HASH_BYTES];
1046 struct berval *value;
1047 struct berval digest;
1049 sa = (SubstringsAssertion *) assertedValue;
1051 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1052 !BER_BVISNULL( &sa->sa_initial ) &&
1053 sa->sa_initial.bv_len >= index_substr_if_minlen )
1056 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
1057 ( flags & SLAP_INDEX_SUBSTR_ANY ))
1059 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1063 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1065 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1066 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
1067 /* don't bother accounting with stepping */
1068 nkeys += sa->sa_any[i].bv_len -
1069 ( index_substr_any_len - 1 );
1074 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1075 !BER_BVISNULL( &sa->sa_final ) &&
1076 sa->sa_final.bv_len >= index_substr_if_minlen )
1079 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
1080 ( flags & SLAP_INDEX_SUBSTR_ANY ))
1082 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1088 return LDAP_SUCCESS;
1091 digest.bv_val = (char *)HASHdigest;
1092 digest.bv_len = HASH_LEN;
1094 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
1097 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1098 !BER_BVISNULL( &sa->sa_initial ) &&
1099 sa->sa_initial.bv_len >= index_substr_if_minlen )
1101 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1102 value = &sa->sa_initial;
1104 klen = index_substr_if_maxlen < value->bv_len
1105 ? index_substr_if_maxlen : value->bv_len;
1107 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1108 hashIter( &HASHcontext, HASHdigest,
1109 (unsigned char *)value->bv_val, klen );
1110 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1112 /* If initial is too long and we have subany indexed, use it
1113 * to match the excess...
1115 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1118 pre = SLAP_INDEX_SUBSTR_PREFIX;
1119 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1120 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
1122 hashIter( &HASHcontext, HASHdigest,
1123 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1124 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1129 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1131 pre = SLAP_INDEX_SUBSTR_PREFIX;
1132 klen = index_substr_any_len;
1134 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1135 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
1139 value = &sa->sa_any[i];
1141 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1143 j <= value->bv_len - index_substr_any_len;
1144 j += index_substr_any_step )
1146 hashIter( &HASHcontext, HASHdigest,
1147 (unsigned char *)&value->bv_val[j], klen );
1148 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1153 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1154 !BER_BVISNULL( &sa->sa_final ) &&
1155 sa->sa_final.bv_len >= index_substr_if_minlen )
1157 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1158 value = &sa->sa_final;
1160 klen = index_substr_if_maxlen < value->bv_len
1161 ? index_substr_if_maxlen : value->bv_len;
1163 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1164 hashIter( &HASHcontext, HASHdigest,
1165 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
1166 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1168 /* If final is too long and we have subany indexed, use it
1169 * to match the excess...
1171 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1174 pre = SLAP_INDEX_SUBSTR_PREFIX;
1175 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1176 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
1178 hashIter( &HASHcontext, HASHdigest,
1179 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1180 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1186 BER_BVZERO( &keys[nkeys] );
1193 return LDAP_SUCCESS;
1203 /* very unforgiving validation, requires no normalization
1204 * before simplistic matching
1206 if( in->bv_len < 3 ) {
1207 return LDAP_INVALID_SYNTAX;
1210 /* RFC 4517 Section 3.3.2 Bit String:
1211 * BitString = SQUOTE *binary-digit SQUOTE "B"
1212 * binary-digit = "0" / "1"
1214 * where SQUOTE [RFC4512] is
1215 * SQUOTE = %x27 ; single quote ("'")
1217 * Example: '0101111101'B
1220 if( in->bv_val[0] != '\'' ||
1221 in->bv_val[in->bv_len - 2] != '\'' ||
1222 in->bv_val[in->bv_len - 1] != 'B' )
1224 return LDAP_INVALID_SYNTAX;
1227 for( i = in->bv_len - 3; i > 0; i-- ) {
1228 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
1229 return LDAP_INVALID_SYNTAX;
1233 return LDAP_SUCCESS;
1237 * Syntaxes from RFC 4517
1242 A value of the Bit String syntax is a sequence of binary digits. The
1243 LDAP-specific encoding of a value of this syntax is defined by the
1246 BitString = SQUOTE *binary-digit SQUOTE "B"
1248 binary-digit = "0" / "1"
1250 The <SQUOTE> rule is defined in [MODELS].
1255 The LDAP definition for the Bit String syntax is:
1257 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
1259 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
1263 3.3.21. Name and Optional UID
1265 A value of the Name and Optional UID syntax is the distinguished name
1266 [MODELS] of an entity optionally accompanied by a unique identifier
1267 that serves to differentiate the entity from others with an identical
1270 The LDAP-specific encoding of a value of this syntax is defined by
1273 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
1275 The <BitString> rule is defined in Section 3.3.2. The
1276 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
1277 defined in [MODELS].
1279 Note that although the '#' character may occur in the string
1280 representation of a distinguished name, no additional escaping of
1281 this character is performed when a <distinguishedName> is encoded in
1282 a <NameAndOptionalUID>.
1285 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
1287 The LDAP definition for the Name and Optional UID syntax is:
1289 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
1291 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
1298 1.4. Common ABNF Productions
1301 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
1303 SQUOTE = %x27 ; single quote ("'")
1308 * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
1309 * be escaped except when at the beginning of a value, the
1310 * definition of Name and Optional UID appears to be flawed,
1311 * because there is no clear means to determine whether the
1312 * UID part is present or not.
1316 * cn=Someone,dc=example,dc=com#'1'B
1318 * could be either a NameAndOptionalUID with trailing UID, i.e.
1320 * DN = "cn=Someone,dc=example,dc=com"
1323 * or a NameAndOptionalUID with no trailing UID, and the AVA
1324 * in the last RDN made of
1326 * attributeType = dc
1327 * attributeValue = com#'1'B
1329 * in fact "com#'1'B" is a valid IA5 string.
1331 * As a consequence, current slapd code takes the presence of
1332 * #<valid BitString> at the end of the string representation
1333 * of a NameAndOptionalUID to mean this is indeed a BitString.
1334 * This is quite arbitrary - it has changed the past and might
1335 * change in the future.
1345 struct berval dn, uid;
1347 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
1349 ber_dupbv( &dn, in );
1350 if( !dn.bv_val ) return LDAP_OTHER;
1352 /* if there's a "#", try bitStringValidate()... */
1353 uid.bv_val = strrchr( dn.bv_val, '#' );
1354 if ( !BER_BVISNULL( &uid ) ) {
1356 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1358 rc = bitStringValidate( NULL, &uid );
1359 if ( rc == LDAP_SUCCESS ) {
1360 /* in case of success, trim the UID,
1361 * otherwise treat it as part of the DN */
1362 dn.bv_len -= uid.bv_len + 1;
1363 uid.bv_val[-1] = '\0';
1367 rc = dnValidate( NULL, &dn );
1369 ber_memfree( dn.bv_val );
1380 assert( val != NULL );
1381 assert( out != NULL );
1384 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1386 if( BER_BVISEMPTY( val ) ) {
1387 ber_dupbv_x( out, val, ctx );
1389 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1390 return LDAP_INVALID_SYNTAX;
1394 struct berval dnval = *val;
1395 struct berval uidval = BER_BVNULL;
1397 uidval.bv_val = strrchr( val->bv_val, '#' );
1398 if ( !BER_BVISNULL( &uidval ) ) {
1400 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1402 rc = bitStringValidate( NULL, &uidval );
1404 if ( rc == LDAP_SUCCESS ) {
1405 ber_dupbv_x( &dnval, val, ctx );
1407 dnval.bv_len -= ++uidval.bv_len;
1408 dnval.bv_val[dnval.bv_len] = '\0';
1411 BER_BVZERO( &uidval );
1415 rc = dnPretty( syntax, &dnval, out, ctx );
1416 if ( dnval.bv_val != val->bv_val ) {
1417 slap_sl_free( dnval.bv_val, ctx );
1419 if( rc != LDAP_SUCCESS ) {
1423 if( !BER_BVISNULL( &uidval ) ) {
1426 tmp = slap_sl_realloc( out->bv_val, out->bv_len
1427 + uidval.bv_len + 1,
1430 ber_memfree_x( out->bv_val, ctx );
1434 memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
1435 out->bv_len += uidval.bv_len;
1436 out->bv_val[out->bv_len] = '\0';
1440 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1442 return LDAP_SUCCESS;
1446 uniqueMemberNormalize(
1451 struct berval *normalized,
1457 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1459 ber_dupbv_x( &out, val, ctx );
1460 if ( BER_BVISEMPTY( &out ) ) {
1464 struct berval uid = BER_BVNULL;
1466 uid.bv_val = strrchr( out.bv_val, '#' );
1467 if ( !BER_BVISNULL( &uid ) ) {
1469 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1471 rc = bitStringValidate( NULL, &uid );
1472 if ( rc == LDAP_SUCCESS ) {
1473 uid.bv_val[-1] = '\0';
1474 out.bv_len -= uid.bv_len + 1;
1480 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1482 if( rc != LDAP_SUCCESS ) {
1483 slap_sl_free( out.bv_val, ctx );
1484 return LDAP_INVALID_SYNTAX;
1487 if( !BER_BVISNULL( &uid ) ) {
1490 tmp = ch_realloc( normalized->bv_val,
1491 normalized->bv_len + uid.bv_len
1492 + STRLENOF("#") + 1 );
1493 if ( tmp == NULL ) {
1494 ber_memfree_x( normalized->bv_val, ctx );
1498 normalized->bv_val = tmp;
1500 /* insert the separator */
1501 normalized->bv_val[normalized->bv_len++] = '#';
1503 /* append the UID */
1504 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1505 uid.bv_val, uid.bv_len );
1506 normalized->bv_len += uid.bv_len;
1509 normalized->bv_val[normalized->bv_len] = '\0';
1512 slap_sl_free( out.bv_val, ctx );
1515 return LDAP_SUCCESS;
1524 struct berval *value,
1525 void *assertedValue )
1528 struct berval *asserted = (struct berval *) assertedValue;
1529 struct berval assertedDN = *asserted;
1530 struct berval assertedUID = BER_BVNULL;
1531 struct berval valueDN = *value;
1532 struct berval valueUID = BER_BVNULL;
1533 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1535 if ( !BER_BVISEMPTY( asserted ) ) {
1536 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1537 if ( !BER_BVISNULL( &assertedUID ) ) {
1538 assertedUID.bv_val++;
1539 assertedUID.bv_len = assertedDN.bv_len
1540 - ( assertedUID.bv_val - assertedDN.bv_val );
1542 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1543 assertedDN.bv_len -= assertedUID.bv_len + 1;
1546 BER_BVZERO( &assertedUID );
1551 if ( !BER_BVISEMPTY( value ) ) {
1553 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1554 if ( !BER_BVISNULL( &valueUID ) ) {
1556 valueUID.bv_len = valueDN.bv_len
1557 - ( valueUID.bv_val - valueDN.bv_val );
1559 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1560 valueDN.bv_len -= valueUID.bv_len + 1;
1563 BER_BVZERO( &valueUID );
1568 if( valueUID.bv_len && assertedUID.bv_len ) {
1570 d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len;
1572 *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1;
1573 return LDAP_SUCCESS;
1576 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1579 return LDAP_SUCCESS;
1582 } else if ( !approx && valueUID.bv_len ) {
1585 return LDAP_SUCCESS;
1587 } else if ( !approx && assertedUID.bv_len ) {
1590 return LDAP_SUCCESS;
1593 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1597 uniqueMemberIndexer(
1602 struct berval *prefix,
1610 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1611 /* just count them */
1615 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1617 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1618 struct berval assertedDN = values[i];
1619 struct berval assertedUID = BER_BVNULL;
1621 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1622 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1623 if ( !BER_BVISNULL( &assertedUID ) ) {
1624 assertedUID.bv_val++;
1625 assertedUID.bv_len = assertedDN.bv_len
1626 - ( assertedUID.bv_val - assertedDN.bv_val );
1628 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1629 assertedDN.bv_len -= assertedUID.bv_len + 1;
1632 BER_BVZERO( &assertedUID );
1637 dnvalues[i] = assertedDN;
1639 BER_BVZERO( &dnvalues[i] );
1641 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1642 dnvalues, keysp, ctx );
1644 slap_sl_free( dnvalues, ctx );
1654 struct berval *prefix,
1655 void * assertedValue,
1659 struct berval *asserted = (struct berval *) assertedValue;
1660 struct berval assertedDN = *asserted;
1661 struct berval assertedUID = BER_BVNULL;
1663 if ( !BER_BVISEMPTY( asserted ) ) {
1664 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1665 if ( !BER_BVISNULL( &assertedUID ) ) {
1666 assertedUID.bv_val++;
1667 assertedUID.bv_len = assertedDN.bv_len
1668 - ( assertedUID.bv_val - assertedDN.bv_val );
1670 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1671 assertedDN.bv_len -= assertedUID.bv_len + 1;
1674 BER_BVZERO( &assertedUID );
1679 return octetStringFilter( use, flags, syntax, mr, prefix,
1680 &assertedDN, keysp, ctx );
1685 * Handling boolean syntax and matching is quite rigid.
1686 * A more flexible approach would be to allow a variety
1687 * of strings to be normalized and prettied into TRUE
1695 /* very unforgiving validation, requires no normalization
1696 * before simplistic matching
1699 if( in->bv_len == 4 ) {
1700 if( bvmatch( in, &slap_true_bv ) ) {
1701 return LDAP_SUCCESS;
1703 } else if( in->bv_len == 5 ) {
1704 if( bvmatch( in, &slap_false_bv ) ) {
1705 return LDAP_SUCCESS;
1709 return LDAP_INVALID_SYNTAX;
1718 struct berval *value,
1719 void *assertedValue )
1721 /* simplistic matching allowed by rigid validation */
1722 struct berval *asserted = (struct berval *) assertedValue;
1723 *matchp = (int) asserted->bv_len - (int) value->bv_len;
1724 return LDAP_SUCCESS;
1727 /*-------------------------------------------------------------------
1728 LDAP/X.500 string syntax / matching rules have a few oddities. This
1729 comment attempts to detail how slapd(8) treats them.
1732 StringSyntax X.500 LDAP Matching/Comments
1733 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1734 PrintableString subset subset i/e + ignore insignificant spaces
1735 PrintableString subset subset i/e + ignore insignificant spaces
1736 NumericString subset subset ignore all spaces
1737 IA5String ASCII ASCII i/e + ignore insignificant spaces
1738 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1740 TelephoneNumber subset subset i + ignore all spaces and "-"
1742 See RFC 4518 for details.
1746 In X.500(93), a directory string can be either a PrintableString,
1747 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1748 In later versions, more CHOICEs were added. In all cases the string
1751 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1752 A directory string cannot be zero length.
1754 For matching, there are both case ignore and exact rules. Both
1755 also require that "insignificant" spaces be ignored.
1756 spaces before the first non-space are ignored;
1757 spaces after the last non-space are ignored;
1758 spaces after a space are ignored.
1759 Note: by these rules (and as clarified in X.520), a string of only
1760 spaces is to be treated as if held one space, not empty (which
1761 would be a syntax error).
1764 In ASN.1, numeric string is just a string of digits and spaces
1765 and could be empty. However, in X.500, all attribute values of
1766 numeric string carry a non-empty constraint. For example:
1768 internationalISDNNumber ATTRIBUTE ::= {
1769 WITH SYNTAX InternationalISDNNumber
1770 EQUALITY MATCHING RULE numericStringMatch
1771 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1772 ID id-at-internationalISDNNumber }
1773 InternationalISDNNumber ::=
1774 NumericString (SIZE(1..ub-international-isdn-number))
1776 Unforunately, some assertion values are don't carry the same
1777 constraint (but its unclear how such an assertion could ever
1778 be true). In LDAP, there is one syntax (numericString) not two
1779 (numericString with constraint, numericString without constraint).
1780 This should be treated as numericString with non-empty constraint.
1781 Note that while someone may have no ISDN number, there are no ISDN
1782 numbers which are zero length.
1784 In matching, spaces are ignored.
1787 In ASN.1, Printable string is just a string of printable characters
1788 and can be empty. In X.500, semantics much like NumericString (see
1789 serialNumber for a like example) excepting uses insignificant space
1790 handling instead of ignore all spaces. They must be non-empty.
1793 Basically same as PrintableString. There are no examples in X.500,
1794 but same logic applies. Empty strings are allowed.
1796 -------------------------------------------------------------------*/
1804 unsigned char *u = (unsigned char *)in->bv_val, *end = (unsigned char *)in->bv_val + in->bv_len;
1806 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1807 /* directory strings cannot be empty */
1808 return LDAP_INVALID_SYNTAX;
1811 for( ; u < end; u += len ) {
1812 /* get the length indicated by the first byte */
1813 len = LDAP_UTF8_CHARLEN2( u, len );
1815 /* very basic checks */
1818 if( (u[5] & 0xC0) != 0x80 ) {
1819 return LDAP_INVALID_SYNTAX;
1822 if( (u[4] & 0xC0) != 0x80 ) {
1823 return LDAP_INVALID_SYNTAX;
1826 if( (u[3] & 0xC0) != 0x80 ) {
1827 return LDAP_INVALID_SYNTAX;
1830 if( (u[2] & 0xC0 )!= 0x80 ) {
1831 return LDAP_INVALID_SYNTAX;
1834 if( (u[1] & 0xC0) != 0x80 ) {
1835 return LDAP_INVALID_SYNTAX;
1838 /* CHARLEN already validated it */
1841 return LDAP_INVALID_SYNTAX;
1844 /* make sure len corresponds with the offset
1845 to the next character */
1846 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1850 return LDAP_INVALID_SYNTAX;
1853 return LDAP_SUCCESS;
1857 UTF8StringNormalize(
1862 struct berval *normalized,
1865 struct berval tmp, nvalue;
1866 int flags, wasspace;
1869 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1871 if( BER_BVISNULL( val ) ) {
1872 /* assume we're dealing with a syntax (e.g., UTF8String)
1873 * which allows empty strings
1875 BER_BVZERO( normalized );
1876 return LDAP_SUCCESS;
1879 flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1880 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1881 flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1882 ? LDAP_UTF8_APPROX : 0;
1884 val = UTF8bvnormalize( val, &tmp, flags, ctx );
1885 /* out of memory or syntax error, the former is unlikely */
1887 return LDAP_INVALID_SYNTAX;
1890 /* collapse spaces (in place) */
1892 nvalue.bv_val = tmp.bv_val;
1894 /* trim leading spaces? */
1895 wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1896 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1898 for( i = 0; i < tmp.bv_len; i++) {
1899 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1900 if( wasspace++ == 0 ) {
1901 /* trim repeated spaces */
1902 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1906 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1910 if( !BER_BVISEMPTY( &nvalue ) ) {
1911 /* trim trailing space? */
1913 (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1914 ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1918 nvalue.bv_val[nvalue.bv_len] = '\0';
1920 } else if ( tmp.bv_len ) {
1921 /* string of all spaces is treated as one space */
1922 nvalue.bv_val[0] = ' ';
1923 nvalue.bv_val[1] = '\0';
1925 } /* should never be entered with 0-length val */
1927 *normalized = nvalue;
1928 return LDAP_SUCCESS;
1932 directoryStringSubstringsMatch(
1937 struct berval *value,
1938 void *assertedValue )
1941 SubstringsAssertion *sub = assertedValue;
1942 struct berval left = *value;
1946 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1947 if ( sub->sa_initial.bv_len > left.bv_len ) {
1948 /* not enough left */
1953 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1954 sub->sa_initial.bv_len );
1960 left.bv_val += sub->sa_initial.bv_len;
1961 left.bv_len -= sub->sa_initial.bv_len;
1963 priorspace = ASCII_SPACE(
1964 sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1967 if ( sub->sa_any ) {
1968 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1972 if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1973 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1975 /* allow next space to match */
1982 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
1986 if ( sub->sa_any[i].bv_len > left.bv_len ) {
1987 /* not enough left */
1992 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
1999 idx = p - left.bv_val;
2001 if ( idx >= left.bv_len ) {
2002 /* this shouldn't happen */
2009 if ( sub->sa_any[i].bv_len > left.bv_len ) {
2010 /* not enough left */
2015 match = memcmp( left.bv_val,
2016 sub->sa_any[i].bv_val,
2017 sub->sa_any[i].bv_len );
2025 left.bv_val += sub->sa_any[i].bv_len;
2026 left.bv_len -= sub->sa_any[i].bv_len;
2028 priorspace = ASCII_SPACE(
2029 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
2033 if ( !BER_BVISNULL( &sub->sa_final ) ) {
2034 if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
2035 && ASCII_SPACE( sub->sa_final.bv_val[0] ))
2037 /* allow next space to match */
2042 if ( sub->sa_final.bv_len > left.bv_len ) {
2043 /* not enough left */
2048 match = memcmp( sub->sa_final.bv_val,
2049 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
2050 sub->sa_final.bv_len );
2059 return LDAP_SUCCESS;
2062 #if defined(SLAPD_APPROX_INITIALS)
2063 # define SLAPD_APPROX_DELIMITER "._ "
2064 # define SLAPD_APPROX_WORDLEN 2
2066 # define SLAPD_APPROX_DELIMITER " "
2067 # define SLAPD_APPROX_WORDLEN 1
2076 struct berval *value,
2077 void *assertedValue )
2079 struct berval *nval, *assertv;
2080 char *val, **values, **words, *c;
2081 int i, count, len, nextchunk=0, nextavail=0;
2083 /* Yes, this is necessary */
2084 nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
2085 if( nval == NULL ) {
2087 return LDAP_SUCCESS;
2090 /* Yes, this is necessary */
2091 assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
2092 NULL, LDAP_UTF8_APPROX, NULL );
2093 if( assertv == NULL ) {
2096 return LDAP_SUCCESS;
2099 /* Isolate how many words there are */
2100 for ( c = nval->bv_val, count = 1; *c; c++ ) {
2101 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
2102 if ( c == NULL ) break;
2107 /* Get a phonetic copy of each word */
2108 words = (char **)ch_malloc( count * sizeof(char *) );
2109 values = (char **)ch_malloc( count * sizeof(char *) );
2110 for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) {
2112 values[i] = phonetic(c);
2115 /* Work through the asserted value's words, to see if at least some
2116 * of the words are there, in the same order. */
2118 while ( (ber_len_t) nextchunk < assertv->bv_len ) {
2119 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
2124 #if defined(SLAPD_APPROX_INITIALS)
2125 else if( len == 1 ) {
2126 /* Single letter words need to at least match one word's initial */
2127 for( i=nextavail; i<count; i++ )
2128 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
2135 /* Isolate the next word in the asserted value and phonetic it */
2136 assertv->bv_val[nextchunk+len] = '\0';
2137 val = phonetic( assertv->bv_val + nextchunk );
2139 /* See if this phonetic chunk is in the remaining words of *value */
2140 for( i=nextavail; i<count; i++ ){
2141 if( !strcmp( val, values[i] ) ){
2149 /* This chunk in the asserted value was NOT within the *value. */
2155 /* Go on to the next word in the asserted value */
2159 /* If some of the words were seen, call it a match */
2160 if( nextavail > 0 ) {
2167 /* Cleanup allocs */
2168 ber_bvfree( assertv );
2169 for( i=0; i<count; i++ ) {
2170 ch_free( values[i] );
2176 return LDAP_SUCCESS;
2185 struct berval *prefix,
2191 int i,j, len, wordcount, keycount=0;
2192 struct berval *newkeys;
2193 BerVarray keys=NULL;
2195 for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
2196 struct berval val = BER_BVNULL;
2197 /* Yes, this is necessary */
2198 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
2199 assert( !BER_BVISNULL( &val ) );
2201 /* Isolate how many words there are. There will be a key for each */
2202 for( wordcount = 0, c = val.bv_val; *c; c++) {
2203 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2204 if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
2206 if (*c == '\0') break;
2210 /* Allocate/increase storage to account for new keys */
2211 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
2212 * sizeof(struct berval) );
2213 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
2214 if( keys ) ch_free( keys );
2217 /* Get a phonetic copy of each word */
2218 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
2220 if( len < SLAPD_APPROX_WORDLEN ) continue;
2221 ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
2222 if( keys[keycount].bv_len ) {
2225 ch_free( keys[keycount].bv_val );
2230 ber_memfree( val.bv_val );
2232 BER_BVZERO( &keys[keycount] );
2235 return LDAP_SUCCESS;
2244 struct berval *prefix,
2245 void * assertedValue,
2254 /* Yes, this is necessary */
2255 val = UTF8bvnormalize( ((struct berval *)assertedValue),
2256 NULL, LDAP_UTF8_APPROX, NULL );
2257 if( val == NULL || BER_BVISNULL( val ) ) {
2258 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2259 BER_BVZERO( &keys[0] );
2262 return LDAP_SUCCESS;
2265 /* Isolate how many words there are. There will be a key for each */
2266 for( count = 0,c = val->bv_val; *c; c++) {
2267 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2268 if( len >= SLAPD_APPROX_WORDLEN ) count++;
2270 if (*c == '\0') break;
2274 /* Allocate storage for new keys */
2275 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2277 /* Get a phonetic copy of each word */
2278 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2280 if( len < SLAPD_APPROX_WORDLEN ) continue;
2281 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2287 BER_BVZERO( &keys[count] );
2290 return LDAP_SUCCESS;
2293 /* Remove all spaces and '-' characters, unless the result would be empty */
2295 telephoneNumberNormalize(
2300 struct berval *normalized,
2305 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2307 /* Ensure q is big enough, though validator should have caught this */
2308 if ( BER_BVISEMPTY( val )) {
2309 BER_BVZERO( normalized );
2310 return LDAP_INVALID_SYNTAX;
2313 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2315 for( p = val->bv_val; *p; p++ ) {
2316 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
2320 if ( q == normalized->bv_val ) {
2325 normalized->bv_len = q - normalized->bv_val;
2327 return LDAP_SUCCESS;
2331 postalAddressValidate(
2335 struct berval bv = *in;
2338 for ( c = 0; c < in->bv_len; c++ ) {
2339 if ( in->bv_val[c] == '\\' ) {
2341 if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2342 && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2344 return LDAP_INVALID_SYNTAX;
2349 if ( in->bv_val[c] == '$' ) {
2350 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2351 if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2352 return LDAP_INVALID_SYNTAX;
2354 bv.bv_val = &in->bv_val[c] + 1;
2358 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2359 return UTF8StringValidate( NULL, &bv );
2363 postalAddressNormalize(
2368 struct berval *normalized,
2371 BerVarray lines = NULL, nlines = NULL;
2373 int rc = LDAP_SUCCESS;
2374 MatchingRule *xmr = NULL;
2377 if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2378 xmr = slap_schema.si_mr_caseIgnoreMatch;
2381 xmr = slap_schema.si_mr_caseExactMatch;
2384 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2385 if ( val->bv_val[c] == '$' ) {
2390 lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2391 nlines = &lines[l + 2];
2393 lines[0].bv_val = val->bv_val;
2394 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2395 if ( val->bv_val[c] == '$' ) {
2396 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2398 lines[l].bv_val = &val->bv_val[c + 1];
2401 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2403 normalized->bv_len = c = l;
2405 for ( l = 0; l <= c; l++ ) {
2406 /* NOTE: we directly normalize each line,
2407 * without unescaping the values, since the special
2408 * values '\24' ('$') and '\5C' ('\') are not affected
2409 * by normalization */
2410 if ( !lines[l].bv_len ) {
2411 nlines[l].bv_len = 0;
2412 nlines[l].bv_val = NULL;
2415 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2416 if ( rc != LDAP_SUCCESS ) {
2417 rc = LDAP_INVALID_SYNTAX;
2421 normalized->bv_len += nlines[l].bv_len;
2424 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2426 p = normalized->bv_val;
2427 for ( l = 0; l <= c ; l++ ) {
2428 p = lutil_strbvcopy( p, &nlines[l] );
2433 assert( p == &normalized->bv_val[normalized->bv_len] );
2436 if ( nlines != NULL ) {
2437 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2438 slap_sl_free( nlines[l].bv_val, ctx );
2441 slap_sl_free( lines, ctx );
2452 struct berval val = *in;
2454 if( BER_BVISEMPTY( &val ) ) {
2455 /* disallow empty strings */
2456 return LDAP_INVALID_SYNTAX;
2459 while( OID_LEADCHAR( val.bv_val[0] ) ) {
2460 if ( val.bv_len == 1 ) {
2461 return LDAP_SUCCESS;
2464 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2471 while ( OID_LEADCHAR( val.bv_val[0] )) {
2475 if ( val.bv_len == 0 ) {
2476 return LDAP_SUCCESS;
2480 if( !OID_SEPARATOR( val.bv_val[0] )) {
2488 return LDAP_INVALID_SYNTAX;
2497 struct berval val = *in;
2499 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2501 if ( val.bv_val[0] == '-' ) {
2505 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2506 return LDAP_INVALID_SYNTAX;
2509 if( val.bv_val[0] == '0' ) { /* "-0" */
2510 return LDAP_INVALID_SYNTAX;
2513 } else if ( val.bv_val[0] == '0' ) {
2514 if( val.bv_len > 1 ) { /* "0<more>" */
2515 return LDAP_INVALID_SYNTAX;
2518 return LDAP_SUCCESS;
2521 for( i=0; i < val.bv_len; i++ ) {
2522 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2523 return LDAP_INVALID_SYNTAX;
2527 return LDAP_SUCCESS;
2536 struct berval *value,
2537 void *assertedValue )
2539 struct berval *asserted = (struct berval *) assertedValue;
2540 int vsign = 1, asign = 1; /* default sign = '+' */
2545 if( v.bv_val[0] == '-' ) {
2551 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2554 if( a.bv_val[0] == '-' ) {
2560 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2562 match = vsign - asign;
2564 match = ( v.bv_len != a.bv_len
2565 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2566 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2567 if( vsign < 0 ) match = -match;
2570 /* Ordering rule used in extensible match filter? */
2571 if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2572 match = (match >= 0);
2575 return LDAP_SUCCESS;
2578 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2579 #define INDEX_INTLEN_CHOP 7
2580 #define INDEX_INTLEN_CHOPBYTES 3
2589 /* Integer index key format, designed for memcmp to collate correctly:
2590 * if too large: one's complement sign*<approx exponent=chopped bytes>,
2591 * two's complement value (sign-extended or chopped as needed),
2592 * however in first byte above, the top <number of exponent-bytes + 1>
2593 * bits are the inverse sign and next bit is the sign as delimiter.
2595 ber_slen_t k = index_intlen_strlen;
2597 unsigned signmask = ~0x7fU;
2598 unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2599 struct berval val = *in, itmp = *tmp;
2601 if ( val.bv_val[0] != '-' ) {
2606 /* Chop least significant digits, increase length instead */
2607 if ( val.bv_len > (ber_len_t) k ) {
2608 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2609 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2610 chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
2613 if ( lutil_str2bin( &val, &itmp, ctx )) {
2614 return LDAP_INVALID_SYNTAX;
2617 /* Omit leading sign byte */
2618 if ( itmp.bv_val[0] == neg ) {
2623 k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2625 assert( chop == 0 );
2626 memset( key->bv_val, neg, k ); /* sign-extend */
2627 } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2628 /* Got exponent -k, or no room for 2 sign bits */
2629 lenp = lenbuf + sizeof(lenbuf);
2630 chop = - (ber_len_t) k;
2632 *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2634 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2635 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2636 * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2637 k = (lenbuf + sizeof(lenbuf)) - lenp;
2638 if ( k > (ber_slen_t) index_intlen )
2640 memcpy( key->bv_val, lenp, k );
2641 itmp.bv_len = index_intlen - k;
2643 memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2644 key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2648 /* Index generation function: Ordered index */
2655 struct berval *prefix,
2665 unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2667 /* count the values and find max needed length */
2669 for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2670 if ( vlen < values[i].bv_len )
2671 vlen = values[i].bv_len;
2673 if ( vlen > maxstrlen )
2676 /* we should have at least one value at this point */
2679 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2680 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2681 keys[i].bv_len = index_intlen;
2682 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2685 keys[i].bv_val = NULL;
2687 if ( vlen > sizeof(ibuf) ) {
2688 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2692 itmp.bv_len = sizeof(ibuf);
2694 for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2695 if ( itmp.bv_val != ibuf ) {
2696 itmp.bv_len = values[i].bv_len;
2697 if ( itmp.bv_len <= sizeof(ibuf) )
2698 itmp.bv_len = sizeof(ibuf);
2699 else if ( itmp.bv_len > maxstrlen )
2700 itmp.bv_len = maxstrlen;
2702 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2704 slap_sl_free( keys, ctx );
2710 if ( itmp.bv_val != ibuf ) {
2711 slap_sl_free( itmp.bv_val, ctx );
2716 /* Index generation function: Ordered index */
2723 struct berval *prefix,
2724 void * assertedValue,
2731 struct berval *value;
2734 value = (struct berval *) assertedValue;
2736 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2738 keys[0].bv_len = index_intlen;
2739 keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2741 keys[1].bv_val = NULL;
2743 iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2744 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2745 if ( iv.bv_len > (int) sizeof(ibuf) ) {
2746 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2749 iv.bv_len = sizeof(ibuf);
2752 rc = integerVal2Key( value, keys, &iv, ctx );
2754 if ( iv.bv_val != ibuf ) {
2755 slap_sl_free( iv.bv_val, ctx );
2761 slap_sl_free( keys, ctx );
2767 countryStringValidate(
2769 struct berval *val )
2771 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2773 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2774 return LDAP_INVALID_SYNTAX;
2776 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2777 return LDAP_INVALID_SYNTAX;
2780 return LDAP_SUCCESS;
2784 printableStringValidate(
2786 struct berval *val )
2790 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2792 for(i=0; i < val->bv_len; i++) {
2793 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2794 return LDAP_INVALID_SYNTAX;
2798 return LDAP_SUCCESS;
2802 printablesStringValidate(
2804 struct berval *val )
2808 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2810 for(i=0,len=0; i < val->bv_len; i++) {
2811 int c = val->bv_val[i];
2815 return LDAP_INVALID_SYNTAX;
2819 } else if ( SLAP_PRINTABLE(c) ) {
2822 return LDAP_INVALID_SYNTAX;
2827 return LDAP_INVALID_SYNTAX;
2830 return LDAP_SUCCESS;
2836 struct berval *val )
2840 for(i=0; i < val->bv_len; i++) {
2841 if( !LDAP_ASCII(val->bv_val[i]) ) {
2842 return LDAP_INVALID_SYNTAX;
2846 return LDAP_SUCCESS;
2855 struct berval *normalized,
2859 int casefold = !SLAP_MR_ASSOCIATED( mr,
2860 slap_schema.si_mr_caseExactIA5Match );
2862 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2866 /* Ignore initial whitespace */
2867 while ( ASCII_SPACE( *p ) ) p++;
2869 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2870 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2871 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2872 normalized->bv_val[normalized->bv_len] = '\0';
2874 p = q = normalized->bv_val;
2877 if ( ASCII_SPACE( *p ) ) {
2880 /* Ignore the extra whitespace */
2881 while ( ASCII_SPACE( *p ) ) {
2885 } else if ( casefold ) {
2886 /* Most IA5 rules require casefolding */
2887 *q++ = TOLOWER(*p); p++;
2894 assert( normalized->bv_val <= p );
2898 * If the string ended in space, backup the pointer one
2899 * position. One is enough because the above loop collapsed
2900 * all whitespace to a single space.
2902 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2904 /* null terminate */
2907 normalized->bv_len = q - normalized->bv_val;
2909 return LDAP_SUCCESS;
2918 if( in->bv_len != 36 ) {
2919 return LDAP_INVALID_SYNTAX;
2922 for( i=0; i<36; i++ ) {
2928 if( in->bv_val[i] != '-' ) {
2929 return LDAP_INVALID_SYNTAX;
2933 if( !ASCII_HEX( in->bv_val[i]) ) {
2934 return LDAP_INVALID_SYNTAX;
2939 return LDAP_SUCCESS;
2950 int rc=LDAP_INVALID_SYNTAX;
2952 assert( in != NULL );
2953 assert( out != NULL );
2955 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2958 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2960 for( i=0; i<36; i++ ) {
2966 if( in->bv_val[i] != '-' ) {
2969 out->bv_val[i] = '-';
2973 if( !ASCII_HEX( in->bv_val[i]) ) {
2976 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2981 out->bv_val[ out->bv_len ] = '\0';
2985 slap_sl_free( out->bv_val, ctx );
2998 struct berval *normalized,
3001 unsigned char octet = '\0';
3005 if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
3006 /* NOTE: must be a normalized UUID */
3007 assert( val->bv_len == 16 );
3009 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
3010 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
3011 val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
3012 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
3014 return LDAP_SUCCESS;
3017 normalized->bv_len = 16;
3018 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
3020 for( i=0, j=0; i<36; i++ ) {
3021 unsigned char nibble;
3022 if( val->bv_val[i] == '-' ) {
3025 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
3026 nibble = val->bv_val[i] - '0';
3028 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
3029 nibble = val->bv_val[i] - ('a'-10);
3031 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
3032 nibble = val->bv_val[i] - ('A'-10);
3035 slap_sl_free( normalized->bv_val, ctx );
3036 BER_BVZERO( normalized );
3037 return LDAP_INVALID_SYNTAX;
3042 normalized->bv_val[j>>1] = octet;
3044 octet = nibble << 4;
3049 normalized->bv_val[normalized->bv_len] = 0;
3050 return LDAP_SUCCESS;
3056 numericStringValidate(
3062 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
3064 for(i=0; i < in->bv_len; i++) {
3065 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
3066 return LDAP_INVALID_SYNTAX;
3070 return LDAP_SUCCESS;
3074 numericStringNormalize(
3079 struct berval *normalized,
3082 /* removal all spaces */
3085 assert( !BER_BVISEMPTY( val ) );
3087 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3090 q = normalized->bv_val;
3093 if ( ASCII_SPACE( *p ) ) {
3094 /* Ignore whitespace */
3101 /* we should have copied no more than is in val */
3102 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3104 /* null terminate */
3107 normalized->bv_len = q - normalized->bv_val;
3109 if( BER_BVISEMPTY( normalized ) ) {
3110 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3111 normalized->bv_val[0] = ' ';
3112 normalized->bv_val[1] = '\0';
3113 normalized->bv_len = 1;
3116 return LDAP_SUCCESS;
3120 * Integer conversion macros that will use the largest available
3123 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3124 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
3125 # define SLAP_LONG long long
3127 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
3128 # define SLAP_LONG long
3129 #endif /* HAVE_STRTOLL ... */
3137 struct berval *value,
3138 void *assertedValue )
3140 SLAP_LONG lValue, lAssertedValue;
3143 /* safe to assume integers are NUL terminated? */
3144 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3145 if( errno == ERANGE )
3147 return LDAP_CONSTRAINT_VIOLATION;
3150 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3152 if( errno == ERANGE )
3154 return LDAP_CONSTRAINT_VIOLATION;
3157 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3158 return LDAP_SUCCESS;
3167 struct berval *value,
3168 void *assertedValue )
3170 SLAP_LONG lValue, lAssertedValue;
3173 /* safe to assume integers are NUL terminated? */
3174 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3175 if( errno == ERANGE )
3177 return LDAP_CONSTRAINT_VIOLATION;
3180 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3182 if( errno == ERANGE )
3184 return LDAP_CONSTRAINT_VIOLATION;
3187 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3188 return LDAP_SUCCESS;
3192 checkNum( struct berval *in, struct berval *out )
3194 /* parse serialNumber */
3195 ber_len_t neg = 0, extra = 0;
3198 out->bv_val = in->bv_val;
3201 if ( out->bv_val[0] == '-' ) {
3206 if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3207 first = out->bv_val[2];
3210 out->bv_len += STRLENOF("0x");
3211 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3212 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3215 } else if ( out->bv_val[0] == '\'' ) {
3216 first = out->bv_val[1];
3219 out->bv_len += STRLENOF("'");
3221 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3222 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3224 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3227 out->bv_len += STRLENOF("'H");
3230 first = out->bv_val[0];
3231 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3232 if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3236 if ( !( out->bv_len > neg ) ) {
3240 if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3248 serialNumberAndIssuerCheck(
3256 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3258 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3259 /* Parse old format */
3260 is->bv_val = ber_bvchr( in, '$' );
3261 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3263 sn->bv_val = in->bv_val;
3264 sn->bv_len = is->bv_val - in->bv_val;
3267 is->bv_len = in->bv_len - (sn->bv_len + 1);
3269 /* eat leading zeros */
3270 for( n=0; n < (sn->bv_len-1); n++ ) {
3271 if( sn->bv_val[n] != '0' ) break;
3276 for( n=0; n < sn->bv_len; n++ ) {
3277 if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3281 /* Parse GSER format */
3286 HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3290 struct berval x = *in;
3296 /* eat leading spaces */
3297 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3301 /* should be at issuer or serialNumber NamedValue */
3302 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3303 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3306 x.bv_val += STRLENOF("issuer");
3307 x.bv_len -= STRLENOF("issuer");
3309 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3313 /* eat leading spaces */
3314 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3318 /* For backward compatibility, this part is optional */
3319 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3320 x.bv_val += STRLENOF("rdnSequence:");
3321 x.bv_len -= STRLENOF("rdnSequence:");
3324 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3328 is->bv_val = x.bv_val;
3331 for ( ; is->bv_len < x.bv_len; ) {
3332 if ( is->bv_val[is->bv_len] != '"' ) {
3336 if ( is->bv_val[is->bv_len+1] == '"' ) {
3344 x.bv_val += is->bv_len + 1;
3345 x.bv_len -= is->bv_len + 1;
3347 have |= HAVE_ISSUER;
3349 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3351 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3353 /* parse serialNumber */
3354 x.bv_val += STRLENOF("serialNumber");
3355 x.bv_len -= STRLENOF("serialNumber");
3357 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3361 /* eat leading spaces */
3362 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3366 if ( checkNum( &x, sn ) ) {
3367 return LDAP_INVALID_SYNTAX;
3370 x.bv_val += sn->bv_len;
3371 x.bv_len -= sn->bv_len;
3376 return LDAP_INVALID_SYNTAX;
3379 /* eat leading spaces */
3380 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3384 if ( have == HAVE_ALL ) {
3388 if ( x.bv_val[0] != ',' ) {
3389 return LDAP_INVALID_SYNTAX;
3396 /* should have no characters left... */
3397 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3399 if ( numdquotes == 0 ) {
3400 ber_dupbv_x( &ni, is, ctx );
3405 ni.bv_len = is->bv_len - numdquotes;
3406 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3407 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3408 if ( is->bv_val[src] == '"' ) {
3411 ni.bv_val[dst] = is->bv_val[src];
3413 ni.bv_val[dst] = '\0';
3423 serialNumberAndIssuerValidate(
3428 struct berval sn, i;
3430 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3433 rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3438 /* validate DN -- doesn't handle double dquote */
3439 rc = dnValidate( NULL, &i );
3441 rc = LDAP_INVALID_SYNTAX;
3444 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3445 slap_sl_free( i.bv_val, NULL );
3448 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3449 in->bv_val, rc, 0 );
3456 serialNumberAndIssuerPretty(
3463 struct berval sn, i, ni = BER_BVNULL;
3466 assert( in != NULL );
3467 assert( out != NULL );
3471 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3474 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3479 rc = dnPretty( syntax, &i, &ni, ctx );
3481 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3482 slap_sl_free( i.bv_val, ctx );
3486 rc = LDAP_INVALID_SYNTAX;
3490 /* make room from sn + "$" */
3491 out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3492 + sn.bv_len + ni.bv_len;
3493 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3495 if ( out->bv_val == NULL ) {
3502 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3503 p = lutil_strbvcopy( p, &sn );
3504 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3505 p = lutil_strbvcopy( p, &ni );
3506 p = lutil_strcopy( p, /*{*/ "\" }" );
3508 assert( p == &out->bv_val[out->bv_len] );
3511 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3512 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3514 slap_sl_free( ni.bv_val, ctx );
3516 return LDAP_SUCCESS;
3526 /* Use hex format. '123456789abcdef'H */
3527 unsigned char *ptr, zero = '\0';
3530 ber_len_t i, len, nlen;
3532 assert( in != NULL );
3533 assert( !BER_BVISNULL( in ) );
3534 assert( out != NULL );
3535 assert( !BER_BVISNULL( out ) );
3537 ptr = (unsigned char *)in->bv_val;
3540 /* Check for minimal encodings */
3542 if ( ptr[0] & 0x80 ) {
3543 if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3547 } else if ( ptr[0] == 0 ) {
3548 if ( !( ptr[1] & 0x80 ) ) {
3555 } else if ( len == 0 ) {
3556 /* FIXME: this should not be possible,
3557 * since a value of zero would have length 1 */
3562 first = !( ptr[0] & 0xf0U );
3563 nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3564 if ( nlen >= out->bv_len ) {
3565 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3571 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3575 for ( ; i < len; i++ ) {
3576 sprintf( sptr, "%02X", ptr[i] );
3583 assert( sptr == &out->bv_val[nlen] );
3590 #define SLAP_SN_BUFLEN (64)
3593 * This routine is called by certificateExactNormalize when
3594 * certificateExactNormalize receives a search string instead of
3595 * a certificate. This routine checks if the search value is valid
3596 * and then returns the normalized value
3599 serialNumberAndIssuerNormalize(
3607 struct berval sn, sn2, sn3, i, ni;
3608 char sbuf2[SLAP_SN_BUFLEN];
3609 char sbuf3[SLAP_SN_BUFLEN];
3613 assert( in != NULL );
3614 assert( out != NULL );
3616 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3619 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3624 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3626 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3627 slap_sl_free( i.bv_val, ctx );
3631 return LDAP_INVALID_SYNTAX;
3634 /* Convert sn to canonical hex */
3636 if ( sn.bv_len > sizeof( sbuf2 ) ) {
3637 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3639 sn2.bv_len = sn.bv_len;
3641 sn3.bv_len = sizeof(sbuf3);
3642 if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
3643 rc = LDAP_INVALID_SYNTAX;
3647 out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3648 + sn3.bv_len + ni.bv_len;
3649 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3650 if ( out->bv_val == NULL ) {
3658 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3659 p = lutil_strbvcopy( p, &sn3 );
3660 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3661 p = lutil_strbvcopy( p, &ni );
3662 p = lutil_strcopy( p, /*{*/ "\" }" );
3664 assert( p == &out->bv_val[out->bv_len] );
3667 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3668 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3670 if ( sn2.bv_val != sbuf2 ) {
3671 slap_sl_free( sn2.bv_val, ctx );
3674 if ( sn3.bv_val != sbuf3 ) {
3675 slap_sl_free( sn3.bv_val, ctx );
3678 slap_sl_free( ni.bv_val, ctx );
3684 certificateExactNormalize(
3689 struct berval *normalized,
3692 BerElementBuffer berbuf;
3693 BerElement *ber = (BerElement *)&berbuf;
3697 char serialbuf2[SLAP_SN_BUFLEN];
3698 struct berval sn, sn2 = BER_BVNULL;
3699 struct berval issuer_dn = BER_BVNULL, bvdn;
3701 int rc = LDAP_INVALID_SYNTAX;
3703 assert( val != NULL );
3705 Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3706 val->bv_val, val->bv_len, 0 );
3708 if ( BER_BVISEMPTY( val ) ) goto done;
3710 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3711 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3714 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3716 ber_init2( ber, val, LBER_USE_DER );
3717 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3718 tag = ber_skip_tag( ber, &len ); /* Sequence */
3719 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3720 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3721 tag = ber_skip_tag( ber, &len );
3722 tag = ber_get_int( ber, &i ); /* version */
3725 /* NOTE: move the test here from certificateValidate,
3726 * so that we can validate certs with serial longer
3727 * than sizeof(ber_int_t) */
3728 tag = ber_skip_tag( ber, &len ); /* serial */
3730 sn.bv_val = (char *)ber->ber_ptr;
3731 sn2.bv_val = serialbuf2;
3732 sn2.bv_len = sizeof(serialbuf2);
3733 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3734 rc = LDAP_INVALID_SYNTAX;
3737 ber_skip_data( ber, len );
3739 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3740 ber_skip_data( ber, len );
3741 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3743 len = ber_ptrlen( ber );
3744 bvdn.bv_val = val->bv_val + len;
3745 bvdn.bv_len = val->bv_len - len;
3747 rc = dnX509normalize( &bvdn, &issuer_dn );
3748 if ( rc != LDAP_SUCCESS ) goto done;
3751 normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3752 + sn2.bv_len + issuer_dn.bv_len;
3753 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3755 p = normalized->bv_val;
3757 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3758 p = lutil_strbvcopy( p, &sn2 );
3759 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3760 p = lutil_strbvcopy( p, &issuer_dn );
3761 p = lutil_strcopy( p, /*{*/ "\" }" );
3766 Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3767 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3769 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3770 if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3775 /* X.509 PKI certificateList stuff */
3777 checkTime( struct berval *in, struct berval *out )
3781 char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3784 assert( in != NULL );
3785 assert( !BER_BVISNULL( in ) );
3786 assert( !BER_BVISEMPTY( in ) );
3788 if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3792 if ( out != NULL ) {
3793 assert( !BER_BVISNULL( out ) );
3794 assert( out->bv_len >= sizeof( buf ) );
3795 bv.bv_val = out->bv_val;
3801 for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3802 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3805 if ( in->bv_val[i] != 'Z' ) {
3810 if ( i != in->bv_len ) {
3814 if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3815 lutil_strncopy( bv.bv_val, in->bv_val, i );
3818 } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3819 char *p = bv.bv_val;
3820 if ( in->bv_val[0] < '7' ) {
3821 p = lutil_strcopy( p, "20" );
3824 p = lutil_strcopy( p, "19" );
3826 lutil_strncopy( p, in->bv_val, i );
3833 rc = generalizedTimeValidate( NULL, &bv );
3834 if ( rc == LDAP_SUCCESS && out != NULL ) {
3835 if ( out->bv_len > bv.bv_len ) {
3836 out->bv_val[ bv.bv_len ] = '\0';
3838 out->bv_len = bv.bv_len;
3841 return rc != LDAP_SUCCESS;
3845 issuerAndThisUpdateCheck(
3852 struct berval x = *in;
3853 struct berval ni = BER_BVNULL;
3854 /* Parse GSER format */
3858 HAVE_THISUPDATE = 0x2,
3859 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3863 if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3865 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3866 return LDAP_INVALID_SYNTAX;
3870 x.bv_len -= STRLENOF("{}");
3873 /* eat leading spaces */
3874 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3878 /* should be at issuer or thisUpdate */
3879 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3880 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3883 x.bv_val += STRLENOF("issuer");
3884 x.bv_len -= STRLENOF("issuer");
3886 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3890 /* eat leading spaces */
3891 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3895 /* For backward compatibility, this part is optional */
3896 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3897 return LDAP_INVALID_SYNTAX;
3899 x.bv_val += STRLENOF("rdnSequence:");
3900 x.bv_len -= STRLENOF("rdnSequence:");
3902 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3906 is->bv_val = x.bv_val;
3909 for ( ; is->bv_len < x.bv_len; ) {
3910 if ( is->bv_val[is->bv_len] != '"' ) {
3914 if ( is->bv_val[is->bv_len+1] == '"' ) {
3922 x.bv_val += is->bv_len + 1;
3923 x.bv_len -= is->bv_len + 1;
3925 have |= HAVE_ISSUER;
3927 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3929 if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3931 /* parse thisUpdate */
3932 x.bv_val += STRLENOF("thisUpdate");
3933 x.bv_len -= STRLENOF("thisUpdate");
3935 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3939 /* eat leading spaces */
3940 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3944 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3948 tu->bv_val = x.bv_val;
3951 for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3952 if ( tu->bv_val[tu->bv_len] == '"' ) {
3956 x.bv_val += tu->bv_len + 1;
3957 x.bv_len -= tu->bv_len + 1;
3959 have |= HAVE_THISUPDATE;
3962 return LDAP_INVALID_SYNTAX;
3965 /* eat leading spaces */
3966 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3970 if ( have == HAVE_ALL ) {
3974 if ( x.bv_val[0] != ',' ) {
3975 return LDAP_INVALID_SYNTAX;
3982 /* should have no characters left... */
3983 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3985 if ( numdquotes == 0 ) {
3986 ber_dupbv_x( &ni, is, ctx );
3991 ni.bv_len = is->bv_len - numdquotes;
3992 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3993 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3994 if ( is->bv_val[src] == '"' ) {
3997 ni.bv_val[dst] = is->bv_val[src];
3999 ni.bv_val[dst] = '\0';
4008 issuerAndThisUpdateValidate(
4013 struct berval i, tu;
4015 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
4018 rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
4023 /* validate DN -- doesn't handle double dquote */
4024 rc = dnValidate( NULL, &i );
4026 rc = LDAP_INVALID_SYNTAX;
4028 } else if ( checkTime( &tu, NULL ) ) {
4029 rc = LDAP_INVALID_SYNTAX;
4032 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4033 slap_sl_free( i.bv_val, NULL );
4036 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
4037 in->bv_val, rc, 0 );
4044 issuerAndThisUpdatePretty(
4051 struct berval i, tu, ni = BER_BVNULL;
4054 assert( in != NULL );
4055 assert( out != NULL );
4059 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
4062 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4067 rc = dnPretty( syntax, &i, &ni, ctx );
4069 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4070 slap_sl_free( i.bv_val, ctx );
4073 if ( rc || checkTime( &tu, NULL ) ) {
4074 rc = LDAP_INVALID_SYNTAX;
4079 out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
4080 + ni.bv_len + tu.bv_len;
4081 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4083 if ( out->bv_val == NULL ) {
4090 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4091 p = lutil_strbvcopy( p, &ni );
4092 p = lutil_strcopy( p, "\", thisUpdate \"" );
4093 p = lutil_strbvcopy( p, &tu );
4094 p = lutil_strcopy( p, /*{*/ "\" }" );
4096 assert( p == &out->bv_val[out->bv_len] );
4099 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4100 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4102 slap_sl_free( ni.bv_val, ctx );
4108 issuerAndThisUpdateNormalize(
4116 struct berval i, ni, tu, tu2;
4117 char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4121 assert( in != NULL );
4122 assert( out != NULL );
4124 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4127 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4132 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4134 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4135 slap_sl_free( i.bv_val, ctx );
4139 tu2.bv_len = sizeof( sbuf );
4140 if ( rc || checkTime( &tu, &tu2 ) ) {
4141 return LDAP_INVALID_SYNTAX;
4144 out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4145 + ni.bv_len + tu2.bv_len;
4146 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4148 if ( out->bv_val == NULL ) {
4156 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4157 p = lutil_strbvcopy( p, &ni );
4158 p = lutil_strcopy( p, "\", thisUpdate \"" );
4159 p = lutil_strbvcopy( p, &tu2 );
4160 p = lutil_strcopy( p, /*{*/ "\" }" );
4162 assert( p == &out->bv_val[out->bv_len] );
4165 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4166 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4168 slap_sl_free( ni.bv_val, ctx );
4174 certificateListExactNormalize(
4179 struct berval *normalized,
4182 BerElementBuffer berbuf;
4183 BerElement *ber = (BerElement *)&berbuf;
4187 struct berval issuer_dn = BER_BVNULL, bvdn,
4189 char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4190 int rc = LDAP_INVALID_SYNTAX;
4192 assert( val != NULL );
4194 Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4195 val->bv_val, val->bv_len, 0 );
4197 if ( BER_BVISEMPTY( val ) ) goto done;
4199 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4200 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4203 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4205 ber_init2( ber, val, LBER_USE_DER );
4206 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
4207 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4208 tag = ber_skip_tag( ber, &len ); /* Sequence */
4209 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4210 tag = ber_peek_tag( ber, &len );
4211 /* Optional version */
4212 if ( tag == LBER_INTEGER ) {
4213 tag = ber_get_int( ber, &version );
4214 assert( tag == LBER_INTEGER );
4215 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4217 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
4218 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4219 ber_skip_data( ber, len );
4221 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
4222 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4223 len = ber_ptrlen( ber );
4224 bvdn.bv_val = val->bv_val + len;
4225 bvdn.bv_len = val->bv_len - len;
4226 tag = ber_skip_tag( ber, &len );
4227 ber_skip_data( ber, len );
4229 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
4230 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4231 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4232 bvtu.bv_val = (char *)ber->ber_ptr;
4235 rc = dnX509normalize( &bvdn, &issuer_dn );
4236 if ( rc != LDAP_SUCCESS ) goto done;
4238 thisUpdate.bv_val = tubuf;
4239 thisUpdate.bv_len = sizeof(tubuf);
4240 if ( checkTime( &bvtu, &thisUpdate ) ) {
4241 rc = LDAP_INVALID_SYNTAX;
4245 normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4246 + issuer_dn.bv_len + thisUpdate.bv_len;
4247 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4249 p = normalized->bv_val;
4251 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4252 p = lutil_strbvcopy( p, &issuer_dn );
4253 p = lutil_strcopy( p, "\", thisUpdate \"" );
4254 p = lutil_strbvcopy( p, &thisUpdate );
4255 p = lutil_strcopy( p, /*{*/ "\" }" );
4260 Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4261 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4263 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4268 /* X.509 PMI serialNumberAndIssuerSerialCheck
4270 AttributeCertificateExactAssertion ::= SEQUENCE {
4271 serialNumber CertificateSerialNumber,
4272 issuer AttCertIssuer }
4274 CertificateSerialNumber ::= INTEGER
4276 AttCertIssuer ::= [0] SEQUENCE {
4277 issuerName GeneralNames OPTIONAL,
4278 baseCertificateID [0] IssuerSerial OPTIONAL,
4279 objectDigestInfo [1] ObjectDigestInfo OPTIONAL }
4280 -- At least one component shall be present
4282 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4284 GeneralName ::= CHOICE {
4285 otherName [0] INSTANCE OF OTHER-NAME,
4286 rfc822Name [1] IA5String,
4287 dNSName [2] IA5String,
4288 x400Address [3] ORAddress,
4289 directoryName [4] Name,
4290 ediPartyName [5] EDIPartyName,
4291 uniformResourceIdentifier [6] IA5String,
4292 iPAddress [7] OCTET STRING,
4293 registeredID [8] OBJECT IDENTIFIER }
4295 IssuerSerial ::= SEQUENCE {
4296 issuer GeneralNames,
4297 serial CertificateSerialNumber,
4298 issuerUID UniqueIdentifier OPTIONAL }
4300 ObjectDigestInfo ::= SEQUENCE {
4301 digestedObjectType ENUMERATED {
4304 otherObjectTypes (2) },
4305 otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
4306 digestAlgorithm AlgorithmIdentifier,
4307 objectDigest BIT STRING }
4309 * The way I interpret it, an assertion should look like
4311 { serialNumber 'dd'H,
4312 issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4313 baseCertificateID { serial '1d'H,
4314 issuer { directoryName:rdnSequence:"cn=zzz" },
4315 issuerUID <value> -- optional
4317 objectDigestInfo { ... } -- optional
4321 * with issuerName, baseCertificateID and objectDigestInfo optional,
4322 * at least one present; the way it's currently implemented, it is
4324 { serialNumber 'dd'H,
4325 issuer { baseCertificateID { serial '1d'H,
4326 issuer { directoryName:rdnSequence:"cn=zzz" }
4331 * with all the above parts mandatory.
4334 serialNumberAndIssuerSerialCheck(
4338 struct berval *i_sn, /* contain serial of baseCertificateID */
4341 /* Parse GSER format */
4346 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4347 } have = HAVE_NONE, have2 = HAVE_NONE;
4349 struct berval x = *in;
4352 if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4355 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4362 /* eat leading spaces */
4363 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4367 /* should be at issuer or serialNumber NamedValue */
4368 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4369 if ( have & HAVE_ISSUER ) {
4370 return LDAP_INVALID_SYNTAX;
4373 /* parse IssuerSerial */
4374 x.bv_val += STRLENOF("issuer");
4375 x.bv_len -= STRLENOF("issuer");
4377 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4381 /* eat leading spaces */
4382 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4386 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4390 /* eat leading spaces */
4391 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4395 if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4396 return LDAP_INVALID_SYNTAX;
4398 x.bv_val += STRLENOF("baseCertificateID ");
4399 x.bv_len -= STRLENOF("baseCertificateID ");
4401 /* eat leading spaces */
4402 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4406 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4411 /* eat leading spaces */
4412 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4416 /* parse issuer of baseCertificateID */
4417 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4418 if ( have2 & HAVE_ISSUER ) {
4419 return LDAP_INVALID_SYNTAX;
4422 x.bv_val += STRLENOF("issuer ");
4423 x.bv_len -= STRLENOF("issuer ");
4425 /* eat leading spaces */
4426 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4430 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4434 /* eat leading spaces */
4435 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4439 if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4440 return LDAP_INVALID_SYNTAX;
4442 x.bv_val += STRLENOF("directoryName:rdnSequence:");
4443 x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4445 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4449 is->bv_val = x.bv_val;
4452 for ( ; is->bv_len < x.bv_len; ) {
4453 if ( is->bv_val[is->bv_len] != '"' ) {
4457 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4465 x.bv_val += is->bv_len + 1;
4466 x.bv_len -= is->bv_len + 1;
4468 /* eat leading spaces */
4469 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4473 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4477 have2 |= HAVE_ISSUER;
4479 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4480 if ( have2 & HAVE_SN ) {
4481 return LDAP_INVALID_SYNTAX;
4484 x.bv_val += STRLENOF("serial ");
4485 x.bv_len -= STRLENOF("serial ");
4487 /* eat leading spaces */
4488 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4492 if ( checkNum( &x, i_sn ) ) {
4493 return LDAP_INVALID_SYNTAX;
4496 x.bv_val += i_sn->bv_len;
4497 x.bv_len -= i_sn->bv_len;
4502 return LDAP_INVALID_SYNTAX;
4505 /* eat leading spaces */
4506 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4510 if ( have2 == HAVE_ALL ) {
4514 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4519 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4523 /* eat leading spaces */
4524 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4528 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4532 have |= HAVE_ISSUER;
4534 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4535 if ( have & HAVE_SN ) {
4536 return LDAP_INVALID_SYNTAX;
4539 /* parse serialNumber */
4540 x.bv_val += STRLENOF("serialNumber");
4541 x.bv_len -= STRLENOF("serialNumber");
4543 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4547 /* eat leading spaces */
4548 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4552 if ( checkNum( &x, sn ) ) {
4553 return LDAP_INVALID_SYNTAX;
4556 x.bv_val += sn->bv_len;
4557 x.bv_len -= sn->bv_len;
4562 return LDAP_INVALID_SYNTAX;
4566 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4570 if ( have == HAVE_ALL ) {
4574 if ( x.bv_val[0] != ',' ) {
4575 return LDAP_INVALID_SYNTAX;
4581 /* should have no characters left... */
4582 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4584 if ( numdquotes == 0 ) {
4585 ber_dupbv_x( &ni, is, ctx );
4590 ni.bv_len = is->bv_len - numdquotes;
4591 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4592 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4593 if ( is->bv_val[src] == '"' ) {
4596 ni.bv_val[dst] = is->bv_val[src];
4598 ni.bv_val[dst] = '\0';
4603 /* need to handle double dquotes here */
4607 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4609 serialNumberAndIssuerSerialValidate(
4614 struct berval sn, i, i_sn;
4616 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4619 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4624 /* validate DN -- doesn't handle double dquote */
4625 rc = dnValidate( NULL, &i );
4627 rc = LDAP_INVALID_SYNTAX;
4630 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4631 slap_sl_free( i.bv_val, NULL );
4635 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4636 in->bv_val, rc, 0 );
4641 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4643 serialNumberAndIssuerSerialPretty(
4649 struct berval sn, i, i_sn, ni = BER_BVNULL;
4653 assert( in != NULL );
4654 assert( out != NULL );
4656 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4659 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4664 rc = dnPretty( syntax, &i, &ni, ctx );
4666 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4667 slap_sl_free( i.bv_val, ctx );
4671 rc = LDAP_INVALID_SYNTAX;
4675 /* make room from sn + "$" */
4676 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4677 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4678 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4680 if ( out->bv_val == NULL ) {
4687 p = lutil_strcopy( p, "{ serialNumber " );
4688 p = lutil_strbvcopy( p, &sn );
4689 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4690 p = lutil_strbvcopy( p, &ni );
4691 p = lutil_strcopy( p, "\" }, serial " );
4692 p = lutil_strbvcopy( p, &i_sn );
4693 p = lutil_strcopy( p, " } } }" );
4695 assert( p == &out->bv_val[out->bv_len] );
4698 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4699 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4701 slap_sl_free( ni.bv_val, ctx );
4706 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4708 * This routine is called by attributeCertificateExactNormalize
4709 * when attributeCertificateExactNormalize receives a search
4710 * string instead of a attribute certificate. This routine
4711 * checks if the search value is valid and then returns the
4715 serialNumberAndIssuerSerialNormalize(
4723 struct berval i, ni = BER_BVNULL,
4724 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4725 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4726 char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4727 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4731 assert( in != NULL );
4732 assert( out != NULL );
4734 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4737 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4742 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4744 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4745 slap_sl_free( i.bv_val, ctx );
4749 rc = LDAP_INVALID_SYNTAX;
4753 /* Convert sn to canonical hex */
4755 sn2.bv_len = sn.bv_len;
4756 if ( sn.bv_len > sizeof( sbuf2 ) ) {
4757 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4759 if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4760 rc = LDAP_INVALID_SYNTAX;
4764 /* Convert i_sn to canonical hex */
4765 i_sn2.bv_val = i_sbuf2;
4766 i_sn2.bv_len = i_sn.bv_len;
4767 if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4768 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4770 if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4771 rc = LDAP_INVALID_SYNTAX;
4776 sn3.bv_len = sizeof(sbuf3);
4777 if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4778 rc = LDAP_INVALID_SYNTAX;
4782 i_sn3.bv_val = i_sbuf3;
4783 i_sn3.bv_len = sizeof(i_sbuf3);
4784 if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4785 rc = LDAP_INVALID_SYNTAX;
4789 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4790 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4791 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4793 if ( out->bv_val == NULL ) {
4801 p = lutil_strcopy( p, "{ serialNumber " );
4802 p = lutil_strbvcopy( p, &sn3 );
4803 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4804 p = lutil_strbvcopy( p, &ni );
4805 p = lutil_strcopy( p, "\" }, serial " );
4806 p = lutil_strbvcopy( p, &i_sn3 );
4807 p = lutil_strcopy( p, " } } }" );
4809 assert( p == &out->bv_val[out->bv_len] );
4812 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4813 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4815 if ( sn2.bv_val != sbuf2 ) {
4816 slap_sl_free( sn2.bv_val, ctx );
4819 if ( i_sn2.bv_val != i_sbuf2 ) {
4820 slap_sl_free( i_sn2.bv_val, ctx );
4823 if ( sn3.bv_val != sbuf3 ) {
4824 slap_sl_free( sn3.bv_val, ctx );
4827 if ( i_sn3.bv_val != i_sbuf3 ) {
4828 slap_sl_free( i_sn3.bv_val, ctx );
4831 slap_sl_free( ni.bv_val, ctx );
4836 /* X.509 PMI attributeCertificateExactNormalize */
4838 attributeCertificateExactNormalize(
4843 struct berval *normalized,
4846 BerElementBuffer berbuf;
4847 BerElement *ber = (BerElement *)&berbuf;
4850 char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4851 struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4852 struct berval issuer_dn = BER_BVNULL, bvdn;
4854 int rc = LDAP_INVALID_SYNTAX;
4856 if ( BER_BVISEMPTY( val ) ) {
4860 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4861 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4864 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4866 ber_init2( ber, val, LBER_USE_DER );
4867 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
4868 tag = ber_skip_tag( ber, &len ); /* Sequence */
4869 tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */
4870 ber_skip_data( ber, len );
4871 tag = ber_skip_tag( ber, &len ); /* Holder Sequence */
4872 ber_skip_data( ber, len );
4875 tag = ber_skip_tag( ber, &len ); /* Sequence */
4876 /* issuerName (GeneralNames sequence; optional)? */
4877 tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */
4878 tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */
4879 tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */
4880 if ( tag != SLAP_X509_GN_DIRECTORYNAME ) {
4881 return LDAP_INVALID_SYNTAX;
4883 tag = ber_peek_tag( ber, &len ); /* sequence of RDN */
4884 len = ber_ptrlen( ber );
4885 bvdn.bv_val = val->bv_val + len;
4886 bvdn.bv_len = val->bv_len - len;
4887 rc = dnX509normalize( &bvdn, &issuer_dn );
4888 if ( rc != LDAP_SUCCESS ) goto done;
4890 tag = ber_skip_tag( ber, &len ); /* sequence of RDN */
4891 ber_skip_data( ber, len );
4892 tag = ber_skip_tag( ber, &len ); /* serial number */
4893 if ( tag != LBER_INTEGER ) {
4894 rc = LDAP_INVALID_SYNTAX;
4897 i_sn.bv_val = (char *)ber->ber_ptr;
4899 i_sn2.bv_val = issuer_serialbuf;
4900 i_sn2.bv_len = sizeof(issuer_serialbuf);
4901 if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4902 rc = LDAP_INVALID_SYNTAX;
4905 ber_skip_data( ber, len );
4907 /* issuerUID (bitstring; optional)? */
4908 /* objectDigestInfo (sequence; optional)? */
4910 tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */
4911 ber_skip_data( ber, len );
4912 tag = ber_skip_tag( ber, &len ); /* serial number */
4913 if ( tag != LBER_INTEGER ) {
4914 rc = LDAP_INVALID_SYNTAX;
4917 sn.bv_val = (char *)ber->ber_ptr;
4919 sn2.bv_val = serialbuf;
4920 sn2.bv_len = sizeof(serialbuf);
4921 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4922 rc = LDAP_INVALID_SYNTAX;
4925 ber_skip_data( ber, len );
4927 normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" )
4928 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4929 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4931 p = normalized->bv_val;
4933 p = lutil_strcopy( p, "{ serialNumber " );
4934 p = lutil_strbvcopy( p, &sn2 );
4935 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4936 p = lutil_strbvcopy( p, &issuer_dn );
4937 p = lutil_strcopy( p, "\" }, serial " );
4938 p = lutil_strbvcopy( p, &i_sn2 );
4939 p = lutil_strcopy( p, " } } }" );
4941 Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4942 normalized->bv_val, NULL, NULL );
4947 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4948 if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4949 if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4962 assert( in != NULL );
4963 assert( !BER_BVISNULL( in ) );
4965 for ( i = 0; i < in->bv_len; i++ ) {
4966 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4967 return LDAP_INVALID_SYNTAX;
4971 return LDAP_SUCCESS;
4974 /* Normalize a SID as used inside a CSN:
4975 * three-digit numeric string */
4982 struct berval *normalized,
4987 assert( val != NULL );
4988 assert( normalized != NULL );
4990 ber_dupbv_x( normalized, val, ctx );
4992 for ( i = 0; i < normalized->bv_len; i++ ) {
4993 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
4994 ber_memfree_x( normalized->bv_val, ctx );
4995 BER_BVZERO( normalized );
4996 return LDAP_INVALID_SYNTAX;
4999 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5002 return LDAP_SUCCESS;
5010 assert( in != NULL );
5011 assert( !BER_BVISNULL( in ) );
5013 if ( in->bv_len != 3 ) {
5014 return LDAP_INVALID_SYNTAX;
5017 return hexValidate( NULL, in );
5020 /* Normalize a SID as used inside a CSN:
5021 * three-digit numeric string */
5028 struct berval *normalized,
5031 if ( val->bv_len != 3 ) {
5032 return LDAP_INVALID_SYNTAX;
5035 return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
5045 return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5048 /* Normalize a SID as used inside a CSN, either as-is
5049 * (assertion value) or extracted from the CSN
5050 * (attribute value) */
5057 struct berval *normalized,
5065 if ( BER_BVISEMPTY( val ) ) {
5066 return LDAP_INVALID_SYNTAX;
5069 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
5070 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
5073 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
5075 ptr = ber_bvchr( val, '#' );
5076 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5077 return LDAP_INVALID_SYNTAX;
5080 bv.bv_val = ptr + 1;
5081 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5083 ptr = ber_bvchr( &bv, '#' );
5084 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5085 return LDAP_INVALID_SYNTAX;
5088 bv.bv_val = ptr + 1;
5089 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5091 ptr = ber_bvchr( &bv, '#' );
5092 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5093 return LDAP_INVALID_SYNTAX;
5096 bv.bv_len = ptr - bv.bv_val;
5098 if ( bv.bv_len == 2 ) {
5099 /* OpenLDAP 2.3 SID */
5101 buf[ 1 ] = bv.bv_val[ 0 ];
5102 buf[ 2 ] = bv.bv_val[ 1 ];
5109 return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5121 assert( in != NULL );
5122 assert( !BER_BVISNULL( in ) );
5124 if ( BER_BVISEMPTY( in ) ) {
5125 return LDAP_INVALID_SYNTAX;
5130 ptr = ber_bvchr( &bv, '#' );
5131 if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5132 return LDAP_INVALID_SYNTAX;
5135 bv.bv_len = ptr - bv.bv_val;
5136 if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5137 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5139 return LDAP_INVALID_SYNTAX;
5142 rc = generalizedTimeValidate( NULL, &bv );
5143 if ( rc != LDAP_SUCCESS ) {
5147 bv.bv_val = ptr + 1;
5148 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5150 ptr = ber_bvchr( &bv, '#' );
5151 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5152 return LDAP_INVALID_SYNTAX;
5155 bv.bv_len = ptr - bv.bv_val;
5156 if ( bv.bv_len != 6 ) {
5157 return LDAP_INVALID_SYNTAX;
5160 rc = hexValidate( NULL, &bv );
5161 if ( rc != LDAP_SUCCESS ) {
5165 bv.bv_val = ptr + 1;
5166 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5168 ptr = ber_bvchr( &bv, '#' );
5169 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5170 return LDAP_INVALID_SYNTAX;
5173 bv.bv_len = ptr - bv.bv_val;
5174 if ( bv.bv_len == 2 ) {
5175 /* tolerate old 2-digit replica-id */
5176 rc = hexValidate( NULL, &bv );
5179 rc = sidValidate( NULL, &bv );
5181 if ( rc != LDAP_SUCCESS ) {
5185 bv.bv_val = ptr + 1;
5186 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5188 if ( bv.bv_len != 6 ) {
5189 return LDAP_INVALID_SYNTAX;
5192 return hexValidate( NULL, &bv );
5195 /* Normalize a CSN in OpenLDAP 2.1 format */
5202 struct berval *normalized,
5205 struct berval gt, cnt, sid, mod;
5207 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5211 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5212 assert( !BER_BVISEMPTY( val ) );
5216 ptr = ber_bvchr( >, '#' );
5217 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5218 return LDAP_INVALID_SYNTAX;
5221 gt.bv_len = ptr - gt.bv_val;
5222 if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5223 return LDAP_INVALID_SYNTAX;
5226 if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5227 return LDAP_INVALID_SYNTAX;
5230 cnt.bv_val = ptr + 1;
5231 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5233 ptr = ber_bvchr( &cnt, '#' );
5234 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5235 return LDAP_INVALID_SYNTAX;
5238 cnt.bv_len = ptr - cnt.bv_val;
5239 if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5240 return LDAP_INVALID_SYNTAX;
5243 if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5244 return LDAP_INVALID_SYNTAX;
5247 cnt.bv_val += STRLENOF( "0x" );
5248 cnt.bv_len -= STRLENOF( "0x" );
5250 sid.bv_val = ptr + 1;
5251 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5253 ptr = ber_bvchr( &sid, '#' );
5254 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5255 return LDAP_INVALID_SYNTAX;
5258 sid.bv_len = ptr - sid.bv_val;
5259 if ( sid.bv_len != STRLENOF( "0" ) ) {
5260 return LDAP_INVALID_SYNTAX;
5263 mod.bv_val = ptr + 1;
5264 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5265 if ( mod.bv_len != STRLENOF( "0000" ) ) {
5266 return LDAP_INVALID_SYNTAX;
5269 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5273 ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5274 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5276 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5278 ptr = lutil_strcopy( ptr, ".000000Z#00" );
5279 ptr = lutil_strbvcopy( ptr, &cnt );
5283 *ptr++ = sid.bv_val[ 0 ];
5287 for ( i = 0; i < mod.bv_len; i++ ) {
5288 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5292 assert( ptr == &bv.bv_val[bv.bv_len] );
5294 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5295 return LDAP_INVALID_SYNTAX;
5298 ber_dupbv_x( normalized, &bv, ctx );
5300 return LDAP_SUCCESS;
5303 /* Normalize a CSN in OpenLDAP 2.3 format */
5310 struct berval *normalized,
5313 struct berval gt, cnt, sid, mod;
5315 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5319 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5320 assert( !BER_BVISEMPTY( val ) );
5324 ptr = ber_bvchr( >, '#' );
5325 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5326 return LDAP_INVALID_SYNTAX;
5329 gt.bv_len = ptr - gt.bv_val;
5330 if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5331 return LDAP_INVALID_SYNTAX;
5334 cnt.bv_val = ptr + 1;
5335 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5337 ptr = ber_bvchr( &cnt, '#' );
5338 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5339 return LDAP_INVALID_SYNTAX;
5342 cnt.bv_len = ptr - cnt.bv_val;
5343 if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5344 return LDAP_INVALID_SYNTAX;
5347 sid.bv_val = ptr + 1;
5348 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5350 ptr = ber_bvchr( &sid, '#' );
5351 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5352 return LDAP_INVALID_SYNTAX;
5355 sid.bv_len = ptr - sid.bv_val;
5356 if ( sid.bv_len != STRLENOF( "00" ) ) {
5357 return LDAP_INVALID_SYNTAX;
5360 mod.bv_val = ptr + 1;
5361 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5362 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5363 return LDAP_INVALID_SYNTAX;
5366 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5370 ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5371 ptr = lutil_strcopy( ptr, ".000000Z#" );
5372 ptr = lutil_strbvcopy( ptr, &cnt );
5375 for ( i = 0; i < sid.bv_len; i++ ) {
5376 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5379 for ( i = 0; i < mod.bv_len; i++ ) {
5380 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5384 assert( ptr == &bv.bv_val[bv.bv_len] );
5385 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5386 return LDAP_INVALID_SYNTAX;
5389 ber_dupbv_x( normalized, &bv, ctx );
5391 return LDAP_SUCCESS;
5394 /* Normalize a CSN */
5401 struct berval *normalized,
5404 struct berval cnt, sid, mod;
5408 assert( val != NULL );
5409 assert( normalized != NULL );
5411 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5413 if ( BER_BVISEMPTY( val ) ) {
5414 return LDAP_INVALID_SYNTAX;
5417 if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5418 /* Openldap <= 2.3 */
5420 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5423 if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5426 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5429 if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5430 return LDAP_INVALID_SYNTAX;
5433 ptr = ber_bvchr( val, '#' );
5434 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5435 return LDAP_INVALID_SYNTAX;
5438 if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5439 return LDAP_INVALID_SYNTAX;
5442 cnt.bv_val = ptr + 1;
5443 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5445 ptr = ber_bvchr( &cnt, '#' );
5446 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5447 return LDAP_INVALID_SYNTAX;
5450 if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5451 return LDAP_INVALID_SYNTAX;
5454 sid.bv_val = ptr + 1;
5455 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5457 ptr = ber_bvchr( &sid, '#' );
5458 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5459 return LDAP_INVALID_SYNTAX;
5462 sid.bv_len = ptr - sid.bv_val;
5463 if ( sid.bv_len != STRLENOF( "000" ) ) {
5464 return LDAP_INVALID_SYNTAX;
5467 mod.bv_val = ptr + 1;
5468 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5470 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5471 return LDAP_INVALID_SYNTAX;
5474 ber_dupbv_x( normalized, val, ctx );
5476 for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5477 i < normalized->bv_len; i++ )
5479 /* assume it's already validated that's all hex digits */
5480 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5483 return LDAP_SUCCESS;
5493 return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5496 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5497 /* slight optimization - does not need the start parameter */
5498 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5503 check_time_syntax (struct berval *val,
5506 struct berval *fraction)
5509 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5510 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
5511 * GeneralizedTime supports leap seconds, UTCTime does not.
5513 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5514 static const int mdays[2][12] = {
5515 /* non-leap years */
5516 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5518 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5521 int part, c, c1, c2, tzoffset, leapyear = 0;
5524 e = p + val->bv_len;
5526 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5527 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5529 for (part = start; part < 7 && p < e; part++) {
5531 if (!ASCII_DIGIT(c1)) {
5536 return LDAP_INVALID_SYNTAX;
5539 if (!ASCII_DIGIT(c)) {
5540 return LDAP_INVALID_SYNTAX;
5542 c += c1 * 10 - '0' * 11;
5543 if ((part | 1) == 3) {
5546 return LDAP_INVALID_SYNTAX;
5549 if (c >= ceiling[part]) {
5550 if (! (c == 60 && part == 6 && start == 0))
5551 return LDAP_INVALID_SYNTAX;
5555 if (part < 5 + start) {
5556 return LDAP_INVALID_SYNTAX;
5558 for (; part < 9; part++) {
5562 /* leapyear check for the Gregorian calendar (year>1581) */
5563 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5567 if (parts[3] >= mdays[leapyear][parts[2]]) {
5568 return LDAP_INVALID_SYNTAX;
5572 fraction->bv_val = p;
5573 fraction->bv_len = 0;
5574 if (p < e && (*p == '.' || *p == ',')) {
5576 while (++p < e && ASCII_DIGIT(*p)) {
5579 if (p - fraction->bv_val == 1) {
5580 return LDAP_INVALID_SYNTAX;
5582 for (end_num = p; end_num[-1] == '0'; --end_num) {
5585 c = end_num - fraction->bv_val;
5586 if (c != 1) fraction->bv_len = c;
5592 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5598 return LDAP_INVALID_SYNTAX;
5604 for (part = 7; part < 9 && p < e; part++) {
5606 if (!ASCII_DIGIT(c1)) {
5611 return LDAP_INVALID_SYNTAX;
5614 if (!ASCII_DIGIT(c2)) {
5615 return LDAP_INVALID_SYNTAX;
5617 parts[part] = c1 * 10 + c2 - '0' * 11;
5618 if (parts[part] >= ceiling[part]) {
5619 return LDAP_INVALID_SYNTAX;
5622 if (part < 8 + start) {
5623 return LDAP_INVALID_SYNTAX;
5626 if (tzoffset == '-') {
5627 /* negative offset to UTC, ie west of Greenwich */
5628 parts[4] += parts[7];
5629 parts[5] += parts[8];
5630 /* offset is just hhmm, no seconds */
5631 for (part = 6; --part >= 0; ) {
5635 c = mdays[leapyear][parts[2]];
5637 if (parts[part] >= c) {
5639 return LDAP_INVALID_SYNTAX;
5644 } else if (part != 5) {
5649 /* positive offset to UTC, ie east of Greenwich */
5650 parts[4] -= parts[7];
5651 parts[5] -= parts[8];
5652 for (part = 6; --part >= 0; ) {
5653 if (parts[part] < 0) {
5655 return LDAP_INVALID_SYNTAX;
5660 /* make first arg to % non-negative */
5661 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5666 } else if (part != 5) {
5673 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5676 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5683 struct berval *normalized )
5687 rc = check_time_syntax(val, 1, parts, NULL);
5688 if (rc != LDAP_SUCCESS) {
5692 normalized->bv_val = ch_malloc( 14 );
5693 if ( normalized->bv_val == NULL ) {
5694 return LBER_ERROR_MEMORY;
5697 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5698 parts[1], parts[2] + 1, parts[3] + 1,
5699 parts[4], parts[5], parts[6] );
5700 normalized->bv_len = 13;
5702 return LDAP_SUCCESS;
5712 return check_time_syntax(in, 1, parts, NULL);
5715 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5718 generalizedTimeValidate(
5723 struct berval fraction;
5724 return check_time_syntax(in, 0, parts, &fraction);
5728 generalizedTimeNormalize(
5733 struct berval *normalized,
5738 struct berval fraction;
5740 rc = check_time_syntax(val, 0, parts, &fraction);
5741 if (rc != LDAP_SUCCESS) {
5745 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5746 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5747 if ( BER_BVISNULL( normalized ) ) {
5748 return LBER_ERROR_MEMORY;
5751 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5752 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5753 parts[4], parts[5], parts[6] );
5754 if ( !BER_BVISEMPTY( &fraction ) ) {
5755 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5756 fraction.bv_val, fraction.bv_len );
5757 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5759 strcpy( normalized->bv_val + len-1, "Z" );
5760 normalized->bv_len = len;
5762 return LDAP_SUCCESS;
5766 generalizedTimeOrderingMatch(
5771 struct berval *value,
5772 void *assertedValue )
5774 struct berval *asserted = (struct berval *) assertedValue;
5775 ber_len_t v_len = value->bv_len;
5776 ber_len_t av_len = asserted->bv_len;
5778 /* ignore trailing 'Z' when comparing */
5779 int match = memcmp( value->bv_val, asserted->bv_val,
5780 (v_len < av_len ? v_len : av_len) - 1 );
5781 if ( match == 0 ) match = v_len - av_len;
5783 /* If used in extensible match filter, match if value < asserted */
5784 if ( flags & SLAP_MR_EXT )
5785 match = (match >= 0);
5788 return LDAP_SUCCESS;
5791 /* Index generation function: Ordered index */
5792 int generalizedTimeIndexer(
5797 struct berval *prefix,
5805 BerValue bvtmp; /* 40 bit index */
5807 struct lutil_timet tt;
5809 bvtmp.bv_len = sizeof(tmp);
5811 for( i=0; values[i].bv_val != NULL; i++ ) {
5812 /* just count them */
5815 /* we should have at least one value at this point */
5818 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5820 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5821 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5822 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5823 /* Use 40 bits of time for key */
5824 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5825 lutil_tm2time( &tm, &tt );
5826 tmp[0] = tt.tt_gsec & 0xff;
5827 tmp[4] = tt.tt_sec & 0xff;
5829 tmp[3] = tt.tt_sec & 0xff;
5831 tmp[2] = tt.tt_sec & 0xff;
5833 tmp[1] = tt.tt_sec & 0xff;
5835 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5839 keys[j].bv_val = NULL;
5844 return LDAP_SUCCESS;
5847 /* Index generation function: Ordered index */
5848 int generalizedTimeFilter(
5853 struct berval *prefix,
5854 void * assertedValue,
5860 BerValue bvtmp; /* 40 bit index */
5861 BerValue *value = (BerValue *) assertedValue;
5863 struct lutil_timet tt;
5865 bvtmp.bv_len = sizeof(tmp);
5867 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5868 /* Use 40 bits of time for key */
5869 if ( value->bv_val && value->bv_len >= 10 &&
5870 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5872 lutil_tm2time( &tm, &tt );
5873 tmp[0] = tt.tt_gsec & 0xff;
5874 tmp[4] = tt.tt_sec & 0xff;
5876 tmp[3] = tt.tt_sec & 0xff;
5878 tmp[2] = tt.tt_sec & 0xff;
5880 tmp[1] = tt.tt_sec & 0xff;
5882 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5883 ber_dupbv_x(keys, &bvtmp, ctx );
5884 keys[1].bv_val = NULL;
5892 return LDAP_SUCCESS;
5896 deliveryMethodValidate(
5898 struct berval *val )
5901 #define LENOF(s) (sizeof(s)-1)
5902 struct berval tmp = *val;
5904 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5905 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5906 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5909 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5911 switch( tmp.bv_val[0] ) {
5914 if(( tmp.bv_len >= LENOF("any") ) &&
5915 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5917 tmp.bv_len -= LENOF("any");
5918 tmp.bv_val += LENOF("any");
5921 return LDAP_INVALID_SYNTAX;
5925 if(( tmp.bv_len >= LENOF("mhs") ) &&
5926 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5928 tmp.bv_len -= LENOF("mhs");
5929 tmp.bv_val += LENOF("mhs");
5932 return LDAP_INVALID_SYNTAX;
5936 if(( tmp.bv_len >= LENOF("physical") ) &&
5937 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5939 tmp.bv_len -= LENOF("physical");
5940 tmp.bv_val += LENOF("physical");
5943 return LDAP_INVALID_SYNTAX;
5946 case 'T': /* telex or teletex or telephone */
5947 if(( tmp.bv_len >= LENOF("telex") ) &&
5948 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5950 tmp.bv_len -= LENOF("telex");
5951 tmp.bv_val += LENOF("telex");
5954 if(( tmp.bv_len >= LENOF("teletex") ) &&
5955 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5957 tmp.bv_len -= LENOF("teletex");
5958 tmp.bv_val += LENOF("teletex");
5961 if(( tmp.bv_len >= LENOF("telephone") ) &&
5962 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5964 tmp.bv_len -= LENOF("telephone");
5965 tmp.bv_val += LENOF("telephone");
5968 return LDAP_INVALID_SYNTAX;
5971 case 'G': /* g3fax or g4fax */
5972 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5973 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5974 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5976 tmp.bv_len -= LENOF("g3fax");
5977 tmp.bv_val += LENOF("g3fax");
5980 return LDAP_INVALID_SYNTAX;
5984 if(( tmp.bv_len >= LENOF("ia5") ) &&
5985 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
5987 tmp.bv_len -= LENOF("ia5");
5988 tmp.bv_val += LENOF("ia5");
5991 return LDAP_INVALID_SYNTAX;
5995 if(( tmp.bv_len >= LENOF("videotex") ) &&
5996 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
5998 tmp.bv_len -= LENOF("videotex");
5999 tmp.bv_val += LENOF("videotex");
6002 return LDAP_INVALID_SYNTAX;
6005 return LDAP_INVALID_SYNTAX;
6008 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
6010 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
6014 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
6018 return LDAP_INVALID_SYNTAX;
6020 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
6029 nisNetgroupTripleValidate(
6031 struct berval *val )
6036 if ( BER_BVISEMPTY( val ) ) {
6037 return LDAP_INVALID_SYNTAX;
6040 p = (char *)val->bv_val;
6041 e = p + val->bv_len;
6043 if ( *p != '(' /*')'*/ ) {
6044 return LDAP_INVALID_SYNTAX;
6047 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
6051 return LDAP_INVALID_SYNTAX;
6054 } else if ( !AD_CHAR( *p ) ) {
6055 return LDAP_INVALID_SYNTAX;
6059 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
6060 return LDAP_INVALID_SYNTAX;
6066 return LDAP_INVALID_SYNTAX;
6069 return LDAP_SUCCESS;
6073 bootParameterValidate(
6075 struct berval *val )
6079 if ( BER_BVISEMPTY( val ) ) {
6080 return LDAP_INVALID_SYNTAX;
6083 p = (char *)val->bv_val;
6084 e = p + val->bv_len;
6087 for (; ( p < e ) && ( *p != '=' ); p++ ) {
6088 if ( !AD_CHAR( *p ) ) {
6089 return LDAP_INVALID_SYNTAX;
6094 return LDAP_INVALID_SYNTAX;
6098 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6099 if ( !AD_CHAR( *p ) ) {
6100 return LDAP_INVALID_SYNTAX;
6105 return LDAP_INVALID_SYNTAX;
6109 for ( p++; p < e; p++ ) {
6110 if ( !SLAP_PRINTABLE( *p ) ) {
6111 return LDAP_INVALID_SYNTAX;
6115 return LDAP_SUCCESS;
6119 firstComponentNormalize(
6124 struct berval *normalized,
6131 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6132 ber_dupbv_x( normalized, val, ctx );
6133 return LDAP_SUCCESS;
6136 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6138 if( ! ( val->bv_val[0] == '(' /*')'*/
6139 && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6140 && ! ( val->bv_val[0] == '{' /*'}'*/
6141 && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6143 return LDAP_INVALID_SYNTAX;
6146 /* trim leading white space */
6148 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6154 /* grab next word */
6155 comp.bv_val = &val->bv_val[len];
6156 len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6157 for( comp.bv_len = 0;
6158 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6164 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6165 rc = numericoidValidate( NULL, &comp );
6166 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6167 rc = integerValidate( NULL, &comp );
6169 rc = LDAP_INVALID_SYNTAX;
6173 if( rc == LDAP_SUCCESS ) {
6174 ber_dupbv_x( normalized, &comp, ctx );
6180 static char *country_gen_syn[] = {
6181 "1.3.6.1.4.1.1466.115.121.1.15", /* Directory String */
6182 "1.3.6.1.4.1.1466.115.121.1.26", /* IA5 String */
6183 "1.3.6.1.4.1.1466.115.121.1.44", /* Printable String */
6187 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6188 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6190 static slap_syntax_defs_rec syntax_defs[] = {
6191 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6192 X_BINARY X_NOT_H_R ")",
6193 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6194 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6195 0, NULL, NULL, NULL},
6196 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6197 0, NULL, NULL, NULL},
6198 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6200 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6201 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6203 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6204 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6205 0, NULL, bitStringValidate, NULL },
6206 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6207 0, NULL, booleanValidate, NULL},
6208 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6209 X_BINARY X_NOT_H_R ")",
6210 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6211 NULL, certificateValidate, NULL},
6212 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6213 X_BINARY X_NOT_H_R ")",
6214 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6215 NULL, certificateListValidate, NULL},
6216 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6217 X_BINARY X_NOT_H_R ")",
6218 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6219 NULL, sequenceValidate, NULL},
6220 {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6221 X_BINARY X_NOT_H_R ")",
6222 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6223 NULL, attributeCertificateValidate, NULL},
6224 #if 0 /* need to go __after__ printableString */
6225 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6226 0, "1.3.6.1.4.1.1466.115.121.1.44",
6227 countryStringValidate, NULL},
6229 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6230 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6231 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6232 0, NULL, rdnValidate, rdnPretty},
6233 #ifdef LDAP_COMP_MATCH
6234 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6235 0, NULL, allComponentsValidate, NULL},
6236 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6237 0, NULL, componentFilterValidate, NULL},
6239 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6240 0, NULL, NULL, NULL},
6241 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6242 0, NULL, deliveryMethodValidate, NULL},
6243 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6244 0, NULL, UTF8StringValidate, NULL},
6245 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6246 0, NULL, NULL, NULL},
6247 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6248 0, NULL, NULL, NULL},
6249 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6250 0, NULL, NULL, NULL},
6251 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6252 0, NULL, NULL, NULL},
6253 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6254 0, NULL, NULL, NULL},
6255 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6256 0, NULL, printablesStringValidate, NULL},
6257 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6258 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6259 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6260 0, NULL, generalizedTimeValidate, NULL},
6261 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6262 0, NULL, NULL, NULL},
6263 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6264 0, NULL, IA5StringValidate, NULL},
6265 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6266 0, NULL, integerValidate, NULL},
6267 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6268 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6269 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6270 0, NULL, NULL, NULL},
6271 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6272 0, NULL, NULL, NULL},
6273 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6274 0, NULL, NULL, NULL},
6275 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6276 0, NULL, NULL, NULL},
6277 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6278 0, NULL, NULL, NULL},
6279 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6280 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6281 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6282 0, NULL, NULL, NULL},
6283 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6284 0, NULL, numericStringValidate, NULL},
6285 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6286 0, NULL, NULL, NULL},
6287 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6288 0, NULL, numericoidValidate, NULL},
6289 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6290 0, NULL, IA5StringValidate, NULL},
6291 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6292 0, NULL, blobValidate, NULL},
6293 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6294 0, NULL, postalAddressValidate, NULL},
6295 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6296 0, NULL, NULL, NULL},
6297 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6298 0, NULL, NULL, NULL},
6299 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6300 0, NULL, printableStringValidate, NULL},
6301 /* moved here because now depends on Directory String, IA5 String
6302 * and Printable String */
6303 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6304 0, country_gen_syn, countryStringValidate, NULL},
6305 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6306 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6307 0, NULL, subtreeSpecificationValidate, NULL},
6308 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6309 X_BINARY X_NOT_H_R ")",
6310 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6311 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6312 0, NULL, printableStringValidate, NULL},
6313 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6314 0, NULL, NULL, NULL},
6315 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6316 0, NULL, printablesStringValidate, NULL},
6317 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6318 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6319 0, NULL, utcTimeValidate, NULL},
6321 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6322 0, NULL, NULL, NULL},
6323 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6324 0, NULL, NULL, NULL},
6325 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6326 0, NULL, NULL, NULL},
6327 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6328 0, NULL, NULL, NULL},
6329 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6330 0, NULL, NULL, NULL},
6332 /* RFC 2307 NIS Syntaxes */
6333 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
6334 0, NULL, nisNetgroupTripleValidate, NULL},
6335 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
6336 0, NULL, bootParameterValidate, NULL},
6338 /* draft-zeilenga-ldap-x509 */
6339 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6340 SLAP_SYNTAX_HIDE, NULL,
6341 serialNumberAndIssuerValidate,
6342 serialNumberAndIssuerPretty},
6343 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6344 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6345 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6346 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6347 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6348 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6349 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6350 SLAP_SYNTAX_HIDE, NULL,
6351 issuerAndThisUpdateValidate,
6352 issuerAndThisUpdatePretty},
6353 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6354 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6355 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6356 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6357 {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6358 SLAP_SYNTAX_HIDE, NULL,
6359 serialNumberAndIssuerSerialValidate,
6360 serialNumberAndIssuerSerialPretty},
6361 {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6362 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6364 #ifdef SLAPD_AUTHPASSWD
6365 /* needs updating */
6366 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6367 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6370 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6371 0, NULL, UUIDValidate, UUIDPretty},
6373 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6374 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6376 {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6377 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6379 /* OpenLDAP Void Syntax */
6380 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6381 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6383 /* FIXME: OID is unused, but not registered yet */
6384 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6385 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6387 /* PKCS#8 Private Keys for X.509 certificates */
6388 {"( 1.3.6.1.4.1.4203.666.2.13 DESC 'OpenLDAP privateKey' )",
6389 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, privateKeyValidate, NULL},
6390 {NULL, 0, NULL, NULL, NULL}
6393 char *csnSIDMatchSyntaxes[] = {
6394 "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6397 char *certificateExactMatchSyntaxes[] = {
6398 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6401 char *certificateListExactMatchSyntaxes[] = {
6402 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6405 char *attributeCertificateExactMatchSyntaxes[] = {
6406 attributeCertificateSyntaxOID /* attributeCertificate */,
6410 #ifdef LDAP_COMP_MATCH
6411 char *componentFilterMatchSyntaxes[] = {
6412 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6413 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6414 attributeCertificateSyntaxOID /* attributeCertificate */,
6419 char *directoryStringSyntaxes[] = {
6420 "1.3.6.1.4.1.1466.115.121.1.11" /* countryString */,
6421 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6422 "1.3.6.1.4.1.1466.115.121.1.50" /* telephoneNumber */,
6425 char *integerFirstComponentMatchSyntaxes[] = {
6426 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6427 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6430 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6431 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6432 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
6433 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6434 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6435 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6436 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6437 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6438 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6443 * Other matching rules in X.520 that we do not use (yet):
6445 * 2.5.13.25 uTCTimeMatch
6446 * 2.5.13.26 uTCTimeOrderingMatch
6447 * 2.5.13.31* directoryStringFirstComponentMatch
6448 * 2.5.13.32* wordMatch
6449 * 2.5.13.33* keywordMatch
6450 * 2.5.13.36+ certificatePairExactMatch
6451 * 2.5.13.37+ certificatePairMatch
6452 * 2.5.13.40+ algorithmIdentifierMatch
6453 * 2.5.13.41* storedPrefixMatch
6454 * 2.5.13.42 attributeCertificateMatch
6455 * 2.5.13.43 readerAndKeyIDMatch
6456 * 2.5.13.44 attributeIntegrityMatch
6458 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6459 * (+) described in draft-zeilenga-ldap-x509
6461 static slap_mrule_defs_rec mrule_defs[] = {
6463 * EQUALITY matching rules must be listed after associated APPROX
6464 * matching rules. So, we list all APPROX matching rules first.
6466 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6467 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6468 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6469 NULL, NULL, directoryStringApproxMatch,
6470 directoryStringApproxIndexer, directoryStringApproxFilter,
6473 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6474 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6475 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6476 NULL, NULL, IA5StringApproxMatch,
6477 IA5StringApproxIndexer, IA5StringApproxFilter,
6481 * Other matching rules
6484 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6485 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6486 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6487 NULL, NULL, octetStringMatch,
6488 octetStringIndexer, octetStringFilter,
6491 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6492 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6493 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6494 NULL, dnNormalize, dnMatch,
6495 octetStringIndexer, octetStringFilter,
6498 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6499 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6500 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6501 NULL, dnNormalize, dnRelativeMatch,
6505 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6506 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6507 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6508 NULL, dnNormalize, dnRelativeMatch,
6512 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6513 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6514 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6515 NULL, dnNormalize, dnRelativeMatch,
6519 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6520 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6521 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6522 NULL, dnNormalize, dnRelativeMatch,
6526 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6527 "SYNTAX 1.2.36.79672281.1.5.0 )",
6528 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6529 NULL, rdnNormalize, rdnMatch,
6530 octetStringIndexer, octetStringFilter,
6533 #ifdef LDAP_COMP_MATCH
6534 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6535 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6536 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6537 NULL, NULL , componentFilterMatch,
6538 octetStringIndexer, octetStringFilter,
6541 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6542 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6543 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6544 NULL, NULL , allComponentsMatch,
6545 octetStringIndexer, octetStringFilter,
6548 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6549 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6550 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6551 NULL, NULL , directoryComponentsMatch,
6552 octetStringIndexer, octetStringFilter,
6556 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6557 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6558 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6559 NULL, UTF8StringNormalize, octetStringMatch,
6560 octetStringIndexer, octetStringFilter,
6561 directoryStringApproxMatchOID },
6563 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6564 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6565 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6566 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6568 "caseIgnoreMatch" },
6570 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6571 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6572 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6573 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6574 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6575 "caseIgnoreMatch" },
6577 {"( 2.5.13.5 NAME 'caseExactMatch' "
6578 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6579 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6580 NULL, UTF8StringNormalize, octetStringMatch,
6581 octetStringIndexer, octetStringFilter,
6582 directoryStringApproxMatchOID },
6584 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6585 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6586 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6587 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6591 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6592 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6593 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6594 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6595 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6598 {"( 2.5.13.8 NAME 'numericStringMatch' "
6599 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6600 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6601 NULL, numericStringNormalize, octetStringMatch,
6602 octetStringIndexer, octetStringFilter,
6605 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6606 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6607 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6608 NULL, numericStringNormalize, octetStringOrderingMatch,
6610 "numericStringMatch" },
6612 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6613 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6614 SLAP_MR_SUBSTR, NULL,
6615 NULL, numericStringNormalize, octetStringSubstringsMatch,
6616 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6617 "numericStringMatch" },
6619 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6620 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6621 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6622 NULL, postalAddressNormalize, octetStringMatch,
6623 octetStringIndexer, octetStringFilter,
6626 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6627 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6628 SLAP_MR_SUBSTR, NULL,
6629 NULL, NULL, NULL, NULL, NULL,
6630 "caseIgnoreListMatch" },
6632 {"( 2.5.13.13 NAME 'booleanMatch' "
6633 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6634 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6635 NULL, NULL, booleanMatch,
6636 octetStringIndexer, octetStringFilter,
6639 {"( 2.5.13.14 NAME 'integerMatch' "
6640 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6641 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6642 NULL, NULL, integerMatch,
6643 integerIndexer, integerFilter,
6646 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6647 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6648 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6649 NULL, NULL, integerMatch,
6653 {"( 2.5.13.16 NAME 'bitStringMatch' "
6654 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6655 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6656 NULL, NULL, octetStringMatch,
6657 octetStringIndexer, octetStringFilter,
6660 {"( 2.5.13.17 NAME 'octetStringMatch' "
6661 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6662 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6663 NULL, NULL, octetStringMatch,
6664 octetStringIndexer, octetStringFilter,
6667 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6668 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6669 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6670 NULL, NULL, octetStringOrderingMatch,
6672 "octetStringMatch" },
6674 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6675 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6676 SLAP_MR_SUBSTR, NULL,
6677 NULL, NULL, octetStringSubstringsMatch,
6678 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6679 "octetStringMatch" },
6681 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6682 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6683 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6685 telephoneNumberNormalize, octetStringMatch,
6686 octetStringIndexer, octetStringFilter,
6689 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6690 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6691 SLAP_MR_SUBSTR, NULL,
6692 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6693 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6694 "telephoneNumberMatch" },
6696 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6697 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6698 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6699 NULL, NULL, NULL, NULL, NULL, NULL },
6701 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6702 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6703 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6704 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6705 uniqueMemberIndexer, uniqueMemberFilter,
6708 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6709 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6710 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6711 NULL, NULL, NULL, NULL, NULL, NULL },
6713 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6714 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6715 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6716 NULL, generalizedTimeNormalize, octetStringMatch,
6717 generalizedTimeIndexer, generalizedTimeFilter,
6720 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6721 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6722 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6723 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6725 "generalizedTimeMatch" },
6727 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6728 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6729 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6730 integerFirstComponentMatchSyntaxes,
6731 NULL, firstComponentNormalize, integerMatch,
6732 octetStringIndexer, octetStringFilter,
6735 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6736 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6737 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6738 objectIdentifierFirstComponentMatchSyntaxes,
6739 NULL, firstComponentNormalize, octetStringMatch,
6740 octetStringIndexer, octetStringFilter,
6743 {"( 2.5.13.34 NAME 'certificateExactMatch' "
6744 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6745 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6746 NULL, certificateExactNormalize, octetStringMatch,
6747 octetStringIndexer, octetStringFilter,
6750 {"( 2.5.13.35 NAME 'certificateMatch' "
6751 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6752 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6753 NULL, NULL, NULL, NULL, NULL,
6756 {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6757 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6758 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6759 NULL, certificateListExactNormalize, octetStringMatch,
6760 octetStringIndexer, octetStringFilter,
6763 {"( 2.5.13.39 NAME 'certificateListMatch' "
6764 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6765 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6766 NULL, NULL, NULL, NULL, NULL,
6769 {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6770 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6771 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6772 NULL, attributeCertificateExactNormalize, octetStringMatch,
6773 octetStringIndexer, octetStringFilter,
6776 {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6777 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6778 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6779 NULL, NULL, NULL, NULL, NULL,
6782 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6783 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6784 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6785 NULL, IA5StringNormalize, octetStringMatch,
6786 octetStringIndexer, octetStringFilter,
6787 IA5StringApproxMatchOID },
6789 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6790 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6791 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6792 NULL, IA5StringNormalize, octetStringMatch,
6793 octetStringIndexer, octetStringFilter,
6794 IA5StringApproxMatchOID },
6796 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6797 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6798 SLAP_MR_SUBSTR, NULL,
6799 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6800 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6801 "caseIgnoreIA5Match" },
6803 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6804 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6805 SLAP_MR_SUBSTR, NULL,
6806 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6807 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6808 "caseExactIA5Match" },
6810 #ifdef SLAPD_AUTHPASSWD
6811 /* needs updating */
6812 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6813 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6814 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6815 NULL, NULL, authPasswordMatch,
6820 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6821 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6823 NULL, NULL, integerBitAndMatch,
6827 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6828 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6830 NULL, NULL, integerBitOrMatch,
6834 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6835 "SYNTAX 1.3.6.1.1.16.1 )",
6836 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6837 NULL, UUIDNormalize, octetStringMatch,
6838 octetStringIndexer, octetStringFilter,
6841 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6842 "SYNTAX 1.3.6.1.1.16.1 )",
6843 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6844 NULL, UUIDNormalize, octetStringOrderingMatch,
6845 octetStringIndexer, octetStringFilter,
6848 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6849 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6850 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6851 NULL, csnNormalize, csnMatch,
6852 csnIndexer, csnFilter,
6855 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6856 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6857 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6858 NULL, csnNormalize, csnOrderingMatch,
6862 {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6863 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6864 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6865 NULL, csnSidNormalize, octetStringMatch,
6866 octetStringIndexer, octetStringFilter,
6869 /* FIXME: OID is unused, but not registered yet */
6870 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6871 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6872 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6873 NULL, authzNormalize, authzMatch,
6877 {"( 1.3.6.1.4.1.4203.666.4.13 NAME 'privateKeyMatch' "
6878 "SYNTAX 1.3.6.1.4.1.4203.666.2.13 )", /* OpenLDAP privateKey */
6879 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6880 NULL, NULL, octetStringMatch,
6884 {NULL, SLAP_MR_NONE, NULL,
6885 NULL, NULL, NULL, NULL, NULL,
6890 slap_schema_init( void )
6895 /* we should only be called once (from main) */
6896 assert( schema_init_done == 0 );
6898 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6899 res = register_syntax( &syntax_defs[i] );
6902 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6903 syntax_defs[i].sd_desc );
6908 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6909 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6910 mrule_defs[i].mrd_compat_syntaxes == NULL )
6913 "slap_schema_init: Ignoring unusable matching rule %s\n",
6914 mrule_defs[i].mrd_desc );
6918 res = register_matching_rule( &mrule_defs[i] );
6922 "slap_schema_init: Error registering matching rule %s\n",
6923 mrule_defs[i].mrd_desc );
6928 res = slap_schema_load();
6929 schema_init_done = 1;
6934 schema_destroy( void )
6943 if( schema_init_done ) {
6944 ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6945 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6946 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );