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,
726 HASH_CONTEXT HASHcontext;
727 unsigned char HASHdigest[HASH_BYTES];
728 struct berval digest;
729 digest.bv_val = (char *)HASHdigest;
730 digest.bv_len = HASH_LEN;
732 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
733 /* just count them */
736 /* we should have at least one value at this point */
739 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
741 slen = syntax->ssyn_oidlen;
742 mlen = mr->smr_oidlen;
744 hashPreset( &HASHcontext, prefix, 0, syntax, mr);
745 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
746 hashIter( &HASHcontext, HASHdigest,
747 (unsigned char *)values[i].bv_val, values[i].bv_len );
748 ber_dupbv_x( &keys[i], &digest, ctx );
751 BER_BVZERO( &keys[i] );
758 /* Index generation function: Asserted value -> index hash key */
759 int octetStringFilter(
764 struct berval *prefix,
765 void * assertedValue,
771 HASH_CONTEXT HASHcontext;
772 unsigned char HASHdigest[HASH_BYTES];
773 struct berval *value = (struct berval *) assertedValue;
774 struct berval digest;
775 digest.bv_val = (char *)HASHdigest;
776 digest.bv_len = HASH_LEN;
778 slen = syntax->ssyn_oidlen;
779 mlen = mr->smr_oidlen;
781 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
783 hashPreset( &HASHcontext, prefix, 0, syntax, mr );
784 hashIter( &HASHcontext, HASHdigest,
785 (unsigned char *)value->bv_val, value->bv_len );
787 ber_dupbv_x( keys, &digest, ctx );
788 BER_BVZERO( &keys[1] );
796 octetStringSubstringsMatch(
801 struct berval *value,
802 void *assertedValue )
805 SubstringsAssertion *sub = assertedValue;
806 struct berval left = *value;
810 /* Add up asserted input length */
811 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
812 inlen += sub->sa_initial.bv_len;
815 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
816 inlen += sub->sa_any[i].bv_len;
819 if ( !BER_BVISNULL( &sub->sa_final ) ) {
820 inlen += sub->sa_final.bv_len;
823 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
824 if ( inlen > left.bv_len ) {
829 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
830 sub->sa_initial.bv_len );
836 left.bv_val += sub->sa_initial.bv_len;
837 left.bv_len -= sub->sa_initial.bv_len;
838 inlen -= sub->sa_initial.bv_len;
841 if ( !BER_BVISNULL( &sub->sa_final ) ) {
842 if ( inlen > left.bv_len ) {
847 match = memcmp( sub->sa_final.bv_val,
848 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
849 sub->sa_final.bv_len );
855 left.bv_len -= sub->sa_final.bv_len;
856 inlen -= sub->sa_final.bv_len;
860 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
865 if ( inlen > left.bv_len ) {
866 /* not enough length */
871 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
875 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
882 idx = p - left.bv_val;
884 if ( idx >= left.bv_len ) {
885 /* this shouldn't happen */
892 if ( sub->sa_any[i].bv_len > left.bv_len ) {
893 /* not enough left */
898 match = memcmp( left.bv_val,
899 sub->sa_any[i].bv_val,
900 sub->sa_any[i].bv_len );
908 left.bv_val += sub->sa_any[i].bv_len;
909 left.bv_len -= sub->sa_any[i].bv_len;
910 inlen -= sub->sa_any[i].bv_len;
919 /* Substring index generation function: Attribute values -> index hash keys */
921 octetStringSubstringsIndexer(
926 struct berval *prefix,
935 HASH_CONTEXT HCany, HCini, HCfin;
936 unsigned char HASHdigest[HASH_BYTES];
937 struct berval digest;
938 digest.bv_val = (char *)HASHdigest;
939 digest.bv_len = HASH_LEN;
943 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
944 /* count number of indices to generate */
945 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
946 if( values[i].bv_len >= index_substr_if_maxlen ) {
947 nkeys += index_substr_if_maxlen -
948 (index_substr_if_minlen - 1);
949 } else if( values[i].bv_len >= index_substr_if_minlen ) {
950 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
954 if( flags & SLAP_INDEX_SUBSTR_ANY ) {
955 if( values[i].bv_len >= index_substr_any_len ) {
956 nkeys += values[i].bv_len - (index_substr_any_len - 1);
960 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
961 if( values[i].bv_len >= index_substr_if_maxlen ) {
962 nkeys += index_substr_if_maxlen -
963 (index_substr_if_minlen - 1);
964 } else if( values[i].bv_len >= index_substr_if_minlen ) {
965 nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
971 /* no keys to generate */
976 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
978 slen = syntax->ssyn_oidlen;
979 mlen = mr->smr_oidlen;
981 if ( flags & SLAP_INDEX_SUBSTR_ANY )
982 hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
983 if( flags & SLAP_INDEX_SUBSTR_INITIAL )
984 hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
985 if( flags & SLAP_INDEX_SUBSTR_FINAL )
986 hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
989 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
992 if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
993 ( values[i].bv_len >= index_substr_any_len ) )
995 max = values[i].bv_len - (index_substr_any_len - 1);
997 for( j=0; j<max; j++ ) {
998 hashIter( &HCany, HASHdigest,
999 (unsigned char *)&values[i].bv_val[j],
1000 index_substr_any_len );
1001 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1005 /* skip if too short */
1006 if( values[i].bv_len < index_substr_if_minlen ) continue;
1008 max = index_substr_if_maxlen < values[i].bv_len
1009 ? index_substr_if_maxlen : values[i].bv_len;
1011 for( j=index_substr_if_minlen; j<=max; j++ ) {
1013 if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1014 hashIter( &HCini, HASHdigest,
1015 (unsigned char *)values[i].bv_val, j );
1016 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1019 if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1020 hashIter( &HCfin, HASHdigest,
1021 (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
1022 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1029 BER_BVZERO( &keys[nkeys] );
1036 return LDAP_SUCCESS;
1039 /* Substring index generation function: Assertion value -> index hash keys */
1041 octetStringSubstringsFilter (
1046 struct berval *prefix,
1047 void * assertedValue,
1051 SubstringsAssertion *sa;
1053 ber_len_t nkeys = 0;
1054 size_t slen, mlen, klen;
1056 HASH_CONTEXT HASHcontext;
1057 unsigned char HASHdigest[HASH_BYTES];
1058 struct berval *value;
1059 struct berval digest;
1061 sa = (SubstringsAssertion *) assertedValue;
1063 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1064 !BER_BVISNULL( &sa->sa_initial ) &&
1065 sa->sa_initial.bv_len >= index_substr_if_minlen )
1068 if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
1069 ( flags & SLAP_INDEX_SUBSTR_ANY ))
1071 nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1075 if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1077 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1078 if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
1079 /* don't bother accounting with stepping */
1080 nkeys += sa->sa_any[i].bv_len -
1081 ( index_substr_any_len - 1 );
1086 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1087 !BER_BVISNULL( &sa->sa_final ) &&
1088 sa->sa_final.bv_len >= index_substr_if_minlen )
1091 if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
1092 ( flags & SLAP_INDEX_SUBSTR_ANY ))
1094 nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1100 return LDAP_SUCCESS;
1103 digest.bv_val = (char *)HASHdigest;
1104 digest.bv_len = HASH_LEN;
1106 slen = syntax->ssyn_oidlen;
1107 mlen = mr->smr_oidlen;
1109 keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
1112 if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1113 !BER_BVISNULL( &sa->sa_initial ) &&
1114 sa->sa_initial.bv_len >= index_substr_if_minlen )
1116 pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1117 value = &sa->sa_initial;
1119 klen = index_substr_if_maxlen < value->bv_len
1120 ? index_substr_if_maxlen : value->bv_len;
1122 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1123 hashIter( &HASHcontext, HASHdigest,
1124 (unsigned char *)value->bv_val, klen );
1125 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1127 /* If initial is too long and we have subany indexed, use it
1128 * to match the excess...
1130 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1133 pre = SLAP_INDEX_SUBSTR_PREFIX;
1134 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1135 for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
1137 hashIter( &HASHcontext, HASHdigest,
1138 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1139 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1144 if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1146 pre = SLAP_INDEX_SUBSTR_PREFIX;
1147 klen = index_substr_any_len;
1149 for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1150 if( sa->sa_any[i].bv_len < index_substr_any_len ) {
1154 value = &sa->sa_any[i];
1156 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1158 j <= value->bv_len - index_substr_any_len;
1159 j += index_substr_any_step )
1161 hashIter( &HASHcontext, HASHdigest,
1162 (unsigned char *)&value->bv_val[j], klen );
1163 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1168 if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1169 !BER_BVISNULL( &sa->sa_final ) &&
1170 sa->sa_final.bv_len >= index_substr_if_minlen )
1172 pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1173 value = &sa->sa_final;
1175 klen = index_substr_if_maxlen < value->bv_len
1176 ? index_substr_if_maxlen : value->bv_len;
1178 hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1179 hashIter( &HASHcontext, HASHdigest,
1180 (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
1181 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1183 /* If final is too long and we have subany indexed, use it
1184 * to match the excess...
1186 if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1189 pre = SLAP_INDEX_SUBSTR_PREFIX;
1190 hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1191 for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
1193 hashIter( &HASHcontext, HASHdigest,
1194 (unsigned char *)&value->bv_val[j], index_substr_any_len );
1195 ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1201 BER_BVZERO( &keys[nkeys] );
1208 return LDAP_SUCCESS;
1218 /* very unforgiving validation, requires no normalization
1219 * before simplistic matching
1221 if( in->bv_len < 3 ) {
1222 return LDAP_INVALID_SYNTAX;
1225 /* RFC 4517 Section 3.3.2 Bit String:
1226 * BitString = SQUOTE *binary-digit SQUOTE "B"
1227 * binary-digit = "0" / "1"
1229 * where SQUOTE [RFC4512] is
1230 * SQUOTE = %x27 ; single quote ("'")
1232 * Example: '0101111101'B
1235 if( in->bv_val[0] != '\'' ||
1236 in->bv_val[in->bv_len - 2] != '\'' ||
1237 in->bv_val[in->bv_len - 1] != 'B' )
1239 return LDAP_INVALID_SYNTAX;
1242 for( i = in->bv_len - 3; i > 0; i-- ) {
1243 if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
1244 return LDAP_INVALID_SYNTAX;
1248 return LDAP_SUCCESS;
1252 * Syntaxes from RFC 4517
1257 A value of the Bit String syntax is a sequence of binary digits. The
1258 LDAP-specific encoding of a value of this syntax is defined by the
1261 BitString = SQUOTE *binary-digit SQUOTE "B"
1263 binary-digit = "0" / "1"
1265 The <SQUOTE> rule is defined in [MODELS].
1270 The LDAP definition for the Bit String syntax is:
1272 ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
1274 This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
1278 3.3.21. Name and Optional UID
1280 A value of the Name and Optional UID syntax is the distinguished name
1281 [MODELS] of an entity optionally accompanied by a unique identifier
1282 that serves to differentiate the entity from others with an identical
1285 The LDAP-specific encoding of a value of this syntax is defined by
1288 NameAndOptionalUID = distinguishedName [ SHARP BitString ]
1290 The <BitString> rule is defined in Section 3.3.2. The
1291 <distinguishedName> rule is defined in [LDAPDN]. The <SHARP> rule is
1292 defined in [MODELS].
1294 Note that although the '#' character may occur in the string
1295 representation of a distinguished name, no additional escaping of
1296 this character is performed when a <distinguishedName> is encoded in
1297 a <NameAndOptionalUID>.
1300 1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
1302 The LDAP definition for the Name and Optional UID syntax is:
1304 ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
1306 This syntax corresponds to the NameAndOptionalUID ASN.1 type from
1313 1.4. Common ABNF Productions
1316 SHARP = %x23 ; octothorpe (or sharp sign) ("#")
1318 SQUOTE = %x27 ; single quote ("'")
1323 * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
1324 * be escaped except when at the beginning of a value, the
1325 * definition of Name and Optional UID appears to be flawed,
1326 * because there is no clear means to determine whether the
1327 * UID part is present or not.
1331 * cn=Someone,dc=example,dc=com#'1'B
1333 * could be either a NameAndOptionalUID with trailing UID, i.e.
1335 * DN = "cn=Someone,dc=example,dc=com"
1338 * or a NameAndOptionalUID with no trailing UID, and the AVA
1339 * in the last RDN made of
1341 * attributeType = dc
1342 * attributeValue = com#'1'B
1344 * in fact "com#'1'B" is a valid IA5 string.
1346 * As a consequence, current slapd code takes the presence of
1347 * #<valid BitString> at the end of the string representation
1348 * of a NameAndOptionalUID to mean this is indeed a BitString.
1349 * This is quite arbitrary - it has changed the past and might
1350 * change in the future.
1360 struct berval dn, uid;
1362 if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
1364 ber_dupbv( &dn, in );
1365 if( !dn.bv_val ) return LDAP_OTHER;
1367 /* if there's a "#", try bitStringValidate()... */
1368 uid.bv_val = strrchr( dn.bv_val, '#' );
1369 if ( !BER_BVISNULL( &uid ) ) {
1371 uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1373 rc = bitStringValidate( NULL, &uid );
1374 if ( rc == LDAP_SUCCESS ) {
1375 /* in case of success, trim the UID,
1376 * otherwise treat it as part of the DN */
1377 dn.bv_len -= uid.bv_len + 1;
1378 uid.bv_val[-1] = '\0';
1382 rc = dnValidate( NULL, &dn );
1384 ber_memfree( dn.bv_val );
1395 assert( val != NULL );
1396 assert( out != NULL );
1399 Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
1401 if( BER_BVISEMPTY( val ) ) {
1402 ber_dupbv_x( out, val, ctx );
1404 } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1405 return LDAP_INVALID_SYNTAX;
1409 struct berval dnval = *val;
1410 struct berval uidval = BER_BVNULL;
1412 uidval.bv_val = strrchr( val->bv_val, '#' );
1413 if ( !BER_BVISNULL( &uidval ) ) {
1415 uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1417 rc = bitStringValidate( NULL, &uidval );
1419 if ( rc == LDAP_SUCCESS ) {
1420 ber_dupbv_x( &dnval, val, ctx );
1422 dnval.bv_len -= ++uidval.bv_len;
1423 dnval.bv_val[dnval.bv_len] = '\0';
1426 BER_BVZERO( &uidval );
1430 rc = dnPretty( syntax, &dnval, out, ctx );
1431 if ( dnval.bv_val != val->bv_val ) {
1432 slap_sl_free( dnval.bv_val, ctx );
1434 if( rc != LDAP_SUCCESS ) {
1438 if( !BER_BVISNULL( &uidval ) ) {
1441 tmp = slap_sl_realloc( out->bv_val, out->bv_len
1442 + uidval.bv_len + 1,
1445 ber_memfree_x( out->bv_val, ctx );
1449 memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
1450 out->bv_len += uidval.bv_len;
1451 out->bv_val[out->bv_len] = '\0';
1455 Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
1457 return LDAP_SUCCESS;
1461 uniqueMemberNormalize(
1466 struct berval *normalized,
1472 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1474 ber_dupbv_x( &out, val, ctx );
1475 if ( BER_BVISEMPTY( &out ) ) {
1479 struct berval uid = BER_BVNULL;
1481 uid.bv_val = strrchr( out.bv_val, '#' );
1482 if ( !BER_BVISNULL( &uid ) ) {
1484 uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1486 rc = bitStringValidate( NULL, &uid );
1487 if ( rc == LDAP_SUCCESS ) {
1488 uid.bv_val[-1] = '\0';
1489 out.bv_len -= uid.bv_len + 1;
1495 rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1497 if( rc != LDAP_SUCCESS ) {
1498 slap_sl_free( out.bv_val, ctx );
1499 return LDAP_INVALID_SYNTAX;
1502 if( !BER_BVISNULL( &uid ) ) {
1505 tmp = ch_realloc( normalized->bv_val,
1506 normalized->bv_len + uid.bv_len
1507 + STRLENOF("#") + 1 );
1508 if ( tmp == NULL ) {
1509 ber_memfree_x( normalized->bv_val, ctx );
1513 normalized->bv_val = tmp;
1515 /* insert the separator */
1516 normalized->bv_val[normalized->bv_len++] = '#';
1518 /* append the UID */
1519 AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1520 uid.bv_val, uid.bv_len );
1521 normalized->bv_len += uid.bv_len;
1524 normalized->bv_val[normalized->bv_len] = '\0';
1527 slap_sl_free( out.bv_val, ctx );
1530 return LDAP_SUCCESS;
1539 struct berval *value,
1540 void *assertedValue )
1543 struct berval *asserted = (struct berval *) assertedValue;
1544 struct berval assertedDN = *asserted;
1545 struct berval assertedUID = BER_BVNULL;
1546 struct berval valueDN = *value;
1547 struct berval valueUID = BER_BVNULL;
1548 int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1550 if ( !BER_BVISEMPTY( asserted ) ) {
1551 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1552 if ( !BER_BVISNULL( &assertedUID ) ) {
1553 assertedUID.bv_val++;
1554 assertedUID.bv_len = assertedDN.bv_len
1555 - ( assertedUID.bv_val - assertedDN.bv_val );
1557 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1558 assertedDN.bv_len -= assertedUID.bv_len + 1;
1561 BER_BVZERO( &assertedUID );
1566 if ( !BER_BVISEMPTY( value ) ) {
1568 valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1569 if ( !BER_BVISNULL( &valueUID ) ) {
1571 valueUID.bv_len = valueDN.bv_len
1572 - ( valueUID.bv_val - valueDN.bv_val );
1574 if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1575 valueDN.bv_len -= valueUID.bv_len + 1;
1578 BER_BVZERO( &valueUID );
1583 if( valueUID.bv_len && assertedUID.bv_len ) {
1585 d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len;
1587 *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1;
1588 return LDAP_SUCCESS;
1591 match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1594 return LDAP_SUCCESS;
1597 } else if ( !approx && valueUID.bv_len ) {
1600 return LDAP_SUCCESS;
1602 } else if ( !approx && assertedUID.bv_len ) {
1605 return LDAP_SUCCESS;
1608 return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1612 uniqueMemberIndexer(
1617 struct berval *prefix,
1625 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1626 /* just count them */
1630 dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1632 for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1633 struct berval assertedDN = values[i];
1634 struct berval assertedUID = BER_BVNULL;
1636 if ( !BER_BVISEMPTY( &assertedDN ) ) {
1637 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1638 if ( !BER_BVISNULL( &assertedUID ) ) {
1639 assertedUID.bv_val++;
1640 assertedUID.bv_len = assertedDN.bv_len
1641 - ( assertedUID.bv_val - assertedDN.bv_val );
1643 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1644 assertedDN.bv_len -= assertedUID.bv_len + 1;
1647 BER_BVZERO( &assertedUID );
1652 dnvalues[i] = assertedDN;
1654 BER_BVZERO( &dnvalues[i] );
1656 rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1657 dnvalues, keysp, ctx );
1659 slap_sl_free( dnvalues, ctx );
1669 struct berval *prefix,
1670 void * assertedValue,
1674 struct berval *asserted = (struct berval *) assertedValue;
1675 struct berval assertedDN = *asserted;
1676 struct berval assertedUID = BER_BVNULL;
1678 if ( !BER_BVISEMPTY( asserted ) ) {
1679 assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1680 if ( !BER_BVISNULL( &assertedUID ) ) {
1681 assertedUID.bv_val++;
1682 assertedUID.bv_len = assertedDN.bv_len
1683 - ( assertedUID.bv_val - assertedDN.bv_val );
1685 if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1686 assertedDN.bv_len -= assertedUID.bv_len + 1;
1689 BER_BVZERO( &assertedUID );
1694 return octetStringFilter( use, flags, syntax, mr, prefix,
1695 &assertedDN, keysp, ctx );
1700 * Handling boolean syntax and matching is quite rigid.
1701 * A more flexible approach would be to allow a variety
1702 * of strings to be normalized and prettied into TRUE
1710 /* very unforgiving validation, requires no normalization
1711 * before simplistic matching
1714 if( in->bv_len == 4 ) {
1715 if( bvmatch( in, &slap_true_bv ) ) {
1716 return LDAP_SUCCESS;
1718 } else if( in->bv_len == 5 ) {
1719 if( bvmatch( in, &slap_false_bv ) ) {
1720 return LDAP_SUCCESS;
1724 return LDAP_INVALID_SYNTAX;
1733 struct berval *value,
1734 void *assertedValue )
1736 /* simplistic matching allowed by rigid validation */
1737 struct berval *asserted = (struct berval *) assertedValue;
1738 *matchp = (int) asserted->bv_len - (int) value->bv_len;
1739 return LDAP_SUCCESS;
1742 /*-------------------------------------------------------------------
1743 LDAP/X.500 string syntax / matching rules have a few oddities. This
1744 comment attempts to detail how slapd(8) treats them.
1747 StringSyntax X.500 LDAP Matching/Comments
1748 DirectoryString CHOICE UTF8 i/e + ignore insignificant spaces
1749 PrintableString subset subset i/e + ignore insignificant spaces
1750 PrintableString subset subset i/e + ignore insignificant spaces
1751 NumericString subset subset ignore all spaces
1752 IA5String ASCII ASCII i/e + ignore insignificant spaces
1753 TeletexString T.61 T.61 i/e + ignore insignificant spaces
1755 TelephoneNumber subset subset i + ignore all spaces and "-"
1757 See RFC 4518 for details.
1761 In X.500(93), a directory string can be either a PrintableString,
1762 a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1763 In later versions, more CHOICEs were added. In all cases the string
1766 In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1767 A directory string cannot be zero length.
1769 For matching, there are both case ignore and exact rules. Both
1770 also require that "insignificant" spaces be ignored.
1771 spaces before the first non-space are ignored;
1772 spaces after the last non-space are ignored;
1773 spaces after a space are ignored.
1774 Note: by these rules (and as clarified in X.520), a string of only
1775 spaces is to be treated as if held one space, not empty (which
1776 would be a syntax error).
1779 In ASN.1, numeric string is just a string of digits and spaces
1780 and could be empty. However, in X.500, all attribute values of
1781 numeric string carry a non-empty constraint. For example:
1783 internationalISDNNumber ATTRIBUTE ::= {
1784 WITH SYNTAX InternationalISDNNumber
1785 EQUALITY MATCHING RULE numericStringMatch
1786 SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1787 ID id-at-internationalISDNNumber }
1788 InternationalISDNNumber ::=
1789 NumericString (SIZE(1..ub-international-isdn-number))
1791 Unforunately, some assertion values are don't carry the same
1792 constraint (but its unclear how such an assertion could ever
1793 be true). In LDAP, there is one syntax (numericString) not two
1794 (numericString with constraint, numericString without constraint).
1795 This should be treated as numericString with non-empty constraint.
1796 Note that while someone may have no ISDN number, there are no ISDN
1797 numbers which are zero length.
1799 In matching, spaces are ignored.
1802 In ASN.1, Printable string is just a string of printable characters
1803 and can be empty. In X.500, semantics much like NumericString (see
1804 serialNumber for a like example) excepting uses insignificant space
1805 handling instead of ignore all spaces. They must be non-empty.
1808 Basically same as PrintableString. There are no examples in X.500,
1809 but same logic applies. Empty strings are allowed.
1811 -------------------------------------------------------------------*/
1819 unsigned char *u = (unsigned char *)in->bv_val, *end = in->bv_val + in->bv_len;
1821 if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1822 /* directory strings cannot be empty */
1823 return LDAP_INVALID_SYNTAX;
1826 for( ; u < end; u += len ) {
1827 /* get the length indicated by the first byte */
1828 len = LDAP_UTF8_CHARLEN2( u, len );
1830 /* very basic checks */
1833 if( (u[5] & 0xC0) != 0x80 ) {
1834 return LDAP_INVALID_SYNTAX;
1837 if( (u[4] & 0xC0) != 0x80 ) {
1838 return LDAP_INVALID_SYNTAX;
1841 if( (u[3] & 0xC0) != 0x80 ) {
1842 return LDAP_INVALID_SYNTAX;
1845 if( (u[2] & 0xC0 )!= 0x80 ) {
1846 return LDAP_INVALID_SYNTAX;
1849 if( (u[1] & 0xC0) != 0x80 ) {
1850 return LDAP_INVALID_SYNTAX;
1853 /* CHARLEN already validated it */
1856 return LDAP_INVALID_SYNTAX;
1859 /* make sure len corresponds with the offset
1860 to the next character */
1861 if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1865 return LDAP_INVALID_SYNTAX;
1868 return LDAP_SUCCESS;
1872 UTF8StringNormalize(
1877 struct berval *normalized,
1880 struct berval tmp, nvalue;
1881 int flags, wasspace;
1884 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1886 if( BER_BVISNULL( val ) ) {
1887 /* assume we're dealing with a syntax (e.g., UTF8String)
1888 * which allows empty strings
1890 BER_BVZERO( normalized );
1891 return LDAP_SUCCESS;
1894 flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1895 ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1896 flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1897 ? LDAP_UTF8_APPROX : 0;
1899 val = UTF8bvnormalize( val, &tmp, flags, ctx );
1900 /* out of memory or syntax error, the former is unlikely */
1902 return LDAP_INVALID_SYNTAX;
1905 /* collapse spaces (in place) */
1907 nvalue.bv_val = tmp.bv_val;
1909 /* trim leading spaces? */
1910 wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1911 (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1913 for( i = 0; i < tmp.bv_len; i++) {
1914 if ( ASCII_SPACE( tmp.bv_val[i] )) {
1915 if( wasspace++ == 0 ) {
1916 /* trim repeated spaces */
1917 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1921 nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1925 if( !BER_BVISEMPTY( &nvalue ) ) {
1926 /* trim trailing space? */
1928 (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1929 ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1933 nvalue.bv_val[nvalue.bv_len] = '\0';
1935 } else if ( tmp.bv_len ) {
1936 /* string of all spaces is treated as one space */
1937 nvalue.bv_val[0] = ' ';
1938 nvalue.bv_val[1] = '\0';
1940 } /* should never be entered with 0-length val */
1942 *normalized = nvalue;
1943 return LDAP_SUCCESS;
1947 directoryStringSubstringsMatch(
1952 struct berval *value,
1953 void *assertedValue )
1956 SubstringsAssertion *sub = assertedValue;
1957 struct berval left = *value;
1961 if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1962 if ( sub->sa_initial.bv_len > left.bv_len ) {
1963 /* not enough left */
1968 match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1969 sub->sa_initial.bv_len );
1975 left.bv_val += sub->sa_initial.bv_len;
1976 left.bv_len -= sub->sa_initial.bv_len;
1978 priorspace = ASCII_SPACE(
1979 sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1982 if ( sub->sa_any ) {
1983 for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1987 if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1988 && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1990 /* allow next space to match */
1997 if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
2001 if ( sub->sa_any[i].bv_len > left.bv_len ) {
2002 /* not enough left */
2007 p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
2014 idx = p - left.bv_val;
2016 if ( idx >= left.bv_len ) {
2017 /* this shouldn't happen */
2024 if ( sub->sa_any[i].bv_len > left.bv_len ) {
2025 /* not enough left */
2030 match = memcmp( left.bv_val,
2031 sub->sa_any[i].bv_val,
2032 sub->sa_any[i].bv_len );
2040 left.bv_val += sub->sa_any[i].bv_len;
2041 left.bv_len -= sub->sa_any[i].bv_len;
2043 priorspace = ASCII_SPACE(
2044 sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
2048 if ( !BER_BVISNULL( &sub->sa_final ) ) {
2049 if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
2050 && ASCII_SPACE( sub->sa_final.bv_val[0] ))
2052 /* allow next space to match */
2057 if ( sub->sa_final.bv_len > left.bv_len ) {
2058 /* not enough left */
2063 match = memcmp( sub->sa_final.bv_val,
2064 &left.bv_val[left.bv_len - sub->sa_final.bv_len],
2065 sub->sa_final.bv_len );
2074 return LDAP_SUCCESS;
2077 #if defined(SLAPD_APPROX_INITIALS)
2078 # define SLAPD_APPROX_DELIMITER "._ "
2079 # define SLAPD_APPROX_WORDLEN 2
2081 # define SLAPD_APPROX_DELIMITER " "
2082 # define SLAPD_APPROX_WORDLEN 1
2091 struct berval *value,
2092 void *assertedValue )
2094 struct berval *nval, *assertv;
2095 char *val, **values, **words, *c;
2096 int i, count, len, nextchunk=0, nextavail=0;
2098 /* Yes, this is necessary */
2099 nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
2100 if( nval == NULL ) {
2102 return LDAP_SUCCESS;
2105 /* Yes, this is necessary */
2106 assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
2107 NULL, LDAP_UTF8_APPROX, NULL );
2108 if( assertv == NULL ) {
2111 return LDAP_SUCCESS;
2114 /* Isolate how many words there are */
2115 for ( c = nval->bv_val, count = 1; *c; c++ ) {
2116 c = strpbrk( c, SLAPD_APPROX_DELIMITER );
2117 if ( c == NULL ) break;
2122 /* Get a phonetic copy of each word */
2123 words = (char **)ch_malloc( count * sizeof(char *) );
2124 values = (char **)ch_malloc( count * sizeof(char *) );
2125 for ( c = nval->bv_val, i = 0; i < count; i++, c += strlen(c) + 1 ) {
2127 values[i] = phonetic(c);
2130 /* Work through the asserted value's words, to see if at least some
2131 * of the words are there, in the same order. */
2133 while ( (ber_len_t) nextchunk < assertv->bv_len ) {
2134 len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
2139 #if defined(SLAPD_APPROX_INITIALS)
2140 else if( len == 1 ) {
2141 /* Single letter words need to at least match one word's initial */
2142 for( i=nextavail; i<count; i++ )
2143 if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
2150 /* Isolate the next word in the asserted value and phonetic it */
2151 assertv->bv_val[nextchunk+len] = '\0';
2152 val = phonetic( assertv->bv_val + nextchunk );
2154 /* See if this phonetic chunk is in the remaining words of *value */
2155 for( i=nextavail; i<count; i++ ){
2156 if( !strcmp( val, values[i] ) ){
2164 /* This chunk in the asserted value was NOT within the *value. */
2170 /* Go on to the next word in the asserted value */
2174 /* If some of the words were seen, call it a match */
2175 if( nextavail > 0 ) {
2182 /* Cleanup allocs */
2183 ber_bvfree( assertv );
2184 for( i=0; i<count; i++ ) {
2185 ch_free( values[i] );
2191 return LDAP_SUCCESS;
2200 struct berval *prefix,
2206 int i,j, len, wordcount, keycount=0;
2207 struct berval *newkeys;
2208 BerVarray keys=NULL;
2210 for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
2211 struct berval val = BER_BVNULL;
2212 /* Yes, this is necessary */
2213 UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
2214 assert( !BER_BVISNULL( &val ) );
2216 /* Isolate how many words there are. There will be a key for each */
2217 for( wordcount = 0, c = val.bv_val; *c; c++) {
2218 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2219 if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
2221 if (*c == '\0') break;
2225 /* Allocate/increase storage to account for new keys */
2226 newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
2227 * sizeof(struct berval) );
2228 AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
2229 if( keys ) ch_free( keys );
2232 /* Get a phonetic copy of each word */
2233 for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
2235 if( len < SLAPD_APPROX_WORDLEN ) continue;
2236 ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
2237 if( keys[keycount].bv_len ) {
2240 ch_free( keys[keycount].bv_val );
2245 ber_memfree( val.bv_val );
2247 BER_BVZERO( &keys[keycount] );
2250 return LDAP_SUCCESS;
2259 struct berval *prefix,
2260 void * assertedValue,
2269 /* Yes, this is necessary */
2270 val = UTF8bvnormalize( ((struct berval *)assertedValue),
2271 NULL, LDAP_UTF8_APPROX, NULL );
2272 if( val == NULL || BER_BVISNULL( val ) ) {
2273 keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2274 BER_BVZERO( &keys[0] );
2277 return LDAP_SUCCESS;
2280 /* Isolate how many words there are. There will be a key for each */
2281 for( count = 0,c = val->bv_val; *c; c++) {
2282 len = strcspn(c, SLAPD_APPROX_DELIMITER);
2283 if( len >= SLAPD_APPROX_WORDLEN ) count++;
2285 if (*c == '\0') break;
2289 /* Allocate storage for new keys */
2290 keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2292 /* Get a phonetic copy of each word */
2293 for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2295 if( len < SLAPD_APPROX_WORDLEN ) continue;
2296 ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2302 BER_BVZERO( &keys[count] );
2305 return LDAP_SUCCESS;
2308 /* Remove all spaces and '-' characters */
2310 telephoneNumberNormalize(
2315 struct berval *normalized,
2320 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2322 /* validator should have refused an empty string */
2323 assert( !BER_BVISEMPTY( val ) );
2325 q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2327 for( p = val->bv_val; *p; p++ ) {
2328 if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
2334 normalized->bv_len = q - normalized->bv_val;
2336 if( BER_BVISEMPTY( normalized ) ) {
2337 slap_sl_free( normalized->bv_val, ctx );
2338 BER_BVZERO( normalized );
2339 return LDAP_INVALID_SYNTAX;
2342 return LDAP_SUCCESS;
2346 postalAddressValidate(
2350 struct berval bv = *in;
2353 for ( c = 0; c < in->bv_len; c++ ) {
2354 if ( in->bv_val[c] == '\\' ) {
2356 if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2357 && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2359 return LDAP_INVALID_SYNTAX;
2364 if ( in->bv_val[c] == '$' ) {
2365 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2366 if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2367 return LDAP_INVALID_SYNTAX;
2369 bv.bv_val = &in->bv_val[c] + 1;
2373 bv.bv_len = &in->bv_val[c] - bv.bv_val;
2374 return UTF8StringValidate( NULL, &bv );
2378 postalAddressNormalize(
2383 struct berval *normalized,
2386 BerVarray lines = NULL, nlines = NULL;
2388 int rc = LDAP_SUCCESS;
2389 MatchingRule *xmr = NULL;
2392 if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2393 xmr = slap_schema.si_mr_caseIgnoreMatch;
2396 xmr = slap_schema.si_mr_caseExactMatch;
2399 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2400 if ( val->bv_val[c] == '$' ) {
2405 lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2406 nlines = &lines[l + 2];
2408 lines[0].bv_val = val->bv_val;
2409 for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2410 if ( val->bv_val[c] == '$' ) {
2411 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2413 lines[l].bv_val = &val->bv_val[c + 1];
2416 lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2418 normalized->bv_len = c = l;
2420 for ( l = 0; l <= c; l++ ) {
2421 /* NOTE: we directly normalize each line,
2422 * without unescaping the values, since the special
2423 * values '\24' ('$') and '\5C' ('\') are not affected
2424 * by normalization */
2425 if ( !lines[l].bv_len ) {
2426 nlines[l].bv_len = 0;
2427 nlines[l].bv_val = NULL;
2430 rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2431 if ( rc != LDAP_SUCCESS ) {
2432 rc = LDAP_INVALID_SYNTAX;
2436 normalized->bv_len += nlines[l].bv_len;
2439 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2441 p = normalized->bv_val;
2442 for ( l = 0; l <= c ; l++ ) {
2443 p = lutil_strbvcopy( p, &nlines[l] );
2448 assert( p == &normalized->bv_val[normalized->bv_len] );
2451 if ( nlines != NULL ) {
2452 for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2453 slap_sl_free( nlines[l].bv_val, ctx );
2456 slap_sl_free( lines, ctx );
2467 struct berval val = *in;
2469 if( BER_BVISEMPTY( &val ) ) {
2470 /* disallow empty strings */
2471 return LDAP_INVALID_SYNTAX;
2474 while( OID_LEADCHAR( val.bv_val[0] ) ) {
2475 if ( val.bv_len == 1 ) {
2476 return LDAP_SUCCESS;
2479 if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2486 while ( OID_LEADCHAR( val.bv_val[0] )) {
2490 if ( val.bv_len == 0 ) {
2491 return LDAP_SUCCESS;
2495 if( !OID_SEPARATOR( val.bv_val[0] )) {
2503 return LDAP_INVALID_SYNTAX;
2512 struct berval val = *in;
2514 if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2516 if ( val.bv_val[0] == '-' ) {
2520 if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2521 return LDAP_INVALID_SYNTAX;
2524 if( val.bv_val[0] == '0' ) { /* "-0" */
2525 return LDAP_INVALID_SYNTAX;
2528 } else if ( val.bv_val[0] == '0' ) {
2529 if( val.bv_len > 1 ) { /* "0<more>" */
2530 return LDAP_INVALID_SYNTAX;
2533 return LDAP_SUCCESS;
2536 for( i=0; i < val.bv_len; i++ ) {
2537 if( !ASCII_DIGIT(val.bv_val[i]) ) {
2538 return LDAP_INVALID_SYNTAX;
2542 return LDAP_SUCCESS;
2551 struct berval *value,
2552 void *assertedValue )
2554 struct berval *asserted = (struct berval *) assertedValue;
2555 int vsign = 1, asign = 1; /* default sign = '+' */
2560 if( v.bv_val[0] == '-' ) {
2566 if( BER_BVISEMPTY( &v ) ) vsign = 0;
2569 if( a.bv_val[0] == '-' ) {
2575 if( BER_BVISEMPTY( &a ) ) vsign = 0;
2577 match = vsign - asign;
2579 match = ( v.bv_len != a.bv_len
2580 ? ( v.bv_len < a.bv_len ? -1 : 1 )
2581 : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2582 if( vsign < 0 ) match = -match;
2585 /* Ordering rule used in extensible match filter? */
2586 if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2587 match = (match >= 0);
2590 return LDAP_SUCCESS;
2593 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2594 #define INDEX_INTLEN_CHOP 7
2595 #define INDEX_INTLEN_CHOPBYTES 3
2604 /* Integer index key format, designed for memcmp to collate correctly:
2605 * if too large: one's complement sign*<approx exponent=chopped bytes>,
2606 * two's complement value (sign-extended or chopped as needed),
2607 * however in first byte above, the top <number of exponent-bytes + 1>
2608 * bits are the inverse sign and next bit is the sign as delimiter.
2610 ber_slen_t k = index_intlen_strlen;
2612 unsigned signmask = ~0x7fU;
2613 unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2614 struct berval val = *in, itmp = *tmp;
2616 if ( val.bv_val[0] != '-' ) {
2621 /* Chop least significant digits, increase length instead */
2622 if ( val.bv_len > (ber_len_t) k ) {
2623 chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2624 val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2625 chop *= INDEX_INTLEN_CHOPBYTES; /* #bytes added */
2628 if ( lutil_str2bin( &val, &itmp, ctx )) {
2629 return LDAP_INVALID_SYNTAX;
2632 /* Omit leading sign byte */
2633 if ( itmp.bv_val[0] == neg ) {
2638 k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2640 assert( chop == 0 );
2641 memset( key->bv_val, neg, k ); /* sign-extend */
2642 } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2643 /* Got exponent -k, or no room for 2 sign bits */
2644 lenp = lenbuf + sizeof(lenbuf);
2645 chop = - (ber_len_t) k;
2647 *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2649 } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2650 /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2651 * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2652 k = (lenbuf + sizeof(lenbuf)) - lenp;
2653 if ( k > (ber_slen_t) index_intlen )
2655 memcpy( key->bv_val, lenp, k );
2656 itmp.bv_len = index_intlen - k;
2658 memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2659 key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2663 /* Index generation function: Ordered index */
2670 struct berval *prefix,
2680 unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2682 /* count the values and find max needed length */
2684 for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2685 if ( vlen < values[i].bv_len )
2686 vlen = values[i].bv_len;
2688 if ( vlen > maxstrlen )
2691 /* we should have at least one value at this point */
2694 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2695 for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2696 keys[i].bv_len = index_intlen;
2697 keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2700 keys[i].bv_val = NULL;
2702 if ( vlen > sizeof(ibuf) ) {
2703 itmp.bv_val = slap_sl_malloc( vlen, ctx );
2707 itmp.bv_len = sizeof(ibuf);
2709 for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2710 if ( itmp.bv_val != ibuf ) {
2711 itmp.bv_len = values[i].bv_len;
2712 if ( itmp.bv_len <= sizeof(ibuf) )
2713 itmp.bv_len = sizeof(ibuf);
2714 else if ( itmp.bv_len > maxstrlen )
2715 itmp.bv_len = maxstrlen;
2717 rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2719 slap_sl_free( keys, ctx );
2725 if ( itmp.bv_val != ibuf ) {
2726 slap_sl_free( itmp.bv_val, ctx );
2731 /* Index generation function: Ordered index */
2738 struct berval *prefix,
2739 void * assertedValue,
2746 struct berval *value;
2749 value = (struct berval *) assertedValue;
2751 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2753 keys[0].bv_len = index_intlen;
2754 keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2756 keys[1].bv_val = NULL;
2758 iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2759 ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2760 if ( iv.bv_len > (int) sizeof(ibuf) ) {
2761 iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2764 iv.bv_len = sizeof(ibuf);
2767 rc = integerVal2Key( value, keys, &iv, ctx );
2769 if ( iv.bv_val != ibuf ) {
2770 slap_sl_free( iv.bv_val, ctx );
2776 slap_sl_free( keys, ctx );
2782 countryStringValidate(
2784 struct berval *val )
2786 if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2788 if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2789 return LDAP_INVALID_SYNTAX;
2791 if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2792 return LDAP_INVALID_SYNTAX;
2795 return LDAP_SUCCESS;
2799 printableStringValidate(
2801 struct berval *val )
2805 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2807 for(i=0; i < val->bv_len; i++) {
2808 if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2809 return LDAP_INVALID_SYNTAX;
2813 return LDAP_SUCCESS;
2817 printablesStringValidate(
2819 struct berval *val )
2823 if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2825 for(i=0,len=0; i < val->bv_len; i++) {
2826 int c = val->bv_val[i];
2830 return LDAP_INVALID_SYNTAX;
2834 } else if ( SLAP_PRINTABLE(c) ) {
2837 return LDAP_INVALID_SYNTAX;
2842 return LDAP_INVALID_SYNTAX;
2845 return LDAP_SUCCESS;
2851 struct berval *val )
2855 for(i=0; i < val->bv_len; i++) {
2856 if( !LDAP_ASCII(val->bv_val[i]) ) {
2857 return LDAP_INVALID_SYNTAX;
2861 return LDAP_SUCCESS;
2870 struct berval *normalized,
2874 int casefold = !SLAP_MR_ASSOCIATED( mr,
2875 slap_schema.si_mr_caseExactIA5Match );
2877 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2881 /* Ignore initial whitespace */
2882 while ( ASCII_SPACE( *p ) ) p++;
2884 normalized->bv_len = val->bv_len - ( p - val->bv_val );
2885 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2886 AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2887 normalized->bv_val[normalized->bv_len] = '\0';
2889 p = q = normalized->bv_val;
2892 if ( ASCII_SPACE( *p ) ) {
2895 /* Ignore the extra whitespace */
2896 while ( ASCII_SPACE( *p ) ) {
2900 } else if ( casefold ) {
2901 /* Most IA5 rules require casefolding */
2902 *q++ = TOLOWER(*p); p++;
2909 assert( normalized->bv_val <= p );
2913 * If the string ended in space, backup the pointer one
2914 * position. One is enough because the above loop collapsed
2915 * all whitespace to a single space.
2917 if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2919 /* null terminate */
2922 normalized->bv_len = q - normalized->bv_val;
2924 return LDAP_SUCCESS;
2933 if( in->bv_len != 36 ) {
2934 return LDAP_INVALID_SYNTAX;
2937 for( i=0; i<36; i++ ) {
2943 if( in->bv_val[i] != '-' ) {
2944 return LDAP_INVALID_SYNTAX;
2948 if( !ASCII_HEX( in->bv_val[i]) ) {
2949 return LDAP_INVALID_SYNTAX;
2954 return LDAP_SUCCESS;
2965 int rc=LDAP_INVALID_SYNTAX;
2967 assert( in != NULL );
2968 assert( out != NULL );
2970 if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2973 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2975 for( i=0; i<36; i++ ) {
2981 if( in->bv_val[i] != '-' ) {
2984 out->bv_val[i] = '-';
2988 if( !ASCII_HEX( in->bv_val[i]) ) {
2991 out->bv_val[i] = TOLOWER( in->bv_val[i] );
2996 out->bv_val[ out->bv_len ] = '\0';
3000 slap_sl_free( out->bv_val, ctx );
3013 struct berval *normalized,
3016 unsigned char octet = '\0';
3020 if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
3021 /* NOTE: must be a normalized UUID */
3022 assert( val->bv_len == 16 );
3024 normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
3025 normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
3026 val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
3027 assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
3029 return LDAP_SUCCESS;
3032 normalized->bv_len = 16;
3033 normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
3035 for( i=0, j=0; i<36; i++ ) {
3036 unsigned char nibble;
3037 if( val->bv_val[i] == '-' ) {
3040 } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
3041 nibble = val->bv_val[i] - '0';
3043 } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
3044 nibble = val->bv_val[i] - ('a'-10);
3046 } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
3047 nibble = val->bv_val[i] - ('A'-10);
3050 slap_sl_free( normalized->bv_val, ctx );
3051 BER_BVZERO( normalized );
3052 return LDAP_INVALID_SYNTAX;
3057 normalized->bv_val[j>>1] = octet;
3059 octet = nibble << 4;
3064 normalized->bv_val[normalized->bv_len] = 0;
3065 return LDAP_SUCCESS;
3071 numericStringValidate(
3077 if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
3079 for(i=0; i < in->bv_len; i++) {
3080 if( !SLAP_NUMERIC(in->bv_val[i]) ) {
3081 return LDAP_INVALID_SYNTAX;
3085 return LDAP_SUCCESS;
3089 numericStringNormalize(
3094 struct berval *normalized,
3097 /* removal all spaces */
3100 assert( !BER_BVISEMPTY( val ) );
3102 normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3105 q = normalized->bv_val;
3108 if ( ASCII_SPACE( *p ) ) {
3109 /* Ignore whitespace */
3116 /* we should have copied no more than is in val */
3117 assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3119 /* null terminate */
3122 normalized->bv_len = q - normalized->bv_val;
3124 if( BER_BVISEMPTY( normalized ) ) {
3125 normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3126 normalized->bv_val[0] = ' ';
3127 normalized->bv_val[1] = '\0';
3128 normalized->bv_len = 1;
3131 return LDAP_SUCCESS;
3135 * Integer conversion macros that will use the largest available
3138 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3139 # define SLAP_STRTOL(n,e,b) strtoll(n,e,b)
3140 # define SLAP_LONG long long
3142 # define SLAP_STRTOL(n,e,b) strtol(n,e,b)
3143 # define SLAP_LONG long
3144 #endif /* HAVE_STRTOLL ... */
3152 struct berval *value,
3153 void *assertedValue )
3155 SLAP_LONG lValue, lAssertedValue;
3158 /* safe to assume integers are NUL terminated? */
3159 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3160 if( errno == ERANGE )
3162 return LDAP_CONSTRAINT_VIOLATION;
3165 lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3167 if( errno == ERANGE )
3169 return LDAP_CONSTRAINT_VIOLATION;
3172 *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3173 return LDAP_SUCCESS;
3182 struct berval *value,
3183 void *assertedValue )
3185 SLAP_LONG lValue, lAssertedValue;
3188 /* safe to assume integers are NUL terminated? */
3189 lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3190 if( errno == ERANGE )
3192 return LDAP_CONSTRAINT_VIOLATION;
3195 lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3197 if( errno == ERANGE )
3199 return LDAP_CONSTRAINT_VIOLATION;
3202 *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3203 return LDAP_SUCCESS;
3207 checkNum( struct berval *in, struct berval *out )
3209 /* parse serialNumber */
3210 ber_len_t neg = 0, extra = 0;
3213 out->bv_val = in->bv_val;
3216 if ( out->bv_val[0] == '-' ) {
3221 if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3222 first = out->bv_val[2];
3225 out->bv_len += STRLENOF("0x");
3226 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3227 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3230 } else if ( out->bv_val[0] == '\'' ) {
3231 first = out->bv_val[1];
3234 out->bv_len += STRLENOF("'");
3236 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3237 if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3239 if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3242 out->bv_len += STRLENOF("'H");
3245 first = out->bv_val[0];
3246 for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3247 if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3251 if ( !( out->bv_len > neg ) ) {
3255 if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3263 serialNumberAndIssuerCheck(
3271 if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3273 if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3274 /* Parse old format */
3275 is->bv_val = ber_bvchr( in, '$' );
3276 if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3278 sn->bv_val = in->bv_val;
3279 sn->bv_len = is->bv_val - in->bv_val;
3282 is->bv_len = in->bv_len - (sn->bv_len + 1);
3284 /* eat leading zeros */
3285 for( n=0; n < (sn->bv_len-1); n++ ) {
3286 if( sn->bv_val[n] != '0' ) break;
3291 for( n=0; n < sn->bv_len; n++ ) {
3292 if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3296 /* Parse GSER format */
3301 HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3305 struct berval x = *in;
3311 /* eat leading spaces */
3312 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3316 /* should be at issuer or serialNumber NamedValue */
3317 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3318 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3321 x.bv_val += STRLENOF("issuer");
3322 x.bv_len -= STRLENOF("issuer");
3324 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3328 /* eat leading spaces */
3329 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3333 /* For backward compatibility, this part is optional */
3334 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3335 x.bv_val += STRLENOF("rdnSequence:");
3336 x.bv_len -= STRLENOF("rdnSequence:");
3339 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3343 is->bv_val = x.bv_val;
3346 for ( ; is->bv_len < x.bv_len; ) {
3347 if ( is->bv_val[is->bv_len] != '"' ) {
3351 if ( is->bv_val[is->bv_len+1] == '"' ) {
3359 x.bv_val += is->bv_len + 1;
3360 x.bv_len -= is->bv_len + 1;
3362 have |= HAVE_ISSUER;
3364 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3366 if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3368 /* parse serialNumber */
3369 x.bv_val += STRLENOF("serialNumber");
3370 x.bv_len -= STRLENOF("serialNumber");
3372 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3376 /* eat leading spaces */
3377 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3381 if ( checkNum( &x, sn ) ) {
3382 return LDAP_INVALID_SYNTAX;
3385 x.bv_val += sn->bv_len;
3386 x.bv_len -= sn->bv_len;
3391 return LDAP_INVALID_SYNTAX;
3394 /* eat leading spaces */
3395 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3399 if ( have == HAVE_ALL ) {
3403 if ( x.bv_val[0] != ',' ) {
3404 return LDAP_INVALID_SYNTAX;
3411 /* should have no characters left... */
3412 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3414 if ( numdquotes == 0 ) {
3415 ber_dupbv_x( &ni, is, ctx );
3420 ni.bv_len = is->bv_len - numdquotes;
3421 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
3422 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3423 if ( is->bv_val[src] == '"' ) {
3426 ni.bv_val[dst] = is->bv_val[src];
3428 ni.bv_val[dst] = '\0';
3438 serialNumberAndIssuerValidate(
3443 struct berval sn, i;
3445 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3448 rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3453 /* validate DN -- doesn't handle double dquote */
3454 rc = dnValidate( NULL, &i );
3456 rc = LDAP_INVALID_SYNTAX;
3459 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3460 slap_sl_free( i.bv_val, NULL );
3463 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3464 in->bv_val, rc, 0 );
3471 serialNumberAndIssuerPretty(
3478 struct berval sn, i, ni = BER_BVNULL;
3481 assert( in != NULL );
3482 assert( out != NULL );
3486 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3489 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3494 rc = dnPretty( syntax, &i, &ni, ctx );
3496 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3497 slap_sl_free( i.bv_val, ctx );
3501 rc = LDAP_INVALID_SYNTAX;
3505 /* make room from sn + "$" */
3506 out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3507 + sn.bv_len + ni.bv_len;
3508 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3510 if ( out->bv_val == NULL ) {
3517 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3518 p = lutil_strbvcopy( p, &sn );
3519 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3520 p = lutil_strbvcopy( p, &ni );
3521 p = lutil_strcopy( p, /*{*/ "\" }" );
3523 assert( p == &out->bv_val[out->bv_len] );
3526 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3527 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3529 slap_sl_free( ni.bv_val, ctx );
3531 return LDAP_SUCCESS;
3541 /* Use hex format. '123456789abcdef'H */
3542 unsigned char *ptr, zero = '\0';
3545 ber_len_t i, len, nlen;
3547 assert( in != NULL );
3548 assert( !BER_BVISNULL( in ) );
3549 assert( out != NULL );
3550 assert( !BER_BVISNULL( out ) );
3552 ptr = (unsigned char *)in->bv_val;
3555 /* Check for minimal encodings */
3557 if ( ptr[0] & 0x80 ) {
3558 if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3562 } else if ( ptr[0] == 0 ) {
3563 if ( !( ptr[1] & 0x80 ) ) {
3570 } else if ( len == 0 ) {
3571 /* FIXME: this should not be possible,
3572 * since a value of zero would have length 1 */
3577 first = !( ptr[0] & 0xf0U );
3578 nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3579 if ( nlen >= out->bv_len ) {
3580 out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3586 sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3590 for ( ; i < len; i++ ) {
3591 sprintf( sptr, "%02X", ptr[i] );
3598 assert( sptr == &out->bv_val[nlen] );
3605 #define SLAP_SN_BUFLEN (64)
3608 * This routine is called by certificateExactNormalize when
3609 * certificateExactNormalize receives a search string instead of
3610 * a certificate. This routine checks if the search value is valid
3611 * and then returns the normalized value
3614 serialNumberAndIssuerNormalize(
3622 struct berval sn, sn2, sn3, i, ni;
3623 char sbuf2[SLAP_SN_BUFLEN];
3624 char sbuf3[SLAP_SN_BUFLEN];
3628 assert( in != NULL );
3629 assert( out != NULL );
3631 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3634 rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3639 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3641 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3642 slap_sl_free( i.bv_val, ctx );
3646 return LDAP_INVALID_SYNTAX;
3649 /* Convert sn to canonical hex */
3651 if ( sn.bv_len > sizeof( sbuf2 ) ) {
3652 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3654 sn2.bv_len = sn.bv_len;
3656 sn3.bv_len = sizeof(sbuf3);
3657 if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
3658 rc = LDAP_INVALID_SYNTAX;
3662 out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3663 + sn3.bv_len + ni.bv_len;
3664 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3665 if ( out->bv_val == NULL ) {
3673 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3674 p = lutil_strbvcopy( p, &sn3 );
3675 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3676 p = lutil_strbvcopy( p, &ni );
3677 p = lutil_strcopy( p, /*{*/ "\" }" );
3679 assert( p == &out->bv_val[out->bv_len] );
3682 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3683 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
3685 if ( sn2.bv_val != sbuf2 ) {
3686 slap_sl_free( sn2.bv_val, ctx );
3689 if ( sn3.bv_val != sbuf3 ) {
3690 slap_sl_free( sn3.bv_val, ctx );
3693 slap_sl_free( ni.bv_val, ctx );
3699 certificateExactNormalize(
3704 struct berval *normalized,
3707 BerElementBuffer berbuf;
3708 BerElement *ber = (BerElement *)&berbuf;
3712 char serialbuf2[SLAP_SN_BUFLEN];
3713 struct berval sn, sn2 = BER_BVNULL;
3714 struct berval issuer_dn = BER_BVNULL, bvdn;
3716 int rc = LDAP_INVALID_SYNTAX;
3718 assert( val != NULL );
3720 Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3721 val->bv_val, val->bv_len, 0 );
3723 if ( BER_BVISEMPTY( val ) ) goto done;
3725 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3726 return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3729 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3731 ber_init2( ber, val, LBER_USE_DER );
3732 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
3733 tag = ber_skip_tag( ber, &len ); /* Sequence */
3734 tag = ber_peek_tag( ber, &len ); /* Optional version? */
3735 if ( tag == SLAP_X509_OPT_C_VERSION ) {
3736 tag = ber_skip_tag( ber, &len );
3737 tag = ber_get_int( ber, &i ); /* version */
3740 /* NOTE: move the test here from certificateValidate,
3741 * so that we can validate certs with serial longer
3742 * than sizeof(ber_int_t) */
3743 tag = ber_skip_tag( ber, &len ); /* serial */
3745 sn.bv_val = (char *)ber->ber_ptr;
3746 sn2.bv_val = serialbuf2;
3747 sn2.bv_len = sizeof(serialbuf2);
3748 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3749 rc = LDAP_INVALID_SYNTAX;
3752 ber_skip_data( ber, len );
3754 tag = ber_skip_tag( ber, &len ); /* SignatureAlg */
3755 ber_skip_data( ber, len );
3756 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
3758 len = ber_ptrlen( ber );
3759 bvdn.bv_val = val->bv_val + len;
3760 bvdn.bv_len = val->bv_len - len;
3762 rc = dnX509normalize( &bvdn, &issuer_dn );
3763 if ( rc != LDAP_SUCCESS ) goto done;
3766 normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3767 + sn2.bv_len + issuer_dn.bv_len;
3768 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3770 p = normalized->bv_val;
3772 p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3773 p = lutil_strbvcopy( p, &sn2 );
3774 p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3775 p = lutil_strbvcopy( p, &issuer_dn );
3776 p = lutil_strcopy( p, /*{*/ "\" }" );
3781 Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3782 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3784 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3785 if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3790 /* X.509 PKI certificateList stuff */
3792 checkTime( struct berval *in, struct berval *out )
3796 char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3799 assert( in != NULL );
3800 assert( !BER_BVISNULL( in ) );
3801 assert( !BER_BVISEMPTY( in ) );
3803 if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3807 if ( out != NULL ) {
3808 assert( !BER_BVISNULL( out ) );
3809 assert( out->bv_len >= sizeof( buf ) );
3810 bv.bv_val = out->bv_val;
3816 for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3817 if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3820 if ( in->bv_val[i] != 'Z' ) {
3825 if ( i != in->bv_len ) {
3829 if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3830 lutil_strncopy( bv.bv_val, in->bv_val, i );
3833 } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3834 char *p = bv.bv_val;
3835 if ( in->bv_val[0] < '7' ) {
3836 p = lutil_strcopy( p, "20" );
3839 p = lutil_strcopy( p, "19" );
3841 lutil_strncopy( p, in->bv_val, i );
3848 rc = generalizedTimeValidate( NULL, &bv );
3849 if ( rc == LDAP_SUCCESS && out != NULL ) {
3850 if ( out->bv_len > bv.bv_len ) {
3851 out->bv_val[ bv.bv_len ] = '\0';
3853 out->bv_len = bv.bv_len;
3856 return rc != LDAP_SUCCESS;
3860 issuerAndThisUpdateCheck(
3867 struct berval x = *in;
3868 struct berval ni = BER_BVNULL;
3869 /* Parse GSER format */
3873 HAVE_THISUPDATE = 0x2,
3874 HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3878 if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3880 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
3881 return LDAP_INVALID_SYNTAX;
3885 x.bv_len -= STRLENOF("{}");
3888 /* eat leading spaces */
3889 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3893 /* should be at issuer or thisUpdate */
3894 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3895 if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3898 x.bv_val += STRLENOF("issuer");
3899 x.bv_len -= STRLENOF("issuer");
3901 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3905 /* eat leading spaces */
3906 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3910 /* For backward compatibility, this part is optional */
3911 if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3912 return LDAP_INVALID_SYNTAX;
3914 x.bv_val += STRLENOF("rdnSequence:");
3915 x.bv_len -= STRLENOF("rdnSequence:");
3917 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3921 is->bv_val = x.bv_val;
3924 for ( ; is->bv_len < x.bv_len; ) {
3925 if ( is->bv_val[is->bv_len] != '"' ) {
3929 if ( is->bv_val[is->bv_len+1] == '"' ) {
3937 x.bv_val += is->bv_len + 1;
3938 x.bv_len -= is->bv_len + 1;
3940 have |= HAVE_ISSUER;
3942 } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3944 if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3946 /* parse thisUpdate */
3947 x.bv_val += STRLENOF("thisUpdate");
3948 x.bv_len -= STRLENOF("thisUpdate");
3950 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3954 /* eat leading spaces */
3955 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3959 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3963 tu->bv_val = x.bv_val;
3966 for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3967 if ( tu->bv_val[tu->bv_len] == '"' ) {
3971 x.bv_val += tu->bv_len + 1;
3972 x.bv_len -= tu->bv_len + 1;
3974 have |= HAVE_THISUPDATE;
3977 return LDAP_INVALID_SYNTAX;
3980 /* eat leading spaces */
3981 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3985 if ( have == HAVE_ALL ) {
3989 if ( x.bv_val[0] != ',' ) {
3990 return LDAP_INVALID_SYNTAX;
3997 /* should have no characters left... */
3998 if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
4000 if ( numdquotes == 0 ) {
4001 ber_dupbv_x( &ni, is, ctx );
4006 ni.bv_len = is->bv_len - numdquotes;
4007 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4008 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4009 if ( is->bv_val[src] == '"' ) {
4012 ni.bv_val[dst] = is->bv_val[src];
4014 ni.bv_val[dst] = '\0';
4023 issuerAndThisUpdateValidate(
4028 struct berval i, tu;
4030 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
4033 rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
4038 /* validate DN -- doesn't handle double dquote */
4039 rc = dnValidate( NULL, &i );
4041 rc = LDAP_INVALID_SYNTAX;
4043 } else if ( checkTime( &tu, NULL ) ) {
4044 rc = LDAP_INVALID_SYNTAX;
4047 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4048 slap_sl_free( i.bv_val, NULL );
4051 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
4052 in->bv_val, rc, 0 );
4059 issuerAndThisUpdatePretty(
4066 struct berval i, tu, ni = BER_BVNULL;
4069 assert( in != NULL );
4070 assert( out != NULL );
4074 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
4077 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4082 rc = dnPretty( syntax, &i, &ni, ctx );
4084 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4085 slap_sl_free( i.bv_val, ctx );
4088 if ( rc || checkTime( &tu, NULL ) ) {
4089 rc = LDAP_INVALID_SYNTAX;
4094 out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
4095 + ni.bv_len + tu.bv_len;
4096 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4098 if ( out->bv_val == NULL ) {
4105 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4106 p = lutil_strbvcopy( p, &ni );
4107 p = lutil_strcopy( p, "\", thisUpdate \"" );
4108 p = lutil_strbvcopy( p, &tu );
4109 p = lutil_strcopy( p, /*{*/ "\" }" );
4111 assert( p == &out->bv_val[out->bv_len] );
4114 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4115 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4117 slap_sl_free( ni.bv_val, ctx );
4123 issuerAndThisUpdateNormalize(
4131 struct berval i, ni, tu, tu2;
4132 char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4136 assert( in != NULL );
4137 assert( out != NULL );
4139 Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4142 rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4147 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4149 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4150 slap_sl_free( i.bv_val, ctx );
4154 tu2.bv_len = sizeof( sbuf );
4155 if ( rc || checkTime( &tu, &tu2 ) ) {
4156 return LDAP_INVALID_SYNTAX;
4159 out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4160 + ni.bv_len + tu2.bv_len;
4161 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4163 if ( out->bv_val == NULL ) {
4171 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4172 p = lutil_strbvcopy( p, &ni );
4173 p = lutil_strcopy( p, "\", thisUpdate \"" );
4174 p = lutil_strbvcopy( p, &tu2 );
4175 p = lutil_strcopy( p, /*{*/ "\" }" );
4177 assert( p == &out->bv_val[out->bv_len] );
4180 Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4181 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4183 slap_sl_free( ni.bv_val, ctx );
4189 certificateListExactNormalize(
4194 struct berval *normalized,
4197 BerElementBuffer berbuf;
4198 BerElement *ber = (BerElement *)&berbuf;
4202 struct berval issuer_dn = BER_BVNULL, bvdn,
4204 char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4205 int rc = LDAP_INVALID_SYNTAX;
4207 assert( val != NULL );
4209 Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4210 val->bv_val, val->bv_len, 0 );
4212 if ( BER_BVISEMPTY( val ) ) goto done;
4214 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4215 return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4218 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4220 ber_init2( ber, val, LBER_USE_DER );
4221 tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
4222 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4223 tag = ber_skip_tag( ber, &len ); /* Sequence */
4224 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4225 tag = ber_peek_tag( ber, &len );
4226 /* Optional version */
4227 if ( tag == LBER_INTEGER ) {
4228 tag = ber_get_int( ber, &version );
4229 assert( tag == LBER_INTEGER );
4230 if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4232 tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
4233 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4234 ber_skip_data( ber, len );
4236 tag = ber_peek_tag( ber, &len ); /* IssuerDN */
4237 if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4238 len = ber_ptrlen( ber );
4239 bvdn.bv_val = val->bv_val + len;
4240 bvdn.bv_len = val->bv_len - len;
4241 tag = ber_skip_tag( ber, &len );
4242 ber_skip_data( ber, len );
4244 tag = ber_skip_tag( ber, &len ); /* thisUpdate */
4245 /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4246 if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4247 bvtu.bv_val = (char *)ber->ber_ptr;
4250 rc = dnX509normalize( &bvdn, &issuer_dn );
4251 if ( rc != LDAP_SUCCESS ) goto done;
4253 thisUpdate.bv_val = tubuf;
4254 thisUpdate.bv_len = sizeof(tubuf);
4255 if ( checkTime( &bvtu, &thisUpdate ) ) {
4256 rc = LDAP_INVALID_SYNTAX;
4260 normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4261 + issuer_dn.bv_len + thisUpdate.bv_len;
4262 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4264 p = normalized->bv_val;
4266 p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4267 p = lutil_strbvcopy( p, &issuer_dn );
4268 p = lutil_strcopy( p, "\", thisUpdate \"" );
4269 p = lutil_strbvcopy( p, &thisUpdate );
4270 p = lutil_strcopy( p, /*{*/ "\" }" );
4275 Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4276 val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4278 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4283 /* X.509 PMI serialNumberAndIssuerSerialCheck
4285 AttributeCertificateExactAssertion ::= SEQUENCE {
4286 serialNumber CertificateSerialNumber,
4287 issuer AttCertIssuer }
4289 CertificateSerialNumber ::= INTEGER
4291 AttCertIssuer ::= [0] SEQUENCE {
4292 issuerName GeneralNames OPTIONAL,
4293 baseCertificateID [0] IssuerSerial OPTIONAL,
4294 objectDigestInfo [1] ObjectDigestInfo OPTIONAL }
4295 -- At least one component shall be present
4297 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4299 GeneralName ::= CHOICE {
4300 otherName [0] INSTANCE OF OTHER-NAME,
4301 rfc822Name [1] IA5String,
4302 dNSName [2] IA5String,
4303 x400Address [3] ORAddress,
4304 directoryName [4] Name,
4305 ediPartyName [5] EDIPartyName,
4306 uniformResourceIdentifier [6] IA5String,
4307 iPAddress [7] OCTET STRING,
4308 registeredID [8] OBJECT IDENTIFIER }
4310 IssuerSerial ::= SEQUENCE {
4311 issuer GeneralNames,
4312 serial CertificateSerialNumber,
4313 issuerUID UniqueIdentifier OPTIONAL }
4315 ObjectDigestInfo ::= SEQUENCE {
4316 digestedObjectType ENUMERATED {
4319 otherObjectTypes (2) },
4320 otherObjectTypeID OBJECT IDENTIFIER OPTIONAL,
4321 digestAlgorithm AlgorithmIdentifier,
4322 objectDigest BIT STRING }
4324 * The way I interpret it, an assertion should look like
4326 { serialNumber 'dd'H,
4327 issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4328 baseCertificateID { serial '1d'H,
4329 issuer { directoryName:rdnSequence:"cn=zzz" },
4330 issuerUID <value> -- optional
4332 objectDigestInfo { ... } -- optional
4336 * with issuerName, baseCertificateID and objectDigestInfo optional,
4337 * at least one present; the way it's currently implemented, it is
4339 { serialNumber 'dd'H,
4340 issuer { baseCertificateID { serial '1d'H,
4341 issuer { directoryName:rdnSequence:"cn=zzz" }
4346 * with all the above parts mandatory.
4349 serialNumberAndIssuerSerialCheck(
4353 struct berval *i_sn, /* contain serial of baseCertificateID */
4356 /* Parse GSER format */
4361 HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4362 } have = HAVE_NONE, have2 = HAVE_NONE;
4364 struct berval x = *in;
4367 if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4370 if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4377 /* eat leading spaces */
4378 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4382 /* should be at issuer or serialNumber NamedValue */
4383 if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4384 if ( have & HAVE_ISSUER ) {
4385 return LDAP_INVALID_SYNTAX;
4388 /* parse IssuerSerial */
4389 x.bv_val += STRLENOF("issuer");
4390 x.bv_len -= STRLENOF("issuer");
4392 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4396 /* eat leading spaces */
4397 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4401 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4405 /* eat leading spaces */
4406 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4410 if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4411 return LDAP_INVALID_SYNTAX;
4413 x.bv_val += STRLENOF("baseCertificateID ");
4414 x.bv_len -= STRLENOF("baseCertificateID ");
4416 /* eat leading spaces */
4417 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4421 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4426 /* eat leading spaces */
4427 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4431 /* parse issuer of baseCertificateID */
4432 if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4433 if ( have2 & HAVE_ISSUER ) {
4434 return LDAP_INVALID_SYNTAX;
4437 x.bv_val += STRLENOF("issuer ");
4438 x.bv_len -= STRLENOF("issuer ");
4440 /* eat leading spaces */
4441 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4445 if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4449 /* eat leading spaces */
4450 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4454 if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4455 return LDAP_INVALID_SYNTAX;
4457 x.bv_val += STRLENOF("directoryName:rdnSequence:");
4458 x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4460 if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4464 is->bv_val = x.bv_val;
4467 for ( ; is->bv_len < x.bv_len; ) {
4468 if ( is->bv_val[is->bv_len] != '"' ) {
4472 if ( is->bv_val[is->bv_len + 1] == '"' ) {
4480 x.bv_val += is->bv_len + 1;
4481 x.bv_len -= is->bv_len + 1;
4483 /* eat leading spaces */
4484 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4488 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4492 have2 |= HAVE_ISSUER;
4494 } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4495 if ( have2 & HAVE_SN ) {
4496 return LDAP_INVALID_SYNTAX;
4499 x.bv_val += STRLENOF("serial ");
4500 x.bv_len -= STRLENOF("serial ");
4502 /* eat leading spaces */
4503 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4507 if ( checkNum( &x, i_sn ) ) {
4508 return LDAP_INVALID_SYNTAX;
4511 x.bv_val += i_sn->bv_len;
4512 x.bv_len -= i_sn->bv_len;
4517 return LDAP_INVALID_SYNTAX;
4520 /* eat leading spaces */
4521 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4525 if ( have2 == HAVE_ALL ) {
4529 if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4534 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4538 /* eat leading spaces */
4539 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4543 if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4547 have |= HAVE_ISSUER;
4549 } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4550 if ( have & HAVE_SN ) {
4551 return LDAP_INVALID_SYNTAX;
4554 /* parse serialNumber */
4555 x.bv_val += STRLENOF("serialNumber");
4556 x.bv_len -= STRLENOF("serialNumber");
4558 if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4562 /* eat leading spaces */
4563 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4567 if ( checkNum( &x, sn ) ) {
4568 return LDAP_INVALID_SYNTAX;
4571 x.bv_val += sn->bv_len;
4572 x.bv_len -= sn->bv_len;
4577 return LDAP_INVALID_SYNTAX;
4581 for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4585 if ( have == HAVE_ALL ) {
4589 if ( x.bv_val[0] != ',' ) {
4590 return LDAP_INVALID_SYNTAX;
4596 /* should have no characters left... */
4597 if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4599 if ( numdquotes == 0 ) {
4600 ber_dupbv_x( &ni, is, ctx );
4605 ni.bv_len = is->bv_len - numdquotes;
4606 ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
4607 for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4608 if ( is->bv_val[src] == '"' ) {
4611 ni.bv_val[dst] = is->bv_val[src];
4613 ni.bv_val[dst] = '\0';
4618 /* need to handle double dquotes here */
4622 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4624 serialNumberAndIssuerSerialValidate(
4629 struct berval sn, i, i_sn;
4631 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4634 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4639 /* validate DN -- doesn't handle double dquote */
4640 rc = dnValidate( NULL, &i );
4642 rc = LDAP_INVALID_SYNTAX;
4645 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4646 slap_sl_free( i.bv_val, NULL );
4650 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4651 in->bv_val, rc, 0 );
4656 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4658 serialNumberAndIssuerSerialPretty(
4664 struct berval sn, i, i_sn, ni = BER_BVNULL;
4668 assert( in != NULL );
4669 assert( out != NULL );
4671 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4674 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4679 rc = dnPretty( syntax, &i, &ni, ctx );
4681 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4682 slap_sl_free( i.bv_val, ctx );
4686 rc = LDAP_INVALID_SYNTAX;
4690 /* make room from sn + "$" */
4691 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4692 + sn.bv_len + ni.bv_len + i_sn.bv_len;
4693 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4695 if ( out->bv_val == NULL ) {
4702 p = lutil_strcopy( p, "{ serialNumber " );
4703 p = lutil_strbvcopy( p, &sn );
4704 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4705 p = lutil_strbvcopy( p, &ni );
4706 p = lutil_strcopy( p, "\" }, serial " );
4707 p = lutil_strbvcopy( p, &i_sn );
4708 p = lutil_strcopy( p, " } } }" );
4710 assert( p == &out->bv_val[out->bv_len] );
4713 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4714 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4716 slap_sl_free( ni.bv_val, ctx );
4721 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4723 * This routine is called by attributeCertificateExactNormalize
4724 * when attributeCertificateExactNormalize receives a search
4725 * string instead of a attribute certificate. This routine
4726 * checks if the search value is valid and then returns the
4730 serialNumberAndIssuerSerialNormalize(
4738 struct berval i, ni = BER_BVNULL,
4739 sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4740 i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4741 char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4742 sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4746 assert( in != NULL );
4747 assert( out != NULL );
4749 Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4752 rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4757 rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4759 if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4760 slap_sl_free( i.bv_val, ctx );
4764 rc = LDAP_INVALID_SYNTAX;
4768 /* Convert sn to canonical hex */
4770 sn2.bv_len = sn.bv_len;
4771 if ( sn.bv_len > sizeof( sbuf2 ) ) {
4772 sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4774 if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4775 rc = LDAP_INVALID_SYNTAX;
4779 /* Convert i_sn to canonical hex */
4780 i_sn2.bv_val = i_sbuf2;
4781 i_sn2.bv_len = i_sn.bv_len;
4782 if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4783 i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4785 if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4786 rc = LDAP_INVALID_SYNTAX;
4791 sn3.bv_len = sizeof(sbuf3);
4792 if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4793 rc = LDAP_INVALID_SYNTAX;
4797 i_sn3.bv_val = i_sbuf3;
4798 i_sn3.bv_len = sizeof(i_sbuf3);
4799 if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4800 rc = LDAP_INVALID_SYNTAX;
4804 out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }")
4805 + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4806 out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4808 if ( out->bv_val == NULL ) {
4816 p = lutil_strcopy( p, "{ serialNumber " );
4817 p = lutil_strbvcopy( p, &sn3 );
4818 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4819 p = lutil_strbvcopy( p, &ni );
4820 p = lutil_strcopy( p, "\" }, serial " );
4821 p = lutil_strbvcopy( p, &i_sn3 );
4822 p = lutil_strcopy( p, " } } }" );
4824 assert( p == &out->bv_val[out->bv_len] );
4827 Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4828 in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
4830 if ( sn2.bv_val != sbuf2 ) {
4831 slap_sl_free( sn2.bv_val, ctx );
4834 if ( i_sn2.bv_val != i_sbuf2 ) {
4835 slap_sl_free( i_sn2.bv_val, ctx );
4838 if ( sn3.bv_val != sbuf3 ) {
4839 slap_sl_free( sn3.bv_val, ctx );
4842 if ( i_sn3.bv_val != i_sbuf3 ) {
4843 slap_sl_free( i_sn3.bv_val, ctx );
4846 slap_sl_free( ni.bv_val, ctx );
4851 /* X.509 PMI attributeCertificateExactNormalize */
4853 attributeCertificateExactNormalize(
4858 struct berval *normalized,
4861 BerElementBuffer berbuf;
4862 BerElement *ber = (BerElement *)&berbuf;
4865 char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4866 struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4867 struct berval issuer_dn = BER_BVNULL, bvdn;
4869 int rc = LDAP_INVALID_SYNTAX;
4871 if ( BER_BVISEMPTY( val ) ) {
4875 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4876 return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4879 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4881 ber_init2( ber, val, LBER_USE_DER );
4882 tag = ber_skip_tag( ber, &len ); /* Signed Sequence */
4883 tag = ber_skip_tag( ber, &len ); /* Sequence */
4884 tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */
4885 ber_skip_data( ber, len );
4886 tag = ber_skip_tag( ber, &len ); /* Holder Sequence */
4887 ber_skip_data( ber, len );
4890 tag = ber_skip_tag( ber, &len ); /* Sequence */
4891 /* issuerName (GeneralNames sequence; optional)? */
4892 tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */
4893 tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */
4894 tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */
4895 if ( tag != SLAP_X509_GN_DIRECTORYNAME ) {
4896 return LDAP_INVALID_SYNTAX;
4898 tag = ber_peek_tag( ber, &len ); /* sequence of RDN */
4899 len = ber_ptrlen( ber );
4900 bvdn.bv_val = val->bv_val + len;
4901 bvdn.bv_len = val->bv_len - len;
4902 rc = dnX509normalize( &bvdn, &issuer_dn );
4903 if ( rc != LDAP_SUCCESS ) goto done;
4905 tag = ber_skip_tag( ber, &len ); /* sequence of RDN */
4906 ber_skip_data( ber, len );
4907 tag = ber_skip_tag( ber, &len ); /* serial number */
4908 if ( tag != LBER_INTEGER ) {
4909 rc = LDAP_INVALID_SYNTAX;
4912 i_sn.bv_val = (char *)ber->ber_ptr;
4914 i_sn2.bv_val = issuer_serialbuf;
4915 i_sn2.bv_len = sizeof(issuer_serialbuf);
4916 if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4917 rc = LDAP_INVALID_SYNTAX;
4920 ber_skip_data( ber, len );
4922 /* issuerUID (bitstring; optional)? */
4923 /* objectDigestInfo (sequence; optional)? */
4925 tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */
4926 ber_skip_data( ber, len );
4927 tag = ber_skip_tag( ber, &len ); /* serial number */
4928 if ( tag != LBER_INTEGER ) {
4929 rc = LDAP_INVALID_SYNTAX;
4932 sn.bv_val = (char *)ber->ber_ptr;
4934 sn2.bv_val = serialbuf;
4935 sn2.bv_len = sizeof(serialbuf);
4936 if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4937 rc = LDAP_INVALID_SYNTAX;
4940 ber_skip_data( ber, len );
4942 normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" )
4943 + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4944 normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4946 p = normalized->bv_val;
4948 p = lutil_strcopy( p, "{ serialNumber " );
4949 p = lutil_strbvcopy( p, &sn2 );
4950 p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4951 p = lutil_strbvcopy( p, &issuer_dn );
4952 p = lutil_strcopy( p, "\" }, serial " );
4953 p = lutil_strbvcopy( p, &i_sn2 );
4954 p = lutil_strcopy( p, " } } }" );
4956 Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4957 normalized->bv_val, NULL, NULL );
4962 if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4963 if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4964 if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4977 assert( in != NULL );
4978 assert( !BER_BVISNULL( in ) );
4980 for ( i = 0; i < in->bv_len; i++ ) {
4981 if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
4982 return LDAP_INVALID_SYNTAX;
4986 return LDAP_SUCCESS;
4989 /* Normalize a SID as used inside a CSN:
4990 * three-digit numeric string */
4997 struct berval *normalized,
5002 assert( val != NULL );
5003 assert( normalized != NULL );
5005 ber_dupbv_x( normalized, val, ctx );
5007 for ( i = 0; i < normalized->bv_len; i++ ) {
5008 if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
5009 ber_memfree_x( normalized->bv_val, ctx );
5010 BER_BVZERO( normalized );
5011 return LDAP_INVALID_SYNTAX;
5014 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5017 return LDAP_SUCCESS;
5025 assert( in != NULL );
5026 assert( !BER_BVISNULL( in ) );
5028 if ( in->bv_len != 3 ) {
5029 return LDAP_INVALID_SYNTAX;
5032 return hexValidate( NULL, in );
5035 /* Normalize a SID as used inside a CSN:
5036 * three-digit numeric string */
5043 struct berval *normalized,
5046 if ( val->bv_len != 3 ) {
5047 return LDAP_INVALID_SYNTAX;
5050 return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
5060 return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5063 /* Normalize a SID as used inside a CSN, either as-is
5064 * (assertion value) or extracted from the CSN
5065 * (attribute value) */
5072 struct berval *normalized,
5080 if ( BER_BVISEMPTY( val ) ) {
5081 return LDAP_INVALID_SYNTAX;
5084 if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
5085 return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
5088 assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
5090 ptr = ber_bvchr( val, '#' );
5091 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5092 return LDAP_INVALID_SYNTAX;
5095 bv.bv_val = ptr + 1;
5096 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5098 ptr = ber_bvchr( &bv, '#' );
5099 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5100 return LDAP_INVALID_SYNTAX;
5103 bv.bv_val = ptr + 1;
5104 bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5106 ptr = ber_bvchr( &bv, '#' );
5107 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5108 return LDAP_INVALID_SYNTAX;
5111 bv.bv_len = ptr - bv.bv_val;
5113 if ( bv.bv_len == 2 ) {
5114 /* OpenLDAP 2.3 SID */
5116 buf[ 1 ] = bv.bv_val[ 0 ];
5117 buf[ 2 ] = bv.bv_val[ 1 ];
5124 return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5136 assert( in != NULL );
5137 assert( !BER_BVISNULL( in ) );
5139 if ( BER_BVISEMPTY( in ) ) {
5140 return LDAP_INVALID_SYNTAX;
5145 ptr = ber_bvchr( &bv, '#' );
5146 if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5147 return LDAP_INVALID_SYNTAX;
5150 bv.bv_len = ptr - bv.bv_val;
5151 if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5152 bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5154 return LDAP_INVALID_SYNTAX;
5157 rc = generalizedTimeValidate( NULL, &bv );
5158 if ( rc != LDAP_SUCCESS ) {
5162 bv.bv_val = ptr + 1;
5163 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5165 ptr = ber_bvchr( &bv, '#' );
5166 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5167 return LDAP_INVALID_SYNTAX;
5170 bv.bv_len = ptr - bv.bv_val;
5171 if ( bv.bv_len != 6 ) {
5172 return LDAP_INVALID_SYNTAX;
5175 rc = hexValidate( NULL, &bv );
5176 if ( rc != LDAP_SUCCESS ) {
5180 bv.bv_val = ptr + 1;
5181 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5183 ptr = ber_bvchr( &bv, '#' );
5184 if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5185 return LDAP_INVALID_SYNTAX;
5188 bv.bv_len = ptr - bv.bv_val;
5189 if ( bv.bv_len == 2 ) {
5190 /* tolerate old 2-digit replica-id */
5191 rc = hexValidate( NULL, &bv );
5194 rc = sidValidate( NULL, &bv );
5196 if ( rc != LDAP_SUCCESS ) {
5200 bv.bv_val = ptr + 1;
5201 bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5203 if ( bv.bv_len != 6 ) {
5204 return LDAP_INVALID_SYNTAX;
5207 return hexValidate( NULL, &bv );
5210 /* Normalize a CSN in OpenLDAP 2.1 format */
5217 struct berval *normalized,
5220 struct berval gt, cnt, sid, mod;
5222 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5226 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5227 assert( !BER_BVISEMPTY( val ) );
5231 ptr = ber_bvchr( >, '#' );
5232 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5233 return LDAP_INVALID_SYNTAX;
5236 gt.bv_len = ptr - gt.bv_val;
5237 if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5238 return LDAP_INVALID_SYNTAX;
5241 if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5242 return LDAP_INVALID_SYNTAX;
5245 cnt.bv_val = ptr + 1;
5246 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5248 ptr = ber_bvchr( &cnt, '#' );
5249 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5250 return LDAP_INVALID_SYNTAX;
5253 cnt.bv_len = ptr - cnt.bv_val;
5254 if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5255 return LDAP_INVALID_SYNTAX;
5258 if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5259 return LDAP_INVALID_SYNTAX;
5262 cnt.bv_val += STRLENOF( "0x" );
5263 cnt.bv_len -= STRLENOF( "0x" );
5265 sid.bv_val = ptr + 1;
5266 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5268 ptr = ber_bvchr( &sid, '#' );
5269 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5270 return LDAP_INVALID_SYNTAX;
5273 sid.bv_len = ptr - sid.bv_val;
5274 if ( sid.bv_len != STRLENOF( "0" ) ) {
5275 return LDAP_INVALID_SYNTAX;
5278 mod.bv_val = ptr + 1;
5279 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5280 if ( mod.bv_len != STRLENOF( "0000" ) ) {
5281 return LDAP_INVALID_SYNTAX;
5284 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5288 ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5289 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5291 ptr = lutil_strncopy( ptr, >.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5293 ptr = lutil_strcopy( ptr, ".000000Z#00" );
5294 ptr = lutil_strbvcopy( ptr, &cnt );
5298 *ptr++ = sid.bv_val[ 0 ];
5302 for ( i = 0; i < mod.bv_len; i++ ) {
5303 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5307 assert( ptr == &bv.bv_val[bv.bv_len] );
5309 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5310 return LDAP_INVALID_SYNTAX;
5313 ber_dupbv_x( normalized, &bv, ctx );
5315 return LDAP_SUCCESS;
5318 /* Normalize a CSN in OpenLDAP 2.3 format */
5325 struct berval *normalized,
5328 struct berval gt, cnt, sid, mod;
5330 char buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5334 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5335 assert( !BER_BVISEMPTY( val ) );
5339 ptr = ber_bvchr( >, '#' );
5340 if ( ptr == NULL || ptr == >.bv_val[gt.bv_len] ) {
5341 return LDAP_INVALID_SYNTAX;
5344 gt.bv_len = ptr - gt.bv_val;
5345 if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5346 return LDAP_INVALID_SYNTAX;
5349 cnt.bv_val = ptr + 1;
5350 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5352 ptr = ber_bvchr( &cnt, '#' );
5353 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5354 return LDAP_INVALID_SYNTAX;
5357 cnt.bv_len = ptr - cnt.bv_val;
5358 if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5359 return LDAP_INVALID_SYNTAX;
5362 sid.bv_val = ptr + 1;
5363 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5365 ptr = ber_bvchr( &sid, '#' );
5366 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5367 return LDAP_INVALID_SYNTAX;
5370 sid.bv_len = ptr - sid.bv_val;
5371 if ( sid.bv_len != STRLENOF( "00" ) ) {
5372 return LDAP_INVALID_SYNTAX;
5375 mod.bv_val = ptr + 1;
5376 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5377 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5378 return LDAP_INVALID_SYNTAX;
5381 bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5385 ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5386 ptr = lutil_strcopy( ptr, ".000000Z#" );
5387 ptr = lutil_strbvcopy( ptr, &cnt );
5390 for ( i = 0; i < sid.bv_len; i++ ) {
5391 *ptr++ = TOLOWER( sid.bv_val[ i ] );
5394 for ( i = 0; i < mod.bv_len; i++ ) {
5395 *ptr++ = TOLOWER( mod.bv_val[ i ] );
5399 assert( ptr == &bv.bv_val[bv.bv_len] );
5400 if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5401 return LDAP_INVALID_SYNTAX;
5404 ber_dupbv_x( normalized, &bv, ctx );
5406 return LDAP_SUCCESS;
5409 /* Normalize a CSN */
5416 struct berval *normalized,
5419 struct berval cnt, sid, mod;
5423 assert( val != NULL );
5424 assert( normalized != NULL );
5426 assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5428 if ( BER_BVISEMPTY( val ) ) {
5429 return LDAP_INVALID_SYNTAX;
5432 if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5433 /* Openldap <= 2.3 */
5435 return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5438 if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5441 return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5444 if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5445 return LDAP_INVALID_SYNTAX;
5448 ptr = ber_bvchr( val, '#' );
5449 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5450 return LDAP_INVALID_SYNTAX;
5453 if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5454 return LDAP_INVALID_SYNTAX;
5457 cnt.bv_val = ptr + 1;
5458 cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5460 ptr = ber_bvchr( &cnt, '#' );
5461 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5462 return LDAP_INVALID_SYNTAX;
5465 if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5466 return LDAP_INVALID_SYNTAX;
5469 sid.bv_val = ptr + 1;
5470 sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5472 ptr = ber_bvchr( &sid, '#' );
5473 if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5474 return LDAP_INVALID_SYNTAX;
5477 sid.bv_len = ptr - sid.bv_val;
5478 if ( sid.bv_len != STRLENOF( "000" ) ) {
5479 return LDAP_INVALID_SYNTAX;
5482 mod.bv_val = ptr + 1;
5483 mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5485 if ( mod.bv_len != STRLENOF( "000000" ) ) {
5486 return LDAP_INVALID_SYNTAX;
5489 ber_dupbv_x( normalized, val, ctx );
5491 for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5492 i < normalized->bv_len; i++ )
5494 /* assume it's already validated that's all hex digits */
5495 normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5498 return LDAP_SUCCESS;
5508 return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5511 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5512 /* slight optimization - does not need the start parameter */
5513 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5518 check_time_syntax (struct berval *val,
5521 struct berval *fraction)
5524 * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5525 * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
5526 * GeneralizedTime supports leap seconds, UTCTime does not.
5528 static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5529 static const int mdays[2][12] = {
5530 /* non-leap years */
5531 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5533 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5536 int part, c, c1, c2, tzoffset, leapyear = 0;
5539 e = p + val->bv_len;
5541 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5542 parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5544 for (part = start; part < 7 && p < e; part++) {
5546 if (!ASCII_DIGIT(c1)) {
5551 return LDAP_INVALID_SYNTAX;
5554 if (!ASCII_DIGIT(c)) {
5555 return LDAP_INVALID_SYNTAX;
5557 c += c1 * 10 - '0' * 11;
5558 if ((part | 1) == 3) {
5561 return LDAP_INVALID_SYNTAX;
5564 if (c >= ceiling[part]) {
5565 if (! (c == 60 && part == 6 && start == 0))
5566 return LDAP_INVALID_SYNTAX;
5570 if (part < 5 + start) {
5571 return LDAP_INVALID_SYNTAX;
5573 for (; part < 9; part++) {
5577 /* leapyear check for the Gregorian calendar (year>1581) */
5578 if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5582 if (parts[3] >= mdays[leapyear][parts[2]]) {
5583 return LDAP_INVALID_SYNTAX;
5587 fraction->bv_val = p;
5588 fraction->bv_len = 0;
5589 if (p < e && (*p == '.' || *p == ',')) {
5591 while (++p < e && ASCII_DIGIT(*p)) {
5594 if (p - fraction->bv_val == 1) {
5595 return LDAP_INVALID_SYNTAX;
5597 for (end_num = p; end_num[-1] == '0'; --end_num) {
5600 c = end_num - fraction->bv_val;
5601 if (c != 1) fraction->bv_len = c;
5607 return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5613 return LDAP_INVALID_SYNTAX;
5619 for (part = 7; part < 9 && p < e; part++) {
5621 if (!ASCII_DIGIT(c1)) {
5626 return LDAP_INVALID_SYNTAX;
5629 if (!ASCII_DIGIT(c2)) {
5630 return LDAP_INVALID_SYNTAX;
5632 parts[part] = c1 * 10 + c2 - '0' * 11;
5633 if (parts[part] >= ceiling[part]) {
5634 return LDAP_INVALID_SYNTAX;
5637 if (part < 8 + start) {
5638 return LDAP_INVALID_SYNTAX;
5641 if (tzoffset == '-') {
5642 /* negative offset to UTC, ie west of Greenwich */
5643 parts[4] += parts[7];
5644 parts[5] += parts[8];
5645 /* offset is just hhmm, no seconds */
5646 for (part = 6; --part >= 0; ) {
5650 c = mdays[leapyear][parts[2]];
5652 if (parts[part] >= c) {
5654 return LDAP_INVALID_SYNTAX;
5659 } else if (part != 5) {
5664 /* positive offset to UTC, ie east of Greenwich */
5665 parts[4] -= parts[7];
5666 parts[5] -= parts[8];
5667 for (part = 6; --part >= 0; ) {
5668 if (parts[part] < 0) {
5670 return LDAP_INVALID_SYNTAX;
5675 /* make first arg to % non-negative */
5676 c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5681 } else if (part != 5) {
5688 return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5691 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5698 struct berval *normalized )
5702 rc = check_time_syntax(val, 1, parts, NULL);
5703 if (rc != LDAP_SUCCESS) {
5707 normalized->bv_val = ch_malloc( 14 );
5708 if ( normalized->bv_val == NULL ) {
5709 return LBER_ERROR_MEMORY;
5712 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5713 parts[1], parts[2] + 1, parts[3] + 1,
5714 parts[4], parts[5], parts[6] );
5715 normalized->bv_len = 13;
5717 return LDAP_SUCCESS;
5727 return check_time_syntax(in, 1, parts, NULL);
5730 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5733 generalizedTimeValidate(
5738 struct berval fraction;
5739 return check_time_syntax(in, 0, parts, &fraction);
5743 generalizedTimeNormalize(
5748 struct berval *normalized,
5753 struct berval fraction;
5755 rc = check_time_syntax(val, 0, parts, &fraction);
5756 if (rc != LDAP_SUCCESS) {
5760 len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5761 normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5762 if ( BER_BVISNULL( normalized ) ) {
5763 return LBER_ERROR_MEMORY;
5766 sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5767 parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5768 parts[4], parts[5], parts[6] );
5769 if ( !BER_BVISEMPTY( &fraction ) ) {
5770 memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5771 fraction.bv_val, fraction.bv_len );
5772 normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5774 strcpy( normalized->bv_val + len-1, "Z" );
5775 normalized->bv_len = len;
5777 return LDAP_SUCCESS;
5781 generalizedTimeOrderingMatch(
5786 struct berval *value,
5787 void *assertedValue )
5789 struct berval *asserted = (struct berval *) assertedValue;
5790 ber_len_t v_len = value->bv_len;
5791 ber_len_t av_len = asserted->bv_len;
5793 /* ignore trailing 'Z' when comparing */
5794 int match = memcmp( value->bv_val, asserted->bv_val,
5795 (v_len < av_len ? v_len : av_len) - 1 );
5796 if ( match == 0 ) match = v_len - av_len;
5798 /* If used in extensible match filter, match if value < asserted */
5799 if ( flags & SLAP_MR_EXT )
5800 match = (match >= 0);
5803 return LDAP_SUCCESS;
5806 /* Index generation function: Ordered index */
5807 int generalizedTimeIndexer(
5812 struct berval *prefix,
5820 BerValue bvtmp; /* 40 bit index */
5822 struct lutil_timet tt;
5824 bvtmp.bv_len = sizeof(tmp);
5826 for( i=0; values[i].bv_val != NULL; i++ ) {
5827 /* just count them */
5830 /* we should have at least one value at this point */
5833 keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5835 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5836 for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5837 assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5838 /* Use 40 bits of time for key */
5839 if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5840 lutil_tm2time( &tm, &tt );
5841 tmp[0] = tt.tt_gsec & 0xff;
5842 tmp[4] = tt.tt_sec & 0xff;
5844 tmp[3] = tt.tt_sec & 0xff;
5846 tmp[2] = tt.tt_sec & 0xff;
5848 tmp[1] = tt.tt_sec & 0xff;
5850 ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5854 keys[j].bv_val = NULL;
5859 return LDAP_SUCCESS;
5862 /* Index generation function: Ordered index */
5863 int generalizedTimeFilter(
5868 struct berval *prefix,
5869 void * assertedValue,
5875 BerValue bvtmp; /* 40 bit index */
5876 BerValue *value = (BerValue *) assertedValue;
5878 struct lutil_timet tt;
5880 bvtmp.bv_len = sizeof(tmp);
5882 /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5883 /* Use 40 bits of time for key */
5884 if ( value->bv_val && value->bv_len >= 10 &&
5885 lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5887 lutil_tm2time( &tm, &tt );
5888 tmp[0] = tt.tt_gsec & 0xff;
5889 tmp[4] = tt.tt_sec & 0xff;
5891 tmp[3] = tt.tt_sec & 0xff;
5893 tmp[2] = tt.tt_sec & 0xff;
5895 tmp[1] = tt.tt_sec & 0xff;
5897 keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5898 ber_dupbv_x(keys, &bvtmp, ctx );
5899 keys[1].bv_val = NULL;
5907 return LDAP_SUCCESS;
5911 deliveryMethodValidate(
5913 struct berval *val )
5916 #define LENOF(s) (sizeof(s)-1)
5917 struct berval tmp = *val;
5919 * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5920 * pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5921 * "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5924 if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5926 switch( tmp.bv_val[0] ) {
5929 if(( tmp.bv_len >= LENOF("any") ) &&
5930 ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5932 tmp.bv_len -= LENOF("any");
5933 tmp.bv_val += LENOF("any");
5936 return LDAP_INVALID_SYNTAX;
5940 if(( tmp.bv_len >= LENOF("mhs") ) &&
5941 ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5943 tmp.bv_len -= LENOF("mhs");
5944 tmp.bv_val += LENOF("mhs");
5947 return LDAP_INVALID_SYNTAX;
5951 if(( tmp.bv_len >= LENOF("physical") ) &&
5952 ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5954 tmp.bv_len -= LENOF("physical");
5955 tmp.bv_val += LENOF("physical");
5958 return LDAP_INVALID_SYNTAX;
5961 case 'T': /* telex or teletex or telephone */
5962 if(( tmp.bv_len >= LENOF("telex") ) &&
5963 ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5965 tmp.bv_len -= LENOF("telex");
5966 tmp.bv_val += LENOF("telex");
5969 if(( tmp.bv_len >= LENOF("teletex") ) &&
5970 ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5972 tmp.bv_len -= LENOF("teletex");
5973 tmp.bv_val += LENOF("teletex");
5976 if(( tmp.bv_len >= LENOF("telephone") ) &&
5977 ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5979 tmp.bv_len -= LENOF("telephone");
5980 tmp.bv_val += LENOF("telephone");
5983 return LDAP_INVALID_SYNTAX;
5986 case 'G': /* g3fax or g4fax */
5987 if(( tmp.bv_len >= LENOF("g3fax") ) && (
5988 ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
5989 ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
5991 tmp.bv_len -= LENOF("g3fax");
5992 tmp.bv_val += LENOF("g3fax");
5995 return LDAP_INVALID_SYNTAX;
5999 if(( tmp.bv_len >= LENOF("ia5") ) &&
6000 ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
6002 tmp.bv_len -= LENOF("ia5");
6003 tmp.bv_val += LENOF("ia5");
6006 return LDAP_INVALID_SYNTAX;
6010 if(( tmp.bv_len >= LENOF("videotex") ) &&
6011 ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
6013 tmp.bv_len -= LENOF("videotex");
6014 tmp.bv_val += LENOF("videotex");
6017 return LDAP_INVALID_SYNTAX;
6020 return LDAP_INVALID_SYNTAX;
6023 if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
6025 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
6029 if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
6033 return LDAP_INVALID_SYNTAX;
6035 while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
6044 nisNetgroupTripleValidate(
6046 struct berval *val )
6051 if ( BER_BVISEMPTY( val ) ) {
6052 return LDAP_INVALID_SYNTAX;
6055 p = (char *)val->bv_val;
6056 e = p + val->bv_len;
6058 if ( *p != '(' /*')'*/ ) {
6059 return LDAP_INVALID_SYNTAX;
6062 for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
6066 return LDAP_INVALID_SYNTAX;
6069 } else if ( !AD_CHAR( *p ) ) {
6070 return LDAP_INVALID_SYNTAX;
6074 if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
6075 return LDAP_INVALID_SYNTAX;
6081 return LDAP_INVALID_SYNTAX;
6084 return LDAP_SUCCESS;
6088 bootParameterValidate(
6090 struct berval *val )
6094 if ( BER_BVISEMPTY( val ) ) {
6095 return LDAP_INVALID_SYNTAX;
6098 p = (char *)val->bv_val;
6099 e = p + val->bv_len;
6102 for (; ( p < e ) && ( *p != '=' ); p++ ) {
6103 if ( !AD_CHAR( *p ) ) {
6104 return LDAP_INVALID_SYNTAX;
6109 return LDAP_INVALID_SYNTAX;
6113 for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6114 if ( !AD_CHAR( *p ) ) {
6115 return LDAP_INVALID_SYNTAX;
6120 return LDAP_INVALID_SYNTAX;
6124 for ( p++; p < e; p++ ) {
6125 if ( !SLAP_PRINTABLE( *p ) ) {
6126 return LDAP_INVALID_SYNTAX;
6130 return LDAP_SUCCESS;
6134 firstComponentNormalize(
6139 struct berval *normalized,
6146 if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6147 ber_dupbv_x( normalized, val, ctx );
6148 return LDAP_SUCCESS;
6151 if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6153 if( ! ( val->bv_val[0] == '(' /*')'*/
6154 && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6155 && ! ( val->bv_val[0] == '{' /*'}'*/
6156 && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6158 return LDAP_INVALID_SYNTAX;
6161 /* trim leading white space */
6163 len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6169 /* grab next word */
6170 comp.bv_val = &val->bv_val[len];
6171 len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6172 for( comp.bv_len = 0;
6173 !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6179 if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6180 rc = numericoidValidate( NULL, &comp );
6181 } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6182 rc = integerValidate( NULL, &comp );
6184 rc = LDAP_INVALID_SYNTAX;
6188 if( rc == LDAP_SUCCESS ) {
6189 ber_dupbv_x( normalized, &comp, ctx );
6195 static char *country_gen_syn[] = {
6196 "1.3.6.1.4.1.1466.115.121.1.15", /* Directory String */
6197 "1.3.6.1.4.1.1466.115.121.1.26", /* IA5 String */
6198 "1.3.6.1.4.1.1466.115.121.1.44", /* Printable String */
6202 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6203 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6205 static slap_syntax_defs_rec syntax_defs[] = {
6206 {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6207 X_BINARY X_NOT_H_R ")",
6208 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6209 {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6210 0, NULL, NULL, NULL},
6211 {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6212 0, NULL, NULL, NULL},
6213 {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6215 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6216 {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6218 SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6219 {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6220 0, NULL, bitStringValidate, NULL },
6221 {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6222 0, NULL, booleanValidate, NULL},
6223 {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6224 X_BINARY X_NOT_H_R ")",
6225 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6226 NULL, certificateValidate, NULL},
6227 {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6228 X_BINARY X_NOT_H_R ")",
6229 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6230 NULL, certificateListValidate, NULL},
6231 {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6232 X_BINARY X_NOT_H_R ")",
6233 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6234 NULL, sequenceValidate, NULL},
6235 {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6236 X_BINARY X_NOT_H_R ")",
6237 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6238 NULL, attributeCertificateValidate, NULL},
6239 #if 0 /* need to go __after__ printableString */
6240 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6241 0, "1.3.6.1.4.1.1466.115.121.1.44",
6242 countryStringValidate, NULL},
6244 {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6245 SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6246 {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6247 0, NULL, rdnValidate, rdnPretty},
6248 #ifdef LDAP_COMP_MATCH
6249 {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6250 0, NULL, allComponentsValidate, NULL},
6251 {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6252 0, NULL, componentFilterValidate, NULL},
6254 {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6255 0, NULL, NULL, NULL},
6256 {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6257 0, NULL, deliveryMethodValidate, NULL},
6258 {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6259 0, NULL, UTF8StringValidate, NULL},
6260 {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6261 0, NULL, NULL, NULL},
6262 {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6263 0, NULL, NULL, NULL},
6264 {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6265 0, NULL, NULL, NULL},
6266 {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6267 0, NULL, NULL, NULL},
6268 {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6269 0, NULL, NULL, NULL},
6270 {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6271 0, NULL, printablesStringValidate, NULL},
6272 {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6273 SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6274 {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6275 0, NULL, generalizedTimeValidate, NULL},
6276 {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6277 0, NULL, NULL, NULL},
6278 {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6279 0, NULL, IA5StringValidate, NULL},
6280 {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6281 0, NULL, integerValidate, NULL},
6282 {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6283 SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6284 {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6285 0, NULL, NULL, NULL},
6286 {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6287 0, NULL, NULL, NULL},
6288 {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6289 0, NULL, NULL, NULL},
6290 {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6291 0, NULL, NULL, NULL},
6292 {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6293 0, NULL, NULL, NULL},
6294 {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6295 SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6296 {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6297 0, NULL, NULL, NULL},
6298 {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6299 0, NULL, numericStringValidate, NULL},
6300 {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6301 0, NULL, NULL, NULL},
6302 {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6303 0, NULL, numericoidValidate, NULL},
6304 {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6305 0, NULL, IA5StringValidate, NULL},
6306 {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6307 0, NULL, blobValidate, NULL},
6308 {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6309 0, NULL, postalAddressValidate, NULL},
6310 {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6311 0, NULL, NULL, NULL},
6312 {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6313 0, NULL, NULL, NULL},
6314 {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6315 0, NULL, printableStringValidate, NULL},
6316 /* moved here because now depends on Directory String, IA5 String
6317 * and Printable String */
6318 {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6319 0, country_gen_syn, countryStringValidate, NULL},
6320 {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6321 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6322 0, NULL, subtreeSpecificationValidate, NULL},
6323 {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6324 X_BINARY X_NOT_H_R ")",
6325 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6326 {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6327 0, NULL, printableStringValidate, NULL},
6328 {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6329 0, NULL, NULL, NULL},
6330 {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6331 0, NULL, printablesStringValidate, NULL},
6332 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6333 {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6334 0, NULL, utcTimeValidate, NULL},
6336 {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6337 0, NULL, NULL, NULL},
6338 {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6339 0, NULL, NULL, NULL},
6340 {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6341 0, NULL, NULL, NULL},
6342 {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6343 0, NULL, NULL, NULL},
6344 {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6345 0, NULL, NULL, NULL},
6347 /* RFC 2307 NIS Syntaxes */
6348 {"( 1.3.6.1.1.1.0.0 DESC 'RFC2307 NIS Netgroup Triple' )",
6349 0, NULL, nisNetgroupTripleValidate, NULL},
6350 {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )",
6351 0, NULL, bootParameterValidate, NULL},
6353 /* draft-zeilenga-ldap-x509 */
6354 {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6355 SLAP_SYNTAX_HIDE, NULL,
6356 serialNumberAndIssuerValidate,
6357 serialNumberAndIssuerPretty},
6358 {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6359 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6360 {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6361 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6362 {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6363 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6364 {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6365 SLAP_SYNTAX_HIDE, NULL,
6366 issuerAndThisUpdateValidate,
6367 issuerAndThisUpdatePretty},
6368 {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6369 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6370 {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6371 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6372 {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6373 SLAP_SYNTAX_HIDE, NULL,
6374 serialNumberAndIssuerSerialValidate,
6375 serialNumberAndIssuerSerialPretty},
6376 {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6377 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6379 #ifdef SLAPD_AUTHPASSWD
6380 /* needs updating */
6381 {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6382 SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6385 {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6386 0, NULL, UUIDValidate, UUIDPretty},
6388 {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6389 SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6391 {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6392 SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6394 /* OpenLDAP Void Syntax */
6395 {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6396 SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6398 /* FIXME: OID is unused, but not registered yet */
6399 {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6400 SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6402 /* PKCS#8 Private Keys for X.509 certificates */
6403 {"( 1.3.6.1.4.1.4203.666.2.13 DESC 'OpenLDAP privateKey' )",
6404 SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, privateKeyValidate, NULL},
6405 {NULL, 0, NULL, NULL, NULL}
6408 char *csnSIDMatchSyntaxes[] = {
6409 "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6412 char *certificateExactMatchSyntaxes[] = {
6413 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6416 char *certificateListExactMatchSyntaxes[] = {
6417 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6420 char *attributeCertificateExactMatchSyntaxes[] = {
6421 attributeCertificateSyntaxOID /* attributeCertificate */,
6425 #ifdef LDAP_COMP_MATCH
6426 char *componentFilterMatchSyntaxes[] = {
6427 "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6428 "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6429 attributeCertificateSyntaxOID /* attributeCertificate */,
6434 char *directoryStringSyntaxes[] = {
6435 "1.3.6.1.4.1.1466.115.121.1.11" /* countryString */,
6436 "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6437 "1.3.6.1.4.1.1466.115.121.1.50" /* telephoneNumber */,
6440 char *integerFirstComponentMatchSyntaxes[] = {
6441 "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6442 "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6445 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6446 "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6447 "1.3.6.1.4.1.1466.115.121.1.3" /* attributeTypeDescription */,
6448 "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6449 "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6450 "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6451 "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6452 "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6453 "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6458 * Other matching rules in X.520 that we do not use (yet):
6460 * 2.5.13.25 uTCTimeMatch
6461 * 2.5.13.26 uTCTimeOrderingMatch
6462 * 2.5.13.31* directoryStringFirstComponentMatch
6463 * 2.5.13.32* wordMatch
6464 * 2.5.13.33* keywordMatch
6465 * 2.5.13.36+ certificatePairExactMatch
6466 * 2.5.13.37+ certificatePairMatch
6467 * 2.5.13.40+ algorithmIdentifierMatch
6468 * 2.5.13.41* storedPrefixMatch
6469 * 2.5.13.42 attributeCertificateMatch
6470 * 2.5.13.43 readerAndKeyIDMatch
6471 * 2.5.13.44 attributeIntegrityMatch
6473 * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6474 * (+) described in draft-zeilenga-ldap-x509
6476 static slap_mrule_defs_rec mrule_defs[] = {
6478 * EQUALITY matching rules must be listed after associated APPROX
6479 * matching rules. So, we list all APPROX matching rules first.
6481 {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6482 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6483 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6484 NULL, NULL, directoryStringApproxMatch,
6485 directoryStringApproxIndexer, directoryStringApproxFilter,
6488 {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6489 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6490 SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6491 NULL, NULL, IA5StringApproxMatch,
6492 IA5StringApproxIndexer, IA5StringApproxFilter,
6496 * Other matching rules
6499 {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6500 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6501 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6502 NULL, NULL, octetStringMatch,
6503 octetStringIndexer, octetStringFilter,
6506 {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6507 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6508 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6509 NULL, dnNormalize, dnMatch,
6510 octetStringIndexer, octetStringFilter,
6513 {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6514 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6515 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6516 NULL, dnNormalize, dnRelativeMatch,
6520 {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6521 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6522 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6523 NULL, dnNormalize, dnRelativeMatch,
6527 {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6528 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6529 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6530 NULL, dnNormalize, dnRelativeMatch,
6534 {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6535 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6536 SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6537 NULL, dnNormalize, dnRelativeMatch,
6541 {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6542 "SYNTAX 1.2.36.79672281.1.5.0 )",
6543 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6544 NULL, rdnNormalize, rdnMatch,
6545 octetStringIndexer, octetStringFilter,
6548 #ifdef LDAP_COMP_MATCH
6549 {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6550 "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6551 SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6552 NULL, NULL , componentFilterMatch,
6553 octetStringIndexer, octetStringFilter,
6556 {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6557 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6558 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6559 NULL, NULL , allComponentsMatch,
6560 octetStringIndexer, octetStringFilter,
6563 {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6564 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6565 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6566 NULL, NULL , directoryComponentsMatch,
6567 octetStringIndexer, octetStringFilter,
6571 {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6572 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6573 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6574 NULL, UTF8StringNormalize, octetStringMatch,
6575 octetStringIndexer, octetStringFilter,
6576 directoryStringApproxMatchOID },
6578 {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6579 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6580 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6581 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6583 "caseIgnoreMatch" },
6585 {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6586 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6587 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6588 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6589 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6590 "caseIgnoreMatch" },
6592 {"( 2.5.13.5 NAME 'caseExactMatch' "
6593 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6594 SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6595 NULL, UTF8StringNormalize, octetStringMatch,
6596 octetStringIndexer, octetStringFilter,
6597 directoryStringApproxMatchOID },
6599 {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6600 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6601 SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6602 NULL, UTF8StringNormalize, octetStringOrderingMatch,
6606 {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6607 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6608 SLAP_MR_SUBSTR, directoryStringSyntaxes,
6609 NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6610 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6613 {"( 2.5.13.8 NAME 'numericStringMatch' "
6614 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6615 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6616 NULL, numericStringNormalize, octetStringMatch,
6617 octetStringIndexer, octetStringFilter,
6620 {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6621 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6622 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6623 NULL, numericStringNormalize, octetStringOrderingMatch,
6625 "numericStringMatch" },
6627 {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6628 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6629 SLAP_MR_SUBSTR, NULL,
6630 NULL, numericStringNormalize, octetStringSubstringsMatch,
6631 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6632 "numericStringMatch" },
6634 {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6635 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6636 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6637 NULL, postalAddressNormalize, octetStringMatch,
6638 octetStringIndexer, octetStringFilter,
6641 {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6642 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6643 SLAP_MR_SUBSTR, NULL,
6644 NULL, NULL, NULL, NULL, NULL,
6645 "caseIgnoreListMatch" },
6647 {"( 2.5.13.13 NAME 'booleanMatch' "
6648 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6649 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6650 NULL, NULL, booleanMatch,
6651 octetStringIndexer, octetStringFilter,
6654 {"( 2.5.13.14 NAME 'integerMatch' "
6655 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6656 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6657 NULL, NULL, integerMatch,
6658 integerIndexer, integerFilter,
6661 {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6662 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6663 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6664 NULL, NULL, integerMatch,
6668 {"( 2.5.13.16 NAME 'bitStringMatch' "
6669 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6670 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6671 NULL, NULL, octetStringMatch,
6672 octetStringIndexer, octetStringFilter,
6675 {"( 2.5.13.17 NAME 'octetStringMatch' "
6676 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6677 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6678 NULL, NULL, octetStringMatch,
6679 octetStringIndexer, octetStringFilter,
6682 {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6683 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6684 SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6685 NULL, NULL, octetStringOrderingMatch,
6687 "octetStringMatch" },
6689 {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6690 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6691 SLAP_MR_SUBSTR, NULL,
6692 NULL, NULL, octetStringSubstringsMatch,
6693 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6694 "octetStringMatch" },
6696 {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6697 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6698 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6700 telephoneNumberNormalize, octetStringMatch,
6701 octetStringIndexer, octetStringFilter,
6704 {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6705 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6706 SLAP_MR_SUBSTR, NULL,
6707 NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6708 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6709 "telephoneNumberMatch" },
6711 {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6712 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6713 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6714 NULL, NULL, NULL, NULL, NULL, NULL },
6716 {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6717 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6718 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6719 NULL, uniqueMemberNormalize, uniqueMemberMatch,
6720 uniqueMemberIndexer, uniqueMemberFilter,
6723 {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6724 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6725 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6726 NULL, NULL, NULL, NULL, NULL, NULL },
6728 {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6729 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6730 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6731 NULL, generalizedTimeNormalize, octetStringMatch,
6732 generalizedTimeIndexer, generalizedTimeFilter,
6735 {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6736 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6737 SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6738 NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6740 "generalizedTimeMatch" },
6742 {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6743 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6744 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6745 integerFirstComponentMatchSyntaxes,
6746 NULL, firstComponentNormalize, integerMatch,
6747 octetStringIndexer, octetStringFilter,
6750 {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6751 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6752 SLAP_MR_EQUALITY | SLAP_MR_EXT,
6753 objectIdentifierFirstComponentMatchSyntaxes,
6754 NULL, firstComponentNormalize, octetStringMatch,
6755 octetStringIndexer, octetStringFilter,
6758 {"( 2.5.13.34 NAME 'certificateExactMatch' "
6759 "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6760 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6761 NULL, certificateExactNormalize, octetStringMatch,
6762 octetStringIndexer, octetStringFilter,
6765 {"( 2.5.13.35 NAME 'certificateMatch' "
6766 "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6767 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6768 NULL, NULL, NULL, NULL, NULL,
6771 {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6772 "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6773 SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6774 NULL, certificateListExactNormalize, octetStringMatch,
6775 octetStringIndexer, octetStringFilter,
6778 {"( 2.5.13.39 NAME 'certificateListMatch' "
6779 "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6780 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6781 NULL, NULL, NULL, NULL, NULL,
6784 {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6785 "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6786 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6787 NULL, attributeCertificateExactNormalize, octetStringMatch,
6788 octetStringIndexer, octetStringFilter,
6791 {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6792 "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6793 SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6794 NULL, NULL, NULL, NULL, NULL,
6797 {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6798 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6799 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6800 NULL, IA5StringNormalize, octetStringMatch,
6801 octetStringIndexer, octetStringFilter,
6802 IA5StringApproxMatchOID },
6804 {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6805 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6806 SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6807 NULL, IA5StringNormalize, octetStringMatch,
6808 octetStringIndexer, octetStringFilter,
6809 IA5StringApproxMatchOID },
6811 {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6812 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6813 SLAP_MR_SUBSTR, NULL,
6814 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6815 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6816 "caseIgnoreIA5Match" },
6818 {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6819 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6820 SLAP_MR_SUBSTR, NULL,
6821 NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6822 octetStringSubstringsIndexer, octetStringSubstringsFilter,
6823 "caseExactIA5Match" },
6825 #ifdef SLAPD_AUTHPASSWD
6826 /* needs updating */
6827 {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6828 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6829 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6830 NULL, NULL, authPasswordMatch,
6835 {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6836 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6838 NULL, NULL, integerBitAndMatch,
6842 {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6843 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6845 NULL, NULL, integerBitOrMatch,
6849 {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6850 "SYNTAX 1.3.6.1.1.16.1 )",
6851 SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6852 NULL, UUIDNormalize, octetStringMatch,
6853 octetStringIndexer, octetStringFilter,
6856 {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6857 "SYNTAX 1.3.6.1.1.16.1 )",
6858 SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6859 NULL, UUIDNormalize, octetStringOrderingMatch,
6860 octetStringIndexer, octetStringFilter,
6863 {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6864 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6865 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6866 NULL, csnNormalize, csnMatch,
6867 csnIndexer, csnFilter,
6870 {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6871 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6872 SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6873 NULL, csnNormalize, csnOrderingMatch,
6877 {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6878 "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6879 SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6880 NULL, csnSidNormalize, octetStringMatch,
6881 octetStringIndexer, octetStringFilter,
6884 /* FIXME: OID is unused, but not registered yet */
6885 {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6886 "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6887 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6888 NULL, authzNormalize, authzMatch,
6892 {"( 1.3.6.1.4.1.4203.666.4.13 NAME 'privateKeyMatch' "
6893 "SYNTAX 1.3.6.1.4.1.4203.666.2.13 )", /* OpenLDAP privateKey */
6894 SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6895 NULL, NULL, octetStringMatch,
6899 {NULL, SLAP_MR_NONE, NULL,
6900 NULL, NULL, NULL, NULL, NULL,
6905 slap_schema_init( void )
6910 /* we should only be called once (from main) */
6911 assert( schema_init_done == 0 );
6913 for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6914 res = register_syntax( &syntax_defs[i] );
6917 fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6918 syntax_defs[i].sd_desc );
6923 for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6924 if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6925 mrule_defs[i].mrd_compat_syntaxes == NULL )
6928 "slap_schema_init: Ignoring unusable matching rule %s\n",
6929 mrule_defs[i].mrd_desc );
6933 res = register_matching_rule( &mrule_defs[i] );
6937 "slap_schema_init: Error registering matching rule %s\n",
6938 mrule_defs[i].mrd_desc );
6943 res = slap_schema_load();
6944 schema_init_done = 1;
6949 schema_destroy( void )
6958 if( schema_init_done ) {
6959 ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6960 ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6961 ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );