1 /*        $NetBSD: schema_init.c,v 1.3 2021/08/14 16:14:58 christos Exp $       */
2 
3 /* schema_init.c - init builtin schema */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2021 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 
19 /*
20  * Syntaxes - implementation notes:
21  *
22  * Validate function(syntax, value):
23  *   Called before the other functions here to check if the value
24  *   is valid according to the syntax.
25  *
26  * Pretty function(syntax, input value, output prettified...):
27  *   If it exists, maps different notations of the same value to a
28  *   unique representation which can be stored in the directory and
29  *   possibly be passed to the Match/Indexer/Filter() functions.
30  *
31  *   E.g. DN "2.5.4.3 = foo\,bar, o = BAZ" -> "cn=foo\2Cbar,o=BAZ",
32  *   but unlike DN normalization, "BAZ" is not mapped to "baz".
33  */
34 
35 /*
36  * Matching rules - implementation notes:
37  *
38  * Matching rules match an attribute value (often from the directory)
39  * against an asserted value (e.g. from a filter).
40  *
41  * Invoked with validated and commonly pretty/normalized arguments, thus
42  * a number of matching rules can simply use the octetString functions.
43  *
44  * Normalize function(...input value, output normalized...):
45  *   If it exists, maps matching values to a unique representation
46  *   which is passed to the Match/Indexer/Filter() functions.
47  *
48  *   Different matching rules can normalize values of the same syntax
49  *   differently.  E.g. caseIgnore rules normalize to lowercase,
50  *   caseExact rules do not.
51  *
52  * Match function(*output matchp, ...value, asserted value):
53  *   On success, set *matchp.  0 means match.  For ORDERING/most EQUALITY,
54  *   less/greater than 0 means value less/greater than asserted.  However:
55  *
56  *   In extensible match filters, ORDERING rules match if value<asserted.
57  *
58  *   EQUALITY rules may order values differently than ORDERING rules for
59  *   speed, since EQUALITY ordering is only used for SLAP_AT_SORTED_VAL.
60  *   Some EQUALITY rules do not order values (ITS#6722).
61  *
62  * Indexer function(...attribute values, *output keysp,...):
63  *   Generates index keys for the attribute values.  Backends can store
64  *   them in an index, a {key->entry ID set} mapping, for the attribute.
65  *
66  *   A search can look up the DN/scope and asserted values in the
67  *   indexes, if any, to narrow down the number of entries to check
68  *   against the search criteria.
69  *
70  * Filter function(...asserted value, *output keysp,...):
71  *   Generates index key(s) for the asserted value, to be looked up in
72  *   the index from the Indexer function.  *keysp is an array because
73  *   substring matching rules can generate multiple lookup keys.
74  *
75  * Index keys:
76  *   A key is usually a hash of match type, attribute value and schema
77  *   info, because one index can contain keys for many filtering types.
78  *
79  *   Some indexes instead have EQUALITY keys ordered so that if
80  *   key(val1) < key(val2), then val1 < val2 by the ORDERING rule.
81  *   That way the ORDERING rule can use the EQUALITY index.
82  *
83  * Substring indexing:
84  *   This chops the attribute values up in small chunks and indexes all
85  *   possible chunks of certain sizes.  Substring filtering looks up
86  *   SOME of the asserted value's chunks, and the caller uses the
87  *   intersection of the resulting entry ID sets.
88  *   See the index_substr_* keywords in slapd.conf(5).
89  */
90 
91 #include <sys/cdefs.h>
92 __RCSID("$NetBSD: schema_init.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
93 
94 #include "portable.h"
95 
96 #include <stdio.h>
97 #ifdef HAVE_LIMITS_H
98 #include <limits.h>
99 #endif
100 
101 #include <ac/ctype.h>
102 #include <ac/errno.h>
103 #include <ac/string.h>
104 #include <ac/socket.h>
105 
106 #include "slap.h"
107 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
108 
109 #include "ldap_utf8.h"
110 
111 #include "lutil.h"
112 #include "lutil_hash.h"
113 
114 #ifdef LUTIL_HASH64_BYTES
115 #define HASH_BYTES                                LUTIL_HASH64_BYTES
116 #define HASH_LEN    hashlen
117 static void (*hashinit)(lutil_HASH_CTX *ctx) = lutil_HASHInit;
118 static void (*hashupdate)(lutil_HASH_CTX *ctx,unsigned char const *buf, ber_len_t len) = lutil_HASHUpdate;
119 static void (*hashfinal)(unsigned char digest[HASH_BYTES], lutil_HASH_CTX *ctx) = lutil_HASHFinal;
120 static int hashlen = LUTIL_HASH_BYTES;
121 #define HASH_Init(c)                              hashinit(c)
122 #define HASH_Update(c,buf,len)          hashupdate(c,buf,len)
123 #define HASH_Final(d,c)                           hashfinal(d,c)
124 
125 /* Toggle between 32 and 64 bit hashing, default to 32 for compatibility
126    -1 to query, returns 1 if 64 bit, 0 if 32.
127    0/1 to set 32/64, returns 0 on success, -1 on failure */
slap_hash64(int onoff)128 int slap_hash64( int onoff )
129 {
130           if ( onoff < 0 ) {
131                     return hashlen == LUTIL_HASH64_BYTES;
132           } else if ( onoff ) {
133                     hashinit = lutil_HASH64Init;
134                     hashupdate = lutil_HASH64Update;
135                     hashfinal = lutil_HASH64Final;
136                     hashlen = LUTIL_HASH64_BYTES;
137           } else {
138                     hashinit = lutil_HASHInit;
139                     hashupdate = lutil_HASHUpdate;
140                     hashfinal = lutil_HASHFinal;
141                     hashlen = LUTIL_HASH_BYTES;
142           }
143           return 0;
144 }
145 
146 #else
147 #define HASH_BYTES                                LUTIL_HASH_BYTES
148 #define HASH_LEN                                  HASH_BYTES
149 #define HASH_Init(c)                              lutil_HASHInit(c)
150 #define HASH_Update(c,buf,len)          lutil_HASHUpdate(c,buf,len)
151 #define HASH_Final(d,c)                           lutil_HASHFinal(d,c)
152 
slap_has64(int onoff)153 int slap_has64( int onoff )
154 {
155           if ( onoff < 0 )
156                     return 0;
157           else
158                     return onoff ? -1 : 0;
159 }
160 
161 #endif
162 #define HASH_CONTEXT                              lutil_HASH_CTX
163 
164 /* approx matching rules */
165 #define directoryStringApproxMatchOID   "1.3.6.1.4.1.4203.666.4.4"
166 #define directoryStringApproxMatch                approxMatch
167 #define directoryStringApproxIndexer    approxIndexer
168 #define directoryStringApproxFilter               approxFilter
169 #define IA5StringApproxMatchOID                             "1.3.6.1.4.1.4203.666.4.5"
170 #define IA5StringApproxMatch                      approxMatch
171 #define IA5StringApproxIndexer                              approxIndexer
172 #define IA5StringApproxFilter                     approxFilter
173 
174 /* Change Sequence Number (CSN) - much of this will change */
175 #define csnMatch                                  octetStringMatch
176 #define csnOrderingMatch                octetStringOrderingMatch
177 #define csnIndexer                                generalizedTimeIndexer
178 #define csnFilter                                 generalizedTimeFilter
179 
180 #define authzMatch                                octetStringMatch
181 
182 /* X.509 PMI ldapSyntaxes */
183 /* FIXME: need to create temporary OIDs under OpenLDAP's arc;
184  * these are currently hijacked
185  *
186  *        1.3.6.1.4.1.4203.666                    OpenLDAP
187  *        1.3.6.1.4.1.4203.666.11                 self-contained works
188  *        1.3.6.1.4.1.4203.666.11.10    X.509 PMI
189  *        1.3.6.1.4.1.4203.666.11.10.2  X.509 PMI ldapSyntaxes
190  *        1.3.6.1.4.1.4203.666.11.10.2.1          AttributeCertificate (supported)
191  *        1.3.6.1.4.1.4203.666.11.10.2.2          AttributeCertificateExactAssertion (supported)
192  *        1.3.6.1.4.1.4203.666.11.10.2.3          AttributeCertificateAssertion (not supported)
193  *        1.3.6.1.4.1.4203.666.11.10.2.4          AttCertPath (X-SUBST'ed right now in pmi.schema)
194  *        1.3.6.1.4.1.4203.666.11.10.2.5          PolicySyntax (X-SUBST'ed right now in pmi.schema)
195  *        1.3.6.1.4.1.4203.666.11.10.2.6          RoleSyntax (X-SUBST'ed right now in pmi.schema)
196  */
197 #if 0 /* from <draft-ietf-pkix-ldap-schema-02.txt> (expired) */
198 #define attributeCertificateSyntaxOID                       "1.2.826.0.1.3344810.7.5"
199 #define attributeCertificateExactAssertionSyntaxOID         "1.2.826.0.1.3344810.7.6"
200 #define attributeCertificateAssertionSyntaxOID              "1.2.826.0.1.3344810.7.7"
201 #else /* from OpenLDAP's experimental oid arc */
202 #define X509_PMI_SyntaxOID                                  "1.3.6.1.4.1.4203.666.11.10.2"
203 #define attributeCertificateSyntaxOID                       X509_PMI_SyntaxOID ".1"
204 #define attributeCertificateExactAssertionSyntaxOID         X509_PMI_SyntaxOID ".2"
205 #define attributeCertificateAssertionSyntaxOID              X509_PMI_SyntaxOID ".3"
206 #endif
207 
208 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
209 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
210 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
211 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
212 
213 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
214 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
215           SLAP_INDEX_INTLEN_DEFAULT );
216 
217 ldap_pvt_thread_mutex_t       ad_index_mutex;
218 ldap_pvt_thread_mutex_t       ad_undef_mutex;
219 ldap_pvt_thread_mutex_t       oc_undef_mutex;
220 
221 static int
222 generalizedTimeValidate(
223           Syntax *syntax,
224           struct berval *in );
225 
226 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
227 static int
228 utcTimeValidate(
229           Syntax *syntax,
230           struct berval *in );
231 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
232 
233 static int
inValidate(Syntax * syntax,struct berval * in)234 inValidate(
235           Syntax *syntax,
236           struct berval *in )
237 {
238           /* no value allowed */
239           return LDAP_INVALID_SYNTAX;
240 }
241 
242 static int
blobValidate(Syntax * syntax,struct berval * in)243 blobValidate(
244           Syntax *syntax,
245           struct berval *in )
246 {
247           /* any value allowed */
248           return LDAP_SUCCESS;
249 }
250 
251 #define berValidate blobValidate
252 
253 static int
sequenceValidate(Syntax * syntax,struct berval * in)254 sequenceValidate(
255           Syntax *syntax,
256           struct berval *in )
257 {
258           if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
259           if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
260 
261           return LDAP_SUCCESS;
262 }
263 
264 /* X.509 related stuff */
265 
266 enum {
267           SLAP_X509_V1                  = 0,
268           SLAP_X509_V2                  = 1,
269           SLAP_X509_V3                  = 2
270 };
271 
272 enum {
273           SLAP_TAG_UTCTIME              = 0x17U,
274           SLAP_TAG_GENERALIZEDTIME      = 0x18U
275 };
276 
277 
278 #define   SLAP_X509_OPTION    (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
279 
280 enum {
281           SLAP_X509_OPT_C_VERSION                 = SLAP_X509_OPTION + 0,
282           SLAP_X509_OPT_C_ISSUERUNIQUEID          = LBER_CLASS_CONTEXT + 1,
283           SLAP_X509_OPT_C_SUBJECTUNIQUEID         = LBER_CLASS_CONTEXT + 2,
284           SLAP_X509_OPT_C_EXTENSIONS    = SLAP_X509_OPTION + 3
285 };
286 
287 enum {
288           SLAP_X509_OPT_CL_CRLEXTENSIONS          = SLAP_X509_OPTION + 0
289 };
290 
291 /*
292 GeneralName ::= CHOICE {
293   otherName                 [0] INSTANCE OF OTHER-NAME,
294   rfc822Name                [1] IA5String,
295   dNSName                   [2] IA5String,
296   x400Address               [3] ORAddress,
297   directoryName             [4] Name,
298   ediPartyName              [5] EDIPartyName,
299   uniformResourceIdentifier [6] IA5String,
300   iPAddress                 [7] OCTET STRING,
301   registeredID              [8] OBJECT IDENTIFIER }
302 */
303 enum {
304           SLAP_X509_GN_OTHERNAME                  = SLAP_X509_OPTION + 0,
305           SLAP_X509_GN_RFC822NAME                 = SLAP_X509_OPTION + 1,
306           SLAP_X509_GN_DNSNAME                    = SLAP_X509_OPTION + 2,
307           SLAP_X509_GN_X400ADDRESS      = SLAP_X509_OPTION + 3,
308           SLAP_X509_GN_DIRECTORYNAME    = SLAP_X509_OPTION + 4,
309           SLAP_X509_GN_EDIPARTYNAME     = SLAP_X509_OPTION + 5,
310           SLAP_X509_GN_URI              = SLAP_X509_OPTION + 6,
311           SLAP_X509_GN_IPADDRESS                  = SLAP_X509_OPTION + 7,
312           SLAP_X509_GN_REGISTEREDID     = SLAP_X509_OPTION + 8
313 };
314 
315 /* X.509 PMI related stuff */
316 enum {
317           SLAP_X509AC_V1                = 0,
318           SLAP_X509AC_V2                = 1
319 };
320 
321 enum {
322           SLAP_X509AC_ISSUER  = SLAP_X509_OPTION + 0
323 };
324 
325 /* X.509 certificate validation */
326 static int
certificateValidate(Syntax * syntax,struct berval * in)327 certificateValidate( Syntax *syntax, struct berval *in )
328 {
329           BerElementBuffer berbuf;
330           BerElement *ber = (BerElement *)&berbuf;
331           ber_tag_t tag;
332           ber_len_t len;
333           ber_int_t version = SLAP_X509_V1;
334 
335           if ( BER_BVISNULL( in ) || BER_BVISEMPTY( in ))
336                     return LDAP_INVALID_SYNTAX;
337 
338           ber_init2( ber, in, LBER_USE_DER );
339           tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
340           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
341           tag = ber_skip_tag( ber, &len );        /* Sequence */
342           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
343           tag = ber_peek_tag( ber, &len );
344           /* Optional version */
345           if ( tag == SLAP_X509_OPT_C_VERSION ) {
346                     tag = ber_skip_tag( ber, &len );
347                     tag = ber_get_int( ber, &version );
348                     if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
349           }
350           /* NOTE: don't try to parse Serial, because it might be longer
351            * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
352           tag = ber_skip_tag( ber, &len );        /* Serial */
353           if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
354           ber_skip_data( ber, len );
355           tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
356           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
357           ber_skip_data( ber, len );
358           tag = ber_skip_tag( ber, &len );        /* Issuer DN */
359           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
360           ber_skip_data( ber, len );
361           tag = ber_skip_tag( ber, &len );        /* Validity */
362           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
363           ber_skip_data( ber, len );
364           tag = ber_skip_tag( ber, &len );        /* Subject DN */
365           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
366           ber_skip_data( ber, len );
367           tag = ber_skip_tag( ber, &len );        /* Subject PublicKeyInfo */
368           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
369           ber_skip_data( ber, len );
370           tag = ber_skip_tag( ber, &len );
371           if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) {    /* issuerUniqueID */
372                     if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
373                     ber_skip_data( ber, len );
374                     tag = ber_skip_tag( ber, &len );
375           }
376           if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) {   /* subjectUniqueID */
377                     if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
378                     ber_skip_data( ber, len );
379                     tag = ber_skip_tag( ber, &len );
380           }
381           if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) {        /* Extensions */
382                     if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
383                     tag = ber_skip_tag( ber, &len );
384                     if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
385                     ber_skip_data( ber, len );
386                     tag = ber_skip_tag( ber, &len );
387           }
388           /* signatureAlgorithm */
389           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
390           ber_skip_data( ber, len );
391           tag = ber_skip_tag( ber, &len );
392           /* Signature */
393           if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
394           ber_skip_data( ber, len );
395           tag = ber_skip_tag( ber, &len );
396           /* Must be at end now */
397           if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
398           return LDAP_SUCCESS;
399 }
400 
401 /* X.509 certificate list validation */
402 static int
403 checkTime( struct berval *in, struct berval *out );
404 
405 static int
certificateListValidate(Syntax * syntax,struct berval * in)406 certificateListValidate( Syntax *syntax, struct berval *in )
407 {
408           BerElementBuffer berbuf;
409           BerElement *ber = (BerElement *)&berbuf;
410           ber_tag_t tag;
411           ber_len_t len, wrapper_len;
412           char *wrapper_start;
413           int wrapper_ok = 0;
414           ber_int_t version = SLAP_X509_V1;
415           struct berval bvdn, bvtu;
416 
417           ber_init2( ber, in, LBER_USE_DER );
418           tag = ber_skip_tag( ber, &wrapper_len );          /* Signed wrapper */
419           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
420           wrapper_start = ber->ber_ptr;
421           tag = ber_skip_tag( ber, &len );        /* Sequence */
422           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
423           tag = ber_peek_tag( ber, &len );
424           /* Optional version */
425           if ( tag == LBER_INTEGER ) {
426                     tag = ber_get_int( ber, &version );
427                     if ( tag != LBER_INTEGER || version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
428           }
429           tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
430           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
431           ber_skip_data( ber, len );
432           tag = ber_peek_tag( ber, &len );        /* Issuer DN */
433           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
434           len = ber_ptrlen( ber );
435           bvdn.bv_val = in->bv_val + len;
436           bvdn.bv_len = in->bv_len - len;
437           tag = ber_skip_tag( ber, &len );
438           ber_skip_data( ber, len );
439           tag = ber_skip_tag( ber, &len );        /* thisUpdate */
440           /* Time is a CHOICE { UTCTime, GeneralizedTime } */
441           if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
442           bvtu.bv_val = (char *)ber->ber_ptr;
443           bvtu.bv_len = len;
444           ber_skip_data( ber, len );
445           /* Optional nextUpdate */
446           tag = ber_skip_tag( ber, &len );
447           if ( tag == SLAP_TAG_UTCTIME || tag == SLAP_TAG_GENERALIZEDTIME ) {
448                     ber_skip_data( ber, len );
449                     tag = ber_skip_tag( ber, &len );
450           }
451           /* revokedCertificates - Sequence of Sequence, Optional */
452           if ( tag == LBER_SEQUENCE ) {
453                     ber_len_t seqlen;
454                     ber_tag_t stag;
455                     stag = ber_peek_tag( ber, &seqlen );
456                     if ( stag == LBER_SEQUENCE || !len ) {
457                               /* RFC5280 requires non-empty, but X.509(2005) allows empty. */
458                               if ( len )
459                                         ber_skip_data( ber, len );
460                               tag = ber_skip_tag( ber, &len );
461                     }
462           }
463           /* Optional Extensions - Sequence of Sequence */
464           if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
465                     ber_len_t seqlen;
466                     if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
467                     tag = ber_peek_tag( ber, &seqlen );
468                     if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
469                     ber_skip_data( ber, len );
470                     tag = ber_skip_tag( ber, &len );
471           }
472           /* signatureAlgorithm */
473           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
474           ber_skip_data( ber, len );
475           tag = ber_skip_tag( ber, &len );
476           /* Signature */
477           if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
478           ber_skip_data( ber, len );
479           if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1;
480           tag = ber_skip_tag( ber, &len );
481           /* Must be at end now */
482           /* NOTE: OpenSSL tolerates CL with garbage past the end */
483           if ( len || tag != LBER_DEFAULT ) {
484                     struct berval issuer_dn = BER_BVNULL, thisUpdate;
485                     char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
486                     int rc;
487 
488                     if ( ! wrapper_ok ) {
489                               return LDAP_INVALID_SYNTAX;
490                     }
491 
492                     rc = dnX509normalize( &bvdn, &issuer_dn );
493                     if ( rc != LDAP_SUCCESS ) {
494                               rc = LDAP_INVALID_SYNTAX;
495                               goto done;
496                     }
497 
498                     thisUpdate.bv_val = tubuf;
499                     thisUpdate.bv_len = sizeof(tubuf);
500                     if ( checkTime( &bvtu, &thisUpdate ) ) {
501                               rc = LDAP_INVALID_SYNTAX;
502                               goto done;
503                     }
504 
505                     Debug( LDAP_DEBUG_ANY,
506                               "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n",
507                               issuer_dn.bv_val, thisUpdate.bv_val );
508 
509 done:;
510                     if ( ! BER_BVISNULL( &issuer_dn ) ) {
511                               ber_memfree( issuer_dn.bv_val );
512                     }
513 
514                     return rc;
515           }
516 
517           return LDAP_SUCCESS;
518 }
519 
520 /* X.509 PMI Attribute Certificate Validate */
521 static int
attributeCertificateValidate(Syntax * syntax,struct berval * in)522 attributeCertificateValidate( Syntax *syntax, struct berval *in )
523 {
524           BerElementBuffer berbuf;
525           BerElement *ber = (BerElement *)&berbuf;
526           ber_tag_t tag;
527           ber_len_t len;
528           ber_int_t version;
529           int cont = 0;
530 
531           ber_init2( ber, in, LBER_USE_DER );
532 
533           tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
534           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
535 
536           tag = ber_skip_tag( ber, &len );        /* Sequence */
537           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
538 
539           tag = ber_peek_tag( ber, &len );        /* Version */
540           if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
541           tag = ber_get_int( ber, &version );     /* X.509 only allows v2 */
542           if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX;
543 
544           tag = ber_skip_tag( ber, &len );        /* Holder */
545           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
546           ber_skip_data( ber, len );
547 
548           tag = ber_skip_tag( ber, &len );        /* Issuer */
549           if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX;
550           ber_skip_data( ber, len );
551 
552           tag = ber_skip_tag( ber, &len );        /* Signature */
553           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
554           ber_skip_data( ber, len );
555 
556           tag = ber_skip_tag( ber, &len );        /* Serial number */
557           if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
558           ber_skip_data( ber, len );
559 
560           tag = ber_skip_tag( ber, &len );        /* AttCertValidityPeriod */
561           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
562           ber_skip_data( ber, len );
563 
564           tag = ber_skip_tag( ber, &len );        /* Attributes */
565           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
566           ber_skip_data( ber, len );
567 
568           tag = ber_peek_tag( ber, &len );
569 
570           if ( tag == LBER_BITSTRING ) {          /* issuerUniqueID */
571                     tag = ber_skip_tag( ber, &len );
572                     ber_skip_data( ber, len );
573                     tag = ber_peek_tag( ber, &len );
574           }
575 
576           if ( tag == LBER_SEQUENCE ) { /* extensions or signatureAlgorithm */
577                     tag = ber_skip_tag( ber, &len );
578                     ber_skip_data( ber, len );
579                     cont++;
580                     tag = ber_peek_tag( ber, &len );
581           }
582 
583           if ( tag == LBER_SEQUENCE ) { /* signatureAlgorithm */
584                     tag = ber_skip_tag( ber, &len );
585                     ber_skip_data( ber, len );
586                     cont++;
587                     tag = ber_peek_tag( ber, &len );
588           }
589 
590           if ( tag == LBER_BITSTRING ) {          /* Signature */
591                     tag = ber_skip_tag( ber, &len );
592                     ber_skip_data( ber, len );
593                     cont++;
594                     tag = ber_peek_tag( ber, &len );
595           }
596 
597           /* Must be at end now */
598           if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX;
599 
600           return LDAP_SUCCESS;
601 }
602 
603 /* accept a PKCS#8 private key */
604 static int
privateKeyValidate(Syntax * syntax,struct berval * val)605 privateKeyValidate(
606           Syntax              *syntax,
607           struct berval       *val )
608 {
609           BerElementBuffer berbuf;
610           BerElement *ber = (BerElement *)&berbuf;
611           ber_tag_t tag;
612           ber_len_t len;
613           ber_int_t version;
614 
615           ber_init2( ber, val, LBER_USE_DER );
616           tag = ber_skip_tag( ber, &len );        /* Sequence */
617           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
618           tag = ber_peek_tag( ber, &len );
619           if ( tag != LBER_INTEGER ) {
620                     /* might be an encrypted key */
621                     if ( tag == LBER_SEQUENCE ) { /* encryptionAlgorithm */
622                               ber_skip_data( ber, len );
623                               tag = ber_skip_tag( ber, &len );        /* encryptedData */
624                               if ( tag != LBER_OCTETSTRING ) return LDAP_INVALID_SYNTAX;
625                               ber_skip_data( ber, len );
626                     } else
627                               return LDAP_INVALID_SYNTAX;
628           } else {
629                     tag = ber_get_int( ber, &version );
630                     tag = ber_skip_tag( ber, &len );        /* AlgorithmIdentifier */
631                     if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
632                     ber_skip_data( ber, len );
633                     tag = ber_skip_tag( ber, &len );        /* PrivateKey */
634                     if ( tag != LBER_OCTETSTRING ) return LDAP_INVALID_SYNTAX;
635                     ber_skip_data( ber, len );
636                     tag = ber_skip_tag( ber, &len );
637                     if ( tag == LBER_SET ) {                          /* Optional Attributes */
638                               ber_skip_data( ber, len );
639                               tag = ber_skip_tag( ber, &len );
640                     }
641           }
642 
643           /* Must be at end now */
644           if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
645           return LDAP_SUCCESS;
646 }
647 
648 int
octetStringMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)649 octetStringMatch(
650           int *matchp,
651           slap_mask_t flags,
652           Syntax *syntax,
653           MatchingRule *mr,
654           struct berval *value,
655           void *assertedValue )
656 {
657           struct berval *asserted = (struct berval *) assertedValue;
658           ber_slen_t d = (ber_slen_t) value->bv_len - (ber_slen_t) asserted->bv_len;
659 
660           /* For speed, order first by length, then by contents */
661           *matchp = d ? (sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1)
662                     : memcmp( value->bv_val, asserted->bv_val, value->bv_len );
663 
664           return LDAP_SUCCESS;
665 }
666 
667 int
octetStringOrderingMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)668 octetStringOrderingMatch(
669           int *matchp,
670           slap_mask_t flags,
671           Syntax *syntax,
672           MatchingRule *mr,
673           struct berval *value,
674           void *assertedValue )
675 {
676           struct berval *asserted = (struct berval *) assertedValue;
677           ber_len_t v_len  = value->bv_len;
678           ber_len_t av_len = asserted->bv_len;
679 
680           int match = memcmp( value->bv_val, asserted->bv_val,
681                     (v_len < av_len ? v_len : av_len) );
682 
683           if( match == 0 )
684                     match = sizeof(v_len) == sizeof(int)
685                               ? (int) v_len - (int) av_len
686                               : v_len < av_len ? -1 : v_len > av_len;
687 
688           /* If used in extensible match filter, match if value < asserted */
689           if ( flags & SLAP_MR_EXT )
690                     match = (match >= 0);
691 
692           *matchp = match;
693           return LDAP_SUCCESS;
694 }
695 
696 /* Initialize HASHcontext from match type and schema info */
697 static void
hashPreset(HASH_CONTEXT * HASHcontext,struct berval * prefix,char pre,Syntax * syntax,MatchingRule * mr)698 hashPreset(
699           HASH_CONTEXT *HASHcontext,
700           struct berval *prefix,
701           char pre,
702           Syntax *syntax,
703           MatchingRule *mr)
704 {
705           HASH_Init(HASHcontext);
706           if(prefix && prefix->bv_len > 0) {
707                     HASH_Update(HASHcontext,
708                               (unsigned char *)prefix->bv_val, prefix->bv_len);
709           }
710           if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
711           HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
712           HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
713           return;
714 }
715 
716 /* Set HASHdigest from HASHcontext and value:len */
717 static void
hashIter(HASH_CONTEXT * HASHcontext,unsigned char * HASHdigest,unsigned char * value,int len)718 hashIter(
719           HASH_CONTEXT *HASHcontext,
720           unsigned char *HASHdigest,
721           unsigned char *value,
722           int len)
723 {
724           HASH_CONTEXT ctx = *HASHcontext;
725           HASH_Update( &ctx, value, len );
726           HASH_Final( HASHdigest, &ctx );
727 }
728 
729 /* Index generation function: Attribute values -> index hash keys */
octetStringIndexer(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,BerVarray values,BerVarray * keysp,void * ctx)730 int octetStringIndexer(
731           slap_mask_t use,
732           slap_mask_t flags,
733           Syntax *syntax,
734           MatchingRule *mr,
735           struct berval *prefix,
736           BerVarray values,
737           BerVarray *keysp,
738           void *ctx )
739 {
740           int i;
741           BerVarray keys;
742           HASH_CONTEXT HASHcontext;
743           unsigned char HASHdigest[HASH_BYTES];
744           struct berval digest;
745           digest.bv_val = (char *)HASHdigest;
746           digest.bv_len = HASH_LEN;
747 
748           for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
749                     /* just count them */
750           }
751 
752           /* we should have at least one value at this point */
753           assert( i > 0 );
754 
755           keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
756 
757           hashPreset( &HASHcontext, prefix, 0, syntax, mr);
758           for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
759                     hashIter( &HASHcontext, HASHdigest,
760                               (unsigned char *)values[i].bv_val, values[i].bv_len );
761                     ber_dupbv_x( &keys[i], &digest, ctx );
762           }
763 
764           BER_BVZERO( &keys[i] );
765 
766           *keysp = keys;
767 
768           return LDAP_SUCCESS;
769 }
770 
771 /* Index generation function: Asserted value -> index hash key */
octetStringFilter(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,void * assertedValue,BerVarray * keysp,void * ctx)772 int octetStringFilter(
773           slap_mask_t use,
774           slap_mask_t flags,
775           Syntax *syntax,
776           MatchingRule *mr,
777           struct berval *prefix,
778           void * assertedValue,
779           BerVarray *keysp,
780           void *ctx )
781 {
782           BerVarray keys;
783           HASH_CONTEXT HASHcontext;
784           unsigned char HASHdigest[HASH_BYTES];
785           struct berval *value = (struct berval *) assertedValue;
786           struct berval digest;
787           digest.bv_val = (char *)HASHdigest;
788           digest.bv_len = HASH_LEN;
789 
790           keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
791 
792           hashPreset( &HASHcontext, prefix, 0, syntax, mr );
793           hashIter( &HASHcontext, HASHdigest,
794                     (unsigned char *)value->bv_val, value->bv_len );
795 
796           ber_dupbv_x( keys, &digest, ctx );
797           BER_BVZERO( &keys[1] );
798 
799           *keysp = keys;
800 
801           return LDAP_SUCCESS;
802 }
803 
804 static int
octetStringSubstringsMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)805 octetStringSubstringsMatch(
806           int *matchp,
807           slap_mask_t flags,
808           Syntax *syntax,
809           MatchingRule *mr,
810           struct berval *value,
811           void *assertedValue )
812 {
813           int match = 0;
814           SubstringsAssertion *sub = assertedValue;
815           struct berval left = *value;
816           int i;
817           ber_len_t inlen = 0;
818 
819           /* Add up asserted input length */
820           if ( !BER_BVISNULL( &sub->sa_initial ) ) {
821                     inlen += sub->sa_initial.bv_len;
822           }
823           if ( sub->sa_any ) {
824                     for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
825                               inlen += sub->sa_any[i].bv_len;
826                     }
827           }
828           if ( !BER_BVISNULL( &sub->sa_final ) ) {
829                     inlen += sub->sa_final.bv_len;
830           }
831 
832           if ( !BER_BVISNULL( &sub->sa_initial ) ) {
833                     if ( inlen > left.bv_len ) {
834                               match = 1;
835                               goto done;
836                     }
837 
838                     match = memcmp( sub->sa_initial.bv_val, left.bv_val,
839                               sub->sa_initial.bv_len );
840 
841                     if ( match != 0 ) {
842                               goto done;
843                     }
844 
845                     left.bv_val += sub->sa_initial.bv_len;
846                     left.bv_len -= sub->sa_initial.bv_len;
847                     inlen -= sub->sa_initial.bv_len;
848           }
849 
850           if ( !BER_BVISNULL( &sub->sa_final ) ) {
851                     if ( inlen > left.bv_len ) {
852                               match = 1;
853                               goto done;
854                     }
855 
856                     match = memcmp( sub->sa_final.bv_val,
857                               &left.bv_val[left.bv_len - sub->sa_final.bv_len],
858                               sub->sa_final.bv_len );
859 
860                     if ( match != 0 ) {
861                               goto done;
862                     }
863 
864                     left.bv_len -= sub->sa_final.bv_len;
865                     inlen -= sub->sa_final.bv_len;
866           }
867 
868           if ( sub->sa_any ) {
869                     for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
870                               ber_len_t idx;
871                               char *p;
872 
873 retry:
874                               if ( inlen > left.bv_len ) {
875                                         /* not enough length */
876                                         match = 1;
877                                         goto done;
878                               }
879 
880                               if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
881                                         continue;
882                               }
883 
884                               p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
885 
886                               if( p == NULL ) {
887                                         match = 1;
888                                         goto done;
889                               }
890 
891                               idx = p - left.bv_val;
892 
893                               if ( idx >= left.bv_len ) {
894                                         /* this shouldn't happen */
895                                         return LDAP_OTHER;
896                               }
897 
898                               left.bv_val = p;
899                               left.bv_len -= idx;
900 
901                               if ( sub->sa_any[i].bv_len > left.bv_len ) {
902                                         /* not enough left */
903                                         match = 1;
904                                         goto done;
905                               }
906 
907                               match = memcmp( left.bv_val,
908                                         sub->sa_any[i].bv_val,
909                                         sub->sa_any[i].bv_len );
910 
911                               if ( match != 0 ) {
912                                         left.bv_val++;
913                                         left.bv_len--;
914                                         goto retry;
915                               }
916 
917                               left.bv_val += sub->sa_any[i].bv_len;
918                               left.bv_len -= sub->sa_any[i].bv_len;
919                               inlen -= sub->sa_any[i].bv_len;
920                     }
921           }
922 
923 done:
924           *matchp = match;
925           return LDAP_SUCCESS;
926 }
927 
928 /* Substring index generation function: Attribute values -> index hash keys */
929 static int
octetStringSubstringsIndexer(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,BerVarray values,BerVarray * keysp,void * ctx)930 octetStringSubstringsIndexer(
931           slap_mask_t use,
932           slap_mask_t flags,
933           Syntax *syntax,
934           MatchingRule *mr,
935           struct berval *prefix,
936           BerVarray values,
937           BerVarray *keysp,
938           void *ctx )
939 {
940           ber_len_t i, nkeys;
941           BerVarray keys;
942 
943           HASH_CONTEXT HCany, HCini, HCfin;
944           unsigned char HASHdigest[HASH_BYTES];
945           struct berval digest;
946           digest.bv_val = (char *)HASHdigest;
947           digest.bv_len = HASH_LEN;
948 
949           nkeys = 0;
950 
951           for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
952                     /* count number of indices to generate */
953                     if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
954                               if( values[i].bv_len >= index_substr_if_maxlen ) {
955                                         nkeys += index_substr_if_maxlen -
956                                                   (index_substr_if_minlen - 1);
957                               } else if( values[i].bv_len >= index_substr_if_minlen ) {
958                                         nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
959                               }
960                     }
961 
962                     if( flags & SLAP_INDEX_SUBSTR_ANY ) {
963                               if( values[i].bv_len >= index_substr_any_len ) {
964                                         nkeys += values[i].bv_len - (index_substr_any_len - 1);
965                               }
966                     }
967 
968                     if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
969                               if( values[i].bv_len >= index_substr_if_maxlen ) {
970                                         nkeys += index_substr_if_maxlen -
971                                                   (index_substr_if_minlen - 1);
972                               } else if( values[i].bv_len >= index_substr_if_minlen ) {
973                                         nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
974                               }
975                     }
976           }
977 
978           if( nkeys == 0 ) {
979                     /* no keys to generate */
980                     *keysp = NULL;
981                     return LDAP_SUCCESS;
982           }
983 
984           keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
985 
986           if ( flags & SLAP_INDEX_SUBSTR_ANY )
987                     hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
988           if( flags & SLAP_INDEX_SUBSTR_INITIAL )
989                     hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
990           if( flags & SLAP_INDEX_SUBSTR_FINAL )
991                     hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
992 
993           nkeys = 0;
994           for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
995                     ber_len_t j,max;
996 
997                     if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
998                               ( values[i].bv_len >= index_substr_any_len ) )
999                     {
1000                               max = values[i].bv_len - (index_substr_any_len - 1);
1001 
1002                               for( j=0; j<max; j++ ) {
1003                                         hashIter( &HCany, HASHdigest,
1004                                                   (unsigned char *)&values[i].bv_val[j],
1005                                                   index_substr_any_len );
1006                                         ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1007                               }
1008                     }
1009 
1010                     /* skip if too short */
1011                     if( values[i].bv_len < index_substr_if_minlen ) continue;
1012 
1013                     max = index_substr_if_maxlen < values[i].bv_len
1014                               ? index_substr_if_maxlen : values[i].bv_len;
1015 
1016                     for( j=index_substr_if_minlen; j<=max; j++ ) {
1017 
1018                               if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
1019                                         hashIter( &HCini, HASHdigest,
1020                                                   (unsigned char *)values[i].bv_val, j );
1021                                         ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1022                               }
1023 
1024                               if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
1025                                         hashIter( &HCfin, HASHdigest,
1026                                                   (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
1027                                         ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1028                               }
1029 
1030                     }
1031           }
1032 
1033           if( nkeys > 0 ) {
1034                     BER_BVZERO( &keys[nkeys] );
1035                     *keysp = keys;
1036           } else {
1037                     ch_free( keys );
1038                     *keysp = NULL;
1039           }
1040 
1041           return LDAP_SUCCESS;
1042 }
1043 
1044 /* Substring index generation function: Assertion value -> index hash keys */
1045 static int
octetStringSubstringsFilter(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,void * assertedValue,BerVarray * keysp,void * ctx)1046 octetStringSubstringsFilter (
1047           slap_mask_t use,
1048           slap_mask_t flags,
1049           Syntax *syntax,
1050           MatchingRule *mr,
1051           struct berval *prefix,
1052           void * assertedValue,
1053           BerVarray *keysp,
1054           void *ctx)
1055 {
1056           SubstringsAssertion *sa;
1057           char pre;
1058           ber_len_t nkeys = 0;
1059           size_t klen;
1060           BerVarray keys;
1061           HASH_CONTEXT HASHcontext;
1062           unsigned char HASHdigest[HASH_BYTES];
1063           struct berval *value;
1064           struct berval digest;
1065 
1066           sa = (SubstringsAssertion *) assertedValue;
1067 
1068           if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1069                     !BER_BVISNULL( &sa->sa_initial ) &&
1070                     sa->sa_initial.bv_len >= index_substr_if_minlen )
1071           {
1072                     nkeys++;
1073                     if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
1074                               ( flags & SLAP_INDEX_SUBSTR_ANY ))
1075                     {
1076                               nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1077                     }
1078           }
1079 
1080           if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1081                     ber_len_t i;
1082                     for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1083                               if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
1084                                         /* don't bother accounting with stepping */
1085                                         nkeys += sa->sa_any[i].bv_len -
1086                                                   ( index_substr_any_len - 1 );
1087                               }
1088                     }
1089           }
1090 
1091           if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1092                     !BER_BVISNULL( &sa->sa_final ) &&
1093                     sa->sa_final.bv_len >= index_substr_if_minlen )
1094           {
1095                     nkeys++;
1096                     if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
1097                               ( flags & SLAP_INDEX_SUBSTR_ANY ))
1098                     {
1099                               nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
1100                     }
1101           }
1102 
1103           if( nkeys == 0 ) {
1104                     *keysp = NULL;
1105                     return LDAP_SUCCESS;
1106           }
1107 
1108           digest.bv_val = (char *)HASHdigest;
1109           digest.bv_len = HASH_LEN;
1110 
1111           keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
1112           nkeys = 0;
1113 
1114           if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
1115                     !BER_BVISNULL( &sa->sa_initial ) &&
1116                     sa->sa_initial.bv_len >= index_substr_if_minlen )
1117           {
1118                     pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
1119                     value = &sa->sa_initial;
1120 
1121                     klen = index_substr_if_maxlen < value->bv_len
1122                               ? index_substr_if_maxlen : value->bv_len;
1123 
1124                     hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1125                     hashIter( &HASHcontext, HASHdigest,
1126                               (unsigned char *)value->bv_val, klen );
1127                     ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1128 
1129                     /* If initial is too long and we have subany indexed, use it
1130                      * to match the excess...
1131                      */
1132                     if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1133                     {
1134                               ber_len_t j;
1135                               pre = SLAP_INDEX_SUBSTR_PREFIX;
1136                               hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1137                               for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
1138                               {
1139                                         hashIter( &HASHcontext, HASHdigest,
1140                                                   (unsigned char *)&value->bv_val[j], index_substr_any_len );
1141                                         ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1142                               }
1143                     }
1144           }
1145 
1146           if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
1147                     ber_len_t i, j;
1148                     pre = SLAP_INDEX_SUBSTR_PREFIX;
1149                     klen = index_substr_any_len;
1150 
1151                     for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
1152                               if( sa->sa_any[i].bv_len < index_substr_any_len ) {
1153                                         continue;
1154                               }
1155 
1156                               value = &sa->sa_any[i];
1157 
1158                               hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1159                               for(j=0;
1160                                         j <= value->bv_len - index_substr_any_len;
1161                                         j += index_substr_any_step )
1162                               {
1163                                         hashIter( &HASHcontext, HASHdigest,
1164                                                   (unsigned char *)&value->bv_val[j], klen );
1165                                         ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1166                               }
1167                     }
1168           }
1169 
1170           if( flags & SLAP_INDEX_SUBSTR_FINAL &&
1171                     !BER_BVISNULL( &sa->sa_final ) &&
1172                     sa->sa_final.bv_len >= index_substr_if_minlen )
1173           {
1174                     pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
1175                     value = &sa->sa_final;
1176 
1177                     klen = index_substr_if_maxlen < value->bv_len
1178                               ? index_substr_if_maxlen : value->bv_len;
1179 
1180                     hashPreset( &HASHcontext, prefix, pre, syntax, mr );
1181                     hashIter( &HASHcontext, HASHdigest,
1182                               (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
1183                     ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1184 
1185                     /* If final is too long and we have subany indexed, use it
1186                      * to match the excess...
1187                      */
1188                     if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
1189                     {
1190                               ber_len_t j;
1191                               pre = SLAP_INDEX_SUBSTR_PREFIX;
1192                               hashPreset( &HASHcontext, prefix, pre, syntax, mr);
1193                               for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
1194                               {
1195                                         hashIter( &HASHcontext, HASHdigest,
1196                                                   (unsigned char *)&value->bv_val[j], index_substr_any_len );
1197                                         ber_dupbv_x( &keys[nkeys++], &digest, ctx );
1198                               }
1199                     }
1200           }
1201 
1202           if( nkeys > 0 ) {
1203                     BER_BVZERO( &keys[nkeys] );
1204                     *keysp = keys;
1205           } else {
1206                     ch_free( keys );
1207                     *keysp = NULL;
1208           }
1209 
1210           return LDAP_SUCCESS;
1211 }
1212 
1213 static int
bitStringValidate(Syntax * syntax,struct berval * in)1214 bitStringValidate(
1215           Syntax *syntax,
1216           struct berval *in )
1217 {
1218           ber_len_t i;
1219 
1220           /* very unforgiving validation, requires no normalization
1221            * before simplistic matching
1222            */
1223           if( in->bv_len < 3 ) {
1224                     return LDAP_INVALID_SYNTAX;
1225           }
1226 
1227           /* RFC 4517 Section 3.3.2 Bit String:
1228            *        BitString    = SQUOTE *binary-digit SQUOTE "B"
1229            *        binary-digit = "0" / "1"
1230            *
1231            * where SQUOTE [RFC4512] is
1232            *        SQUOTE  = %x27 ; single quote ("'")
1233            *
1234            * Example: '0101111101'B
1235            */
1236 
1237           if( in->bv_val[0] != '\'' ||
1238                     in->bv_val[in->bv_len - 2] != '\'' ||
1239                     in->bv_val[in->bv_len - 1] != 'B' )
1240           {
1241                     return LDAP_INVALID_SYNTAX;
1242           }
1243 
1244           for( i = in->bv_len - 3; i > 0; i-- ) {
1245                     if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
1246                               return LDAP_INVALID_SYNTAX;
1247                     }
1248           }
1249 
1250           return LDAP_SUCCESS;
1251 }
1252 
1253 /*
1254  * Syntaxes from RFC 4517
1255  *
1256 
1257 3.3.2.  Bit String
1258 
1259    A value of the Bit String syntax is a sequence of binary digits.  The
1260    LDAP-specific encoding of a value of this syntax is defined by the
1261    following ABNF:
1262 
1263       BitString    = SQUOTE *binary-digit SQUOTE "B"
1264 
1265       binary-digit = "0" / "1"
1266 
1267    The <SQUOTE> rule is defined in [MODELS].
1268 
1269       Example:
1270          '0101111101'B
1271 
1272    The LDAP definition for the Bit String syntax is:
1273 
1274       ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
1275 
1276    This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
1277 
1278    ...
1279 
1280 3.3.21.  Name and Optional UID
1281 
1282    A value of the Name and Optional UID syntax is the distinguished name
1283    [MODELS] of an entity optionally accompanied by a unique identifier
1284    that serves to differentiate the entity from others with an identical
1285    distinguished name.
1286 
1287    The LDAP-specific encoding of a value of this syntax is defined by
1288    the following ABNF:
1289 
1290        NameAndOptionalUID = distinguishedName [ SHARP BitString ]
1291 
1292    The <BitString> rule is defined in Section 3.3.2.  The
1293    <distinguishedName> rule is defined in [LDAPDN].  The <SHARP> rule is
1294    defined in [MODELS].
1295 
1296    Note that although the '#' character may occur in the string
1297    representation of a distinguished name, no additional escaping of
1298    this character is performed when a <distinguishedName> is encoded in
1299    a <NameAndOptionalUID>.
1300 
1301       Example:
1302          1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
1303 
1304    The LDAP definition for the Name and Optional UID syntax is:
1305 
1306       ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
1307 
1308    This syntax corresponds to the NameAndOptionalUID ASN.1 type from
1309    [X.520].
1310 
1311  *
1312  * RFC 4512 says:
1313  *
1314 
1315 1.4. Common ABNF Productions
1316 
1317   ...
1318       SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
1319   ...
1320       SQUOTE  = %x27 ; single quote ("'")
1321   ...
1322 
1323  *
1324  * Note:
1325  * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
1326  * be escaped except when at the beginning of a value, the
1327  * definition of Name and Optional UID appears to be flawed,
1328  * because there is no clear means to determine whether the
1329  * UID part is present or not.
1330  *
1331  * Example:
1332  *
1333  *        cn=Someone,dc=example,dc=com#'1'B
1334  *
1335  * could be either a NameAndOptionalUID with trailing UID, i.e.
1336  *
1337  *        DN = "cn=Someone,dc=example,dc=com"
1338  *        UID = "'1'B"
1339  *
1340  * or a NameAndOptionalUID with no trailing UID, and the AVA
1341  * in the last RDN made of
1342  *
1343  *        attributeType = dc
1344  *        attributeValue = com#'1'B
1345  *
1346  * in fact "com#'1'B" is a valid IA5 string.
1347  *
1348  * As a consequence, current slapd code takes the presence of
1349  * #<valid BitString> at the end of the string representation
1350  * of a NameAndOptionalUID to mean this is indeed a BitString.
1351  * This is quite arbitrary - it has changed the past and might
1352  * change in the future.
1353  */
1354 
1355 
1356 static int
nameUIDValidate(Syntax * syntax,struct berval * in)1357 nameUIDValidate(
1358           Syntax *syntax,
1359           struct berval *in )
1360 {
1361           int rc;
1362           struct berval dn, uid;
1363 
1364           if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
1365 
1366           ber_dupbv( &dn, in );
1367           if( !dn.bv_val ) return LDAP_OTHER;
1368 
1369           /* if there's a "#", try bitStringValidate()... */
1370           uid.bv_val = strrchr( dn.bv_val, '#' );
1371           if ( !BER_BVISNULL( &uid ) ) {
1372                     uid.bv_val++;
1373                     uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
1374 
1375                     rc = bitStringValidate( NULL, &uid );
1376                     if ( rc == LDAP_SUCCESS ) {
1377                               /* in case of success, trim the UID,
1378                                * otherwise treat it as part of the DN */
1379                               dn.bv_len -= uid.bv_len + 1;
1380                               uid.bv_val[-1] = '\0';
1381                     }
1382           }
1383 
1384           rc = dnValidate( NULL, &dn );
1385 
1386           ber_memfree( dn.bv_val );
1387           return rc;
1388 }
1389 
1390 int
nameUIDPretty(Syntax * syntax,struct berval * val,struct berval * out,void * ctx)1391 nameUIDPretty(
1392           Syntax *syntax,
1393           struct berval *val,
1394           struct berval *out,
1395           void *ctx )
1396 {
1397           assert( val != NULL );
1398           assert( out != NULL );
1399 
1400 
1401           Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val );
1402 
1403           if( BER_BVISEMPTY( val ) ) {
1404                     ber_dupbv_x( out, val, ctx );
1405 
1406           } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
1407                     return LDAP_INVALID_SYNTAX;
1408 
1409           } else {
1410                     int                 rc;
1411                     struct berval       dnval = *val;
1412                     struct berval       uidval = BER_BVNULL;
1413 
1414                     uidval.bv_val = strrchr( val->bv_val, '#' );
1415                     if ( !BER_BVISNULL( &uidval ) ) {
1416                               uidval.bv_val++;
1417                               uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
1418 
1419                               rc = bitStringValidate( NULL, &uidval );
1420 
1421                               if ( rc == LDAP_SUCCESS ) {
1422                                         ber_dupbv_x( &dnval, val, ctx );
1423                                         uidval.bv_val--;
1424                                         dnval.bv_len -= ++uidval.bv_len;
1425                                         dnval.bv_val[dnval.bv_len] = '\0';
1426 
1427                               } else {
1428                                         BER_BVZERO( &uidval );
1429                               }
1430                     }
1431 
1432                     rc = dnPretty( syntax, &dnval, out, ctx );
1433                     if ( dnval.bv_val != val->bv_val ) {
1434                               slap_sl_free( dnval.bv_val, ctx );
1435                     }
1436                     if( rc != LDAP_SUCCESS ) {
1437                               return rc;
1438                     }
1439 
1440                     if( !BER_BVISNULL( &uidval ) ) {
1441                               char      *tmp;
1442 
1443                               tmp = slap_sl_realloc( out->bv_val, out->bv_len
1444                                         + uidval.bv_len + 1,
1445                                         ctx );
1446                               if( tmp == NULL ) {
1447                                         ber_memfree_x( out->bv_val, ctx );
1448                                         return LDAP_OTHER;
1449                               }
1450                               out->bv_val = tmp;
1451                               memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
1452                               out->bv_len += uidval.bv_len;
1453                               out->bv_val[out->bv_len] = '\0';
1454                     }
1455           }
1456 
1457           Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val );
1458 
1459           return LDAP_SUCCESS;
1460 }
1461 
1462 static int
uniqueMemberNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)1463 uniqueMemberNormalize(
1464           slap_mask_t usage,
1465           Syntax *syntax,
1466           MatchingRule *mr,
1467           struct berval *val,
1468           struct berval *normalized,
1469           void *ctx )
1470 {
1471           struct berval out;
1472           int rc;
1473 
1474           assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
1475 
1476           ber_dupbv_x( &out, val, ctx );
1477           if ( BER_BVISEMPTY( &out ) ) {
1478                     *normalized = out;
1479 
1480           } else {
1481                     struct berval uid = BER_BVNULL;
1482 
1483                     uid.bv_val = strrchr( out.bv_val, '#' );
1484                     if ( !BER_BVISNULL( &uid ) ) {
1485                               uid.bv_val++;
1486                               uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
1487 
1488                               rc = bitStringValidate( NULL, &uid );
1489                               if ( rc == LDAP_SUCCESS ) {
1490                                         uid.bv_val[-1] = '\0';
1491                                         out.bv_len -= uid.bv_len + 1;
1492                               } else {
1493                                         BER_BVZERO( &uid );
1494                               }
1495                     }
1496 
1497                     rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
1498 
1499                     if( rc != LDAP_SUCCESS ) {
1500                               slap_sl_free( out.bv_val, ctx );
1501                               return LDAP_INVALID_SYNTAX;
1502                     }
1503 
1504                     if( !BER_BVISNULL( &uid ) ) {
1505                               char      *tmp;
1506 
1507                               tmp = ch_realloc( normalized->bv_val,
1508                                         normalized->bv_len + uid.bv_len
1509                                         + STRLENOF("#") + 1 );
1510                               if ( tmp == NULL ) {
1511                                         ber_memfree_x( normalized->bv_val, ctx );
1512                                         return LDAP_OTHER;
1513                               }
1514 
1515                               normalized->bv_val = tmp;
1516 
1517                               /* insert the separator */
1518                               normalized->bv_val[normalized->bv_len++] = '#';
1519 
1520                               /* append the UID */
1521                               AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
1522                                         uid.bv_val, uid.bv_len );
1523                               normalized->bv_len += uid.bv_len;
1524 
1525                               /* terminate */
1526                               normalized->bv_val[normalized->bv_len] = '\0';
1527                     }
1528 
1529                     slap_sl_free( out.bv_val, ctx );
1530           }
1531 
1532           return LDAP_SUCCESS;
1533 }
1534 
1535 static int
uniqueMemberMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)1536 uniqueMemberMatch(
1537           int *matchp,
1538           slap_mask_t flags,
1539           Syntax *syntax,
1540           MatchingRule *mr,
1541           struct berval *value,
1542           void *assertedValue )
1543 {
1544           int match;
1545           struct berval *asserted = (struct berval *) assertedValue;
1546           struct berval assertedDN = *asserted;
1547           struct berval assertedUID = BER_BVNULL;
1548           struct berval valueDN = *value;
1549           struct berval valueUID = BER_BVNULL;
1550           int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
1551 
1552           if ( !BER_BVISEMPTY( asserted ) ) {
1553                     assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1554                     if ( !BER_BVISNULL( &assertedUID ) ) {
1555                               assertedUID.bv_val++;
1556                               assertedUID.bv_len = assertedDN.bv_len
1557                                         - ( assertedUID.bv_val - assertedDN.bv_val );
1558 
1559                               if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1560                                         assertedDN.bv_len -= assertedUID.bv_len + 1;
1561 
1562                               } else {
1563                                         BER_BVZERO( &assertedUID );
1564                               }
1565                     }
1566           }
1567 
1568           if ( !BER_BVISEMPTY( value ) ) {
1569 
1570                     valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
1571                     if ( !BER_BVISNULL( &valueUID ) ) {
1572                               valueUID.bv_val++;
1573                               valueUID.bv_len = valueDN.bv_len
1574                                         - ( valueUID.bv_val - valueDN.bv_val );
1575 
1576                               if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
1577                                         valueDN.bv_len -= valueUID.bv_len + 1;
1578 
1579                               } else {
1580                                         BER_BVZERO( &valueUID );
1581                               }
1582                     }
1583           }
1584 
1585           if( valueUID.bv_len && assertedUID.bv_len ) {
1586                     ber_slen_t d;
1587                     d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len;
1588                     if ( d ) {
1589                               *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1;
1590                               return LDAP_SUCCESS;
1591                     }
1592 
1593                     match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
1594                     if( match ) {
1595                               *matchp = match;
1596                               return LDAP_SUCCESS;
1597                     }
1598 
1599           } else if ( !approx && valueUID.bv_len ) {
1600                     match = -1;
1601                     *matchp = match;
1602                     return LDAP_SUCCESS;
1603 
1604           } else if ( !approx && assertedUID.bv_len ) {
1605                     match = 1;
1606                     *matchp = match;
1607                     return LDAP_SUCCESS;
1608           }
1609 
1610           return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
1611 }
1612 
1613 static int
uniqueMemberIndexer(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,BerVarray values,BerVarray * keysp,void * ctx)1614 uniqueMemberIndexer(
1615           slap_mask_t use,
1616           slap_mask_t flags,
1617           Syntax *syntax,
1618           MatchingRule *mr,
1619           struct berval *prefix,
1620           BerVarray values,
1621           BerVarray *keysp,
1622           void *ctx )
1623 {
1624           BerVarray dnvalues;
1625           int rc;
1626           int i;
1627           for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1628                     /* just count them */
1629           }
1630           assert( i > 0 );
1631 
1632           dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
1633 
1634           for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
1635                     struct berval assertedDN = values[i];
1636                     struct berval assertedUID = BER_BVNULL;
1637 
1638                     if ( !BER_BVISEMPTY( &assertedDN ) ) {
1639                               assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1640                               if ( !BER_BVISNULL( &assertedUID ) ) {
1641                                         assertedUID.bv_val++;
1642                                         assertedUID.bv_len = assertedDN.bv_len
1643                                                   - ( assertedUID.bv_val - assertedDN.bv_val );
1644 
1645                                         if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1646                                                   assertedDN.bv_len -= assertedUID.bv_len + 1;
1647 
1648                                         } else {
1649                                                   BER_BVZERO( &assertedUID );
1650                                         }
1651                               }
1652                     }
1653 
1654                     dnvalues[i] = assertedDN;
1655           }
1656           BER_BVZERO( &dnvalues[i] );
1657 
1658           rc = octetStringIndexer( use, flags, syntax, mr, prefix,
1659                     dnvalues, keysp, ctx );
1660 
1661           slap_sl_free( dnvalues, ctx );
1662           return rc;
1663 }
1664 
1665 static int
uniqueMemberFilter(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,void * assertedValue,BerVarray * keysp,void * ctx)1666 uniqueMemberFilter(
1667           slap_mask_t use,
1668           slap_mask_t flags,
1669           Syntax *syntax,
1670           MatchingRule *mr,
1671           struct berval *prefix,
1672           void * assertedValue,
1673           BerVarray *keysp,
1674           void *ctx )
1675 {
1676           struct berval *asserted = (struct berval *) assertedValue;
1677           struct berval assertedDN = *asserted;
1678           struct berval assertedUID = BER_BVNULL;
1679 
1680           if ( !BER_BVISEMPTY( asserted ) ) {
1681                     assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
1682                     if ( !BER_BVISNULL( &assertedUID ) ) {
1683                               assertedUID.bv_val++;
1684                               assertedUID.bv_len = assertedDN.bv_len
1685                                         - ( assertedUID.bv_val - assertedDN.bv_val );
1686 
1687                               if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
1688                                         assertedDN.bv_len -= assertedUID.bv_len + 1;
1689 
1690                               } else {
1691                                         BER_BVZERO( &assertedUID );
1692                               }
1693                     }
1694           }
1695 
1696           return octetStringFilter( use, flags, syntax, mr, prefix,
1697                     &assertedDN, keysp, ctx );
1698 }
1699 
1700 
1701 /*
1702  * Handling boolean syntax and matching is quite rigid.
1703  * A more flexible approach would be to allow a variety
1704  * of strings to be normalized and prettied into TRUE
1705  * and FALSE.
1706  */
1707 static int
booleanValidate(Syntax * syntax,struct berval * in)1708 booleanValidate(
1709           Syntax *syntax,
1710           struct berval *in )
1711 {
1712           /* very unforgiving validation, requires no normalization
1713            * before simplistic matching
1714            */
1715 
1716           if( in->bv_len == 4 ) {
1717                     if( bvmatch( in, &slap_true_bv ) ) {
1718                               return LDAP_SUCCESS;
1719                     }
1720           } else if( in->bv_len == 5 ) {
1721                     if( bvmatch( in, &slap_false_bv ) ) {
1722                               return LDAP_SUCCESS;
1723                     }
1724           }
1725 
1726           return LDAP_INVALID_SYNTAX;
1727 }
1728 
1729 static int
booleanMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)1730 booleanMatch(
1731           int *matchp,
1732           slap_mask_t flags,
1733           Syntax *syntax,
1734           MatchingRule *mr,
1735           struct berval *value,
1736           void *assertedValue )
1737 {
1738           /* simplistic matching allowed by rigid validation */
1739           struct berval *asserted = (struct berval *) assertedValue;
1740           *matchp = (int) asserted->bv_len - (int) value->bv_len;
1741           return LDAP_SUCCESS;
1742 }
1743 
1744 /*-------------------------------------------------------------------
1745 LDAP/X.500 string syntax / matching rules have a few oddities.  This
1746 comment attempts to detail how slapd(8) treats them.
1747 
1748 Summary:
1749   StringSyntax                X.500     LDAP      Matching/Comments
1750   DirectoryString   CHOICE    UTF8      i/e + ignore insignificant spaces
1751   PrintableString   subset    subset    i/e + ignore insignificant spaces
1752   PrintableString   subset    subset    i/e + ignore insignificant spaces
1753   NumericString               subset    subset    ignore all spaces
1754   IA5String                             ASCII     ASCII     i/e + ignore insignificant spaces
1755   TeletexString               T.61      T.61      i/e + ignore insignificant spaces
1756 
1757   TelephoneNumber   subset    subset    i + ignore all spaces and "-"
1758 
1759   See RFC 4518 for details.
1760 
1761 
1762 Directory String -
1763   In X.500(93), a directory string can be either a PrintableString,
1764   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
1765   In later versions, more CHOICEs were added.  In all cases the string
1766   must be non-empty.
1767 
1768   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
1769   A directory string cannot be zero length.
1770 
1771   For matching, there are both case ignore and exact rules.  Both
1772   also require that "insignificant" spaces be ignored.
1773           spaces before the first non-space are ignored;
1774           spaces after the last non-space are ignored;
1775           spaces after a space are ignored.
1776   Note: by these rules (and as clarified in X.520), a string of only
1777   spaces is to be treated as if held one space, not empty (which
1778   would be a syntax error).
1779 
1780 NumericString
1781   In ASN.1, numeric string is just a string of digits and spaces
1782   and could be empty.  However, in X.500, all attribute values of
1783   numeric string carry a non-empty constraint.  For example:
1784 
1785           internationalISDNNumber ATTRIBUTE ::= {
1786                     WITH SYNTAX InternationalISDNNumber
1787                     EQUALITY MATCHING RULE numericStringMatch
1788                     SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
1789                     ID id-at-internationalISDNNumber }
1790           InternationalISDNNumber ::=
1791               NumericString (SIZE(1..ub-international-isdn-number))
1792 
1793   Unfortunately, some assertion values are don't carry the same
1794   constraint (but its unclear how such an assertion could ever
1795   be true). In LDAP, there is one syntax (numericString) not two
1796   (numericString with constraint, numericString without constraint).
1797   This should be treated as numericString with non-empty constraint.
1798   Note that while someone may have no ISDN number, there are no ISDN
1799   numbers which are zero length.
1800 
1801   In matching, spaces are ignored.
1802 
1803 PrintableString
1804   In ASN.1, Printable string is just a string of printable characters
1805   and can be empty.  In X.500, semantics much like NumericString (see
1806   serialNumber for a like example) excepting uses insignificant space
1807   handling instead of ignore all spaces.  They must be non-empty.
1808 
1809 IA5String
1810   Basically same as PrintableString.  There are no examples in X.500,
1811   but same logic applies.  Empty strings are allowed.
1812 
1813 -------------------------------------------------------------------*/
1814 
1815 static int
UTF8StringValidate(Syntax * syntax,struct berval * in)1816 UTF8StringValidate(
1817           Syntax *syntax,
1818           struct berval *in )
1819 {
1820           int len;
1821           unsigned char *u = (unsigned char *)in->bv_val, *end = (unsigned char *)in->bv_val + in->bv_len;
1822 
1823           if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
1824                     /* directory strings cannot be empty */
1825                     return LDAP_INVALID_SYNTAX;
1826           }
1827 
1828           for( ; u < end; u += len ) {
1829                     /* get the length indicated by the first byte */
1830                     len = LDAP_UTF8_CHARLEN2( u, len );
1831 
1832                     /* very basic checks */
1833                     switch( len ) {
1834                               case 6:
1835                                         if( (u[5] & 0xC0) != 0x80 ) {
1836                                                   return LDAP_INVALID_SYNTAX;
1837                                         }
1838                               case 5:
1839                                         if( (u[4] & 0xC0) != 0x80 ) {
1840                                                   return LDAP_INVALID_SYNTAX;
1841                                         }
1842                               case 4:
1843                                         if( (u[3] & 0xC0) != 0x80 ) {
1844                                                   return LDAP_INVALID_SYNTAX;
1845                                         }
1846                               case 3:
1847                                         if( (u[2] & 0xC0 )!= 0x80 ) {
1848                                                   return LDAP_INVALID_SYNTAX;
1849                                         }
1850                               case 2:
1851                                         if( (u[1] & 0xC0) != 0x80 ) {
1852                                                   return LDAP_INVALID_SYNTAX;
1853                                         }
1854                               case 1:
1855                                         /* CHARLEN already validated it */
1856                                         break;
1857                               default:
1858                                         return LDAP_INVALID_SYNTAX;
1859                     }
1860 
1861                     /* make sure len corresponds with the offset
1862                               to the next character */
1863                     if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
1864           }
1865 
1866           if( u > end ) {
1867                     return LDAP_INVALID_SYNTAX;
1868           }
1869 
1870           return LDAP_SUCCESS;
1871 }
1872 
1873 static int
UTF8StringNormalize(slap_mask_t use,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)1874 UTF8StringNormalize(
1875           slap_mask_t use,
1876           Syntax *syntax,
1877           MatchingRule *mr,
1878           struct berval *val,
1879           struct berval *normalized,
1880           void *ctx )
1881 {
1882           struct berval tmp, nvalue;
1883           int flags, wasspace;
1884           ber_len_t i;
1885 
1886           assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
1887 
1888           if( BER_BVISNULL( val ) ) {
1889                     /* assume we're dealing with a syntax (e.g., UTF8String)
1890                      * which allows empty strings
1891                      */
1892                     BER_BVZERO( normalized );
1893                     return LDAP_SUCCESS;
1894           }
1895 
1896           flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
1897                     ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
1898           flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
1899                     ? LDAP_UTF8_APPROX : 0;
1900 
1901           val = UTF8bvnormalize( val, &tmp, flags, ctx );
1902           /* out of memory or syntax error, the former is unlikely */
1903           if( val == NULL ) {
1904                     return LDAP_INVALID_SYNTAX;
1905           }
1906 
1907           /* collapse spaces (in place) */
1908           nvalue.bv_len = 0;
1909           nvalue.bv_val = tmp.bv_val;
1910 
1911           /* trim leading spaces? */
1912           wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
1913                     (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
1914 
1915           for( i = 0; i < tmp.bv_len; i++) {
1916                     if ( ASCII_SPACE( tmp.bv_val[i] )) {
1917                               if( wasspace++ == 0 ) {
1918                                         /* trim repeated spaces */
1919                                         nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1920                               }
1921                     } else {
1922                               wasspace = 0;
1923                               nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
1924                     }
1925           }
1926 
1927           if( !BER_BVISEMPTY( &nvalue ) ) {
1928                     /* trim trailing space? */
1929                     if( wasspace && (
1930                               (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
1931                               ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
1932                     {
1933                               --nvalue.bv_len;
1934                     }
1935                     nvalue.bv_val[nvalue.bv_len] = '\0';
1936 
1937           } else if ( tmp.bv_len )  {
1938                     /* string of all spaces is treated as one space */
1939                     nvalue.bv_val[0] = ' ';
1940                     nvalue.bv_val[1] = '\0';
1941                     nvalue.bv_len = 1;
1942           }         /* should never be entered with 0-length val */
1943 
1944           *normalized = nvalue;
1945           return LDAP_SUCCESS;
1946 }
1947 
1948 static int
directoryStringSubstringsMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)1949 directoryStringSubstringsMatch(
1950           int *matchp,
1951           slap_mask_t flags,
1952           Syntax *syntax,
1953           MatchingRule *mr,
1954           struct berval *value,
1955           void *assertedValue )
1956 {
1957           int match = 0;
1958           SubstringsAssertion *sub = assertedValue;
1959           struct berval left = *value;
1960           ber_len_t i;
1961           int priorspace=0;
1962 
1963           if ( !BER_BVISNULL( &sub->sa_initial ) ) {
1964                     if ( sub->sa_initial.bv_len > left.bv_len ) {
1965                               /* not enough left */
1966                               match = 1;
1967                               goto done;
1968                     }
1969 
1970                     match = memcmp( sub->sa_initial.bv_val, left.bv_val,
1971                               sub->sa_initial.bv_len );
1972 
1973                     if ( match != 0 ) {
1974                               goto done;
1975                     }
1976 
1977                     left.bv_val += sub->sa_initial.bv_len;
1978                     left.bv_len -= sub->sa_initial.bv_len;
1979 
1980                     priorspace = ASCII_SPACE(
1981                               sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
1982           }
1983 
1984           if ( sub->sa_any ) {
1985                     for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
1986                               ber_len_t idx;
1987                               char *p;
1988 
1989                               if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] )
1990                                         && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
1991                               {
1992                                         /* allow next space to match */
1993                                         left.bv_val--;
1994                                         left.bv_len++;
1995                               }
1996                               priorspace=0;
1997 
1998 retry:
1999                               if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
2000                                         continue;
2001                               }
2002 
2003                               if ( sub->sa_any[i].bv_len > left.bv_len ) {
2004                                         /* not enough left */
2005                                         match = 1;
2006                                         goto done;
2007                               }
2008 
2009                               p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
2010 
2011                               if( p == NULL ) {
2012                                         match = 1;
2013                                         goto done;
2014                               }
2015 
2016                               idx = p - left.bv_val;
2017 
2018                               if ( idx >= left.bv_len ) {
2019                                         /* this shouldn't happen */
2020                                         return LDAP_OTHER;
2021                               }
2022 
2023                               left.bv_val = p;
2024                               left.bv_len -= idx;
2025 
2026                               if ( sub->sa_any[i].bv_len > left.bv_len ) {
2027                                         /* not enough left */
2028                                         match = 1;
2029                                         goto done;
2030                               }
2031 
2032                               match = memcmp( left.bv_val,
2033                                         sub->sa_any[i].bv_val,
2034                                         sub->sa_any[i].bv_len );
2035 
2036                               if ( match != 0 ) {
2037                                         left.bv_val++;
2038                                         left.bv_len--;
2039                                         goto retry;
2040                               }
2041 
2042                               left.bv_val += sub->sa_any[i].bv_len;
2043                               left.bv_len -= sub->sa_any[i].bv_len;
2044 
2045                               priorspace = ASCII_SPACE(
2046                                         sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
2047                     }
2048           }
2049 
2050           if ( !BER_BVISNULL( &sub->sa_final ) ) {
2051                     if( priorspace && !BER_BVISEMPTY( &sub->sa_final )
2052                               && ASCII_SPACE( sub->sa_final.bv_val[0] ))
2053                     {
2054                               /* allow next space to match */
2055                               left.bv_val--;
2056                               left.bv_len++;
2057                     }
2058 
2059                     if ( sub->sa_final.bv_len > left.bv_len ) {
2060                               /* not enough left */
2061                               match = 1;
2062                               goto done;
2063                     }
2064 
2065                     match = memcmp( sub->sa_final.bv_val,
2066                               &left.bv_val[left.bv_len - sub->sa_final.bv_len],
2067                               sub->sa_final.bv_len );
2068 
2069                     if ( match != 0 ) {
2070                               goto done;
2071                     }
2072           }
2073 
2074 done:
2075           *matchp = match;
2076           return LDAP_SUCCESS;
2077 }
2078 
2079 #if defined(SLAPD_APPROX_INITIALS)
2080 #         define SLAPD_APPROX_DELIMITER "._ "
2081 #         define SLAPD_APPROX_WORDLEN 2
2082 #else
2083 #         define SLAPD_APPROX_DELIMITER " "
2084 #         define SLAPD_APPROX_WORDLEN 1
2085 #endif
2086 
2087 static int
approxMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)2088 approxMatch(
2089           int *matchp,
2090           slap_mask_t flags,
2091           Syntax *syntax,
2092           MatchingRule *mr,
2093           struct berval *value,
2094           void *assertedValue )
2095 {
2096           struct berval *nval, *assertv;
2097           char *val, **values, **words, *c;
2098           int i, count, len, nextchunk=0, nextavail=0;
2099 
2100           /* Yes, this is necessary */
2101           nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
2102           if( nval == NULL ) {
2103                     *matchp = 1;
2104                     return LDAP_SUCCESS;
2105           }
2106 
2107           /* Yes, this is necessary */
2108           assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
2109                     NULL, LDAP_UTF8_APPROX, NULL );
2110           if( assertv == NULL ) {
2111                     ber_bvfree( nval );
2112                     *matchp = 1;
2113                     return LDAP_SUCCESS;
2114           }
2115 
2116           /* Isolate how many words there are */
2117           for ( c = nval->bv_val, count = 1; *c; c++ ) {
2118                     c = strpbrk( c, SLAPD_APPROX_DELIMITER );
2119                     if ( c == NULL ) break;
2120                     *c = '\0';
2121                     count++;
2122           }
2123 
2124           /* Get a phonetic copy of each word */
2125           words = (char **)ch_malloc( count * sizeof(char *) );
2126           values = (char **)ch_malloc( count * sizeof(char *) );
2127           for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
2128                     words[i] = c;
2129                     values[i] = phonetic(c);
2130           }
2131 
2132           /* Work through the asserted value's words, to see if at least some
2133            * of the words are there, in the same order. */
2134           len = 0;
2135           while ( (ber_len_t) nextchunk < assertv->bv_len ) {
2136                     len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
2137                     if( len == 0 ) {
2138                               nextchunk++;
2139                               continue;
2140                     }
2141 #if defined(SLAPD_APPROX_INITIALS)
2142                     else if( len == 1 ) {
2143                               /* Single letter words need to at least match one word's initial */
2144                               for( i=nextavail; i<count; i++ )
2145                                         if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
2146                                                   nextavail=i+1;
2147                                                   break;
2148                                         }
2149                     }
2150 #endif
2151                     else {
2152                               /* Isolate the next word in the asserted value and phonetic it */
2153                               assertv->bv_val[nextchunk+len] = '\0';
2154                               val = phonetic( assertv->bv_val + nextchunk );
2155 
2156                               /* See if this phonetic chunk is in the remaining words of *value */
2157                               for( i=nextavail; i<count; i++ ){
2158                                         if( !strcmp( val, values[i] ) ){
2159                                                   nextavail = i+1;
2160                                                   break;
2161                                         }
2162                               }
2163                               ch_free( val );
2164                     }
2165 
2166                     /* This chunk in the asserted value was NOT within the *value. */
2167                     if( i >= count ) {
2168                               nextavail=-1;
2169                               break;
2170                     }
2171 
2172                     /* Go on to the next word in the asserted value */
2173                     nextchunk += len+1;
2174           }
2175 
2176           /* If some of the words were seen, call it a match */
2177           if( nextavail > 0 ) {
2178                     *matchp = 0;
2179           }
2180           else {
2181                     *matchp = 1;
2182           }
2183 
2184           /* Cleanup allocs */
2185           ber_bvfree( assertv );
2186           for( i=0; i<count; i++ ) {
2187                     ch_free( values[i] );
2188           }
2189           ch_free( values );
2190           ch_free( words );
2191           ber_bvfree( nval );
2192 
2193           return LDAP_SUCCESS;
2194 }
2195 
2196 static int
approxIndexer(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,BerVarray values,BerVarray * keysp,void * ctx)2197 approxIndexer(
2198           slap_mask_t use,
2199           slap_mask_t flags,
2200           Syntax *syntax,
2201           MatchingRule *mr,
2202           struct berval *prefix,
2203           BerVarray values,
2204           BerVarray *keysp,
2205           void *ctx )
2206 {
2207           char *c;
2208           int i,j, len, wordcount, keycount=0;
2209           struct berval *newkeys;
2210           BerVarray keys=NULL;
2211 
2212           for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
2213                     struct berval val = BER_BVNULL;
2214                     /* Yes, this is necessary */
2215                     UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
2216                     assert( !BER_BVISNULL( &val ) );
2217 
2218                     /* Isolate how many words there are. There will be a key for each */
2219                     for( wordcount = 0, c = val.bv_val; *c; c++) {
2220                               len = strcspn(c, SLAPD_APPROX_DELIMITER);
2221                               if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
2222                               c+= len;
2223                               if (*c == '\0') break;
2224                               *c = '\0';
2225                     }
2226 
2227                     /* Allocate/increase storage to account for new keys */
2228                     newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1)
2229                               * sizeof(struct berval) );
2230                     AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
2231                     if( keys ) ch_free( keys );
2232                     keys = newkeys;
2233 
2234                     /* Get a phonetic copy of each word */
2235                     for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
2236                               len = strlen( c );
2237                               if( len < SLAPD_APPROX_WORDLEN ) continue;
2238                               ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
2239                               if( keys[keycount].bv_len ) {
2240                                         keycount++;
2241                               } else {
2242                                         ch_free( keys[keycount].bv_val );
2243                               }
2244                               i++;
2245                     }
2246 
2247                     ber_memfree( val.bv_val );
2248           }
2249           BER_BVZERO( &keys[keycount] );
2250           *keysp = keys;
2251 
2252           return LDAP_SUCCESS;
2253 }
2254 
2255 static int
approxFilter(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,void * assertedValue,BerVarray * keysp,void * ctx)2256 approxFilter(
2257           slap_mask_t use,
2258           slap_mask_t flags,
2259           Syntax *syntax,
2260           MatchingRule *mr,
2261           struct berval *prefix,
2262           void * assertedValue,
2263           BerVarray *keysp,
2264           void *ctx )
2265 {
2266           char *c;
2267           int i, count, len;
2268           struct berval *val;
2269           BerVarray keys;
2270 
2271           /* Yes, this is necessary */
2272           val = UTF8bvnormalize( ((struct berval *)assertedValue),
2273                     NULL, LDAP_UTF8_APPROX, NULL );
2274           if( val == NULL || BER_BVISNULL( val ) ) {
2275                     keys = (struct berval *)ch_malloc( sizeof(struct berval) );
2276                     BER_BVZERO( &keys[0] );
2277                     *keysp = keys;
2278                     ber_bvfree( val );
2279                     return LDAP_SUCCESS;
2280           }
2281 
2282           /* Isolate how many words there are. There will be a key for each */
2283           for( count = 0,c = val->bv_val; *c; c++) {
2284                     len = strcspn(c, SLAPD_APPROX_DELIMITER);
2285                     if( len >= SLAPD_APPROX_WORDLEN ) count++;
2286                     c+= len;
2287                     if (*c == '\0') break;
2288                     *c = '\0';
2289           }
2290 
2291           /* Allocate storage for new keys */
2292           keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
2293 
2294           /* Get a phonetic copy of each word */
2295           for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
2296                     len = strlen(c);
2297                     if( len < SLAPD_APPROX_WORDLEN ) continue;
2298                     ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
2299                     i++;
2300           }
2301 
2302           ber_bvfree( val );
2303 
2304           BER_BVZERO( &keys[count] );
2305           *keysp = keys;
2306 
2307           return LDAP_SUCCESS;
2308 }
2309 
2310 /* Remove all spaces and '-' characters, unless the result would be empty */
2311 static int
telephoneNumberNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)2312 telephoneNumberNormalize(
2313           slap_mask_t usage,
2314           Syntax *syntax,
2315           MatchingRule *mr,
2316           struct berval *val,
2317           struct berval *normalized,
2318           void *ctx )
2319 {
2320           char *q;
2321           ber_len_t c;
2322 
2323           assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
2324 
2325           /* Ensure q is big enough, though validator should have caught this */
2326           if ( BER_BVISEMPTY( val )) {
2327                     BER_BVZERO( normalized );
2328                     return LDAP_INVALID_SYNTAX;
2329           }
2330 
2331           q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
2332 
2333           for( c = 0; c < val->bv_len; c++ ) {
2334                     if ( ! ( ASCII_SPACE( val->bv_val[c] ) || val->bv_val[c] == '-' )) {
2335                               *q++ = val->bv_val[c];
2336                     }
2337           }
2338           if ( q == normalized->bv_val ) {
2339                     *q++ = ' ';
2340           }
2341           *q = '\0';
2342 
2343           normalized->bv_len = q - normalized->bv_val;
2344 
2345           return LDAP_SUCCESS;
2346 }
2347 
2348 static int
postalAddressValidate(Syntax * syntax,struct berval * in)2349 postalAddressValidate(
2350           Syntax *syntax,
2351           struct berval *in )
2352 {
2353           struct berval bv = *in;
2354           ber_len_t c;
2355 
2356           for ( c = 0; c < in->bv_len; c++ ) {
2357                     if ( in->bv_val[c] == '\\' ) {
2358                               c++;
2359                               if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
2360                                         && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
2361                               {
2362                                         return LDAP_INVALID_SYNTAX;
2363                               }
2364                               continue;
2365                     }
2366 
2367                     if ( in->bv_val[c] == '$' ) {
2368                               bv.bv_len = &in->bv_val[c] - bv.bv_val;
2369                               if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
2370                                         return LDAP_INVALID_SYNTAX;
2371                               }
2372                               bv.bv_val = &in->bv_val[c] + 1;
2373                     }
2374           }
2375 
2376           bv.bv_len = &in->bv_val[c] - bv.bv_val;
2377           return UTF8StringValidate( NULL, &bv );
2378 }
2379 
2380 static int
postalAddressNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)2381 postalAddressNormalize(
2382           slap_mask_t usage,
2383           Syntax *syntax,
2384           MatchingRule *mr,
2385           struct berval *val,
2386           struct berval *normalized,
2387           void *ctx )
2388 {
2389           BerVarray lines = NULL, nlines = NULL;
2390           ber_len_t l, c;
2391           int rc = LDAP_SUCCESS;
2392           MatchingRule *xmr = NULL;
2393           char *p;
2394 
2395           if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
2396                     xmr = slap_schema.si_mr_caseIgnoreMatch;
2397 
2398           } else {
2399                     xmr = slap_schema.si_mr_caseExactMatch;
2400           }
2401 
2402           for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2403                     if ( val->bv_val[c] == '$' ) {
2404                               l++;
2405                     }
2406           }
2407 
2408           lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
2409           nlines = &lines[l + 2];
2410 
2411           lines[0].bv_val = val->bv_val;
2412           for ( l = 0, c = 0; c < val->bv_len; c++ ) {
2413                     if ( val->bv_val[c] == '$' ) {
2414                               lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2415                               l++;
2416                               lines[l].bv_val = &val->bv_val[c + 1];
2417                     }
2418           }
2419           lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
2420 
2421           normalized->bv_len = c = l;
2422 
2423           for ( l = 0; l <= c; l++ ) {
2424                     /* NOTE: we directly normalize each line,
2425                      * without unescaping the values, since the special
2426                      * values '\24' ('$') and '\5C' ('\') are not affected
2427                      * by normalization */
2428                     if ( !lines[l].bv_len ) {
2429                               nlines[l].bv_len = 0;
2430                               nlines[l].bv_val = NULL;
2431                               continue;
2432                     }
2433                     rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
2434                     if ( rc != LDAP_SUCCESS ) {
2435                               rc = LDAP_INVALID_SYNTAX;
2436                               goto done;
2437                     }
2438 
2439                     normalized->bv_len += nlines[l].bv_len;
2440           }
2441 
2442           normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2443 
2444           p = normalized->bv_val;
2445           for ( l = 0; l <= c ; l++ ) {
2446                     p = lutil_strbvcopy( p, &nlines[l] );
2447                     *p++ = '$';
2448           }
2449           *--p = '\0';
2450 
2451           assert( p == &normalized->bv_val[normalized->bv_len] );
2452 
2453 done:;
2454           if ( nlines != NULL ) {
2455                     for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
2456                               slap_sl_free( nlines[l].bv_val, ctx );
2457                     }
2458 
2459                     slap_sl_free( lines, ctx );
2460           }
2461 
2462           return rc;
2463 }
2464 
2465 int
numericoidValidate(Syntax * syntax,struct berval * in)2466 numericoidValidate(
2467           Syntax *syntax,
2468           struct berval *in )
2469 {
2470           struct berval val = *in;
2471 
2472           if( BER_BVISEMPTY( &val ) ) {
2473                     /* disallow empty strings */
2474                     return LDAP_INVALID_SYNTAX;
2475           }
2476 
2477           while( OID_LEADCHAR( val.bv_val[0] ) ) {
2478                     if ( val.bv_len == 1 ) {
2479                               return LDAP_SUCCESS;
2480                     }
2481 
2482                     if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
2483                               break;
2484                     }
2485 
2486                     val.bv_val++;
2487                     val.bv_len--;
2488 
2489                     while ( OID_LEADCHAR( val.bv_val[0] )) {
2490                               val.bv_val++;
2491                               val.bv_len--;
2492 
2493                               if ( val.bv_len == 0 ) {
2494                                         return LDAP_SUCCESS;
2495                               }
2496                     }
2497 
2498                     if( !OID_SEPARATOR( val.bv_val[0] )) {
2499                               break;
2500                     }
2501 
2502                     val.bv_val++;
2503                     val.bv_len--;
2504           }
2505 
2506           return LDAP_INVALID_SYNTAX;
2507 }
2508 
2509 static int
integerValidate(Syntax * syntax,struct berval * in)2510 integerValidate(
2511           Syntax *syntax,
2512           struct berval *in )
2513 {
2514           ber_len_t i;
2515           struct berval val = *in;
2516 
2517           if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
2518 
2519           if ( val.bv_val[0] == '-' ) {
2520                     val.bv_len--;
2521                     val.bv_val++;
2522 
2523                     if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
2524                               return LDAP_INVALID_SYNTAX;
2525                     }
2526 
2527                     if( val.bv_val[0] == '0' ) { /* "-0" */
2528                               return LDAP_INVALID_SYNTAX;
2529                     }
2530 
2531           } else if ( val.bv_val[0] == '0' ) {
2532                     if( val.bv_len > 1 ) { /* "0<more>" */
2533                               return LDAP_INVALID_SYNTAX;
2534                     }
2535 
2536                     return LDAP_SUCCESS;
2537           }
2538 
2539           for( i=0; i < val.bv_len; i++ ) {
2540                     if( !ASCII_DIGIT(val.bv_val[i]) ) {
2541                               return LDAP_INVALID_SYNTAX;
2542                     }
2543           }
2544 
2545           return LDAP_SUCCESS;
2546 }
2547 
2548 static int
integerMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)2549 integerMatch(
2550           int *matchp,
2551           slap_mask_t flags,
2552           Syntax *syntax,
2553           MatchingRule *mr,
2554           struct berval *value,
2555           void *assertedValue )
2556 {
2557           struct berval *asserted = (struct berval *) assertedValue;
2558           int vsign = 1, asign = 1;     /* default sign = '+' */
2559           struct berval v, a;
2560           int match;
2561 
2562           v = *value;
2563           if( v.bv_val[0] == '-' ) {
2564                     vsign = -1;
2565                     v.bv_val++;
2566                     v.bv_len--;
2567           }
2568 
2569           if( BER_BVISEMPTY( &v ) ) vsign = 0;
2570 
2571           a = *asserted;
2572           if( a.bv_val[0] == '-' ) {
2573                     asign = -1;
2574                     a.bv_val++;
2575                     a.bv_len--;
2576           }
2577 
2578           if( BER_BVISEMPTY( &a ) ) vsign = 0;
2579 
2580           match = vsign - asign;
2581           if( match == 0 ) {
2582                     match = ( v.bv_len != a.bv_len
2583                               ? ( v.bv_len < a.bv_len ? -1 : 1 )
2584                               : memcmp( v.bv_val, a.bv_val, v.bv_len ));
2585                     if( vsign < 0 ) match = -match;
2586           }
2587 
2588           /* Ordering rule used in extensible match filter? */
2589           if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
2590                     match = (match >= 0);
2591 
2592           *matchp = match;
2593           return LDAP_SUCCESS;
2594 }
2595 
2596 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
2597 #define INDEX_INTLEN_CHOP 7
2598 #define INDEX_INTLEN_CHOPBYTES 3
2599 
2600 static int
integerVal2Key(struct berval * in,struct berval * key,struct berval * tmp,void * ctx)2601 integerVal2Key(
2602           struct berval *in,
2603           struct berval *key,
2604           struct berval *tmp,
2605           void *ctx )
2606 {
2607           /* Integer index key format, designed for memcmp to collate correctly:
2608            * if too large: one's complement sign*<approx exponent=chopped bytes>,
2609            * two's complement value (sign-extended or chopped as needed),
2610            * however in first byte above, the top <number of exponent-bytes + 1>
2611            * bits are the inverse sign and next bit is the sign as delimiter.
2612            */
2613           ber_slen_t k = index_intlen_strlen;
2614           ber_len_t chop = 0;
2615           unsigned signmask = ~0x7fU;
2616           unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
2617           struct berval val = *in, itmp = *tmp;
2618 
2619           if ( val.bv_val[0] != '-' ) {
2620                     neg = 0;
2621                     --k;
2622           }
2623 
2624           /* Chop least significant digits, increase length instead */
2625           if ( val.bv_len > (ber_len_t) k ) {
2626                     chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
2627                     val.bv_len -= chop * INDEX_INTLEN_CHOP; /* #digits chopped */
2628                     chop *= INDEX_INTLEN_CHOPBYTES;                   /* #bytes added */
2629           }
2630 
2631           if ( lutil_str2bin( &val, &itmp, ctx )) {
2632                     return LDAP_INVALID_SYNTAX;
2633           }
2634 
2635           /* Omit leading sign byte */
2636           if ( itmp.bv_val[0] == neg ) {
2637                     itmp.bv_val++;
2638                     itmp.bv_len--;
2639           }
2640 
2641           k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
2642           if ( k > 0 ) {
2643                     assert( chop == 0 );
2644                     memset( key->bv_val, neg, k );          /* sign-extend */
2645           } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
2646                     /* Got exponent -k, or no room for 2 sign bits */
2647                     lenp = lenbuf + sizeof(lenbuf);
2648                     chop = - (ber_len_t) k;
2649                     do {
2650                               *--lenp = ((unsigned char) chop & 0xff) ^ neg;
2651                               signmask >>= 1;
2652                     } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
2653                     /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
2654                      * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
2655                     k = (lenbuf + sizeof(lenbuf)) - lenp;
2656                     if ( k > (ber_slen_t) index_intlen )
2657                               k = index_intlen;
2658                     memcpy( key->bv_val, lenp, k );
2659                     itmp.bv_len = index_intlen - k;
2660           }
2661           memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
2662           key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
2663           return 0;
2664 }
2665 
2666 /* Index generation function: Ordered index */
2667 static int
integerIndexer(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,BerVarray values,BerVarray * keysp,void * ctx)2668 integerIndexer(
2669           slap_mask_t use,
2670           slap_mask_t flags,
2671           Syntax *syntax,
2672           MatchingRule *mr,
2673           struct berval *prefix,
2674           BerVarray values,
2675           BerVarray *keysp,
2676           void *ctx )
2677 {
2678           char ibuf[64];
2679           struct berval itmp;
2680           BerVarray keys;
2681           ber_len_t vlen;
2682           int i, rc;
2683           unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2684 
2685           /* count the values and find max needed length */
2686           vlen = 0;
2687           for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2688                     if ( vlen < values[i].bv_len )
2689                               vlen = values[i].bv_len;
2690           }
2691           if ( vlen > maxstrlen )
2692                     vlen = maxstrlen;
2693 
2694           /* we should have at least one value at this point */
2695           assert( i > 0 );
2696 
2697           keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
2698           for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
2699                     keys[i].bv_len = index_intlen;
2700                     keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
2701           }
2702           keys[i].bv_len = 0;
2703           keys[i].bv_val = NULL;
2704 
2705           if ( vlen > sizeof(ibuf) ) {
2706                     itmp.bv_val = slap_sl_malloc( vlen, ctx );
2707           } else {
2708                     itmp.bv_val = ibuf;
2709           }
2710           itmp.bv_len = sizeof(ibuf);
2711 
2712           for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
2713                     if ( itmp.bv_val != ibuf ) {
2714                               itmp.bv_len = values[i].bv_len;
2715                               if ( itmp.bv_len <= sizeof(ibuf) )
2716                                         itmp.bv_len = sizeof(ibuf);
2717                               else if ( itmp.bv_len > maxstrlen )
2718                                         itmp.bv_len = maxstrlen;
2719                     }
2720                     rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
2721                     if ( rc ) {
2722                               slap_sl_free( keys, ctx );
2723                               goto func_leave;
2724                     }
2725           }
2726           *keysp = keys;
2727 func_leave:
2728           if ( itmp.bv_val != ibuf ) {
2729                     slap_sl_free( itmp.bv_val, ctx );
2730           }
2731           return rc;
2732 }
2733 
2734 /* Index generation function: Ordered index */
2735 static int
integerFilter(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,void * assertedValue,BerVarray * keysp,void * ctx)2736 integerFilter(
2737           slap_mask_t use,
2738           slap_mask_t flags,
2739           Syntax *syntax,
2740           MatchingRule *mr,
2741           struct berval *prefix,
2742           void * assertedValue,
2743           BerVarray *keysp,
2744           void *ctx )
2745 {
2746           char ibuf[64];
2747           struct berval iv;
2748           BerVarray keys;
2749           struct berval *value;
2750           int rc;
2751 
2752           value = (struct berval *) assertedValue;
2753 
2754           keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
2755 
2756           keys[0].bv_len = index_intlen;
2757           keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
2758           keys[1].bv_len = 0;
2759           keys[1].bv_val = NULL;
2760 
2761           iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
2762                     ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
2763           if ( iv.bv_len > (int) sizeof(ibuf) ) {
2764                     iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
2765           } else {
2766                     iv.bv_val = ibuf;
2767                     iv.bv_len = sizeof(ibuf);
2768           }
2769 
2770           rc = integerVal2Key( value, keys, &iv, ctx );
2771 
2772           if ( iv.bv_val != ibuf ) {
2773                     slap_sl_free( iv.bv_val, ctx );
2774           }
2775 
2776           if ( rc == 0 )
2777                     *keysp = keys;
2778           else
2779                     slap_sl_free( keys, ctx );
2780 
2781           return rc;
2782 }
2783 
2784 static int
countryStringValidate(Syntax * syntax,struct berval * val)2785 countryStringValidate(
2786           Syntax *syntax,
2787           struct berval *val )
2788 {
2789           if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
2790 
2791           if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
2792                     return LDAP_INVALID_SYNTAX;
2793           }
2794           if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
2795                     return LDAP_INVALID_SYNTAX;
2796           }
2797 
2798           return LDAP_SUCCESS;
2799 }
2800 
2801 static int
printableStringValidate(Syntax * syntax,struct berval * val)2802 printableStringValidate(
2803           Syntax *syntax,
2804           struct berval *val )
2805 {
2806           ber_len_t i;
2807 
2808           if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2809 
2810           for(i=0; i < val->bv_len; i++) {
2811                     if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
2812                               return LDAP_INVALID_SYNTAX;
2813                     }
2814           }
2815 
2816           return LDAP_SUCCESS;
2817 }
2818 
2819 static int
printablesStringValidate(Syntax * syntax,struct berval * val)2820 printablesStringValidate(
2821           Syntax *syntax,
2822           struct berval *val )
2823 {
2824           ber_len_t i, len;
2825 
2826           if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
2827 
2828           for(i=0,len=0; i < val->bv_len; i++) {
2829                     int c = val->bv_val[i];
2830 
2831                     if( c == '$' ) {
2832                               if( len == 0 ) {
2833                                         return LDAP_INVALID_SYNTAX;
2834                               }
2835                               len = 0;
2836 
2837                     } else if ( SLAP_PRINTABLE(c) ) {
2838                               len++;
2839                     } else {
2840                               return LDAP_INVALID_SYNTAX;
2841                     }
2842           }
2843 
2844           if( len == 0 ) {
2845                     return LDAP_INVALID_SYNTAX;
2846           }
2847 
2848           return LDAP_SUCCESS;
2849 }
2850 
2851 static int
IA5StringValidate(Syntax * syntax,struct berval * val)2852 IA5StringValidate(
2853           Syntax *syntax,
2854           struct berval *val )
2855 {
2856           ber_len_t i;
2857 
2858           for(i=0; i < val->bv_len; i++) {
2859                     if( !LDAP_ASCII(val->bv_val[i]) ) {
2860                               return LDAP_INVALID_SYNTAX;
2861                     }
2862           }
2863 
2864           return LDAP_SUCCESS;
2865 }
2866 
2867 static int
IA5StringNormalize(slap_mask_t use,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)2868 IA5StringNormalize(
2869           slap_mask_t use,
2870           Syntax *syntax,
2871           MatchingRule *mr,
2872           struct berval *val,
2873           struct berval *normalized,
2874           void *ctx )
2875 {
2876           char *p, *q, *end;
2877           int casefold = !SLAP_MR_ASSOCIATED( mr,
2878                     slap_schema.si_mr_caseExactIA5Match );
2879 
2880           assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
2881 
2882           p = val->bv_val;
2883           end = val->bv_val + val->bv_len;
2884 
2885           /* Ignore initial whitespace */
2886           while ( p < end && ASCII_SPACE( *p ) ) p++;
2887 
2888           normalized->bv_len = p < end ? (val->bv_len - ( p - val->bv_val )) : 0;
2889           normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
2890           AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
2891           normalized->bv_val[normalized->bv_len] = '\0';
2892 
2893           p = q = normalized->bv_val;
2894 
2895           while ( *p ) {
2896                     if ( ASCII_SPACE( *p ) ) {
2897                               *q++ = *p++;
2898 
2899                               /* Ignore the extra whitespace */
2900                               while ( ASCII_SPACE( *p ) ) {
2901                                         p++;
2902                               }
2903 
2904                     } else if ( casefold ) {
2905                               /* Most IA5 rules require casefolding */
2906                               *q++ = TOLOWER(*p); p++;
2907 
2908                     } else {
2909                               *q++ = *p++;
2910                     }
2911           }
2912 
2913           assert( normalized->bv_val <= p );
2914           assert( q <= p );
2915 
2916           /*
2917            * If the string ended in space, backup the pointer one
2918            * position.  One is enough because the above loop collapsed
2919            * all whitespace to a single space.
2920            */
2921           if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
2922 
2923           /* null terminate */
2924           *q = '\0';
2925 
2926           normalized->bv_len = q - normalized->bv_val;
2927 
2928           return LDAP_SUCCESS;
2929 }
2930 
2931 static int
UUIDValidate(Syntax * syntax,struct berval * in)2932 UUIDValidate(
2933           Syntax *syntax,
2934           struct berval *in )
2935 {
2936           int i;
2937           if( in->bv_len != 36 ) {
2938                     return LDAP_INVALID_SYNTAX;
2939           }
2940 
2941           for( i=0; i<36; i++ ) {
2942                     switch(i) {
2943                               case 8:
2944                               case 13:
2945                               case 18:
2946                               case 23:
2947                                         if( in->bv_val[i] != '-' ) {
2948                                                   return LDAP_INVALID_SYNTAX;
2949                                         }
2950                                         break;
2951                               default:
2952                                         if( !ASCII_HEX( in->bv_val[i]) ) {
2953                                                   return LDAP_INVALID_SYNTAX;
2954                                         }
2955                     }
2956           }
2957 
2958           return LDAP_SUCCESS;
2959 }
2960 
2961 static int
UUIDPretty(Syntax * syntax,struct berval * in,struct berval * out,void * ctx)2962 UUIDPretty(
2963           Syntax *syntax,
2964           struct berval *in,
2965           struct berval *out,
2966           void *ctx )
2967 {
2968           int i;
2969           int rc=LDAP_INVALID_SYNTAX;
2970 
2971           assert( in != NULL );
2972           assert( out != NULL );
2973 
2974           if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
2975 
2976           out->bv_len = 36;
2977           out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
2978 
2979           for( i=0; i<36; i++ ) {
2980                     switch(i) {
2981                               case 8:
2982                               case 13:
2983                               case 18:
2984                               case 23:
2985                                         if( in->bv_val[i] != '-' ) {
2986                                                   goto handle_error;
2987                                         }
2988                                         out->bv_val[i] = '-';
2989                                         break;
2990 
2991                               default:
2992                                         if( !ASCII_HEX( in->bv_val[i]) ) {
2993                                                   goto handle_error;
2994                                         }
2995                                         out->bv_val[i] = TOLOWER( in->bv_val[i] );
2996                     }
2997           }
2998 
2999           rc = LDAP_SUCCESS;
3000           out->bv_val[ out->bv_len ] = '\0';
3001 
3002           if( 0 ) {
3003 handle_error:
3004                     slap_sl_free( out->bv_val, ctx );
3005                     out->bv_val = NULL;
3006           }
3007 
3008           return rc;
3009 }
3010 
3011 int
UUIDNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)3012 UUIDNormalize(
3013           slap_mask_t usage,
3014           Syntax *syntax,
3015           MatchingRule *mr,
3016           struct berval *val,
3017           struct berval *normalized,
3018           void *ctx )
3019 {
3020           unsigned char octet = '\0';
3021           int i;
3022           int j;
3023 
3024           if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
3025                     /* NOTE: must be a normalized UUID */
3026                     if( val->bv_len != 16 )
3027                               return LDAP_INVALID_SYNTAX;
3028 
3029                     normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
3030                     normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
3031                               val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
3032                     if( normalized->bv_len != STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) )
3033                               return LDAP_INVALID_SYNTAX;
3034 
3035                     return LDAP_SUCCESS;
3036           }
3037 
3038           normalized->bv_len = 16;
3039           normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
3040 
3041           for( i=0, j=0; i<36; i++ ) {
3042                     unsigned char nibble;
3043                     if( val->bv_val[i] == '-' ) {
3044                               continue;
3045 
3046                     } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
3047                               nibble = val->bv_val[i] - '0';
3048 
3049                     } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
3050                               nibble = val->bv_val[i] - ('a'-10);
3051 
3052                     } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
3053                               nibble = val->bv_val[i] - ('A'-10);
3054 
3055                     } else {
3056                               slap_sl_free( normalized->bv_val, ctx );
3057                               BER_BVZERO( normalized );
3058                               return LDAP_INVALID_SYNTAX;
3059                     }
3060 
3061                     if( j & 1 ) {
3062                               octet |= nibble;
3063                               normalized->bv_val[j>>1] = octet;
3064                     } else {
3065                               octet = nibble << 4;
3066                     }
3067                     j++;
3068           }
3069 
3070           normalized->bv_val[normalized->bv_len] = 0;
3071           return LDAP_SUCCESS;
3072 }
3073 
3074 
3075 
3076 int
numericStringValidate(Syntax * syntax,struct berval * in)3077 numericStringValidate(
3078           Syntax *syntax,
3079           struct berval *in )
3080 {
3081           ber_len_t i;
3082 
3083           if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
3084 
3085           for(i=0; i < in->bv_len; i++) {
3086                     if( !SLAP_NUMERIC(in->bv_val[i]) ) {
3087                               return LDAP_INVALID_SYNTAX;
3088                     }
3089           }
3090 
3091           return LDAP_SUCCESS;
3092 }
3093 
3094 static int
numericStringNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)3095 numericStringNormalize(
3096           slap_mask_t usage,
3097           Syntax *syntax,
3098           MatchingRule *mr,
3099           struct berval *val,
3100           struct berval *normalized,
3101           void *ctx )
3102 {
3103           /* removal all spaces */
3104           char *p, *q;
3105 
3106           assert( !BER_BVISEMPTY( val ) );
3107 
3108           normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
3109 
3110           p = val->bv_val;
3111           q = normalized->bv_val;
3112 
3113           while ( *p ) {
3114                     if ( ASCII_SPACE( *p ) ) {
3115                               /* Ignore whitespace */
3116                               p++;
3117                     } else {
3118                               *q++ = *p++;
3119                     }
3120           }
3121 
3122           /* we should have copied no more than is in val */
3123           assert( (q - normalized->bv_val) <= (p - val->bv_val) );
3124 
3125           /* null terminate */
3126           *q = '\0';
3127 
3128           normalized->bv_len = q - normalized->bv_val;
3129 
3130           if( BER_BVISEMPTY( normalized ) ) {
3131                     normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
3132                     normalized->bv_val[0] = ' ';
3133                     normalized->bv_val[1] = '\0';
3134                     normalized->bv_len = 1;
3135           }
3136 
3137           return LDAP_SUCCESS;
3138 }
3139 
3140 /*
3141  * Integer conversion macros that will use the largest available
3142  * type.
3143  */
3144 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
3145 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b)
3146 # define SLAP_LONG           long long
3147 #else
3148 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
3149 # define SLAP_LONG           long
3150 #endif /* HAVE_STRTOLL ... */
3151 
3152 static int
integerBitAndMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)3153 integerBitAndMatch(
3154           int *matchp,
3155           slap_mask_t flags,
3156           Syntax *syntax,
3157           MatchingRule *mr,
3158           struct berval *value,
3159           void *assertedValue )
3160 {
3161           SLAP_LONG lValue, lAssertedValue;
3162 
3163           errno = 0;
3164           /* safe to assume integers are NUL terminated? */
3165           lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3166           if( errno == ERANGE )
3167           {
3168                     return LDAP_CONSTRAINT_VIOLATION;
3169           }
3170 
3171           lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
3172                     NULL, 10);
3173           if( errno == ERANGE )
3174           {
3175                     return LDAP_CONSTRAINT_VIOLATION;
3176           }
3177 
3178           *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
3179           return LDAP_SUCCESS;
3180 }
3181 
3182 static int
integerBitOrMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)3183 integerBitOrMatch(
3184           int *matchp,
3185           slap_mask_t flags,
3186           Syntax *syntax,
3187           MatchingRule *mr,
3188           struct berval *value,
3189           void *assertedValue )
3190 {
3191           SLAP_LONG lValue, lAssertedValue;
3192 
3193           errno = 0;
3194           /* safe to assume integers are NUL terminated? */
3195           lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
3196           if( errno == ERANGE )
3197           {
3198                     return LDAP_CONSTRAINT_VIOLATION;
3199           }
3200 
3201           lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
3202                     NULL, 10);
3203           if( errno == ERANGE )
3204           {
3205                     return LDAP_CONSTRAINT_VIOLATION;
3206           }
3207 
3208           *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
3209           return LDAP_SUCCESS;
3210 }
3211 
3212 static int
checkNum(struct berval * in,struct berval * out)3213 checkNum( struct berval *in, struct berval *out )
3214 {
3215           /* parse serialNumber */
3216           ber_len_t neg = 0, extra = 0;
3217           char first = '\0';
3218 
3219           out->bv_val = in->bv_val;
3220           out->bv_len = 0;
3221 
3222           if ( out->bv_val[0] == '-' ) {
3223                     neg++;
3224                     out->bv_len++;
3225           }
3226 
3227           if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
3228                     first = out->bv_val[2];
3229                     extra = 2;
3230 
3231                     out->bv_len += STRLENOF("0x");
3232                     for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3233                               if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3234                     }
3235 
3236           } else if ( out->bv_val[0] == '\'' ) {
3237                     first = out->bv_val[1];
3238                     extra = 3;
3239 
3240                     out->bv_len += STRLENOF("'");
3241 
3242                     for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3243                               if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
3244                     }
3245                     if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
3246                               return -1;
3247                     }
3248                     out->bv_len += STRLENOF("'H");
3249 
3250           } else {
3251                     first = out->bv_val[0];
3252                     for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
3253                               if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
3254                     }
3255           }
3256 
3257           if ( !( out->bv_len > neg ) ) {
3258                     return -1;
3259           }
3260 
3261           if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
3262                     return -1;
3263           }
3264 
3265           return 0;
3266 }
3267 
3268 static int
serialNumberAndIssuerCheck(struct berval * in,struct berval * sn,struct berval * is,void * ctx)3269 serialNumberAndIssuerCheck(
3270           struct berval *in,
3271           struct berval *sn,
3272           struct berval *is,
3273           void *ctx )
3274 {
3275           ber_len_t n;
3276 
3277           if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
3278 
3279           if( in->bv_val[0] != '{' || in->bv_val[in->bv_len-1] != '}' ) {
3280                     /* Parse old format */
3281                     is->bv_val = ber_bvchr( in, '$' );
3282                     if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
3283 
3284                     sn->bv_val = in->bv_val;
3285                     sn->bv_len = is->bv_val - in->bv_val;
3286 
3287                     is->bv_val++;
3288                     is->bv_len = in->bv_len - (sn->bv_len + 1);
3289 
3290                     /* eat leading zeros */
3291                     for( n=0; n < (sn->bv_len-1); n++ ) {
3292                               if( sn->bv_val[n] != '0' ) break;
3293                     }
3294                     sn->bv_val += n;
3295                     sn->bv_len -= n;
3296 
3297                     for( n=0; n < sn->bv_len; n++ ) {
3298                               if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
3299                     }
3300 
3301           } else {
3302                     /* Parse GSER format */
3303                     enum {
3304                               HAVE_NONE = 0x0,
3305                               HAVE_ISSUER = 0x1,
3306                               HAVE_SN = 0x2,
3307                               HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
3308                     } have = HAVE_NONE;
3309 
3310                     int numdquotes = 0, gotquote;
3311                     struct berval x = *in;
3312                     struct berval ni;
3313                     x.bv_val++;
3314                     x.bv_len -= 2;
3315 
3316                     do {
3317                               /* eat leading spaces */
3318                               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3319                                         /* empty */;
3320                               }
3321 
3322                               /* should be at issuer or serialNumber NamedValue */
3323                               if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3324                                         if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3325 
3326                                         /* parse issuer */
3327                                         x.bv_val += STRLENOF("issuer");
3328                                         x.bv_len -= STRLENOF("issuer");
3329 
3330                                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3331                                         x.bv_val++;
3332                                         x.bv_len--;
3333 
3334                                         /* eat leading spaces */
3335                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3336                                                   /* empty */;
3337                                         }
3338 
3339                                         /* For backward compatibility, this part is optional */
3340                                         if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
3341                                                   x.bv_val += STRLENOF("rdnSequence:");
3342                                                   x.bv_len -= STRLENOF("rdnSequence:");
3343                                         }
3344 
3345                                         if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3346                                         x.bv_val++;
3347                                         x.bv_len--;
3348 
3349                                         is->bv_val = x.bv_val;
3350                                         is->bv_len = 0;
3351 
3352                                         for ( gotquote=0; is->bv_len < x.bv_len; ) {
3353                                                   if ( is->bv_val[is->bv_len] != '"' ) {
3354                                                             is->bv_len++;
3355                                                             continue;
3356                                                   }
3357                                                   gotquote = 1;
3358                                                   if ( is->bv_val[is->bv_len+1] == '"' ) {
3359                                                             /* double dquote */
3360                                                             numdquotes++;
3361                                                             is->bv_len += 2;
3362                                                             continue;
3363                                                   }
3364                                                   break;
3365                                         }
3366                                         if ( !gotquote ) return LDAP_INVALID_SYNTAX;
3367 
3368                                         x.bv_val += is->bv_len + 1;
3369                                         x.bv_len -= is->bv_len + 1;
3370 
3371                                         have |= HAVE_ISSUER;
3372 
3373                               } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
3374                               {
3375                                         if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
3376 
3377                                         /* parse serialNumber */
3378                                         x.bv_val += STRLENOF("serialNumber");
3379                                         x.bv_len -= STRLENOF("serialNumber");
3380 
3381                                         if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3382                                         x.bv_val++;
3383                                         x.bv_len--;
3384 
3385                                         /* eat leading spaces */
3386                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3387                                                   /* empty */;
3388                                         }
3389 
3390                                         if ( checkNum( &x, sn ) ) {
3391                                                   return LDAP_INVALID_SYNTAX;
3392                                         }
3393 
3394                                         x.bv_val += sn->bv_len;
3395                                         x.bv_len -= sn->bv_len;
3396 
3397                                         have |= HAVE_SN;
3398 
3399                               } else {
3400                                         return LDAP_INVALID_SYNTAX;
3401                               }
3402 
3403                               /* eat leading spaces */
3404                               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3405                                         /* empty */;
3406                               }
3407 
3408                               if ( have == HAVE_ALL ) {
3409                                         break;
3410                               }
3411 
3412                               if ( x.bv_val[0] != ',' ) {
3413                                         return LDAP_INVALID_SYNTAX;
3414                               }
3415 
3416                               x.bv_val++;
3417                               x.bv_len--;
3418                     } while ( 1 );
3419 
3420                     /* should have no characters left... */
3421                     if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
3422 
3423                     if ( numdquotes == 0 ) {
3424                               ber_dupbv_x( &ni, is, ctx );
3425 
3426                     } else {
3427                               ber_len_t src, dst;
3428 
3429                               ni.bv_len = is->bv_len - numdquotes;
3430                               ni.bv_val = slap_sl_malloc( ni.bv_len + 1, ctx );
3431                               for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
3432                                         if ( is->bv_val[src] == '"' ) {
3433                                                   src++;
3434                                         }
3435                                         ni.bv_val[dst] = is->bv_val[src];
3436                               }
3437                               ni.bv_val[dst] = '\0';
3438                     }
3439 
3440                     *is = ni;
3441           }
3442 
3443           return 0;
3444 }
3445 
3446 static int
serialNumberAndIssuerValidate(Syntax * syntax,struct berval * in)3447 serialNumberAndIssuerValidate(
3448           Syntax *syntax,
3449           struct berval *in )
3450 {
3451           int rc;
3452           struct berval sn, i;
3453 
3454           Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
3455                     in->bv_val );
3456 
3457           rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
3458           if ( rc ) {
3459                     goto done;
3460           }
3461 
3462           /* validate DN -- doesn't handle double dquote */
3463           rc = dnValidate( NULL, &i );
3464           if ( rc ) {
3465                     rc = LDAP_INVALID_SYNTAX;
3466           }
3467 
3468           if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3469                     slap_sl_free( i.bv_val, NULL );
3470           }
3471 
3472           Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
3473                     in->bv_val, rc );
3474 
3475 done:;
3476           return rc;
3477 }
3478 
3479 static int
serialNumberAndIssuerPretty(Syntax * syntax,struct berval * in,struct berval * out,void * ctx)3480 serialNumberAndIssuerPretty(
3481           Syntax *syntax,
3482           struct berval *in,
3483           struct berval *out,
3484           void *ctx )
3485 {
3486           int rc;
3487           struct berval sn, i, ni = BER_BVNULL;
3488           char *p;
3489 
3490           assert( in != NULL );
3491           assert( out != NULL );
3492 
3493           BER_BVZERO( out );
3494 
3495           Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
3496                     in->bv_val );
3497 
3498           rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3499           if ( rc ) {
3500                     goto done;
3501           }
3502 
3503           rc = dnPretty( syntax, &i, &ni, ctx );
3504 
3505           if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3506                     slap_sl_free( i.bv_val, ctx );
3507           }
3508 
3509           if ( rc ) {
3510                     rc = LDAP_INVALID_SYNTAX;
3511                     goto done;
3512           }
3513 
3514           /* make room from sn + "$" */
3515           out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
3516                     + sn.bv_len + ni.bv_len;
3517           out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3518 
3519           if ( out->bv_val == NULL ) {
3520                     out->bv_len = 0;
3521                     rc = LDAP_OTHER;
3522                     goto done;
3523           }
3524 
3525           p = out->bv_val;
3526           p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3527           p = lutil_strbvcopy( p, &sn );
3528           p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3529           p = lutil_strbvcopy( p, &ni );
3530           p = lutil_strcopy( p, /*{*/ "\" }" );
3531 
3532           assert( p == &out->bv_val[out->bv_len] );
3533 
3534 done:;
3535           Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
3536                     in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)" );
3537 
3538           slap_sl_free( ni.bv_val, ctx );
3539 
3540           return LDAP_SUCCESS;
3541 }
3542 
3543 static int
slap_bin2hex(struct berval * in,struct berval * out,void * ctx)3544 slap_bin2hex(
3545           struct berval *in,
3546           struct berval *out,
3547           void *ctx )
3548 
3549 {
3550           /* Use hex format. '123456789abcdef'H */
3551           unsigned char *ptr, zero = '\0';
3552           char *sptr;
3553           int first;
3554           ber_len_t i, len, nlen;
3555 
3556           assert( in != NULL );
3557           assert( !BER_BVISNULL( in ) );
3558           assert( out != NULL );
3559           assert( !BER_BVISNULL( out ) );
3560 
3561           ptr = (unsigned char *)in->bv_val;
3562           len = in->bv_len;
3563 
3564           /* Check for minimal encodings */
3565           if ( len > 1 ) {
3566                     if ( ptr[0] & 0x80 ) {
3567                               if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
3568                                         return -1;
3569                               }
3570 
3571                     } else if ( ptr[0] == 0 ) {
3572                               if ( !( ptr[1] & 0x80 ) ) {
3573                                         return -1;
3574                               }
3575                               len--;
3576                               ptr++;
3577                     }
3578 
3579           } else if ( len == 0 ) {
3580                     /* FIXME: this should not be possible,
3581                      * since a value of zero would have length 1 */
3582                     len = 1;
3583                     ptr = &zero;
3584           }
3585 
3586           first = !( ptr[0] & 0xf0U );
3587           nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
3588           if ( nlen >= out->bv_len ) {
3589                     out->bv_val = slap_sl_malloc( nlen + 1, ctx );
3590           }
3591           sptr = out->bv_val;
3592           *sptr++ = '\'';
3593           i = 0;
3594           if ( first ) {
3595                     sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
3596                     sptr++;
3597                     i = 1;
3598           }
3599           for ( ; i < len; i++ ) {
3600                     sprintf( sptr, "%02X", ptr[i] );
3601                     sptr += 2;
3602           }
3603           *sptr++ = '\'';
3604           *sptr++ = 'H';
3605           *sptr = '\0';
3606 
3607           assert( sptr == &out->bv_val[nlen] );
3608 
3609           out->bv_len = nlen;
3610 
3611           return 0;
3612 }
3613 
3614 #define SLAP_SN_BUFLEN        (64)
3615 
3616 /*
3617  * This routine is called by certificateExactNormalize when
3618  * certificateExactNormalize receives a search string instead of
3619  * a certificate. This routine checks if the search value is valid
3620  * and then returns the normalized value
3621  */
3622 static int
serialNumberAndIssuerNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * in,struct berval * out,void * ctx)3623 serialNumberAndIssuerNormalize(
3624           slap_mask_t usage,
3625           Syntax *syntax,
3626           MatchingRule *mr,
3627           struct berval *in,
3628           struct berval *out,
3629           void *ctx )
3630 {
3631           struct berval sn, sn2, sn3, i, ni;
3632           char sbuf2[SLAP_SN_BUFLEN];
3633           char sbuf3[SLAP_SN_BUFLEN];
3634           char *p;
3635           int rc;
3636 
3637           assert( in != NULL );
3638           assert( out != NULL );
3639 
3640           Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
3641                     in->bv_val );
3642 
3643           rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
3644           if ( rc ) {
3645                     return rc;
3646           }
3647 
3648           rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
3649 
3650           if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
3651                     slap_sl_free( i.bv_val, ctx );
3652           }
3653 
3654           if ( rc ) {
3655                     return LDAP_INVALID_SYNTAX;
3656           }
3657 
3658           /* Convert sn to canonical hex */
3659           sn2.bv_val = sbuf2;
3660           if ( sn.bv_len > sizeof( sbuf2 ) ) {
3661                     sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
3662           }
3663           sn2.bv_len = sn.bv_len;
3664           sn3.bv_val = sbuf3;
3665           sn3.bv_len = sizeof(sbuf3);
3666           if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
3667                     rc = LDAP_INVALID_SYNTAX;
3668                     goto func_leave;
3669           }
3670 
3671           out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3672                     + sn3.bv_len + ni.bv_len;
3673           out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
3674           if ( out->bv_val == NULL ) {
3675                     out->bv_len = 0;
3676                     rc = LDAP_OTHER;
3677                     goto func_leave;
3678           }
3679 
3680           p = out->bv_val;
3681 
3682           p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3683           p = lutil_strbvcopy( p, &sn3 );
3684           p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3685           p = lutil_strbvcopy( p, &ni );
3686           p = lutil_strcopy( p, /*{*/ "\" }" );
3687 
3688           assert( p == &out->bv_val[out->bv_len] );
3689 
3690 func_leave:
3691           Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
3692                     in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)" );
3693 
3694           if ( sn2.bv_val != sbuf2 ) {
3695                     slap_sl_free( sn2.bv_val, ctx );
3696           }
3697 
3698           if ( sn3.bv_val != sbuf3 ) {
3699                     slap_sl_free( sn3.bv_val, ctx );
3700           }
3701 
3702           slap_sl_free( ni.bv_val, ctx );
3703 
3704           return rc;
3705 }
3706 
3707 static int
certificateExactNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)3708 certificateExactNormalize(
3709           slap_mask_t usage,
3710           Syntax *syntax,
3711           MatchingRule *mr,
3712           struct berval *val,
3713           struct berval *normalized,
3714           void *ctx )
3715 {
3716           BerElementBuffer berbuf;
3717           BerElement *ber = (BerElement *)&berbuf;
3718           ber_tag_t tag;
3719           ber_len_t len;
3720           ber_int_t i;
3721           char serialbuf2[SLAP_SN_BUFLEN];
3722           struct berval sn, sn2 = BER_BVNULL;
3723           struct berval issuer_dn = BER_BVNULL, bvdn;
3724           char *p;
3725           int rc = LDAP_INVALID_SYNTAX;
3726 
3727           assert( val != NULL );
3728 
3729           Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
3730                     val->bv_val, val->bv_len );
3731 
3732           if ( BER_BVISEMPTY( val ) ) goto done;
3733 
3734           if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
3735                     return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
3736           }
3737 
3738           assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
3739 
3740           ber_init2( ber, val, LBER_USE_DER );
3741           tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
3742           tag = ber_skip_tag( ber, &len );        /* Sequence */
3743           tag = ber_peek_tag( ber, &len );        /* Optional version? */
3744           if ( tag == SLAP_X509_OPT_C_VERSION ) {
3745                     tag = ber_skip_tag( ber, &len );
3746                     tag = ber_get_int( ber, &i ); /* version */
3747           }
3748 
3749           /* NOTE: move the test here from certificateValidate,
3750            * so that we can validate certs with serial longer
3751            * than sizeof(ber_int_t) */
3752           tag = ber_skip_tag( ber, &len );        /* serial */
3753           sn.bv_len = len;
3754           sn.bv_val = (char *)ber->ber_ptr;
3755           sn2.bv_val = serialbuf2;
3756           sn2.bv_len = sizeof(serialbuf2);
3757           if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
3758                     rc = LDAP_INVALID_SYNTAX;
3759                     goto done;
3760           }
3761           ber_skip_data( ber, len );
3762 
3763           tag = ber_skip_tag( ber, &len );        /* SignatureAlg */
3764           ber_skip_data( ber, len );
3765           tag = ber_peek_tag( ber, &len );        /* IssuerDN */
3766           if ( len ) {
3767                     len = ber_ptrlen( ber );
3768                     bvdn.bv_val = val->bv_val + len;
3769                     bvdn.bv_len = val->bv_len - len;
3770 
3771                     rc = dnX509normalize( &bvdn, &issuer_dn );
3772                     if ( rc != LDAP_SUCCESS ) {
3773                               rc = LDAP_INVALID_SYNTAX;
3774                               goto done;
3775                     }
3776           }
3777 
3778           normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
3779                     + sn2.bv_len + issuer_dn.bv_len;
3780           normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
3781 
3782           p = normalized->bv_val;
3783 
3784           p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
3785           p = lutil_strbvcopy( p, &sn2 );
3786           p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
3787           p = lutil_strbvcopy( p, &issuer_dn );
3788           p = lutil_strcopy( p, /*{*/ "\" }" );
3789 
3790           rc = LDAP_SUCCESS;
3791 
3792 done:
3793           Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
3794                     val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
3795 
3796           if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
3797           if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
3798 
3799           return rc;
3800 }
3801 
3802 /* X.509 PKI certificateList stuff */
3803 static int
checkTime(struct berval * in,struct berval * out)3804 checkTime( struct berval *in, struct berval *out )
3805 {
3806           int rc;
3807           ber_len_t i;
3808           char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
3809           struct berval bv;
3810 
3811           assert( in != NULL );
3812           assert( !BER_BVISNULL( in ) );
3813           assert( !BER_BVISEMPTY( in ) );
3814 
3815           if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
3816                     return -1;
3817           }
3818 
3819           if ( out != NULL ) {
3820                     assert( !BER_BVISNULL( out ) );
3821                     assert( out->bv_len >= sizeof( buf ) );
3822                     bv.bv_val = out->bv_val;
3823 
3824           } else {
3825                     bv.bv_val = buf;
3826           }
3827 
3828           for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
3829                     if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
3830           }
3831 
3832           if ( in->bv_val[i] != 'Z' ) {
3833                     return -1;
3834           }
3835           i++;
3836 
3837           if ( i != in->bv_len ) {
3838                     return -1;
3839           }
3840 
3841           if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
3842                     lutil_strncopy( bv.bv_val, in->bv_val, i );
3843                     bv.bv_len = i;
3844 
3845           } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
3846                     char *p = bv.bv_val;
3847                     if ( in->bv_val[0] < '7' ) {
3848                               p = lutil_strcopy( p, "20" );
3849 
3850                     } else {
3851                               p = lutil_strcopy( p, "19" );
3852                     }
3853                     lutil_strncopy( p, in->bv_val, i );
3854                     bv.bv_len = 2 + i;
3855 
3856           } else {
3857                     return -1;
3858           }
3859 
3860           rc = generalizedTimeValidate( NULL, &bv );
3861           if ( rc == LDAP_SUCCESS && out != NULL ) {
3862                     if ( out->bv_len > bv.bv_len ) {
3863                               out->bv_val[ bv.bv_len ] = '\0';
3864                     }
3865                     out->bv_len = bv.bv_len;
3866           }
3867 
3868           return rc != LDAP_SUCCESS;
3869 }
3870 
3871 static int
issuerAndThisUpdateCheck(struct berval * in,struct berval * is,struct berval * tu,void * ctx)3872 issuerAndThisUpdateCheck(
3873           struct berval *in,
3874           struct berval *is,
3875           struct berval *tu,
3876           void *ctx )
3877 {
3878           int numdquotes = 0;
3879           struct berval x = *in;
3880           struct berval ni = BER_BVNULL;
3881           /* Parse GSER format */
3882           enum {
3883                     HAVE_NONE = 0x0,
3884                     HAVE_ISSUER = 0x1,
3885                     HAVE_THISUPDATE = 0x2,
3886                     HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
3887           } have = HAVE_NONE;
3888 
3889 
3890           if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
3891 
3892           if ( in->bv_val[0] != '{' || in->bv_val[in->bv_len-1] != '}' ) {
3893                     return LDAP_INVALID_SYNTAX;
3894           }
3895 
3896           x.bv_val++;
3897           x.bv_len -= STRLENOF("{}");
3898 
3899           do {
3900                     /* eat leading spaces */
3901                     for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3902                               /* empty */;
3903                     }
3904 
3905                     /* should be at issuer or thisUpdate */
3906                     if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
3907                               if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
3908 
3909                               /* parse issuer */
3910                               x.bv_val += STRLENOF("issuer");
3911                               x.bv_len -= STRLENOF("issuer");
3912 
3913                               if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3914                               x.bv_val++;
3915                               x.bv_len--;
3916 
3917                               /* eat leading spaces */
3918                               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3919                                         /* empty */;
3920                               }
3921 
3922                               /* For backward compatibility, this part is optional */
3923                               if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
3924                                         return LDAP_INVALID_SYNTAX;
3925                               }
3926                               x.bv_val += STRLENOF("rdnSequence:");
3927                               x.bv_len -= STRLENOF("rdnSequence:");
3928 
3929                               if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3930                               x.bv_val++;
3931                               x.bv_len--;
3932 
3933                               is->bv_val = x.bv_val;
3934                               is->bv_len = 0;
3935 
3936                               for ( ; is->bv_len < x.bv_len; ) {
3937                                         if ( is->bv_val[is->bv_len] != '"' ) {
3938                                                   is->bv_len++;
3939                                                   continue;
3940                                         }
3941                                         if ( is->bv_val[is->bv_len+1] == '"' ) {
3942                                                   /* double dquote */
3943                                                   numdquotes++;
3944                                                   is->bv_len += 2;
3945                                                   continue;
3946                                         }
3947                                         break;
3948                               }
3949                               x.bv_val += is->bv_len + 1;
3950                               x.bv_len -= is->bv_len + 1;
3951 
3952                               have |= HAVE_ISSUER;
3953 
3954                     } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
3955                     {
3956                               if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
3957 
3958                               /* parse thisUpdate */
3959                               x.bv_val += STRLENOF("thisUpdate");
3960                               x.bv_len -= STRLENOF("thisUpdate");
3961 
3962                               if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
3963                               x.bv_val++;
3964                               x.bv_len--;
3965 
3966                               /* eat leading spaces */
3967                               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3968                                         /* empty */;
3969                               }
3970 
3971                               if ( !x.bv_len || x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
3972                               x.bv_val++;
3973                               x.bv_len--;
3974 
3975                               tu->bv_val = x.bv_val;
3976                               tu->bv_len = 0;
3977 
3978                               for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
3979                                         if ( tu->bv_val[tu->bv_len] == '"' ) {
3980                                                   break;
3981                                         }
3982                               }
3983                               if ( tu->bv_len < STRLENOF("YYYYmmddHHmmssZ") ) return LDAP_INVALID_SYNTAX;
3984 
3985                               x.bv_val += tu->bv_len + 1;
3986                               x.bv_len -= tu->bv_len + 1;
3987 
3988                               have |= HAVE_THISUPDATE;
3989 
3990                     } else {
3991                               return LDAP_INVALID_SYNTAX;
3992                     }
3993 
3994                     /* eat leading spaces */
3995                     for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
3996                               /* empty */;
3997                     }
3998 
3999                     if ( have == HAVE_ALL ) {
4000                               break;
4001                     }
4002 
4003                     if ( x.bv_val[0] != ',' ) {
4004                               return LDAP_INVALID_SYNTAX;
4005                     }
4006 
4007                     x.bv_val++;
4008                     x.bv_len--;
4009           } while ( 1 );
4010 
4011           /* should have no characters left... */
4012           if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
4013 
4014           if ( numdquotes == 0 ) {
4015                     ber_dupbv_x( &ni, is, ctx );
4016 
4017           } else {
4018                     ber_len_t src, dst;
4019 
4020                     ni.bv_len = is->bv_len - numdquotes;
4021                     ni.bv_val = slap_sl_malloc( ni.bv_len + 1, ctx );
4022                     for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4023                               if ( is->bv_val[src] == '"' ) {
4024                                         src++;
4025                               }
4026                               ni.bv_val[dst] = is->bv_val[src];
4027                     }
4028                     ni.bv_val[dst] = '\0';
4029           }
4030 
4031           *is = ni;
4032 
4033           return 0;
4034 }
4035 
4036 static int
issuerAndThisUpdateValidate(Syntax * syntax,struct berval * in)4037 issuerAndThisUpdateValidate(
4038           Syntax *syntax,
4039           struct berval *in )
4040 {
4041           int rc;
4042           struct berval i, tu;
4043 
4044           Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
4045                     in->bv_val );
4046 
4047           rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
4048           if ( rc ) {
4049                     goto done;
4050           }
4051 
4052           /* validate DN -- doesn't handle double dquote */
4053           rc = dnValidate( NULL, &i );
4054           if ( rc ) {
4055                     rc = LDAP_INVALID_SYNTAX;
4056 
4057           } else if ( checkTime( &tu, NULL ) ) {
4058                     rc = LDAP_INVALID_SYNTAX;
4059           }
4060 
4061           if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4062                     slap_sl_free( i.bv_val, NULL );
4063           }
4064 
4065           Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
4066                     in->bv_val, rc );
4067 
4068 done:;
4069           return rc;
4070 }
4071 
4072 static int
issuerAndThisUpdatePretty(Syntax * syntax,struct berval * in,struct berval * out,void * ctx)4073 issuerAndThisUpdatePretty(
4074           Syntax *syntax,
4075           struct berval *in,
4076           struct berval *out,
4077           void *ctx )
4078 {
4079           int rc;
4080           struct berval i, tu, ni = BER_BVNULL;
4081           char *p;
4082 
4083           assert( in != NULL );
4084           assert( out != NULL );
4085 
4086           BER_BVZERO( out );
4087 
4088           Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
4089                     in->bv_val );
4090 
4091           rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4092           if ( rc ) {
4093                     goto done;
4094           }
4095 
4096           rc = dnPretty( syntax, &i, &ni, ctx );
4097 
4098           if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4099                     slap_sl_free( i.bv_val, ctx );
4100           }
4101 
4102           if ( rc || checkTime( &tu, NULL ) ) {
4103                     rc = LDAP_INVALID_SYNTAX;
4104                     goto done;
4105           }
4106 
4107           /* make room */
4108           out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
4109                     + ni.bv_len + tu.bv_len;
4110           out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4111 
4112           if ( out->bv_val == NULL ) {
4113                     out->bv_len = 0;
4114                     rc = LDAP_OTHER;
4115                     goto done;
4116           }
4117 
4118           p = out->bv_val;
4119           p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4120           p = lutil_strbvcopy( p, &ni );
4121           p = lutil_strcopy( p, "\", thisUpdate \"" );
4122           p = lutil_strbvcopy( p, &tu );
4123           p = lutil_strcopy( p, /*{*/ "\" }" );
4124 
4125           assert( p == &out->bv_val[out->bv_len] );
4126 
4127 done:;
4128           Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
4129                     in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)" );
4130 
4131           slap_sl_free( ni.bv_val, ctx );
4132 
4133           return rc;
4134 }
4135 
4136 static int
issuerAndThisUpdateNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * in,struct berval * out,void * ctx)4137 issuerAndThisUpdateNormalize(
4138           slap_mask_t usage,
4139           Syntax *syntax,
4140           MatchingRule *mr,
4141           struct berval *in,
4142           struct berval *out,
4143           void *ctx )
4144 {
4145           struct berval i, ni, tu, tu2;
4146           char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4147           char *p;
4148           int rc;
4149 
4150           assert( in != NULL );
4151           assert( out != NULL );
4152 
4153           Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
4154                     in->bv_val );
4155 
4156           rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
4157           if ( rc ) {
4158                     return rc;
4159           }
4160 
4161           rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4162 
4163           if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4164                     slap_sl_free( i.bv_val, ctx );
4165           }
4166 
4167           tu2.bv_val = sbuf;
4168           tu2.bv_len = sizeof( sbuf );
4169           if ( rc || checkTime( &tu, &tu2 ) ) {
4170                     return LDAP_INVALID_SYNTAX;
4171           }
4172 
4173           out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4174                     + ni.bv_len + tu2.bv_len;
4175           out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4176 
4177           if ( out->bv_val == NULL ) {
4178                     out->bv_len = 0;
4179                     rc = LDAP_OTHER;
4180                     goto func_leave;
4181           }
4182 
4183           p = out->bv_val;
4184 
4185           p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
4186           p = lutil_strbvcopy( p, &ni );
4187           p = lutil_strcopy( p, "\", thisUpdate \"" );
4188           p = lutil_strbvcopy( p, &tu2 );
4189           p = lutil_strcopy( p, /*{*/ "\" }" );
4190 
4191           assert( p == &out->bv_val[out->bv_len] );
4192 
4193 func_leave:
4194           Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
4195                     in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)" );
4196 
4197           slap_sl_free( ni.bv_val, ctx );
4198 
4199           return rc;
4200 }
4201 
4202 static int
certificateListExactNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)4203 certificateListExactNormalize(
4204           slap_mask_t usage,
4205           Syntax *syntax,
4206           MatchingRule *mr,
4207           struct berval *val,
4208           struct berval *normalized,
4209           void *ctx )
4210 {
4211           BerElementBuffer berbuf;
4212           BerElement *ber = (BerElement *)&berbuf;
4213           ber_tag_t tag;
4214           ber_len_t len;
4215           ber_int_t version;
4216           struct berval issuer_dn = BER_BVNULL, bvdn,
4217                     thisUpdate, bvtu;
4218           char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
4219           int rc = LDAP_INVALID_SYNTAX;
4220 
4221           assert( val != NULL );
4222 
4223           Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
4224                     val->bv_val, val->bv_len );
4225 
4226           if ( BER_BVISEMPTY( val ) ) goto done;
4227 
4228           if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4229                     return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
4230           }
4231 
4232           assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4233 
4234           ber_init2( ber, val, LBER_USE_DER );
4235           tag = ber_skip_tag( ber, &len );        /* Signed wrapper */
4236           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4237           tag = ber_skip_tag( ber, &len );        /* Sequence */
4238           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4239           tag = ber_peek_tag( ber, &len );
4240           /* Optional version */
4241           if ( tag == LBER_INTEGER ) {
4242                     tag = ber_get_int( ber, &version );
4243                     assert( tag == LBER_INTEGER );
4244                     if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
4245           }
4246           tag = ber_skip_tag( ber, &len );        /* Signature Algorithm */
4247           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4248           ber_skip_data( ber, len );
4249 
4250           tag = ber_peek_tag( ber, &len );        /* IssuerDN */
4251           if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
4252           len = ber_ptrlen( ber );
4253           bvdn.bv_val = val->bv_val + len;
4254           bvdn.bv_len = val->bv_len - len;
4255           tag = ber_skip_tag( ber, &len );
4256           ber_skip_data( ber, len );
4257 
4258           tag = ber_skip_tag( ber, &len );        /* thisUpdate */
4259           /* Time is a CHOICE { UTCTime, GeneralizedTime } */
4260           if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
4261           bvtu.bv_val = (char *)ber->ber_ptr;
4262           bvtu.bv_len = len;
4263 
4264           rc = dnX509normalize( &bvdn, &issuer_dn );
4265           if ( rc != LDAP_SUCCESS ) {
4266                     rc = LDAP_INVALID_SYNTAX;
4267                     goto done;
4268           }
4269 
4270           thisUpdate.bv_val = tubuf;
4271           thisUpdate.bv_len = sizeof(tubuf);
4272           if ( checkTime( &bvtu, &thisUpdate ) ) {
4273                     rc = LDAP_INVALID_SYNTAX;
4274                     goto done;
4275           }
4276 
4277           normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
4278                     + issuer_dn.bv_len + thisUpdate.bv_len;
4279           normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4280 
4281           p = normalized->bv_val;
4282 
4283           p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
4284           p = lutil_strbvcopy( p, &issuer_dn );
4285           p = lutil_strcopy( p, "\", thisUpdate \"" );
4286           p = lutil_strbvcopy( p, &thisUpdate );
4287           p = lutil_strcopy( p, /*{*/ "\" }" );
4288 
4289           rc = LDAP_SUCCESS;
4290 
4291 done:
4292           Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
4293                     val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
4294 
4295           if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4296 
4297           return rc;
4298 }
4299 
4300 /* X.509 PMI serialNumberAndIssuerSerialCheck
4301 
4302 AttributeCertificateExactAssertion     ::= SEQUENCE {
4303    serialNumber              CertificateSerialNumber,
4304    issuer                    AttCertIssuer }
4305 
4306 CertificateSerialNumber ::= INTEGER
4307 
4308 AttCertIssuer ::=    [0] SEQUENCE {
4309 issuerName                     GeneralNames OPTIONAL,
4310 baseCertificateID         [0] IssuerSerial OPTIONAL,
4311 objectDigestInfo          [1] ObjectDigestInfo OPTIONAL }
4312 -- At least one component shall be present
4313 
4314 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
4315 
4316 GeneralName ::= CHOICE {
4317   otherName                 [0] INSTANCE OF OTHER-NAME,
4318   rfc822Name                [1] IA5String,
4319   dNSName                   [2] IA5String,
4320   x400Address               [3] ORAddress,
4321   directoryName             [4] Name,
4322   ediPartyName              [5] EDIPartyName,
4323   uniformResourceIdentifier [6] IA5String,
4324   iPAddress                 [7] OCTET STRING,
4325   registeredID              [8] OBJECT IDENTIFIER }
4326 
4327 IssuerSerial ::= SEQUENCE {
4328    issuer       GeneralNames,
4329    serial       CertificateSerialNumber,
4330    issuerUID UniqueIdentifier OPTIONAL }
4331 
4332 ObjectDigestInfo ::= SEQUENCE {
4333    digestedObjectType ENUMERATED {
4334       publicKey           (0),
4335       publicKeyCert       (1),
4336       otherObjectTypes    (2) },
4337    otherObjectTypeID      OBJECT IDENTIFIER OPTIONAL,
4338    digestAlgorithm        AlgorithmIdentifier,
4339    objectDigest           BIT STRING }
4340 
4341  * The way I interpret it, an assertion should look like
4342 
4343  { serialNumber 'dd'H,
4344    issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
4345             baseCertificateID { serial '1d'H,
4346                                 issuer { directoryName:rdnSequence:"cn=zzz" },
4347                                 issuerUID <value>              -- optional
4348                               },                               -- optional
4349             objectDigestInfo { ... }                           -- optional
4350           }
4351  }
4352 
4353  * with issuerName, baseCertificateID and objectDigestInfo optional,
4354  * at least one present; the way it's currently implemented, it is
4355 
4356  { serialNumber 'dd'H,
4357    issuer { baseCertificateID { serial '1d'H,
4358                                 issuer { directoryName:rdnSequence:"cn=zzz" }
4359                               }
4360           }
4361  }
4362 
4363  * with all the above parts mandatory.
4364  */
4365 static int
serialNumberAndIssuerSerialCheck(struct berval * in,struct berval * sn,struct berval * is,struct berval * i_sn,void * ctx)4366 serialNumberAndIssuerSerialCheck(
4367           struct berval *in,
4368           struct berval *sn,
4369           struct berval *is,
4370           struct berval *i_sn,          /* contain serial of baseCertificateID */
4371           void *ctx )
4372 {
4373           /* Parse GSER format */
4374           enum {
4375                     HAVE_NONE = 0x0,
4376                     HAVE_SN = 0x1,
4377                     HAVE_ISSUER = 0x2,
4378                     HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
4379           } have = HAVE_NONE, have2 = HAVE_NONE;
4380           int numdquotes = 0;
4381           struct berval x = *in;
4382           struct berval ni;
4383 
4384           if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
4385 
4386           /* no old format */
4387           if ( in->bv_val[0] != '{' || in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
4388 
4389           x.bv_val++;
4390           x.bv_len -= 2;
4391 
4392           do {
4393 
4394                     /* eat leading spaces */
4395                     for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4396                               /* empty */;
4397                     }
4398 
4399                     /* should be at issuer or serialNumber NamedValue */
4400                     if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
4401                               if ( have & HAVE_ISSUER ) {
4402                                         return LDAP_INVALID_SYNTAX;
4403                               }
4404 
4405                               /* parse IssuerSerial */
4406                               x.bv_val += STRLENOF("issuer");
4407                               x.bv_len -= STRLENOF("issuer");
4408 
4409                               if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4410                               x.bv_val++;
4411                               x.bv_len--;
4412 
4413                               /* eat leading spaces */
4414                               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4415                                         /* empty */;
4416                               }
4417 
4418                               if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4419                               x.bv_val++;
4420                               x.bv_len--;
4421 
4422                               /* eat leading spaces */
4423                               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4424                                         /* empty */;
4425                               }
4426 
4427                               if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
4428                                         return LDAP_INVALID_SYNTAX;
4429                               }
4430                               x.bv_val += STRLENOF("baseCertificateID ");
4431                               x.bv_len -= STRLENOF("baseCertificateID ");
4432 
4433                               /* eat leading spaces */
4434                               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4435                                         /* empty */;
4436                               }
4437 
4438                               if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4439                               x.bv_val++;
4440                               x.bv_len--;
4441 
4442                               do {
4443                                         /* eat leading spaces */
4444                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4445                                                   /* empty */;
4446                                         }
4447 
4448                                         /* parse issuer of baseCertificateID */
4449                                         if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
4450                                                   if ( have2 & HAVE_ISSUER ) {
4451                                                             return LDAP_INVALID_SYNTAX;
4452                                                   }
4453 
4454                                                   x.bv_val += STRLENOF("issuer ");
4455                                                   x.bv_len -= STRLENOF("issuer ");
4456 
4457                                                   /* eat leading spaces */
4458                                                   for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4459                                                             /* empty */;
4460                                                   }
4461 
4462                                                   if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
4463                                                   x.bv_val++;
4464                                                   x.bv_len--;
4465 
4466                                                   /* eat leading spaces */
4467                                                   for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4468                                                             /* empty */;
4469                                                   }
4470 
4471                                                   if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
4472                                                             return LDAP_INVALID_SYNTAX;
4473                                                   }
4474                                                   x.bv_val += STRLENOF("directoryName:rdnSequence:");
4475                                                   x.bv_len -= STRLENOF("directoryName:rdnSequence:");
4476 
4477                                                   if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
4478                                                   x.bv_val++;
4479                                                   x.bv_len--;
4480 
4481                                                   is->bv_val = x.bv_val;
4482                                                   is->bv_len = 0;
4483 
4484                                                   for ( ; is->bv_len < x.bv_len; ) {
4485                                                             if ( is->bv_val[is->bv_len] != '"' ) {
4486                                                                       is->bv_len++;
4487                                                                       continue;
4488                                                             }
4489                                                             if ( is->bv_val[is->bv_len + 1] == '"' ) {
4490                                                                       /* double dquote */
4491                                                                       numdquotes++;
4492                                                                       is->bv_len += 2;
4493                                                                       continue;
4494                                                             }
4495                                                             break;
4496                                                   }
4497                                                   x.bv_val += is->bv_len + 1;
4498                                                   x.bv_len -= is->bv_len + 1;
4499 
4500                                                   /* eat leading spaces */
4501                                                   for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4502                                                             /* empty */;
4503                                                   }
4504 
4505                                                   if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4506                                                   x.bv_val++;
4507                                                   x.bv_len--;
4508 
4509                                                   have2 |= HAVE_ISSUER;
4510 
4511                                         } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
4512                                                   if ( have2 & HAVE_SN ) {
4513                                                             return LDAP_INVALID_SYNTAX;
4514                                                   }
4515 
4516                                                   x.bv_val += STRLENOF("serial ");
4517                                                   x.bv_len -= STRLENOF("serial ");
4518 
4519                                                   /* eat leading spaces */
4520                                                   for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
4521                                                             /* empty */;
4522                                                   }
4523 
4524                                                   if ( checkNum( &x, i_sn ) ) {
4525                                                             return LDAP_INVALID_SYNTAX;
4526                                                   }
4527 
4528                                                   x.bv_val += i_sn->bv_len;
4529                                                   x.bv_len -= i_sn->bv_len;
4530 
4531                                                   have2 |= HAVE_SN;
4532 
4533                                         } else {
4534                                                   return LDAP_INVALID_SYNTAX;
4535                                         }
4536 
4537                                         /* eat leading spaces */
4538                                         for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4539                                                   /* empty */;
4540                                         }
4541 
4542                                         if ( have2 == HAVE_ALL ) {
4543                                                   break;
4544                                         }
4545 
4546                                         if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
4547                                         x.bv_val++;
4548                                         x.bv_len--;
4549                               } while ( 1 );
4550 
4551                               if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4552                               x.bv_val++;
4553                               x.bv_len--;
4554 
4555                               /* eat leading spaces */
4556                               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4557                                         /* empty */;
4558                               }
4559 
4560                               if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
4561                               x.bv_val++;
4562                               x.bv_len--;
4563 
4564                               have |= HAVE_ISSUER;
4565 
4566                     } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
4567                               if ( have & HAVE_SN ) {
4568                                         return LDAP_INVALID_SYNTAX;
4569                               }
4570 
4571                               /* parse serialNumber */
4572                               x.bv_val += STRLENOF("serialNumber");
4573                               x.bv_len -= STRLENOF("serialNumber");
4574 
4575                               if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
4576                               x.bv_val++;
4577                               x.bv_len--;
4578 
4579                               /* eat leading spaces */
4580                               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4581                                         /* empty */;
4582                               }
4583 
4584                               if ( checkNum( &x, sn ) ) {
4585                                         return LDAP_INVALID_SYNTAX;
4586                               }
4587 
4588                               x.bv_val += sn->bv_len;
4589                               x.bv_len -= sn->bv_len;
4590 
4591                               have |= HAVE_SN;
4592 
4593                     } else {
4594                               return LDAP_INVALID_SYNTAX;
4595                     }
4596 
4597                     /* eat spaces */
4598                     for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
4599                               /* empty */;
4600                     }
4601 
4602                     if ( have == HAVE_ALL ) {
4603                               break;
4604                     }
4605 
4606                     if ( x.bv_val[0] != ',' ) {
4607                               return LDAP_INVALID_SYNTAX;
4608                     }
4609                     x.bv_val++ ;
4610                     x.bv_len--;
4611           } while ( 1 );
4612 
4613           /* should have no characters left... */
4614           if( x.bv_len ) return LDAP_INVALID_SYNTAX;
4615 
4616           if ( numdquotes == 0 ) {
4617                     ber_dupbv_x( &ni, is, ctx );
4618 
4619           } else {
4620                     ber_len_t src, dst;
4621 
4622                     ni.bv_len = is->bv_len - numdquotes;
4623                     ni.bv_val = slap_sl_malloc( ni.bv_len + 1, ctx );
4624                     for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
4625                               if ( is->bv_val[src] == '"' ) {
4626                                         src++;
4627                               }
4628                               ni.bv_val[dst] = is->bv_val[src];
4629                     }
4630                     ni.bv_val[dst] = '\0';
4631           }
4632 
4633           *is = ni;
4634 
4635           /* need to handle double dquotes here */
4636           return 0;
4637 }
4638 
4639 /* X.509 PMI serialNumberAndIssuerSerialValidate */
4640 static int
serialNumberAndIssuerSerialValidate(Syntax * syntax,struct berval * in)4641 serialNumberAndIssuerSerialValidate(
4642           Syntax *syntax,
4643           struct berval *in )
4644 {
4645           int rc;
4646           struct berval sn, i, i_sn;
4647 
4648           Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
4649                     in->bv_val );
4650 
4651           rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
4652           if ( rc ) {
4653                     goto done;
4654           }
4655 
4656           /* validate DN -- doesn't handle double dquote */
4657           rc = dnValidate( NULL, &i );
4658           if ( rc ) {
4659                     rc = LDAP_INVALID_SYNTAX;
4660           }
4661 
4662           if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4663                     slap_sl_free( i.bv_val, NULL );
4664           }
4665 
4666 done:;
4667           Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
4668                     in->bv_val, rc );
4669 
4670           return rc;
4671 }
4672 
4673 /* X.509 PMI serialNumberAndIssuerSerialPretty */
4674 static int
serialNumberAndIssuerSerialPretty(Syntax * syntax,struct berval * in,struct berval * out,void * ctx)4675 serialNumberAndIssuerSerialPretty(
4676           Syntax *syntax,
4677           struct berval *in,
4678           struct berval *out,
4679           void *ctx )
4680 {
4681           struct berval sn, i, i_sn, ni = BER_BVNULL;
4682           char *p;
4683           int rc;
4684 
4685           assert( in != NULL );
4686           assert( out != NULL );
4687 
4688           Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
4689                     in->bv_val );
4690 
4691           rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4692           if ( rc ) {
4693                     goto done;
4694           }
4695 
4696           rc = dnPretty( syntax, &i, &ni, ctx );
4697 
4698           if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4699                     slap_sl_free( i.bv_val, ctx );
4700           }
4701 
4702           if ( rc ) {
4703                     rc = LDAP_INVALID_SYNTAX;
4704                     goto done;
4705           }
4706 
4707           /* make room from sn + "$" */
4708           out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4709                     + sn.bv_len + ni.bv_len + i_sn.bv_len;
4710           out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4711 
4712           if ( out->bv_val == NULL ) {
4713                     out->bv_len = 0;
4714                     rc = LDAP_OTHER;
4715                     goto done;
4716           }
4717 
4718           p = out->bv_val;
4719           p = lutil_strcopy( p, "{ serialNumber " );
4720           p = lutil_strbvcopy( p, &sn );
4721           p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4722           p = lutil_strbvcopy( p, &ni );
4723           p = lutil_strcopy( p, "\" }, serial " );
4724           p = lutil_strbvcopy( p, &i_sn );
4725           p = lutil_strcopy( p, " } } }" );
4726 
4727           assert( p == &out->bv_val[out->bv_len] );
4728 
4729 done:;
4730           Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
4731                     in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)" );
4732 
4733           slap_sl_free( ni.bv_val, ctx );
4734 
4735           return rc;
4736 }
4737 
4738 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
4739 /*
4740  * This routine is called by attributeCertificateExactNormalize
4741  * when attributeCertificateExactNormalize receives a search
4742  * string instead of a attribute certificate. This routine
4743  * checks if the search value is valid and then returns the
4744  * normalized value
4745  */
4746 static int
serialNumberAndIssuerSerialNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * in,struct berval * out,void * ctx)4747 serialNumberAndIssuerSerialNormalize(
4748           slap_mask_t usage,
4749           Syntax *syntax,
4750           MatchingRule *mr,
4751           struct berval *in,
4752           struct berval *out,
4753           void *ctx )
4754 {
4755           struct berval i, ni = BER_BVNULL,
4756                     sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
4757                     i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
4758           char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
4759                     sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
4760           char *p;
4761           int rc;
4762 
4763           assert( in != NULL );
4764           assert( out != NULL );
4765 
4766           Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
4767                     in->bv_val );
4768 
4769           rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
4770           if ( rc ) {
4771                     goto func_leave;
4772           }
4773 
4774           rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
4775 
4776           if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
4777                     slap_sl_free( i.bv_val, ctx );
4778           }
4779 
4780           if ( rc ) {
4781                     rc = LDAP_INVALID_SYNTAX;
4782                     goto func_leave;
4783           }
4784 
4785           /* Convert sn to canonical hex */
4786           sn2.bv_val = sbuf2;
4787           sn2.bv_len = sn.bv_len;
4788           if ( sn.bv_len > sizeof( sbuf2 ) ) {
4789                     sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
4790           }
4791           if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
4792                     rc = LDAP_INVALID_SYNTAX;
4793                     goto func_leave;
4794           }
4795 
4796         /* Convert i_sn to canonical hex */
4797           i_sn2.bv_val = i_sbuf2;
4798           i_sn2.bv_len = i_sn.bv_len;
4799           if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
4800                     i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
4801           }
4802           if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
4803                     rc = LDAP_INVALID_SYNTAX;
4804                     goto func_leave;
4805           }
4806 
4807           sn3.bv_val = sbuf3;
4808           sn3.bv_len = sizeof(sbuf3);
4809           if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
4810                     rc = LDAP_INVALID_SYNTAX;
4811                     goto func_leave;
4812           }
4813 
4814           i_sn3.bv_val = i_sbuf3;
4815           i_sn3.bv_len = sizeof(i_sbuf3);
4816           if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
4817                     rc = LDAP_INVALID_SYNTAX;
4818                     goto func_leave;
4819           }
4820 
4821           out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
4822                     + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
4823           out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
4824 
4825           if ( out->bv_val == NULL ) {
4826                     out->bv_len = 0;
4827                     rc = LDAP_OTHER;
4828                     goto func_leave;
4829           }
4830 
4831           p = out->bv_val;
4832 
4833           p = lutil_strcopy( p, "{ serialNumber " );
4834           p = lutil_strbvcopy( p, &sn3 );
4835           p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4836           p = lutil_strbvcopy( p, &ni );
4837           p = lutil_strcopy( p, "\" }, serial " );
4838           p = lutil_strbvcopy( p, &i_sn3 );
4839           p = lutil_strcopy( p, " } } }" );
4840 
4841           assert( p == &out->bv_val[out->bv_len] );
4842 
4843 func_leave:
4844           Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
4845                     in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)" );
4846 
4847           if ( sn2.bv_val != sbuf2 ) {
4848                     slap_sl_free( sn2.bv_val, ctx );
4849           }
4850 
4851           if ( i_sn2.bv_val != i_sbuf2 ) {
4852                     slap_sl_free( i_sn2.bv_val, ctx );
4853           }
4854 
4855           if ( sn3.bv_val != sbuf3 ) {
4856                     slap_sl_free( sn3.bv_val, ctx );
4857           }
4858 
4859           if ( i_sn3.bv_val != i_sbuf3 ) {
4860                     slap_sl_free( i_sn3.bv_val, ctx );
4861           }
4862 
4863           slap_sl_free( ni.bv_val, ctx );
4864 
4865           return rc;
4866 }
4867 
4868 /* X.509 PMI attributeCertificateExactNormalize */
4869 static int
attributeCertificateExactNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)4870 attributeCertificateExactNormalize(
4871           slap_mask_t usage,
4872           Syntax *syntax,
4873           MatchingRule *mr,
4874           struct berval *val,
4875           struct berval *normalized,
4876           void *ctx )
4877 {
4878           BerElementBuffer berbuf;
4879           BerElement *ber = (BerElement *)&berbuf;
4880           ber_tag_t tag;
4881           ber_len_t len;
4882           char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
4883           struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
4884           struct berval issuer_dn = BER_BVNULL, bvdn;
4885           char *p;
4886           int rc = LDAP_INVALID_SYNTAX;
4887 
4888           if ( BER_BVISEMPTY( val ) ) {
4889                     return rc;
4890           }
4891 
4892           if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
4893                     return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
4894           }
4895 
4896           assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
4897 
4898           ber_init2( ber, val, LBER_USE_DER );
4899           tag = ber_skip_tag( ber, &len );        /* Signed Sequence */
4900           tag = ber_skip_tag( ber, &len );        /* Sequence */
4901           tag = ber_skip_tag( ber, &len );        /* (Mandatory) version; must be v2(1) */
4902           ber_skip_data( ber, len );
4903           tag = ber_skip_tag( ber, &len );        /* Holder Sequence */
4904           ber_skip_data( ber, len );
4905 
4906           /* Issuer */
4907           tag = ber_skip_tag( ber, &len );        /* Sequence */
4908                                                             /* issuerName (GeneralNames sequence; optional)? */
4909           tag = ber_skip_tag( ber, &len );        /* baseCertificateID (sequence; optional)? */
4910           tag = ber_skip_tag( ber, &len );        /* GeneralNames (sequence) */
4911           tag = ber_skip_tag( ber, &len );        /* directoryName (we only accept this form of GeneralName) */
4912           if ( tag != SLAP_X509_GN_DIRECTORYNAME ) {
4913                     return LDAP_INVALID_SYNTAX;
4914           }
4915           tag = ber_peek_tag( ber, &len );        /* sequence of RDN */
4916           len = ber_ptrlen( ber );
4917           bvdn.bv_val = val->bv_val + len;
4918           bvdn.bv_len = val->bv_len - len;
4919           rc = dnX509normalize( &bvdn, &issuer_dn );
4920           if ( rc != LDAP_SUCCESS ) {
4921                     rc = LDAP_INVALID_SYNTAX;
4922                     goto done;
4923           }
4924 
4925           tag = ber_skip_tag( ber, &len );        /* sequence of RDN */
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;
4930                     goto done;
4931           }
4932           i_sn.bv_val = (char *)ber->ber_ptr;
4933           i_sn.bv_len = len;
4934           i_sn2.bv_val = issuer_serialbuf;
4935           i_sn2.bv_len = sizeof(issuer_serialbuf);
4936           if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
4937                     rc = LDAP_INVALID_SYNTAX;
4938                     goto done;
4939           }
4940           ber_skip_data( ber, len );
4941 
4942                                                             /* issuerUID (bitstring; optional)? */
4943                                                             /* objectDigestInfo (sequence; optional)? */
4944 
4945           tag = ber_skip_tag( ber, &len );        /* Signature (sequence) */
4946           ber_skip_data( ber, len );
4947           tag = ber_skip_tag( ber, &len );        /* serial number */
4948           if ( tag != LBER_INTEGER ) {
4949                     rc = LDAP_INVALID_SYNTAX;
4950                     goto done;
4951           }
4952           sn.bv_val = (char *)ber->ber_ptr;
4953           sn.bv_len = len;
4954           sn2.bv_val = serialbuf;
4955           sn2.bv_len = sizeof(serialbuf);
4956           if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
4957                     rc = LDAP_INVALID_SYNTAX;
4958                     goto done;
4959           }
4960           ber_skip_data( ber, len );
4961 
4962           normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }" )
4963                     + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
4964           normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
4965 
4966           p = normalized->bv_val;
4967 
4968           p = lutil_strcopy( p, "{ serialNumber " );
4969           p = lutil_strbvcopy( p, &sn2 );
4970           p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
4971           p = lutil_strbvcopy( p, &issuer_dn );
4972           p = lutil_strcopy( p, "\" }, serial " );
4973           p = lutil_strbvcopy( p, &i_sn2 );
4974           p = lutil_strcopy( p, " } } }" );
4975 
4976           Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
4977                     normalized->bv_val );
4978 
4979           rc = LDAP_SUCCESS;
4980 
4981 done:
4982           if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
4983           if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
4984           if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
4985 
4986           return rc;
4987 }
4988 
4989 
4990 static int
hexValidate(Syntax * syntax,struct berval * in)4991 hexValidate(
4992           Syntax *syntax,
4993           struct berval *in )
4994 {
4995           ber_len_t i;
4996 
4997           assert( in != NULL );
4998           assert( !BER_BVISNULL( in ) );
4999 
5000           for ( i = 0; i < in->bv_len; i++ ) {
5001                     if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
5002                               return LDAP_INVALID_SYNTAX;
5003                     }
5004           }
5005 
5006           return LDAP_SUCCESS;
5007 }
5008 
5009 /* Normalize a SID as used inside a CSN:
5010  * three-digit numeric string */
5011 static int
hexNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)5012 hexNormalize(
5013           slap_mask_t usage,
5014           Syntax *syntax,
5015           MatchingRule *mr,
5016           struct berval *val,
5017           struct berval *normalized,
5018           void *ctx )
5019 {
5020           ber_len_t i;
5021 
5022           assert( val != NULL );
5023           assert( normalized != NULL );
5024 
5025           ber_dupbv_x( normalized, val, ctx );
5026 
5027           for ( i = 0; i < normalized->bv_len; i++ ) {
5028                     if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
5029                               ber_memfree_x( normalized->bv_val, ctx );
5030                               BER_BVZERO( normalized );
5031                               return LDAP_INVALID_SYNTAX;
5032                     }
5033 
5034                     normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5035           }
5036 
5037           return LDAP_SUCCESS;
5038 }
5039 
5040 static int
sidValidate(Syntax * syntax,struct berval * in)5041 sidValidate (
5042           Syntax *syntax,
5043           struct berval *in )
5044 {
5045           assert( in != NULL );
5046           assert( !BER_BVISNULL( in ) );
5047 
5048           if ( in->bv_len != 3 ) {
5049                     return LDAP_INVALID_SYNTAX;
5050           }
5051 
5052           return hexValidate( NULL, in );
5053 }
5054 
5055 /* Normalize a SID as used inside a CSN:
5056  * three-digit numeric string */
5057 static int
sidNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)5058 sidNormalize(
5059           slap_mask_t usage,
5060           Syntax *syntax,
5061           MatchingRule *mr,
5062           struct berval *val,
5063           struct berval *normalized,
5064           void *ctx )
5065 {
5066           if ( val->bv_len != 3 ) {
5067                     return LDAP_INVALID_SYNTAX;
5068           }
5069 
5070           return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
5071 }
5072 
5073 static int
sidPretty(Syntax * syntax,struct berval * val,struct berval * out,void * ctx)5074 sidPretty(
5075           Syntax *syntax,
5076           struct berval *val,
5077           struct berval *out,
5078           void *ctx )
5079 {
5080           return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5081 }
5082 
5083 /* Normalize a SID as used inside a CSN, either as-is
5084  * (assertion value) or extracted from the CSN
5085  * (attribute value) */
5086 static int
csnSidNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)5087 csnSidNormalize(
5088           slap_mask_t usage,
5089           Syntax *syntax,
5090           MatchingRule *mr,
5091           struct berval *val,
5092           struct berval *normalized,
5093           void *ctx )
5094 {
5095           struct berval       bv;
5096           char                *ptr,
5097                               buf[ 4 ];
5098 
5099 
5100           if ( BER_BVISEMPTY( val ) ) {
5101                     return LDAP_INVALID_SYNTAX;
5102           }
5103 
5104           if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
5105                     return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
5106           }
5107 
5108           assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
5109 
5110           ptr = ber_bvchr( val, '#' );
5111           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5112                     return LDAP_INVALID_SYNTAX;
5113           }
5114 
5115           bv.bv_val = ptr + 1;
5116           bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5117 
5118           ptr = ber_bvchr( &bv, '#' );
5119           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5120                     return LDAP_INVALID_SYNTAX;
5121           }
5122 
5123           bv.bv_val = ptr + 1;
5124           bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
5125 
5126           ptr = ber_bvchr( &bv, '#' );
5127           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5128                     return LDAP_INVALID_SYNTAX;
5129           }
5130 
5131           bv.bv_len = ptr - bv.bv_val;
5132 
5133           if ( bv.bv_len == 2 ) {
5134                     /* OpenLDAP 2.3 SID */
5135                     buf[ 0 ] = '0';
5136                     buf[ 1 ] = bv.bv_val[ 0 ];
5137                     buf[ 2 ] = bv.bv_val[ 1 ];
5138                     buf[ 3 ] = '\0';
5139 
5140                     bv.bv_val = buf;
5141                     bv.bv_len = 3;
5142           }
5143 
5144           return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
5145 }
5146 
5147 static int
csnValidate(Syntax * syntax,struct berval * in)5148 csnValidate(
5149           Syntax *syntax,
5150           struct berval *in )
5151 {
5152           struct berval       bv;
5153           char                *ptr;
5154           int                 rc;
5155 
5156           assert( in != NULL );
5157 
5158           if ( BER_BVISNULL( in ) || BER_BVISEMPTY( in ) ) {
5159                     return LDAP_INVALID_SYNTAX;
5160           }
5161 
5162           bv = *in;
5163 
5164           ptr = ber_bvchr( &bv, '#' );
5165           if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
5166                     return LDAP_INVALID_SYNTAX;
5167           }
5168 
5169           bv.bv_len = ptr - bv.bv_val;
5170           if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
5171                     bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
5172           {
5173                     return LDAP_INVALID_SYNTAX;
5174           }
5175 
5176           rc = generalizedTimeValidate( NULL, &bv );
5177           if ( rc != LDAP_SUCCESS ) {
5178                     return rc;
5179           }
5180 
5181           bv.bv_val = ptr + 1;
5182           bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5183 
5184           ptr = ber_bvchr( &bv, '#' );
5185           if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5186                     return LDAP_INVALID_SYNTAX;
5187           }
5188 
5189           bv.bv_len = ptr - bv.bv_val;
5190           if ( bv.bv_len != 6 ) {
5191                     return LDAP_INVALID_SYNTAX;
5192           }
5193 
5194           rc = hexValidate( NULL, &bv );
5195           if ( rc != LDAP_SUCCESS ) {
5196                     return rc;
5197           }
5198 
5199           bv.bv_val = ptr + 1;
5200           bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5201 
5202           ptr = ber_bvchr( &bv, '#' );
5203           if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
5204                     return LDAP_INVALID_SYNTAX;
5205           }
5206 
5207           bv.bv_len = ptr - bv.bv_val;
5208           if ( bv.bv_len == 2 ) {
5209                     /* tolerate old 2-digit replica-id */
5210                     rc = hexValidate( NULL, &bv );
5211 
5212           } else {
5213                     rc = sidValidate( NULL, &bv );
5214           }
5215           if ( rc != LDAP_SUCCESS ) {
5216                     return rc;
5217           }
5218 
5219           bv.bv_val = ptr + 1;
5220           bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
5221 
5222           if ( bv.bv_len != 6 ) {
5223                     return LDAP_INVALID_SYNTAX;
5224           }
5225 
5226           return hexValidate( NULL, &bv );
5227 }
5228 
5229 /* Normalize a CSN in OpenLDAP 2.1 format */
5230 static int
csnNormalize21(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)5231 csnNormalize21(
5232           slap_mask_t usage,
5233           Syntax *syntax,
5234           MatchingRule *mr,
5235           struct berval *val,
5236           struct berval *normalized,
5237           void *ctx )
5238 {
5239           struct berval       gt, cnt, sid, mod;
5240           struct berval       bv;
5241           char                buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5242           char                *ptr;
5243           ber_len_t i;
5244 
5245           assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5246           assert( !BER_BVISEMPTY( val ) );
5247 
5248           gt = *val;
5249 
5250           ptr = ber_bvchr( &gt, '#' );
5251           if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
5252                     return LDAP_INVALID_SYNTAX;
5253           }
5254 
5255           gt.bv_len = ptr - gt.bv_val;
5256           if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
5257                     return LDAP_INVALID_SYNTAX;
5258           }
5259 
5260           if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
5261                     return LDAP_INVALID_SYNTAX;
5262           }
5263 
5264           cnt.bv_val = ptr + 1;
5265           cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5266 
5267           ptr = ber_bvchr( &cnt, '#' );
5268           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5269                     return LDAP_INVALID_SYNTAX;
5270           }
5271 
5272           cnt.bv_len = ptr - cnt.bv_val;
5273           if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
5274                     return LDAP_INVALID_SYNTAX;
5275           }
5276 
5277           if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
5278                     return LDAP_INVALID_SYNTAX;
5279           }
5280 
5281           cnt.bv_val += STRLENOF( "0x" );
5282           cnt.bv_len -= STRLENOF( "0x" );
5283 
5284           sid.bv_val = ptr + 1;
5285           sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5286 
5287           ptr = ber_bvchr( &sid, '#' );
5288           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5289                     return LDAP_INVALID_SYNTAX;
5290           }
5291 
5292           sid.bv_len = ptr - sid.bv_val;
5293           if ( sid.bv_len != STRLENOF( "0" ) ) {
5294                     return LDAP_INVALID_SYNTAX;
5295           }
5296 
5297           mod.bv_val = ptr + 1;
5298           mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5299           if ( mod.bv_len != STRLENOF( "0000" ) ) {
5300                     return LDAP_INVALID_SYNTAX;
5301           }
5302 
5303           bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5304           bv.bv_val = buf;
5305 
5306           ptr = bv.bv_val;
5307           ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
5308           ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
5309                     STRLENOF( "MM" ) );
5310           ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
5311                     STRLENOF( "SS" ) );
5312           ptr = lutil_strcopy( ptr, ".000000Z#00" );
5313           ptr = lutil_strbvcopy( ptr, &cnt );
5314           *ptr++ = '#';
5315           *ptr++ = '0';
5316           *ptr++ = '0';
5317           *ptr++ = sid.bv_val[ 0 ];
5318           *ptr++ = '#';
5319           *ptr++ = '0';
5320           *ptr++ = '0';
5321           for ( i = 0; i < mod.bv_len; i++ ) {
5322                     *ptr++ = TOLOWER( mod.bv_val[ i ] );
5323           }
5324           *ptr = '\0';
5325 
5326           assert( ptr == &bv.bv_val[bv.bv_len] );
5327 
5328           if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5329                     return LDAP_INVALID_SYNTAX;
5330           }
5331 
5332           ber_dupbv_x( normalized, &bv, ctx );
5333 
5334           return LDAP_SUCCESS;
5335 }
5336 
5337 /* Normalize a CSN in OpenLDAP 2.3 format */
5338 static int
csnNormalize23(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)5339 csnNormalize23(
5340           slap_mask_t usage,
5341           Syntax *syntax,
5342           MatchingRule *mr,
5343           struct berval *val,
5344           struct berval *normalized,
5345           void *ctx )
5346 {
5347           struct berval       gt, cnt, sid, mod;
5348           struct berval       bv;
5349           char                buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
5350           char                *ptr;
5351           ber_len_t i;
5352 
5353           assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5354           assert( !BER_BVISEMPTY( val ) );
5355 
5356           gt = *val;
5357 
5358           ptr = ber_bvchr( &gt, '#' );
5359           if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
5360                     return LDAP_INVALID_SYNTAX;
5361           }
5362 
5363           gt.bv_len = ptr - gt.bv_val;
5364           if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
5365                     return LDAP_INVALID_SYNTAX;
5366           }
5367 
5368           cnt.bv_val = ptr + 1;
5369           cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5370 
5371           ptr = ber_bvchr( &cnt, '#' );
5372           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5373                     return LDAP_INVALID_SYNTAX;
5374           }
5375 
5376           cnt.bv_len = ptr - cnt.bv_val;
5377           if ( cnt.bv_len != STRLENOF( "000000" ) ) {
5378                     return LDAP_INVALID_SYNTAX;
5379           }
5380 
5381           sid.bv_val = ptr + 1;
5382           sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5383 
5384           ptr = ber_bvchr( &sid, '#' );
5385           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5386                     return LDAP_INVALID_SYNTAX;
5387           }
5388 
5389           sid.bv_len = ptr - sid.bv_val;
5390           if ( sid.bv_len != STRLENOF( "00" ) ) {
5391                     return LDAP_INVALID_SYNTAX;
5392           }
5393 
5394           mod.bv_val = ptr + 1;
5395           mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5396           if ( mod.bv_len != STRLENOF( "000000" ) ) {
5397                     return LDAP_INVALID_SYNTAX;
5398           }
5399 
5400           bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
5401           bv.bv_val = buf;
5402 
5403           ptr = bv.bv_val;
5404           ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
5405           ptr = lutil_strcopy( ptr, ".000000Z#" );
5406           ptr = lutil_strbvcopy( ptr, &cnt );
5407           *ptr++ = '#';
5408           *ptr++ = '0';
5409           for ( i = 0; i < sid.bv_len; i++ ) {
5410                     *ptr++ = TOLOWER( sid.bv_val[ i ] );
5411           }
5412           *ptr++ = '#';
5413           for ( i = 0; i < mod.bv_len; i++ ) {
5414                     *ptr++ = TOLOWER( mod.bv_val[ i ] );
5415           }
5416           *ptr = '\0';
5417 
5418           if ( ptr != &bv.bv_val[bv.bv_len] ||
5419                     csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
5420                     return LDAP_INVALID_SYNTAX;
5421           }
5422 
5423           ber_dupbv_x( normalized, &bv, ctx );
5424 
5425           return LDAP_SUCCESS;
5426 }
5427 
5428 /* Normalize a CSN */
5429 static int
csnNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)5430 csnNormalize(
5431           slap_mask_t usage,
5432           Syntax *syntax,
5433           MatchingRule *mr,
5434           struct berval *val,
5435           struct berval *normalized,
5436           void *ctx )
5437 {
5438           struct berval       cnt, sid, mod;
5439           char                *ptr;
5440           ber_len_t i;
5441 
5442           assert( val != NULL );
5443           assert( normalized != NULL );
5444 
5445           assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
5446 
5447           if ( BER_BVISEMPTY( val ) ) {
5448                     return LDAP_INVALID_SYNTAX;
5449           }
5450 
5451           if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
5452                     /* Openldap <= 2.3 */
5453 
5454                     return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
5455           }
5456 
5457           if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
5458                     /* Openldap 2.1 */
5459 
5460                     return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
5461           }
5462 
5463           if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
5464                     return LDAP_INVALID_SYNTAX;
5465           }
5466 
5467           ptr = ber_bvchr( val, '#' );
5468           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5469                     return LDAP_INVALID_SYNTAX;
5470           }
5471 
5472           if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
5473                     return LDAP_INVALID_SYNTAX;
5474           }
5475 
5476           cnt.bv_val = ptr + 1;
5477           cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
5478 
5479           ptr = ber_bvchr( &cnt, '#' );
5480           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5481                     return LDAP_INVALID_SYNTAX;
5482           }
5483 
5484           if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
5485                     return LDAP_INVALID_SYNTAX;
5486           }
5487 
5488           sid.bv_val = ptr + 1;
5489           sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
5490 
5491           ptr = ber_bvchr( &sid, '#' );
5492           if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
5493                     return LDAP_INVALID_SYNTAX;
5494           }
5495 
5496           sid.bv_len = ptr - sid.bv_val;
5497           if ( sid.bv_len != STRLENOF( "000" ) ) {
5498                     return LDAP_INVALID_SYNTAX;
5499           }
5500 
5501           mod.bv_val = ptr + 1;
5502           mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
5503 
5504           if ( mod.bv_len != STRLENOF( "000000" ) ) {
5505                     return LDAP_INVALID_SYNTAX;
5506           }
5507 
5508           ber_dupbv_x( normalized, val, ctx );
5509 
5510           for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
5511                     i < normalized->bv_len; i++ )
5512           {
5513                     /* assume it's already validated that's all hex digits */
5514                     normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
5515           }
5516 
5517           return LDAP_SUCCESS;
5518 }
5519 
5520 static int
csnPretty(Syntax * syntax,struct berval * val,struct berval * out,void * ctx)5521 csnPretty(
5522           Syntax *syntax,
5523           struct berval *val,
5524           struct berval *out,
5525           void *ctx )
5526 {
5527           return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
5528 }
5529 
5530 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
5531 /* slight optimization - does not need the start parameter */
5532 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
5533 enum { start = 0 };
5534 #endif
5535 
5536 static int
check_time_syntax(struct berval * val,int start,int * parts,struct berval * fraction)5537 check_time_syntax (struct berval *val,
5538           int start,
5539           int *parts,
5540           struct berval *fraction)
5541 {
5542           /*
5543            * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
5544            * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
5545            * GeneralizedTime supports leap seconds, UTCTime does not.
5546            */
5547           static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
5548           static const int mdays[2][12] = {
5549                     /* non-leap years */
5550                     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
5551                     /* leap years */
5552                     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
5553           };
5554           char *p, *e;
5555           int part, c, c1, c2, tzoffset, leapyear = 0;
5556 
5557           p = val->bv_val;
5558           e = p + val->bv_len;
5559 
5560 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5561           parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
5562 #endif
5563           for (part = start; part < 7 && p < e; part++) {
5564                     c1 = *p;
5565                     if (!ASCII_DIGIT(c1)) {
5566                               break;
5567                     }
5568                     p++;
5569                     if (p == e) {
5570                               return LDAP_INVALID_SYNTAX;
5571                     }
5572                     c = *p++;
5573                     if (!ASCII_DIGIT(c)) {
5574                               return LDAP_INVALID_SYNTAX;
5575                     }
5576                     c += c1 * 10 - '0' * 11;
5577                     if ((part | 1) == 3) {
5578                               --c;
5579                               if (c < 0) {
5580                                         return LDAP_INVALID_SYNTAX;
5581                               }
5582                     }
5583                     if (c >= ceiling[part]) {
5584                               if (! (c == 60 && part == 6 && start == 0))
5585                                         return LDAP_INVALID_SYNTAX;
5586                     }
5587                     parts[part] = c;
5588           }
5589           if (part < 5 + start) {
5590                     return LDAP_INVALID_SYNTAX;
5591           }
5592           for (; part < 9; part++) {
5593                     parts[part] = 0;
5594           }
5595 
5596           /* leapyear check for the Gregorian calendar (year>1581) */
5597           if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
5598                     leapyear = 1;
5599           }
5600 
5601           if (parts[3] >= mdays[leapyear][parts[2]]) {
5602                     return LDAP_INVALID_SYNTAX;
5603           }
5604 
5605           if (start == 0) {
5606                     fraction->bv_val = p;
5607                     fraction->bv_len = 0;
5608                     if (p < e && (*p == '.' || *p == ',')) {
5609                               char *end_num;
5610                               while (++p < e && ASCII_DIGIT(*p)) {
5611                                         /* EMPTY */;
5612                               }
5613                               if (p - fraction->bv_val == 1) {
5614                                         return LDAP_INVALID_SYNTAX;
5615                               }
5616                               for (end_num = p; end_num[-1] == '0'; --end_num) {
5617                                         /* EMPTY */;
5618                               }
5619                               c = end_num - fraction->bv_val;
5620                               if (c != 1) fraction->bv_len = c;
5621                     }
5622           }
5623 
5624           if (p == e) {
5625                     /* no time zone */
5626                     return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5627           }
5628 
5629           tzoffset = *p++;
5630           switch (tzoffset) {
5631           default:
5632                     return LDAP_INVALID_SYNTAX;
5633           case 'Z':
5634                     /* UTC */
5635                     break;
5636           case '+':
5637           case '-':
5638                     for (part = 7; part < 9 && p < e; part++) {
5639                               c1 = *p;
5640                               if (!ASCII_DIGIT(c1)) {
5641                                         break;
5642                               }
5643                               p++;
5644                               if (p == e) {
5645                                         return LDAP_INVALID_SYNTAX;
5646                               }
5647                               c2 = *p++;
5648                               if (!ASCII_DIGIT(c2)) {
5649                                         return LDAP_INVALID_SYNTAX;
5650                               }
5651                               parts[part] = c1 * 10 + c2 - '0' * 11;
5652                               if (parts[part] >= ceiling[part]) {
5653                                         return LDAP_INVALID_SYNTAX;
5654                               }
5655                     }
5656                     if (part < 8 + start) {
5657                               return LDAP_INVALID_SYNTAX;
5658                     }
5659 
5660                     if (tzoffset == '-') {
5661                               /* negative offset to UTC, ie west of Greenwich */
5662                               parts[4] += parts[7];
5663                               parts[5] += parts[8];
5664                               /* offset is just hhmm, no seconds */
5665                               for (part = 6; --part >= 0; ) {
5666                                         if (part != 3) {
5667                                                   c = ceiling[part];
5668                                         } else {
5669                                                   c = mdays[leapyear][parts[2]];
5670                                         }
5671                                         if (parts[part] >= c) {
5672                                                   if (part == 0) {
5673                                                             return LDAP_INVALID_SYNTAX;
5674                                                   }
5675                                                   parts[part] -= c;
5676                                                   parts[part - 1]++;
5677                                                   continue;
5678                                         } else if (part != 5) {
5679                                                   break;
5680                                         }
5681                               }
5682                     } else {
5683                               /* positive offset to UTC, ie east of Greenwich */
5684                               parts[4] -= parts[7];
5685                               parts[5] -= parts[8];
5686                               for (part = 6; --part >= 0; ) {
5687                                         if (parts[part] < 0) {
5688                                                   if (part == 0) {
5689                                                             return LDAP_INVALID_SYNTAX;
5690                                                   }
5691                                                   if (part != 3) {
5692                                                             c = ceiling[part];
5693                                                   } else {
5694                                                             /* make first arg to % non-negative */
5695                                                             c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
5696                                                   }
5697                                                   parts[part] += c;
5698                                                   parts[part - 1]--;
5699                                                   continue;
5700                                         } else if (part != 5) {
5701                                                   break;
5702                                         }
5703                               }
5704                     }
5705           }
5706 
5707           return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
5708 }
5709 
5710 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
5711 
5712 #if 0
5713 static int
5714 xutcTimeNormalize(
5715           Syntax *syntax,
5716           struct berval *val,
5717           struct berval *normalized )
5718 {
5719           int parts[9], rc;
5720 
5721           rc = check_time_syntax(val, 1, parts, NULL);
5722           if (rc != LDAP_SUCCESS) {
5723                     return rc;
5724           }
5725 
5726           normalized->bv_val = ch_malloc( 14 );
5727           if ( normalized->bv_val == NULL ) {
5728                     return LBER_ERROR_MEMORY;
5729           }
5730 
5731           sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
5732                     parts[1], parts[2] + 1, parts[3] + 1,
5733                     parts[4], parts[5], parts[6] );
5734           normalized->bv_len = 13;
5735 
5736           return LDAP_SUCCESS;
5737 }
5738 #endif /* 0 */
5739 
5740 static int
utcTimeValidate(Syntax * syntax,struct berval * in)5741 utcTimeValidate(
5742           Syntax *syntax,
5743           struct berval *in )
5744 {
5745           int parts[9];
5746           return check_time_syntax(in, 1, parts, NULL);
5747 }
5748 
5749 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
5750 
5751 static int
generalizedTimeValidate(Syntax * syntax,struct berval * in)5752 generalizedTimeValidate(
5753           Syntax *syntax,
5754           struct berval *in )
5755 {
5756           int parts[9];
5757           struct berval fraction;
5758           return check_time_syntax(in, 0, parts, &fraction);
5759 }
5760 
5761 static int
generalizedTimeNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)5762 generalizedTimeNormalize(
5763           slap_mask_t usage,
5764           Syntax *syntax,
5765           MatchingRule *mr,
5766           struct berval *val,
5767           struct berval *normalized,
5768           void *ctx )
5769 {
5770           int parts[9], rc;
5771           unsigned int len;
5772           struct berval fraction;
5773 
5774           rc = check_time_syntax(val, 0, parts, &fraction);
5775           if (rc != LDAP_SUCCESS) {
5776                     return rc;
5777           }
5778 
5779           len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
5780           normalized->bv_val = slap_sl_malloc( len + 1, ctx );
5781           if ( BER_BVISNULL( normalized ) ) {
5782                     return LBER_ERROR_MEMORY;
5783           }
5784 
5785           sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
5786                     parts[0], parts[1], parts[2] + 1, parts[3] + 1,
5787                     parts[4], parts[5], parts[6] );
5788           if ( !BER_BVISEMPTY( &fraction ) ) {
5789                     memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
5790                               fraction.bv_val, fraction.bv_len );
5791                     normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
5792           }
5793           strcpy( normalized->bv_val + len-1, "Z" );
5794           normalized->bv_len = len;
5795 
5796           return LDAP_SUCCESS;
5797 }
5798 
5799 static int
generalizedTimeOrderingMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)5800 generalizedTimeOrderingMatch(
5801           int *matchp,
5802           slap_mask_t flags,
5803           Syntax *syntax,
5804           MatchingRule *mr,
5805           struct berval *value,
5806           void *assertedValue )
5807 {
5808           struct berval *asserted = (struct berval *) assertedValue;
5809           ber_len_t v_len  = value->bv_len;
5810           ber_len_t av_len = asserted->bv_len;
5811 
5812           /* ignore trailing 'Z' when comparing */
5813           int match = memcmp( value->bv_val, asserted->bv_val,
5814                     (v_len < av_len ? v_len : av_len) - 1 );
5815           if ( match == 0 ) match = v_len - av_len;
5816 
5817           /* If used in extensible match filter, match if value < asserted */
5818           if ( flags & SLAP_MR_EXT )
5819                     match = (match >= 0);
5820 
5821           *matchp = match;
5822           return LDAP_SUCCESS;
5823 }
5824 
5825 /* Index generation function: Ordered index */
generalizedTimeIndexer(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,BerVarray values,BerVarray * keysp,void * ctx)5826 int generalizedTimeIndexer(
5827           slap_mask_t use,
5828           slap_mask_t flags,
5829           Syntax *syntax,
5830           MatchingRule *mr,
5831           struct berval *prefix,
5832           BerVarray values,
5833           BerVarray *keysp,
5834           void *ctx )
5835 {
5836           int i, j;
5837           BerVarray keys;
5838           char tmp[5];
5839           BerValue bvtmp; /* 40 bit index */
5840           struct lutil_tm tm;
5841           struct lutil_timet tt;
5842 
5843           bvtmp.bv_len = sizeof(tmp);
5844           bvtmp.bv_val = tmp;
5845           for( i=0; values[i].bv_val != NULL; i++ ) {
5846                     /* just count them */
5847           }
5848 
5849           /* we should have at least one value at this point */
5850           assert( i > 0 );
5851 
5852           keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
5853 
5854           /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5855           for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
5856                     assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
5857                     /* Use 40 bits of time for key */
5858                     if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
5859                               lutil_tm2gtime( &tm, &tt );
5860                               tmp[0] = tt.tt_gsec & 0xff;
5861                               tmp[4] = tt.tt_sec & 0xff;
5862                               tt.tt_sec >>= 8;
5863                               tmp[3] = tt.tt_sec & 0xff;
5864                               tt.tt_sec >>= 8;
5865                               tmp[2] = tt.tt_sec & 0xff;
5866                               tt.tt_sec >>= 8;
5867                               tmp[1] = tt.tt_sec & 0xff;
5868 
5869                               ber_dupbv_x(&keys[j++], &bvtmp, ctx );
5870                     }
5871           }
5872 
5873           keys[j].bv_val = NULL;
5874           keys[j].bv_len = 0;
5875 
5876           *keysp = keys;
5877 
5878           return LDAP_SUCCESS;
5879 }
5880 
5881 /* Index generation function: Ordered index */
generalizedTimeFilter(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,void * assertedValue,BerVarray * keysp,void * ctx)5882 int generalizedTimeFilter(
5883           slap_mask_t use,
5884           slap_mask_t flags,
5885           Syntax *syntax,
5886           MatchingRule *mr,
5887           struct berval *prefix,
5888           void * assertedValue,
5889           BerVarray *keysp,
5890           void *ctx )
5891 {
5892           BerVarray keys;
5893           char tmp[5];
5894           BerValue bvtmp; /* 40 bit index */
5895           BerValue *value = (BerValue *) assertedValue;
5896           struct lutil_tm tm;
5897           struct lutil_timet tt;
5898 
5899           bvtmp.bv_len = sizeof(tmp);
5900           bvtmp.bv_val = tmp;
5901           /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
5902           /* Use 40 bits of time for key */
5903           if ( value->bv_val && value->bv_len >= 10 &&
5904                     lutil_parsetime( value->bv_val, &tm ) == 0 ) {
5905 
5906                     lutil_tm2gtime( &tm, &tt );
5907                     tmp[0] = tt.tt_gsec & 0xff;
5908                     tmp[4] = tt.tt_sec & 0xff;
5909                     tt.tt_sec >>= 8;
5910                     tmp[3] = tt.tt_sec & 0xff;
5911                     tt.tt_sec >>= 8;
5912                     tmp[2] = tt.tt_sec & 0xff;
5913                     tt.tt_sec >>= 8;
5914                     tmp[1] = tt.tt_sec & 0xff;
5915 
5916                     keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
5917                     ber_dupbv_x(keys, &bvtmp, ctx );
5918                     keys[1].bv_val = NULL;
5919                     keys[1].bv_len = 0;
5920           } else {
5921                     keys = NULL;
5922           }
5923 
5924           *keysp = keys;
5925 
5926           return LDAP_SUCCESS;
5927 }
5928 
5929 static int
deliveryMethodValidate(Syntax * syntax,struct berval * val)5930 deliveryMethodValidate(
5931           Syntax *syntax,
5932           struct berval *val )
5933 {
5934 #undef LENOF
5935 #define LENOF(s) (sizeof(s)-1)
5936           struct berval tmp = *val;
5937           /*
5938      *    DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
5939            *        pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
5940            *                  "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
5941            */
5942 again:
5943           if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
5944 
5945           switch( tmp.bv_val[0] ) {
5946           case 'a':
5947           case 'A':
5948                     if(( tmp.bv_len >= LENOF("any") ) &&
5949                               ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
5950                     {
5951                               tmp.bv_len -= LENOF("any");
5952                               tmp.bv_val += LENOF("any");
5953                               break;
5954                     }
5955                     return LDAP_INVALID_SYNTAX;
5956 
5957           case 'm':
5958           case 'M':
5959                     if(( tmp.bv_len >= LENOF("mhs") ) &&
5960                               ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
5961                     {
5962                               tmp.bv_len -= LENOF("mhs");
5963                               tmp.bv_val += LENOF("mhs");
5964                               break;
5965                     }
5966                     return LDAP_INVALID_SYNTAX;
5967 
5968           case 'p':
5969           case 'P':
5970                     if(( tmp.bv_len >= LENOF("physical") ) &&
5971                               ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
5972                     {
5973                               tmp.bv_len -= LENOF("physical");
5974                               tmp.bv_val += LENOF("physical");
5975                               break;
5976                     }
5977                     return LDAP_INVALID_SYNTAX;
5978 
5979           case 't':
5980           case 'T': /* telex or teletex or telephone */
5981                     if(( tmp.bv_len >= LENOF("telex") ) &&
5982                               ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
5983                     {
5984                               tmp.bv_len -= LENOF("telex");
5985                               tmp.bv_val += LENOF("telex");
5986                               break;
5987                     }
5988                     if(( tmp.bv_len >= LENOF("teletex") ) &&
5989                               ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
5990                     {
5991                               tmp.bv_len -= LENOF("teletex");
5992                               tmp.bv_val += LENOF("teletex");
5993                               break;
5994                     }
5995                     if(( tmp.bv_len >= LENOF("telephone") ) &&
5996                               ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
5997                     {
5998                               tmp.bv_len -= LENOF("telephone");
5999                               tmp.bv_val += LENOF("telephone");
6000                               break;
6001                     }
6002                     return LDAP_INVALID_SYNTAX;
6003 
6004           case 'g':
6005           case 'G': /* g3fax or g4fax */
6006                     if(( tmp.bv_len >= LENOF("g3fax") ) && (
6007                               ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
6008                               ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
6009                     {
6010                               tmp.bv_len -= LENOF("g3fax");
6011                               tmp.bv_val += LENOF("g3fax");
6012                               break;
6013                     }
6014                     return LDAP_INVALID_SYNTAX;
6015 
6016           case 'i':
6017           case 'I':
6018                     if(( tmp.bv_len >= LENOF("ia5") ) &&
6019                               ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
6020                     {
6021                               tmp.bv_len -= LENOF("ia5");
6022                               tmp.bv_val += LENOF("ia5");
6023                               break;
6024                     }
6025                     return LDAP_INVALID_SYNTAX;
6026 
6027           case 'v':
6028           case 'V':
6029                     if(( tmp.bv_len >= LENOF("videotex") ) &&
6030                               ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
6031                     {
6032                               tmp.bv_len -= LENOF("videotex");
6033                               tmp.bv_val += LENOF("videotex");
6034                               break;
6035                     }
6036                     return LDAP_INVALID_SYNTAX;
6037 
6038           default:
6039                     return LDAP_INVALID_SYNTAX;
6040           }
6041 
6042           if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
6043 
6044           while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
6045                     tmp.bv_len--;
6046                     tmp.bv_val++;
6047           }
6048           if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
6049                     tmp.bv_len--;
6050                     tmp.bv_val++;
6051           } else {
6052                     return LDAP_INVALID_SYNTAX;
6053           }
6054           while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
6055                     tmp.bv_len--;
6056                     tmp.bv_val++;
6057           }
6058 
6059           goto again;
6060 }
6061 
6062 static int
nisNetgroupTripleValidate(Syntax * syntax,struct berval * val)6063 nisNetgroupTripleValidate(
6064           Syntax *syntax,
6065           struct berval *val )
6066 {
6067           char *p, *e;
6068           int commas = 0;
6069 
6070           if ( BER_BVISEMPTY( val ) ) {
6071                     return LDAP_INVALID_SYNTAX;
6072           }
6073 
6074           p = (char *)val->bv_val;
6075           e = p + val->bv_len;
6076 
6077           if ( *p != '(' /*')'*/ ) {
6078                     return LDAP_INVALID_SYNTAX;
6079           }
6080 
6081           for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
6082                     if ( *p == ',' ) {
6083                               commas++;
6084                               if ( commas > 2 ) {
6085                                         return LDAP_INVALID_SYNTAX;
6086                               }
6087 
6088                     } else if ( !AD_CHAR( *p ) ) {
6089                               return LDAP_INVALID_SYNTAX;
6090                     }
6091           }
6092 
6093           if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
6094                     return LDAP_INVALID_SYNTAX;
6095           }
6096 
6097           p++;
6098 
6099           if (p != e) {
6100                     return LDAP_INVALID_SYNTAX;
6101           }
6102 
6103           return LDAP_SUCCESS;
6104 }
6105 
6106 static int
bootParameterValidate(Syntax * syntax,struct berval * val)6107 bootParameterValidate(
6108           Syntax *syntax,
6109           struct berval *val )
6110 {
6111           char *p, *e;
6112 
6113           if ( BER_BVISEMPTY( val ) ) {
6114                     return LDAP_INVALID_SYNTAX;
6115           }
6116 
6117           p = (char *)val->bv_val;
6118           e = p + val->bv_len;
6119 
6120           /* key */
6121           for (; ( p < e ) && ( *p != '=' ); p++ ) {
6122                     if ( !AD_CHAR( *p ) ) {
6123                               return LDAP_INVALID_SYNTAX;
6124                     }
6125           }
6126 
6127           if ( *p != '=' ) {
6128                     return LDAP_INVALID_SYNTAX;
6129           }
6130 
6131           /* server */
6132           for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
6133                     if ( !AD_CHAR( *p ) ) {
6134                               return LDAP_INVALID_SYNTAX;
6135                     }
6136           }
6137 
6138           if ( *p != ':' ) {
6139                     return LDAP_INVALID_SYNTAX;
6140           }
6141 
6142           /* path */
6143           for ( p++; p < e; p++ ) {
6144                     if ( !SLAP_PRINTABLE( *p ) ) {
6145                               return LDAP_INVALID_SYNTAX;
6146                     }
6147           }
6148 
6149           return LDAP_SUCCESS;
6150 }
6151 
6152 static int
firstComponentNormalize(slap_mask_t usage,Syntax * syntax,MatchingRule * mr,struct berval * val,struct berval * normalized,void * ctx)6153 firstComponentNormalize(
6154           slap_mask_t usage,
6155           Syntax *syntax,
6156           MatchingRule *mr,
6157           struct berval *val,
6158           struct berval *normalized,
6159           void *ctx )
6160 {
6161           int rc;
6162           struct berval comp;
6163           ber_len_t len;
6164 
6165           if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
6166                     ber_dupbv_x( normalized, val, ctx );
6167                     return LDAP_SUCCESS;
6168           }
6169 
6170           if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
6171 
6172           if( ! ( val->bv_val[0] == '(' /*')'*/
6173                               && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
6174                     && ! ( val->bv_val[0] == '{' /*'}'*/
6175                               && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
6176           {
6177                     return LDAP_INVALID_SYNTAX;
6178           }
6179 
6180           /* trim leading white space */
6181           for( len=1;
6182                     len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
6183                     len++ )
6184           {
6185                     /* empty */
6186           }
6187 
6188           /* grab next word */
6189           comp.bv_val = &val->bv_val[len];
6190           len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
6191           for( comp.bv_len = 0;
6192                     !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
6193                     comp.bv_len++ )
6194           {
6195                     /* empty */
6196           }
6197 
6198           if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
6199                     rc = numericoidValidate( NULL, &comp );
6200           } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
6201                     rc = integerValidate( NULL, &comp );
6202           } else {
6203                     rc = LDAP_INVALID_SYNTAX;
6204           }
6205 
6206 
6207           if( rc == LDAP_SUCCESS ) {
6208                     ber_dupbv_x( normalized, &comp, ctx );
6209           }
6210 
6211           return rc;
6212 }
6213 
6214 static char *country_gen_syn[] = {
6215           "1.3.6.1.4.1.1466.115.121.1.15",        /* Directory String */
6216           "1.3.6.1.4.1.1466.115.121.1.26",        /* IA5 String */
6217           "1.3.6.1.4.1.1466.115.121.1.44",        /* Printable String */
6218           NULL
6219 };
6220 
6221 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
6222 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
6223 
6224 static slap_syntax_defs_rec syntax_defs[] = {
6225           {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
6226                     X_BINARY X_NOT_H_R ")",
6227                     SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
6228           {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
6229                     0, NULL, NULL, NULL},
6230           {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
6231                     0, NULL, NULL, NULL},
6232           {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
6233                     X_NOT_H_R ")",
6234                     SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6235           {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
6236                     X_NOT_H_R ")",
6237                     SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6238           {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
6239                     0, NULL, bitStringValidate, NULL },
6240           {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
6241                     0, NULL, booleanValidate, NULL},
6242           {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
6243                     X_BINARY X_NOT_H_R ")",
6244                     SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6245                     NULL, certificateValidate, NULL},
6246           {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
6247                     X_BINARY X_NOT_H_R ")",
6248                     SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6249                     NULL, certificateListValidate, NULL},
6250           {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
6251                     X_BINARY X_NOT_H_R ")",
6252                     SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6253                     NULL, sequenceValidate, NULL},
6254           {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
6255                     X_BINARY X_NOT_H_R ")",
6256                     SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
6257                     NULL, attributeCertificateValidate, NULL},
6258 #if 0     /* need to go __after__ printableString */
6259           {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6260                     0, "1.3.6.1.4.1.1466.115.121.1.44",
6261                     countryStringValidate, NULL},
6262 #endif
6263           {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
6264                     SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
6265           {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
6266                     0, NULL, rdnValidate, rdnPretty},
6267 #ifdef LDAP_COMP_MATCH
6268           {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
6269                     0, NULL, allComponentsValidate, NULL},
6270           {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
6271                     0, NULL, componentFilterValidate, NULL},
6272 #endif
6273           {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
6274                     0, NULL, NULL, NULL},
6275           {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
6276                     0, NULL, deliveryMethodValidate, NULL},
6277           {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
6278                     0, NULL, UTF8StringValidate, NULL},
6279           {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
6280                     0, NULL, NULL, NULL},
6281           {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
6282                     0, NULL, NULL, NULL},
6283           {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
6284                     0, NULL, NULL, NULL},
6285           {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
6286                     0, NULL, NULL, NULL},
6287           {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
6288                     0, NULL, NULL, NULL},
6289           {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
6290                     0, NULL, printablesStringValidate, NULL},
6291           {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
6292                     SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
6293           {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
6294                     0, NULL, generalizedTimeValidate, NULL},
6295           {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
6296                     0, NULL, NULL, NULL},
6297           {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
6298                     0, NULL, IA5StringValidate, NULL},
6299           {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
6300                     0, NULL, integerValidate, NULL},
6301           {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
6302                     SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
6303           {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
6304                     0, NULL, NULL, NULL},
6305           {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
6306                     0, NULL, NULL, NULL},
6307           {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
6308                     0, NULL, NULL, NULL},
6309           {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
6310                     0, NULL, NULL, NULL},
6311           {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
6312                     0, NULL, NULL, NULL},
6313           {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
6314                     SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
6315           {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
6316                     0, NULL, NULL, NULL},
6317           {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
6318                     0, NULL, numericStringValidate, NULL},
6319           {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
6320                     0, NULL, NULL, NULL},
6321           {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
6322                     0, NULL, numericoidValidate, NULL},
6323           {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
6324                     0, NULL, IA5StringValidate, NULL},
6325           {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
6326                     0, NULL, blobValidate, NULL},
6327           {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
6328                     0, NULL, postalAddressValidate, NULL},
6329           {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
6330                     0, NULL, NULL, NULL},
6331           {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
6332                     0, NULL, NULL, NULL},
6333           {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
6334                     0, NULL, printableStringValidate, NULL},
6335           /* moved here because now depends on Directory String, IA5 String
6336            * and Printable String */
6337           {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
6338                     0, country_gen_syn, countryStringValidate, NULL},
6339           {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
6340 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
6341                     0, NULL, subtreeSpecificationValidate, NULL},
6342           {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
6343                     X_BINARY X_NOT_H_R ")",
6344                     SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
6345           {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
6346                     0, NULL, printableStringValidate, NULL},
6347           {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
6348                     0, NULL, NULL, NULL},
6349           {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
6350                     0, NULL, printablesStringValidate, NULL},
6351 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
6352           {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
6353                     0, NULL, utcTimeValidate, NULL},
6354 #endif
6355           {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
6356                     0, NULL, NULL, NULL},
6357           {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
6358                     0, NULL, NULL, NULL},
6359           {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
6360                     0, NULL, NULL, NULL},
6361           {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
6362                     0, NULL, NULL, NULL},
6363           {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
6364                     0, NULL, NULL, NULL},
6365 
6366           /* RFC 2307 NIS Syntaxes */
6367           {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
6368                     0, NULL, nisNetgroupTripleValidate, NULL},
6369           {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
6370                     0, NULL, bootParameterValidate, NULL},
6371 
6372           /* draft-zeilenga-ldap-x509 */
6373           {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
6374                     SLAP_SYNTAX_HIDE, NULL,
6375                     serialNumberAndIssuerValidate,
6376                     serialNumberAndIssuerPretty},
6377           {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
6378                     SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6379           {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
6380                     SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6381           {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
6382                     SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6383           {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
6384                     SLAP_SYNTAX_HIDE, NULL,
6385                     issuerAndThisUpdateValidate,
6386                     issuerAndThisUpdatePretty},
6387           {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
6388                     SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6389           {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
6390                     SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6391           {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
6392                     SLAP_SYNTAX_HIDE, NULL,
6393                     serialNumberAndIssuerSerialValidate,
6394                     serialNumberAndIssuerSerialPretty},
6395           {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
6396                     SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6397 
6398 #ifdef SLAPD_AUTHPASSWD
6399           /* needs updating */
6400           {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
6401                     SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
6402 #endif
6403 
6404           {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
6405                     0, NULL, UUIDValidate, UUIDPretty},
6406 
6407           {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
6408                     SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
6409 
6410           {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
6411                     SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
6412 
6413           /* OpenLDAP Void Syntax */
6414           {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
6415                     SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
6416 
6417           /* FIXME: OID is unused, but not registered yet */
6418           {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
6419                     SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
6420 
6421           /* PKCS#8 Private Keys for X.509 certificates */
6422           {"( 1.2.840.113549.1.8.1.1 DESC 'PKCS#8 PrivateKeyInfo' )",
6423                     SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, privateKeyValidate, NULL},
6424           {NULL, 0, NULL, NULL, NULL}
6425 };
6426 
6427 char *csnSIDMatchSyntaxes[] = {
6428           "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
6429           NULL
6430 };
6431 char *certificateExactMatchSyntaxes[] = {
6432           "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6433           NULL
6434 };
6435 char *certificateListExactMatchSyntaxes[] = {
6436           "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6437           NULL
6438 };
6439 char *attributeCertificateExactMatchSyntaxes[] = {
6440           attributeCertificateSyntaxOID  /* attributeCertificate */,
6441           NULL
6442 };
6443 
6444 #ifdef LDAP_COMP_MATCH
6445 char *componentFilterMatchSyntaxes[] = {
6446           "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
6447           "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
6448           attributeCertificateSyntaxOID /* attributeCertificate */,
6449           NULL
6450 };
6451 #endif
6452 
6453 char *directoryStringSyntaxes[] = {
6454           "1.3.6.1.4.1.1466.115.121.1.11" /* countryString */,
6455           "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
6456           "1.3.6.1.4.1.1466.115.121.1.50" /* telephoneNumber */,
6457           NULL
6458 };
6459 char *integerFirstComponentMatchSyntaxes[] = {
6460           "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
6461           "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
6462           NULL
6463 };
6464 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
6465           "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
6466           "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
6467           "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
6468           "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
6469           "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
6470           "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
6471           "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
6472           "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
6473           NULL
6474 };
6475 
6476 /*
6477  * Other matching rules in X.520 that we do not use (yet):
6478  *
6479  * 2.5.13.25        uTCTimeMatch
6480  * 2.5.13.26        uTCTimeOrderingMatch
6481  * 2.5.13.31*       directoryStringFirstComponentMatch
6482  * 2.5.13.32*       wordMatch
6483  * 2.5.13.33*       keywordMatch
6484  * 2.5.13.36+       certificatePairExactMatch
6485  * 2.5.13.37+       certificatePairMatch
6486  * 2.5.13.40+       algorithmIdentifierMatch
6487  * 2.5.13.41*       storedPrefixMatch
6488  * 2.5.13.42        attributeCertificateMatch
6489  * 2.5.13.43        readerAndKeyIDMatch
6490  * 2.5.13.44        attributeIntegrityMatch
6491  *
6492  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
6493  * (+) described in draft-zeilenga-ldap-x509
6494  */
6495 static slap_mrule_defs_rec mrule_defs[] = {
6496           /*
6497            * EQUALITY matching rules must be listed after associated APPROX
6498            * matching rules.  So, we list all APPROX matching rules first.
6499            */
6500           {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
6501                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6502                     SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6503                     NULL, NULL, directoryStringApproxMatch,
6504                     directoryStringApproxIndexer, directoryStringApproxFilter,
6505                     NULL},
6506 
6507           {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
6508                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6509                     SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
6510                     NULL, NULL, IA5StringApproxMatch,
6511                     IA5StringApproxIndexer, IA5StringApproxFilter,
6512                     NULL},
6513 
6514           /*
6515            * Other matching rules
6516            */
6517 
6518           {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
6519                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
6520                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6521                     NULL, NULL, octetStringMatch,
6522                     octetStringIndexer, octetStringFilter,
6523                     NULL },
6524 
6525           {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
6526                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6527                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6528                     NULL, dnNormalize, dnMatch,
6529                     octetStringIndexer, octetStringFilter,
6530                     NULL },
6531 
6532           {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
6533                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6534                     SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6535                     NULL, dnNormalize, dnRelativeMatch,
6536                     NULL, NULL,
6537                     NULL },
6538 
6539           {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
6540                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6541                     SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6542                     NULL, dnNormalize, dnRelativeMatch,
6543                     NULL, NULL,
6544                     NULL },
6545 
6546           {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
6547                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6548                     SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6549                     NULL, dnNormalize, dnRelativeMatch,
6550                     NULL, NULL,
6551                     NULL },
6552 
6553           {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
6554                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
6555                     SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
6556                     NULL, dnNormalize, dnRelativeMatch,
6557                     NULL, NULL,
6558                     NULL },
6559 
6560           {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
6561                     "SYNTAX 1.2.36.79672281.1.5.0 )",
6562                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6563                     NULL, rdnNormalize, rdnMatch,
6564                     octetStringIndexer, octetStringFilter,
6565                     NULL },
6566 
6567 #ifdef LDAP_COMP_MATCH
6568           {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
6569                     "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
6570                     SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
6571                     NULL, NULL , componentFilterMatch,
6572                     octetStringIndexer, octetStringFilter,
6573                     NULL },
6574 
6575         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
6576                 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6577                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6578                 NULL, NULL , allComponentsMatch,
6579                 octetStringIndexer, octetStringFilter,
6580                 NULL },
6581 
6582         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
6583                 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
6584                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
6585                 NULL, NULL , directoryComponentsMatch,
6586                 octetStringIndexer, octetStringFilter,
6587                 NULL },
6588 #endif
6589 
6590           {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
6591                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6592                     SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6593                     NULL, UTF8StringNormalize, octetStringMatch,
6594                     octetStringIndexer, octetStringFilter,
6595                     directoryStringApproxMatchOID },
6596 
6597           {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
6598                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6599                     SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6600                     NULL, UTF8StringNormalize, octetStringOrderingMatch,
6601                     NULL, NULL,
6602                     "caseIgnoreMatch" },
6603 
6604           {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
6605                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6606                     SLAP_MR_SUBSTR, directoryStringSyntaxes,
6607                     NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6608                     octetStringSubstringsIndexer, octetStringSubstringsFilter,
6609                     "caseIgnoreMatch" },
6610 
6611           {"( 2.5.13.5 NAME 'caseExactMatch' "
6612                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6613                     SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
6614                     NULL, UTF8StringNormalize, octetStringMatch,
6615                     octetStringIndexer, octetStringFilter,
6616                     directoryStringApproxMatchOID },
6617 
6618           {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
6619                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
6620                     SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
6621                     NULL, UTF8StringNormalize, octetStringOrderingMatch,
6622                     NULL, NULL,
6623                     "caseExactMatch" },
6624 
6625           {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
6626                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6627                     SLAP_MR_SUBSTR, directoryStringSyntaxes,
6628                     NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
6629                     octetStringSubstringsIndexer, octetStringSubstringsFilter,
6630                     "caseExactMatch" },
6631 
6632           {"( 2.5.13.8 NAME 'numericStringMatch' "
6633                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6634                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6635                     NULL, numericStringNormalize, octetStringMatch,
6636                     octetStringIndexer, octetStringFilter,
6637                     NULL },
6638 
6639           {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
6640                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
6641                     SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6642                     NULL, numericStringNormalize, octetStringOrderingMatch,
6643                     NULL, NULL,
6644                     "numericStringMatch" },
6645 
6646           {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
6647                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6648                     SLAP_MR_SUBSTR, NULL,
6649                     NULL, numericStringNormalize, octetStringSubstringsMatch,
6650                     octetStringSubstringsIndexer, octetStringSubstringsFilter,
6651                     "numericStringMatch" },
6652 
6653           {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
6654                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
6655                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6656                     NULL, postalAddressNormalize, octetStringMatch,
6657                     octetStringIndexer, octetStringFilter,
6658                     NULL },
6659 
6660           {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
6661                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6662                     SLAP_MR_SUBSTR, NULL,
6663                     NULL, postalAddressNormalize, directoryStringSubstringsMatch,
6664                     octetStringSubstringsIndexer, octetStringSubstringsFilter,
6665                     "caseIgnoreListMatch" },
6666 
6667           {"( 2.5.13.13 NAME 'booleanMatch' "
6668                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
6669                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6670                     NULL, NULL, booleanMatch,
6671                     octetStringIndexer, octetStringFilter,
6672                     NULL },
6673 
6674           {"( 2.5.13.14 NAME 'integerMatch' "
6675                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6676                     SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6677                     NULL, NULL, integerMatch,
6678                     integerIndexer, integerFilter,
6679                     NULL },
6680 
6681           {"( 2.5.13.15 NAME 'integerOrderingMatch' "
6682                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
6683                     SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6684                     NULL, NULL, integerMatch,
6685                     NULL, NULL,
6686                     "integerMatch" },
6687 
6688           {"( 2.5.13.16 NAME 'bitStringMatch' "
6689                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
6690                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6691                     NULL, NULL, octetStringMatch,
6692                     octetStringIndexer, octetStringFilter,
6693                     NULL },
6694 
6695           {"( 2.5.13.17 NAME 'octetStringMatch' "
6696                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6697                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6698                     NULL, NULL, octetStringMatch,
6699                     octetStringIndexer, octetStringFilter,
6700                     NULL },
6701 
6702           {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
6703                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6704                     SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
6705                     NULL, NULL, octetStringOrderingMatch,
6706                     NULL, NULL,
6707                     "octetStringMatch" },
6708 
6709           {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
6710                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
6711                     SLAP_MR_SUBSTR, NULL,
6712                     NULL, NULL, octetStringSubstringsMatch,
6713                     octetStringSubstringsIndexer, octetStringSubstringsFilter,
6714                     "octetStringMatch" },
6715 
6716           {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
6717                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
6718                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6719                     NULL,
6720                     telephoneNumberNormalize, octetStringMatch,
6721                     octetStringIndexer, octetStringFilter,
6722                     NULL },
6723 
6724           {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
6725                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
6726                     SLAP_MR_SUBSTR, NULL,
6727                     NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
6728                     octetStringSubstringsIndexer, octetStringSubstringsFilter,
6729                     "telephoneNumberMatch" },
6730 
6731           {"( 2.5.13.22 NAME 'presentationAddressMatch' "
6732                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
6733                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6734                     NULL, NULL, NULL, NULL, NULL, NULL },
6735 
6736           {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
6737                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
6738                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6739                     NULL, uniqueMemberNormalize, uniqueMemberMatch,
6740                     uniqueMemberIndexer, uniqueMemberFilter,
6741                     NULL },
6742 
6743           {"( 2.5.13.24 NAME 'protocolInformationMatch' "
6744                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
6745                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6746                     NULL, NULL, NULL, NULL, NULL, NULL },
6747 
6748           {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
6749                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6750                     SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6751                     NULL, generalizedTimeNormalize, octetStringMatch,
6752                     generalizedTimeIndexer, generalizedTimeFilter,
6753                     NULL },
6754 
6755           {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
6756                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
6757                     SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6758                     NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
6759                     NULL, NULL,
6760                     "generalizedTimeMatch" },
6761 
6762           {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
6763                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6764                     SLAP_MR_EQUALITY | SLAP_MR_EXT,
6765                               integerFirstComponentMatchSyntaxes,
6766                     NULL, firstComponentNormalize, integerMatch,
6767                     octetStringIndexer, octetStringFilter,
6768                     NULL },
6769 
6770           {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
6771                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
6772                     SLAP_MR_EQUALITY | SLAP_MR_EXT,
6773                               objectIdentifierFirstComponentMatchSyntaxes,
6774                     NULL, firstComponentNormalize, octetStringMatch,
6775                     octetStringIndexer, octetStringFilter,
6776                     NULL },
6777 
6778           {"( 2.5.13.34 NAME 'certificateExactMatch' "
6779                     "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
6780                     SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
6781                     NULL, certificateExactNormalize, octetStringMatch,
6782                     octetStringIndexer, octetStringFilter,
6783                     NULL },
6784 
6785           {"( 2.5.13.35 NAME 'certificateMatch' "
6786                     "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
6787                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6788                     NULL, NULL, NULL, NULL, NULL,
6789                     NULL },
6790 
6791           {"( 2.5.13.38 NAME 'certificateListExactMatch' "
6792                     "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
6793                     SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
6794                     NULL, certificateListExactNormalize, octetStringMatch,
6795                     octetStringIndexer, octetStringFilter,
6796                     NULL },
6797 
6798           {"( 2.5.13.39 NAME 'certificateListMatch' "
6799                     "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
6800                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6801                     NULL, NULL, NULL, NULL, NULL,
6802                     NULL },
6803 
6804           {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
6805                     "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
6806                     SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
6807                     NULL, attributeCertificateExactNormalize, octetStringMatch,
6808                     octetStringIndexer, octetStringFilter,
6809                     NULL },
6810 
6811           {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
6812                     "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
6813                     SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
6814                     NULL, NULL, NULL, NULL, NULL,
6815                     NULL },
6816 
6817           {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
6818                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6819                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6820                     NULL, IA5StringNormalize, octetStringMatch,
6821                     octetStringIndexer, octetStringFilter,
6822                     IA5StringApproxMatchOID },
6823 
6824           {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
6825                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6826                     SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
6827                     NULL, IA5StringNormalize, octetStringMatch,
6828                     octetStringIndexer, octetStringFilter,
6829                     IA5StringApproxMatchOID },
6830 
6831           {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
6832                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6833                     SLAP_MR_SUBSTR, NULL,
6834                     NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6835                     octetStringSubstringsIndexer, octetStringSubstringsFilter,
6836                     "caseIgnoreIA5Match" },
6837 
6838           {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
6839                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
6840                     SLAP_MR_SUBSTR, NULL,
6841                     NULL, IA5StringNormalize, directoryStringSubstringsMatch,
6842                     octetStringSubstringsIndexer, octetStringSubstringsFilter,
6843                     "caseExactIA5Match" },
6844 
6845 #ifdef SLAPD_AUTHPASSWD
6846           /* needs updating */
6847           {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
6848                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
6849                     SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6850                     NULL, NULL, authPasswordMatch,
6851                     NULL, NULL,
6852                     NULL},
6853 #endif
6854 
6855           {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
6856                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6857                     SLAP_MR_EXT, NULL,
6858                     NULL, NULL, integerBitAndMatch,
6859                     NULL, NULL,
6860                     "integerMatch" },
6861 
6862           {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
6863                     "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
6864                     SLAP_MR_EXT, NULL,
6865                     NULL, NULL, integerBitOrMatch,
6866                     NULL, NULL,
6867                     "integerMatch" },
6868 
6869           {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
6870                     "SYNTAX 1.3.6.1.1.16.1 )",
6871                     SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
6872                     NULL, UUIDNormalize, octetStringMatch,
6873                     octetStringIndexer, octetStringFilter,
6874                     NULL},
6875 
6876           {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
6877                     "SYNTAX 1.3.6.1.1.16.1 )",
6878                     SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
6879                     NULL, UUIDNormalize, octetStringOrderingMatch,
6880                     octetStringIndexer, octetStringFilter,
6881                     "UUIDMatch"},
6882 
6883           {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
6884                     "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6885                     SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
6886                     NULL, csnNormalize, csnMatch,
6887                     csnIndexer, csnFilter,
6888                     NULL},
6889 
6890           {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
6891                     "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
6892                     SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
6893                     NULL, csnNormalize, csnOrderingMatch,
6894                     NULL, NULL,
6895                     "CSNMatch" },
6896 
6897           {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
6898                     "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
6899                     SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
6900                     NULL, csnSidNormalize, octetStringMatch,
6901                     octetStringIndexer, octetStringFilter,
6902                     NULL },
6903 
6904           /* FIXME: OID is unused, but not registered yet */
6905           {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
6906                     "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
6907                     SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6908                     NULL, authzNormalize, authzMatch,
6909                     NULL, NULL,
6910                     NULL},
6911 
6912           {"( 1.3.6.1.4.1.4203.666.4.13 NAME 'privateKeyMatch' "
6913                     "SYNTAX 1.2.840.113549.1.8.1.1 )", /* PKCS#8 privateKey */
6914                     SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
6915                     NULL, NULL, octetStringMatch,
6916                     NULL, NULL,
6917                     NULL},
6918 
6919           {NULL, SLAP_MR_NONE, NULL,
6920                     NULL, NULL, NULL, NULL, NULL,
6921                     NULL }
6922 };
6923 
6924 int
slap_schema_init(void)6925 slap_schema_init( void )
6926 {
6927           int                 res;
6928           int                 i;
6929 
6930           /* we should only be called once (from main) */
6931           assert( schema_init_done == 0 );
6932 
6933           for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
6934                     res = register_syntax( &syntax_defs[i] );
6935 
6936                     if ( res ) {
6937                               fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
6938                                          syntax_defs[i].sd_desc );
6939                               return LDAP_OTHER;
6940                     }
6941           }
6942 
6943           for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
6944                     if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
6945                               mrule_defs[i].mrd_compat_syntaxes == NULL )
6946                     {
6947                               fprintf( stderr,
6948                                         "slap_schema_init: Ignoring unusable matching rule %s\n",
6949                                          mrule_defs[i].mrd_desc );
6950                               continue;
6951                     }
6952 
6953                     res = register_matching_rule( &mrule_defs[i] );
6954 
6955                     if ( res ) {
6956                               fprintf( stderr,
6957                                         "slap_schema_init: Error registering matching rule %s\n",
6958                                          mrule_defs[i].mrd_desc );
6959                               return LDAP_OTHER;
6960                     }
6961           }
6962 
6963           res = slap_schema_load();
6964           schema_init_done = 1;
6965           return res;
6966 }
6967 
6968 void
schema_destroy(void)6969 schema_destroy( void )
6970 {
6971           oidm_destroy();
6972           oc_destroy();
6973           at_destroy();
6974           mr_destroy();
6975           mru_destroy();
6976           syn_destroy();
6977 
6978           if( schema_init_done ) {
6979                     ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
6980                     ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
6981                     ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
6982           }
6983 }
6984