Back to index

openldap  2.4.31
schema_init.c
Go to the documentation of this file.
00001 /* schema_init.c - init builtin schema */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 /*
00018  * Syntaxes - implementation notes:
00019  *
00020  * Validate function(syntax, value):
00021  *   Called before the other functions here to check if the value
00022  *   is valid according to the syntax.
00023  *
00024  * Pretty function(syntax, input value, output prettified...):
00025  *   If it exists, maps different notations of the same value to a
00026  *   unique representation which can be stored in the directory and
00027  *   possibly be passed to the Match/Indexer/Filter() functions.
00028  *
00029  *   E.g. DN "2.5.4.3 = foo\,bar, o = BAZ" -> "cn=foo\2Cbar,o=BAZ",
00030  *   but unlike DN normalization, "BAZ" is not mapped to "baz".
00031  */
00032 
00033 /*
00034  * Matching rules - implementation notes:
00035  *
00036  * Matching rules match an attribute value (often from the directory)
00037  * against an asserted value (e.g. from a filter).
00038  *
00039  * Invoked with validated and commonly pretty/normalized arguments, thus
00040  * a number of matching rules can simply use the octetString functions.
00041  *
00042  * Normalize function(...input value, output normalized...):
00043  *   If it exists, maps matching values to a unique representation
00044  *   which is passed to the Match/Indexer/Filter() functions.
00045  *
00046  *   Different matching rules can normalize values of the same syntax
00047  *   differently.  E.g. caseIgnore rules normalize to lowercase,
00048  *   caseExact rules do not.
00049  *
00050  * Match function(*output matchp, ...value, asserted value):
00051  *   On success, set *matchp.  0 means match.  For ORDERING/most EQUALITY,
00052  *   less/greater than 0 means value less/greater than asserted.  However:
00053  *
00054  *   In extensible match filters, ORDERING rules match if value<asserted.
00055  *
00056  *   EQUALITY rules may order values differently than ORDERING rules for
00057  *   speed, since EQUALITY ordering is only used for SLAP_AT_SORTED_VAL.
00058  *   Some EQUALITY rules do not order values (ITS#6722).
00059  *
00060  * Indexer function(...attribute values, *output keysp,...):
00061  *   Generates index keys for the attribute values.  Backends can store
00062  *   them in an index, a {key->entry ID set} mapping, for the attribute.
00063  *
00064  *   A search can look up the DN/scope and asserted values in the
00065  *   indexes, if any, to narrow down the number of entires to check
00066  *   against the search criteria.
00067  *
00068  * Filter function(...asserted value, *output keysp,...):
00069  *   Generates index key(s) for the asserted value, to be looked up in
00070  *   the index from the Indexer function.  *keysp is an array because
00071  *   substring matching rules can generate multiple lookup keys.
00072  *
00073  * Index keys:
00074  *   A key is usually a hash of match type, attribute value and schema
00075  *   info, because one index can contain keys for many filtering types.
00076  *
00077  *   Some indexes instead have EQUALITY keys ordered so that if
00078  *   key(val1) < key(val2), then val1 < val2 by the ORDERING rule.
00079  *   That way the ORDERING rule can use the EQUALITY index.
00080  *
00081  * Substring indexing:
00082  *   This chops the attribute values up in small chunks and indexes all
00083  *   possible chunks of certain sizes.  Substring filtering looks up
00084  *   SOME of the asserted value's chunks, and the caller uses the
00085  *   intersection of the resulting entry ID sets.
00086  *   See the index_substr_* keywords in slapd.conf(5).
00087  */
00088 
00089 #include "portable.h"
00090 
00091 #include <stdio.h>
00092 #ifdef HAVE_LIMITS_H
00093 #include <limits.h>
00094 #endif
00095 
00096 #include <ac/ctype.h>
00097 #include <ac/errno.h>
00098 #include <ac/string.h>
00099 #include <ac/socket.h>
00100 
00101 #include "slap.h"
00102 #include "../../libraries/liblber/lber-int.h" /* get ber_ptrlen() */
00103 
00104 #include "ldap_utf8.h"
00105 
00106 #include "lutil.h"
00107 #include "lutil_hash.h"
00108 #define HASH_BYTES                        LUTIL_HASH_BYTES
00109 #define HASH_CONTEXT               lutil_HASH_CTX
00110 #define HASH_Init(c)               lutil_HASHInit(c)
00111 #define HASH_Update(c,buf,len)     lutil_HASHUpdate(c,buf,len)
00112 #define HASH_Final(d,c)                   lutil_HASHFinal(d,c)
00113 
00114 /* approx matching rules */
00115 #define directoryStringApproxMatchOID     "1.3.6.1.4.1.4203.666.4.4"
00116 #define directoryStringApproxMatch        approxMatch
00117 #define directoryStringApproxIndexer      approxIndexer
00118 #define directoryStringApproxFilter              approxFilter
00119 #define IA5StringApproxMatchOID                  "1.3.6.1.4.1.4203.666.4.5"
00120 #define IA5StringApproxMatch                     approxMatch
00121 #define IA5StringApproxIndexer                   approxIndexer
00122 #define IA5StringApproxFilter                    approxFilter
00123 
00124 /* Change Sequence Number (CSN) - much of this will change */
00125 #define csnMatch                          octetStringMatch
00126 #define csnOrderingMatch           octetStringOrderingMatch
00127 #define csnIndexer                        generalizedTimeIndexer
00128 #define csnFilter                         generalizedTimeFilter
00129 
00130 #define authzMatch                        octetStringMatch
00131 
00132 /* X.509 PMI ldapSyntaxes */
00133 /* FIXME: need to create temporary OIDs under OpenLDAP's arc;
00134  * these are currently hijacked
00135  *
00136  *     1.3.6.1.4.1.4203.666        OpenLDAP
00137  *     1.3.6.1.4.1.4203.666.11            self-contained works
00138  *     1.3.6.1.4.1.4203.666.11.10  X.509 PMI
00139  *     1.3.6.1.4.1.4203.666.11.10.2       X.509 PMI ldapSyntaxes
00140  *     1.3.6.1.4.1.4203.666.11.10.2.1     AttributeCertificate (supported)
00141  *     1.3.6.1.4.1.4203.666.11.10.2.2     AttributeCertificateExactAssertion (supported)
00142  *     1.3.6.1.4.1.4203.666.11.10.2.3     AttributeCertificateAssertion (not supported)
00143  *     1.3.6.1.4.1.4203.666.11.10.2.4     AttCertPath (X-SUBST'ed right now in pmi.schema)
00144  *     1.3.6.1.4.1.4203.666.11.10.2.5     PolicySyntax (X-SUBST'ed right now in pmi.schema)
00145  *     1.3.6.1.4.1.4203.666.11.10.2.6     RoleSyntax (X-SUBST'ed right now in pmi.schema)
00146  */
00147 #if 0 /* from <draft-ietf-pkix-ldap-schema-02.txt> (expired) */
00148 #define attributeCertificateSyntaxOID                   "1.2.826.0.1.3344810.7.5"
00149 #define attributeCertificateExactAssertionSyntaxOID     "1.2.826.0.1.3344810.7.6"
00150 #define attributeCertificateAssertionSyntaxOID          "1.2.826.0.1.3344810.7.7"
00151 #else /* from OpenLDAP's experimental oid arc */
00152 #define X509_PMI_SyntaxOID                       "1.3.6.1.4.1.4203.666.11.10.2"
00153 #define attributeCertificateSyntaxOID                   X509_PMI_SyntaxOID ".1"
00154 #define attributeCertificateExactAssertionSyntaxOID     X509_PMI_SyntaxOID ".2"
00155 #define attributeCertificateAssertionSyntaxOID          X509_PMI_SyntaxOID ".3"
00156 #endif
00157 
00158 unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT;
00159 unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT;
00160 unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT;
00161 unsigned int index_substr_any_step = SLAP_INDEX_SUBSTR_ANY_STEP_DEFAULT;
00162 
00163 unsigned int index_intlen = SLAP_INDEX_INTLEN_DEFAULT;
00164 unsigned int index_intlen_strlen = SLAP_INDEX_INTLEN_STRLEN(
00165        SLAP_INDEX_INTLEN_DEFAULT );
00166 
00167 ldap_pvt_thread_mutex_t     ad_index_mutex;
00168 ldap_pvt_thread_mutex_t     ad_undef_mutex;
00169 ldap_pvt_thread_mutex_t     oc_undef_mutex;
00170 
00171 static int
00172 generalizedTimeValidate(
00173        Syntax *syntax,
00174        struct berval *in );
00175 
00176 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
00177 static int
00178 utcTimeValidate(
00179        Syntax *syntax,
00180        struct berval *in );
00181 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
00182 
00183 static int
00184 inValidate(
00185        Syntax *syntax,
00186        struct berval *in )
00187 {
00188        /* no value allowed */
00189        return LDAP_INVALID_SYNTAX;
00190 }
00191 
00192 static int
00193 blobValidate(
00194        Syntax *syntax,
00195        struct berval *in )
00196 {
00197        /* any value allowed */
00198        return LDAP_SUCCESS;
00199 }
00200 
00201 #define berValidate blobValidate
00202 
00203 static int
00204 sequenceValidate(
00205        Syntax *syntax,
00206        struct berval *in )
00207 {
00208        if ( in->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
00209        if ( in->bv_val[0] != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00210 
00211        return LDAP_SUCCESS;
00212 }
00213 
00214 /* X.509 related stuff */
00215 
00216 enum {
00217        SLAP_X509_V1         = 0,
00218        SLAP_X509_V2         = 1,
00219        SLAP_X509_V3         = 2
00220 };
00221 
00222 enum {
00223        SLAP_TAG_UTCTIME            = 0x17U,
00224        SLAP_TAG_GENERALIZEDTIME    = 0x18U
00225 };
00226 
00227 
00228 #define       SLAP_X509_OPTION     (LBER_CLASS_CONTEXT|LBER_CONSTRUCTED)
00229 
00230 enum {
00231        SLAP_X509_OPT_C_VERSION            = SLAP_X509_OPTION + 0,
00232        SLAP_X509_OPT_C_ISSUERUNIQUEID     = LBER_CLASS_CONTEXT + 1,
00233        SLAP_X509_OPT_C_SUBJECTUNIQUEID    = LBER_CLASS_CONTEXT + 2,
00234        SLAP_X509_OPT_C_EXTENSIONS  = SLAP_X509_OPTION + 3
00235 };
00236 
00237 enum {
00238        SLAP_X509_OPT_CL_CRLEXTENSIONS     = SLAP_X509_OPTION + 0
00239 };
00240 
00241 /*
00242 GeneralName ::= CHOICE {
00243   otherName                 [0] INSTANCE OF OTHER-NAME,
00244   rfc822Name                [1] IA5String,
00245   dNSName                   [2] IA5String,
00246   x400Address               [3] ORAddress,
00247   directoryName             [4] Name,
00248   ediPartyName              [5] EDIPartyName,
00249   uniformResourceIdentifier [6] IA5String,
00250   iPAddress                 [7] OCTET STRING,
00251   registeredID              [8] OBJECT IDENTIFIER }
00252 */
00253 enum {
00254        SLAP_X509_GN_OTHERNAME             = SLAP_X509_OPTION + 0,
00255        SLAP_X509_GN_RFC822NAME            = SLAP_X509_OPTION + 1,
00256        SLAP_X509_GN_DNSNAME        = SLAP_X509_OPTION + 2,
00257        SLAP_X509_GN_X400ADDRESS    = SLAP_X509_OPTION + 3,
00258        SLAP_X509_GN_DIRECTORYNAME  = SLAP_X509_OPTION + 4,
00259        SLAP_X509_GN_EDIPARTYNAME   = SLAP_X509_OPTION + 5,
00260        SLAP_X509_GN_URI            = SLAP_X509_OPTION + 6,
00261        SLAP_X509_GN_IPADDRESS             = SLAP_X509_OPTION + 7,
00262        SLAP_X509_GN_REGISTEREDID   = SLAP_X509_OPTION + 8
00263 };
00264 
00265 /* X.509 PMI related stuff */
00266 enum {
00267        SLAP_X509AC_V1              = 0,
00268        SLAP_X509AC_V2              = 1
00269 };
00270 
00271 enum {
00272        SLAP_X509AC_ISSUER   = SLAP_X509_OPTION + 0
00273 };
00274 
00275 /* X.509 certificate validation */
00276 static int
00277 certificateValidate( Syntax *syntax, struct berval *in )
00278 {
00279        BerElementBuffer berbuf;
00280        BerElement *ber = (BerElement *)&berbuf;
00281        ber_tag_t tag;
00282        ber_len_t len;
00283        ber_int_t version = SLAP_X509_V1;
00284 
00285        ber_init2( ber, in, LBER_USE_DER );
00286        tag = ber_skip_tag( ber, &len );   /* Signed wrapper */
00287        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00288        tag = ber_skip_tag( ber, &len );   /* Sequence */
00289        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00290        tag = ber_peek_tag( ber, &len );
00291        /* Optional version */
00292        if ( tag == SLAP_X509_OPT_C_VERSION ) {
00293               tag = ber_skip_tag( ber, &len );
00294               tag = ber_get_int( ber, &version );
00295               if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
00296        }
00297        /* NOTE: don't try to parse Serial, because it might be longer
00298         * than sizeof(ber_int_t); deferred to certificateExactNormalize() */
00299        tag = ber_skip_tag( ber, &len );   /* Serial */
00300        if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
00301        ber_skip_data( ber, len );
00302        tag = ber_skip_tag( ber, &len );   /* Signature Algorithm */
00303        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00304        ber_skip_data( ber, len );
00305        tag = ber_skip_tag( ber, &len );   /* Issuer DN */
00306        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00307        ber_skip_data( ber, len );
00308        tag = ber_skip_tag( ber, &len );   /* Validity */
00309        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00310        ber_skip_data( ber, len );
00311        tag = ber_skip_tag( ber, &len );   /* Subject DN */
00312        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00313        ber_skip_data( ber, len );
00314        tag = ber_skip_tag( ber, &len );   /* Subject PublicKeyInfo */
00315        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00316        ber_skip_data( ber, len );
00317        tag = ber_skip_tag( ber, &len );
00318        if ( tag == SLAP_X509_OPT_C_ISSUERUNIQUEID ) {   /* issuerUniqueID */
00319               if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
00320               ber_skip_data( ber, len );
00321               tag = ber_skip_tag( ber, &len );
00322        }
00323        if ( tag == SLAP_X509_OPT_C_SUBJECTUNIQUEID ) {  /* subjectUniqueID */
00324               if ( version < SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
00325               ber_skip_data( ber, len );
00326               tag = ber_skip_tag( ber, &len );
00327        }
00328        if ( tag == SLAP_X509_OPT_C_EXTENSIONS ) {       /* Extensions */
00329               if ( version < SLAP_X509_V3 ) return LDAP_INVALID_SYNTAX;
00330               tag = ber_skip_tag( ber, &len );
00331               if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00332               ber_skip_data( ber, len );
00333               tag = ber_skip_tag( ber, &len );
00334        }
00335        /* signatureAlgorithm */
00336        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00337        ber_skip_data( ber, len );
00338        tag = ber_skip_tag( ber, &len );
00339        /* Signature */
00340        if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
00341        ber_skip_data( ber, len );
00342        tag = ber_skip_tag( ber, &len );
00343        /* Must be at end now */
00344        if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
00345        return LDAP_SUCCESS;
00346 }
00347 
00348 /* X.509 certificate list validation */
00349 static int
00350 checkTime( struct berval *in, struct berval *out );
00351 
00352 static int
00353 certificateListValidate( Syntax *syntax, struct berval *in )
00354 {
00355        BerElementBuffer berbuf;
00356        BerElement *ber = (BerElement *)&berbuf;
00357        ber_tag_t tag;
00358        ber_len_t len, wrapper_len;
00359        char *wrapper_start;
00360        int wrapper_ok = 0;
00361        ber_int_t version = SLAP_X509_V1;
00362        struct berval bvdn, bvtu;
00363 
00364        ber_init2( ber, in, LBER_USE_DER );
00365        tag = ber_skip_tag( ber, &wrapper_len );  /* Signed wrapper */
00366        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00367        wrapper_start = ber->ber_ptr;
00368        tag = ber_skip_tag( ber, &len );   /* Sequence */
00369        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00370        tag = ber_peek_tag( ber, &len );
00371        /* Optional version */
00372        if ( tag == LBER_INTEGER ) {
00373               tag = ber_get_int( ber, &version );
00374               assert( tag == LBER_INTEGER );
00375               if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
00376        }
00377        tag = ber_skip_tag( ber, &len );   /* Signature Algorithm */
00378        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00379        ber_skip_data( ber, len );
00380        tag = ber_peek_tag( ber, &len );   /* Issuer DN */
00381        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00382        len = ber_ptrlen( ber );
00383        bvdn.bv_val = in->bv_val + len;
00384        bvdn.bv_len = in->bv_len - len;
00385        tag = ber_skip_tag( ber, &len );
00386        ber_skip_data( ber, len );
00387        tag = ber_skip_tag( ber, &len );   /* thisUpdate */
00388        /* Time is a CHOICE { UTCTime, GeneralizedTime } */
00389        if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
00390        bvtu.bv_val = (char *)ber->ber_ptr;
00391        bvtu.bv_len = len;
00392        ber_skip_data( ber, len );
00393        /* Optional nextUpdate */
00394        tag = ber_skip_tag( ber, &len );
00395        if ( tag == SLAP_TAG_UTCTIME || tag == SLAP_TAG_GENERALIZEDTIME ) {
00396               ber_skip_data( ber, len );
00397               tag = ber_skip_tag( ber, &len );
00398        }
00399        /* revokedCertificates - Sequence of Sequence, Optional */
00400        if ( tag == LBER_SEQUENCE ) {
00401               ber_len_t seqlen;
00402               ber_tag_t stag;
00403               stag = ber_peek_tag( ber, &seqlen );
00404               if ( stag == LBER_SEQUENCE || !len ) {
00405                      /* RFC5280 requires non-empty, but X.509(2005) allows empty. */
00406                      if ( len )
00407                             ber_skip_data( ber, len );
00408                      tag = ber_skip_tag( ber, &len );
00409               }
00410        }
00411        /* Optional Extensions - Sequence of Sequence */
00412        if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
00413               ber_len_t seqlen;
00414               if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
00415               tag = ber_peek_tag( ber, &seqlen );
00416               if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00417               ber_skip_data( ber, len );
00418               tag = ber_skip_tag( ber, &len );
00419        }
00420        /* signatureAlgorithm */
00421        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00422        ber_skip_data( ber, len );
00423        tag = ber_skip_tag( ber, &len );
00424        /* Signature */
00425        if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX; 
00426        ber_skip_data( ber, len );
00427        if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1;
00428        tag = ber_skip_tag( ber, &len );
00429        /* Must be at end now */
00430        /* NOTE: OpenSSL tolerates CL with garbage past the end */
00431        if ( len || tag != LBER_DEFAULT ) {
00432               struct berval issuer_dn = BER_BVNULL, thisUpdate;
00433               char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
00434               int rc;
00435 
00436               if ( ! wrapper_ok ) {
00437                      return LDAP_INVALID_SYNTAX;
00438               }
00439 
00440               rc = dnX509normalize( &bvdn, &issuer_dn );
00441               if ( rc != LDAP_SUCCESS ) {
00442                      rc = LDAP_INVALID_SYNTAX;
00443                      goto done;
00444               }
00445 
00446               thisUpdate.bv_val = tubuf;
00447               thisUpdate.bv_len = sizeof(tubuf); 
00448               if ( checkTime( &bvtu, &thisUpdate ) ) {
00449                      rc = LDAP_INVALID_SYNTAX;
00450                      goto done;
00451               }
00452 
00453               Debug( LDAP_DEBUG_ANY,
00454                      "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n",
00455                      issuer_dn.bv_val, thisUpdate.bv_val, 0 );
00456 
00457 done:;
00458               if ( ! BER_BVISNULL( &issuer_dn ) ) {
00459                      ber_memfree( issuer_dn.bv_val );
00460               }
00461 
00462               return rc;
00463        }
00464 
00465        return LDAP_SUCCESS;
00466 }
00467 
00468 /* X.509 PMI Attribute Certificate Validate */
00469 static int
00470 attributeCertificateValidate( Syntax *syntax, struct berval *in )
00471 {
00472        BerElementBuffer berbuf;
00473        BerElement *ber = (BerElement *)&berbuf;
00474        ber_tag_t tag;
00475        ber_len_t len;
00476        ber_int_t version;
00477        int cont = 0;
00478 
00479        ber_init2( ber, in, LBER_USE_DER );
00480        
00481        tag = ber_skip_tag( ber, &len );   /* Signed wrapper */
00482        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00483 
00484        tag = ber_skip_tag( ber, &len );   /* Sequence */
00485        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00486 
00487        tag = ber_peek_tag( ber, &len );   /* Version */
00488        if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
00489        tag = ber_get_int( ber, &version );       /* X.509 only allows v2 */
00490        if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX;
00491 
00492        tag = ber_skip_tag( ber, &len );   /* Holder */
00493        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00494        ber_skip_data( ber, len );
00495 
00496        tag = ber_skip_tag( ber, &len );   /* Issuer */
00497        if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX;
00498        ber_skip_data( ber, len );
00499 
00500        tag = ber_skip_tag( ber, &len );   /* Signature */
00501        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00502        ber_skip_data( ber, len );
00503 
00504        tag = ber_skip_tag( ber, &len );   /* Serial number */
00505        if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX;
00506        ber_skip_data( ber, len );
00507 
00508        tag = ber_skip_tag( ber, &len );   /* AttCertValidityPeriod */
00509        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00510        ber_skip_data( ber, len );
00511 
00512        tag = ber_skip_tag( ber, &len );   /* Attributes */
00513        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
00514        ber_skip_data( ber, len );
00515 
00516        tag = ber_peek_tag( ber, &len );
00517 
00518        if ( tag == LBER_BITSTRING ) {     /* issuerUniqueID */
00519               tag = ber_skip_tag( ber, &len );
00520               ber_skip_data( ber, len );
00521               tag = ber_peek_tag( ber, &len );
00522        }
00523 
00524        if ( tag == LBER_SEQUENCE ) {      /* extensions or signatureAlgorithm */
00525               tag = ber_skip_tag( ber, &len );
00526               ber_skip_data( ber, len );
00527               cont++;
00528               tag = ber_peek_tag( ber, &len );
00529        }
00530 
00531        if ( tag == LBER_SEQUENCE ) {      /* signatureAlgorithm */
00532               tag = ber_skip_tag( ber, &len );
00533               ber_skip_data( ber, len );
00534               cont++;
00535               tag = ber_peek_tag( ber, &len );
00536        }
00537 
00538        if ( tag == LBER_BITSTRING ) {     /* Signature */
00539               tag = ber_skip_tag( ber, &len );
00540               ber_skip_data( ber, len );
00541               cont++;
00542               tag = ber_peek_tag( ber, &len );
00543        }
00544 
00545        /* Must be at end now */
00546        if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX;
00547 
00548        return LDAP_SUCCESS;
00549 }
00550 
00551 int
00552 octetStringMatch(
00553        int *matchp,
00554        slap_mask_t flags,
00555        Syntax *syntax,
00556        MatchingRule *mr,
00557        struct berval *value,
00558        void *assertedValue )
00559 {
00560        struct berval *asserted = (struct berval *) assertedValue;
00561        ber_slen_t d = (ber_slen_t) value->bv_len - (ber_slen_t) asserted->bv_len;
00562 
00563        /* For speed, order first by length, then by contents */
00564        *matchp = d ? (sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1)
00565               : memcmp( value->bv_val, asserted->bv_val, value->bv_len );
00566 
00567        return LDAP_SUCCESS;
00568 }
00569 
00570 int
00571 octetStringOrderingMatch(
00572        int *matchp,
00573        slap_mask_t flags,
00574        Syntax *syntax,
00575        MatchingRule *mr,
00576        struct berval *value,
00577        void *assertedValue )
00578 {
00579        struct berval *asserted = (struct berval *) assertedValue;
00580        ber_len_t v_len  = value->bv_len;
00581        ber_len_t av_len = asserted->bv_len;
00582 
00583        int match = memcmp( value->bv_val, asserted->bv_val,
00584               (v_len < av_len ? v_len : av_len) );
00585 
00586        if( match == 0 )
00587               match = sizeof(v_len) == sizeof(int)
00588                      ? (int) v_len - (int) av_len
00589                      : v_len < av_len ? -1 : v_len > av_len;
00590 
00591        /* If used in extensible match filter, match if value < asserted */
00592        if ( flags & SLAP_MR_EXT )
00593               match = (match >= 0);
00594 
00595        *matchp = match;
00596        return LDAP_SUCCESS;
00597 }
00598 
00599 /* Initialize HASHcontext from match type and schema info */
00600 static void
00601 hashPreset(
00602        HASH_CONTEXT *HASHcontext,
00603        struct berval *prefix,
00604        char pre,
00605        Syntax *syntax,
00606        MatchingRule *mr)
00607 {
00608        HASH_Init(HASHcontext);
00609        if(prefix && prefix->bv_len > 0) {
00610               HASH_Update(HASHcontext,
00611                      (unsigned char *)prefix->bv_val, prefix->bv_len);
00612        }
00613        if(pre) HASH_Update(HASHcontext, (unsigned char*)&pre, sizeof(pre));
00614        HASH_Update(HASHcontext, (unsigned char*)syntax->ssyn_oid, syntax->ssyn_oidlen);
00615        HASH_Update(HASHcontext, (unsigned char*)mr->smr_oid, mr->smr_oidlen);
00616        return;
00617 }
00618 
00619 /* Set HASHdigest from HASHcontext and value:len */
00620 static void
00621 hashIter(
00622        HASH_CONTEXT *HASHcontext,
00623        unsigned char *HASHdigest,
00624        unsigned char *value,
00625        int len)
00626 {
00627        HASH_CONTEXT ctx = *HASHcontext;
00628        HASH_Update( &ctx, value, len );
00629        HASH_Final( HASHdigest, &ctx );
00630 }
00631 
00632 /* Index generation function: Attribute values -> index hash keys */
00633 int octetStringIndexer(
00634        slap_mask_t use,
00635        slap_mask_t flags,
00636        Syntax *syntax,
00637        MatchingRule *mr,
00638        struct berval *prefix,
00639        BerVarray values,
00640        BerVarray *keysp,
00641        void *ctx )
00642 {
00643        int i;
00644        size_t slen, mlen;
00645        BerVarray keys;
00646        HASH_CONTEXT HASHcontext;
00647        unsigned char HASHdigest[HASH_BYTES];
00648        struct berval digest;
00649        digest.bv_val = (char *)HASHdigest;
00650        digest.bv_len = sizeof(HASHdigest);
00651 
00652        for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
00653               /* just count them */
00654        }
00655 
00656        /* we should have at least one value at this point */
00657        assert( i > 0 );
00658 
00659        keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
00660 
00661        slen = syntax->ssyn_oidlen;
00662        mlen = mr->smr_oidlen;
00663 
00664        hashPreset( &HASHcontext, prefix, 0, syntax, mr);
00665        for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
00666               hashIter( &HASHcontext, HASHdigest,
00667                      (unsigned char *)values[i].bv_val, values[i].bv_len );
00668               ber_dupbv_x( &keys[i], &digest, ctx );
00669        }
00670 
00671        BER_BVZERO( &keys[i] );
00672 
00673        *keysp = keys;
00674 
00675        return LDAP_SUCCESS;
00676 }
00677 
00678 /* Index generation function: Asserted value -> index hash key */
00679 int octetStringFilter(
00680        slap_mask_t use,
00681        slap_mask_t flags,
00682        Syntax *syntax,
00683        MatchingRule *mr,
00684        struct berval *prefix,
00685        void * assertedValue,
00686        BerVarray *keysp,
00687        void *ctx )
00688 {
00689        size_t slen, mlen;
00690        BerVarray keys;
00691        HASH_CONTEXT HASHcontext;
00692        unsigned char HASHdigest[HASH_BYTES];
00693        struct berval *value = (struct berval *) assertedValue;
00694        struct berval digest;
00695        digest.bv_val = (char *)HASHdigest;
00696        digest.bv_len = sizeof(HASHdigest);
00697 
00698        slen = syntax->ssyn_oidlen;
00699        mlen = mr->smr_oidlen;
00700 
00701        keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
00702 
00703        hashPreset( &HASHcontext, prefix, 0, syntax, mr );
00704        hashIter( &HASHcontext, HASHdigest,
00705               (unsigned char *)value->bv_val, value->bv_len );
00706 
00707        ber_dupbv_x( keys, &digest, ctx );
00708        BER_BVZERO( &keys[1] );
00709 
00710        *keysp = keys;
00711 
00712        return LDAP_SUCCESS;
00713 }
00714 
00715 static int
00716 octetStringSubstringsMatch(
00717        int *matchp,
00718        slap_mask_t flags,
00719        Syntax *syntax,
00720        MatchingRule *mr,
00721        struct berval *value,
00722        void *assertedValue )
00723 {
00724        int match = 0;
00725        SubstringsAssertion *sub = assertedValue;
00726        struct berval left = *value;
00727        int i;
00728        ber_len_t inlen = 0;
00729 
00730        /* Add up asserted input length */
00731        if ( !BER_BVISNULL( &sub->sa_initial ) ) {
00732               inlen += sub->sa_initial.bv_len;
00733        }
00734        if ( sub->sa_any ) {
00735               for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
00736                      inlen += sub->sa_any[i].bv_len;
00737               }
00738        }
00739        if ( !BER_BVISNULL( &sub->sa_final ) ) {
00740               inlen += sub->sa_final.bv_len;
00741        }
00742 
00743        if ( !BER_BVISNULL( &sub->sa_initial ) ) {
00744               if ( inlen > left.bv_len ) {
00745                      match = 1;
00746                      goto done;
00747               }
00748 
00749               match = memcmp( sub->sa_initial.bv_val, left.bv_val,
00750                      sub->sa_initial.bv_len );
00751 
00752               if ( match != 0 ) {
00753                      goto done;
00754               }
00755 
00756               left.bv_val += sub->sa_initial.bv_len;
00757               left.bv_len -= sub->sa_initial.bv_len;
00758               inlen -= sub->sa_initial.bv_len;
00759        }
00760 
00761        if ( !BER_BVISNULL( &sub->sa_final ) ) {
00762               if ( inlen > left.bv_len ) {
00763                      match = 1;
00764                      goto done;
00765               }
00766 
00767               match = memcmp( sub->sa_final.bv_val,
00768                      &left.bv_val[left.bv_len - sub->sa_final.bv_len],
00769                      sub->sa_final.bv_len );
00770 
00771               if ( match != 0 ) {
00772                      goto done;
00773               }
00774 
00775               left.bv_len -= sub->sa_final.bv_len;
00776               inlen -= sub->sa_final.bv_len;
00777        }
00778 
00779        if ( sub->sa_any ) {
00780               for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
00781                      ber_len_t idx;
00782                      char *p;
00783 
00784 retry:
00785                      if ( inlen > left.bv_len ) {
00786                             /* not enough length */
00787                             match = 1;
00788                             goto done;
00789                      }
00790 
00791                      if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
00792                             continue;
00793                      }
00794 
00795                      p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
00796 
00797                      if( p == NULL ) {
00798                             match = 1;
00799                             goto done;
00800                      }
00801 
00802                      idx = p - left.bv_val;
00803 
00804                      if ( idx >= left.bv_len ) {
00805                             /* this shouldn't happen */
00806                             return LDAP_OTHER;
00807                      }
00808 
00809                      left.bv_val = p;
00810                      left.bv_len -= idx;
00811 
00812                      if ( sub->sa_any[i].bv_len > left.bv_len ) {
00813                             /* not enough left */
00814                             match = 1;
00815                             goto done;
00816                      }
00817 
00818                      match = memcmp( left.bv_val,
00819                             sub->sa_any[i].bv_val,
00820                             sub->sa_any[i].bv_len );
00821 
00822                      if ( match != 0 ) {
00823                             left.bv_val++;
00824                             left.bv_len--;
00825                             goto retry;
00826                      }
00827 
00828                      left.bv_val += sub->sa_any[i].bv_len;
00829                      left.bv_len -= sub->sa_any[i].bv_len;
00830                      inlen -= sub->sa_any[i].bv_len;
00831               }
00832        }
00833 
00834 done:
00835        *matchp = match;
00836        return LDAP_SUCCESS;
00837 }
00838 
00839 /* Substring index generation function: Attribute values -> index hash keys */
00840 static int
00841 octetStringSubstringsIndexer(
00842        slap_mask_t use,
00843        slap_mask_t flags,
00844        Syntax *syntax,
00845        MatchingRule *mr,
00846        struct berval *prefix,
00847        BerVarray values,
00848        BerVarray *keysp,
00849        void *ctx )
00850 {
00851        ber_len_t i, nkeys;
00852        size_t slen, mlen;
00853        BerVarray keys;
00854 
00855        HASH_CONTEXT HCany, HCini, HCfin;
00856        unsigned char HASHdigest[HASH_BYTES];
00857        struct berval digest;
00858        digest.bv_val = (char *)HASHdigest;
00859        digest.bv_len = sizeof(HASHdigest);
00860 
00861        nkeys = 0;
00862 
00863        for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
00864               /* count number of indices to generate */
00865               if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
00866                      if( values[i].bv_len >= index_substr_if_maxlen ) {
00867                             nkeys += index_substr_if_maxlen -
00868                                    (index_substr_if_minlen - 1);
00869                      } else if( values[i].bv_len >= index_substr_if_minlen ) {
00870                             nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
00871                      }
00872               }
00873 
00874               if( flags & SLAP_INDEX_SUBSTR_ANY ) {
00875                      if( values[i].bv_len >= index_substr_any_len ) {
00876                             nkeys += values[i].bv_len - (index_substr_any_len - 1);
00877                      }
00878               }
00879 
00880               if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
00881                      if( values[i].bv_len >= index_substr_if_maxlen ) {
00882                             nkeys += index_substr_if_maxlen -
00883                                    (index_substr_if_minlen - 1);
00884                      } else if( values[i].bv_len >= index_substr_if_minlen ) {
00885                             nkeys += values[i].bv_len - (index_substr_if_minlen - 1);
00886                      }
00887               }
00888        }
00889 
00890        if( nkeys == 0 ) {
00891               /* no keys to generate */
00892               *keysp = NULL;
00893               return LDAP_SUCCESS;
00894        }
00895 
00896        keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
00897 
00898        slen = syntax->ssyn_oidlen;
00899        mlen = mr->smr_oidlen;
00900 
00901        if ( flags & SLAP_INDEX_SUBSTR_ANY )
00902               hashPreset( &HCany, prefix, SLAP_INDEX_SUBSTR_PREFIX, syntax, mr );
00903        if( flags & SLAP_INDEX_SUBSTR_INITIAL )
00904               hashPreset( &HCini, prefix, SLAP_INDEX_SUBSTR_INITIAL_PREFIX, syntax, mr );
00905        if( flags & SLAP_INDEX_SUBSTR_FINAL )
00906               hashPreset( &HCfin, prefix, SLAP_INDEX_SUBSTR_FINAL_PREFIX, syntax, mr );
00907 
00908        nkeys = 0;
00909        for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
00910               ber_len_t j,max;
00911 
00912               if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
00913                      ( values[i].bv_len >= index_substr_any_len ) )
00914               {
00915                      max = values[i].bv_len - (index_substr_any_len - 1);
00916 
00917                      for( j=0; j<max; j++ ) {
00918                             hashIter( &HCany, HASHdigest,
00919                                    (unsigned char *)&values[i].bv_val[j],
00920                                    index_substr_any_len );
00921                             ber_dupbv_x( &keys[nkeys++], &digest, ctx );
00922                      }
00923               }
00924 
00925               /* skip if too short */ 
00926               if( values[i].bv_len < index_substr_if_minlen ) continue;
00927 
00928               max = index_substr_if_maxlen < values[i].bv_len
00929                      ? index_substr_if_maxlen : values[i].bv_len;
00930 
00931               for( j=index_substr_if_minlen; j<=max; j++ ) {
00932 
00933                      if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
00934                             hashIter( &HCini, HASHdigest,
00935                                    (unsigned char *)values[i].bv_val, j );
00936                             ber_dupbv_x( &keys[nkeys++], &digest, ctx );
00937                      }
00938 
00939                      if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
00940                             hashIter( &HCfin, HASHdigest,
00941                                    (unsigned char *)&values[i].bv_val[values[i].bv_len-j], j );
00942                             ber_dupbv_x( &keys[nkeys++], &digest, ctx );
00943                      }
00944 
00945               }
00946        }
00947 
00948        if( nkeys > 0 ) {
00949               BER_BVZERO( &keys[nkeys] );
00950               *keysp = keys;
00951        } else {
00952               ch_free( keys );
00953               *keysp = NULL;
00954        }
00955 
00956        return LDAP_SUCCESS;
00957 }
00958 
00959 /* Substring index generation function: Assertion value -> index hash keys */
00960 static int
00961 octetStringSubstringsFilter (
00962        slap_mask_t use,
00963        slap_mask_t flags,
00964        Syntax *syntax,
00965        MatchingRule *mr,
00966        struct berval *prefix,
00967        void * assertedValue,
00968        BerVarray *keysp,
00969        void *ctx)
00970 {
00971        SubstringsAssertion *sa;
00972        char pre;
00973        ber_len_t nkeys = 0;
00974        size_t slen, mlen, klen;
00975        BerVarray keys;
00976        HASH_CONTEXT HASHcontext;
00977        unsigned char HASHdigest[HASH_BYTES];
00978        struct berval *value;
00979        struct berval digest;
00980 
00981        sa = (SubstringsAssertion *) assertedValue;
00982 
00983        if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
00984               !BER_BVISNULL( &sa->sa_initial ) &&
00985               sa->sa_initial.bv_len >= index_substr_if_minlen )
00986        {
00987               nkeys++;
00988               if ( sa->sa_initial.bv_len > index_substr_if_maxlen &&
00989                      ( flags & SLAP_INDEX_SUBSTR_ANY ))
00990               {
00991                      nkeys += 1 + (sa->sa_initial.bv_len - index_substr_if_maxlen) / index_substr_any_step;
00992               }
00993        }
00994 
00995        if ( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
00996               ber_len_t i;
00997               for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
00998                      if( sa->sa_any[i].bv_len >= index_substr_any_len ) {
00999                             /* don't bother accounting with stepping */
01000                             nkeys += sa->sa_any[i].bv_len -
01001                                    ( index_substr_any_len - 1 );
01002                      }
01003               }
01004        }
01005 
01006        if( flags & SLAP_INDEX_SUBSTR_FINAL &&
01007               !BER_BVISNULL( &sa->sa_final ) &&
01008               sa->sa_final.bv_len >= index_substr_if_minlen )
01009        {
01010               nkeys++;
01011               if ( sa->sa_final.bv_len > index_substr_if_maxlen &&
01012                      ( flags & SLAP_INDEX_SUBSTR_ANY ))
01013               {
01014                      nkeys += 1 + (sa->sa_final.bv_len - index_substr_if_maxlen) / index_substr_any_step;
01015               }
01016        }
01017 
01018        if( nkeys == 0 ) {
01019               *keysp = NULL;
01020               return LDAP_SUCCESS;
01021        }
01022 
01023        digest.bv_val = (char *)HASHdigest;
01024        digest.bv_len = sizeof(HASHdigest);
01025 
01026        slen = syntax->ssyn_oidlen;
01027        mlen = mr->smr_oidlen;
01028 
01029        keys = slap_sl_malloc( sizeof( struct berval ) * (nkeys+1), ctx );
01030        nkeys = 0;
01031 
01032        if( flags & SLAP_INDEX_SUBSTR_INITIAL &&
01033               !BER_BVISNULL( &sa->sa_initial ) &&
01034               sa->sa_initial.bv_len >= index_substr_if_minlen )
01035        {
01036               pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
01037               value = &sa->sa_initial;
01038 
01039               klen = index_substr_if_maxlen < value->bv_len
01040                      ? index_substr_if_maxlen : value->bv_len;
01041 
01042               hashPreset( &HASHcontext, prefix, pre, syntax, mr );
01043               hashIter( &HASHcontext, HASHdigest,
01044                      (unsigned char *)value->bv_val, klen );
01045               ber_dupbv_x( &keys[nkeys++], &digest, ctx );
01046 
01047               /* If initial is too long and we have subany indexed, use it
01048                * to match the excess...
01049                */
01050               if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
01051               {
01052                      ber_len_t j;
01053                      pre = SLAP_INDEX_SUBSTR_PREFIX;
01054                      hashPreset( &HASHcontext, prefix, pre, syntax, mr);
01055                      for ( j=index_substr_if_maxlen-1; j <= value->bv_len - index_substr_any_len; j+=index_substr_any_step )
01056                      {
01057                             hashIter( &HASHcontext, HASHdigest,
01058                                    (unsigned char *)&value->bv_val[j], index_substr_any_len );
01059                             ber_dupbv_x( &keys[nkeys++], &digest, ctx );
01060                      }
01061               }
01062        }
01063 
01064        if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
01065               ber_len_t i, j;
01066               pre = SLAP_INDEX_SUBSTR_PREFIX;
01067               klen = index_substr_any_len;
01068 
01069               for( i=0; !BER_BVISNULL( &sa->sa_any[i] ); i++ ) {
01070                      if( sa->sa_any[i].bv_len < index_substr_any_len ) {
01071                             continue;
01072                      }
01073 
01074                      value = &sa->sa_any[i];
01075 
01076                      hashPreset( &HASHcontext, prefix, pre, syntax, mr);
01077                      for(j=0;
01078                             j <= value->bv_len - index_substr_any_len;
01079                             j += index_substr_any_step )
01080                      {
01081                             hashIter( &HASHcontext, HASHdigest,
01082                                    (unsigned char *)&value->bv_val[j], klen ); 
01083                             ber_dupbv_x( &keys[nkeys++], &digest, ctx );
01084                      }
01085               }
01086        }
01087 
01088        if( flags & SLAP_INDEX_SUBSTR_FINAL &&
01089               !BER_BVISNULL( &sa->sa_final ) &&
01090               sa->sa_final.bv_len >= index_substr_if_minlen )
01091        {
01092               pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
01093               value = &sa->sa_final;
01094 
01095               klen = index_substr_if_maxlen < value->bv_len
01096                      ? index_substr_if_maxlen : value->bv_len;
01097 
01098               hashPreset( &HASHcontext, prefix, pre, syntax, mr );
01099               hashIter( &HASHcontext, HASHdigest,
01100                      (unsigned char *)&value->bv_val[value->bv_len-klen], klen );
01101               ber_dupbv_x( &keys[nkeys++], &digest, ctx );
01102 
01103               /* If final is too long and we have subany indexed, use it
01104                * to match the excess...
01105                */
01106               if (value->bv_len > index_substr_if_maxlen && (flags & SLAP_INDEX_SUBSTR_ANY))
01107               {
01108                      ber_len_t j;
01109                      pre = SLAP_INDEX_SUBSTR_PREFIX;
01110                      hashPreset( &HASHcontext, prefix, pre, syntax, mr);
01111                      for ( j=0; j <= value->bv_len - index_substr_if_maxlen; j+=index_substr_any_step )
01112                      {
01113                             hashIter( &HASHcontext, HASHdigest,
01114                                    (unsigned char *)&value->bv_val[j], index_substr_any_len );
01115                             ber_dupbv_x( &keys[nkeys++], &digest, ctx );
01116                      }
01117               }
01118        }
01119 
01120        if( nkeys > 0 ) {
01121               BER_BVZERO( &keys[nkeys] );
01122               *keysp = keys;
01123        } else {
01124               ch_free( keys );
01125               *keysp = NULL;
01126        }
01127 
01128        return LDAP_SUCCESS;
01129 }
01130 
01131 static int
01132 bitStringValidate(
01133        Syntax *syntax,
01134        struct berval *in )
01135 {
01136        ber_len_t i;
01137 
01138        /* very unforgiving validation, requires no normalization
01139         * before simplistic matching
01140         */
01141        if( in->bv_len < 3 ) {
01142               return LDAP_INVALID_SYNTAX;
01143        }
01144 
01145        /* RFC 4517 Section 3.3.2 Bit String:
01146         *     BitString    = SQUOTE *binary-digit SQUOTE "B"
01147         *     binary-digit = "0" / "1"
01148         *
01149         * where SQUOTE [RFC4512] is
01150         *     SQUOTE  = %x27 ; single quote ("'")
01151         *
01152         * Example: '0101111101'B
01153         */
01154        
01155        if( in->bv_val[0] != '\'' ||
01156               in->bv_val[in->bv_len - 2] != '\'' ||
01157               in->bv_val[in->bv_len - 1] != 'B' )
01158        {
01159               return LDAP_INVALID_SYNTAX;
01160        }
01161 
01162        for( i = in->bv_len - 3; i > 0; i-- ) {
01163               if( in->bv_val[i] != '0' && in->bv_val[i] != '1' ) {
01164                      return LDAP_INVALID_SYNTAX;
01165               }
01166        }
01167 
01168        return LDAP_SUCCESS;
01169 }
01170 
01171 /*
01172  * Syntaxes from RFC 4517
01173  *
01174 
01175 3.3.2.  Bit String
01176 
01177    A value of the Bit String syntax is a sequence of binary digits.  The
01178    LDAP-specific encoding of a value of this syntax is defined by the
01179    following ABNF:
01180 
01181       BitString    = SQUOTE *binary-digit SQUOTE "B"
01182 
01183       binary-digit = "0" / "1"
01184 
01185    The <SQUOTE> rule is defined in [MODELS].
01186 
01187       Example:
01188          '0101111101'B
01189 
01190    The LDAP definition for the Bit String syntax is:
01191 
01192       ( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )
01193 
01194    This syntax corresponds to the BIT STRING ASN.1 type from [ASN.1].
01195 
01196    ...
01197 
01198 3.3.21.  Name and Optional UID
01199 
01200    A value of the Name and Optional UID syntax is the distinguished name
01201    [MODELS] of an entity optionally accompanied by a unique identifier
01202    that serves to differentiate the entity from others with an identical
01203    distinguished name.
01204 
01205    The LDAP-specific encoding of a value of this syntax is defined by
01206    the following ABNF:
01207 
01208        NameAndOptionalUID = distinguishedName [ SHARP BitString ]
01209 
01210    The <BitString> rule is defined in Section 3.3.2.  The
01211    <distinguishedName> rule is defined in [LDAPDN].  The <SHARP> rule is
01212    defined in [MODELS].
01213 
01214    Note that although the '#' character may occur in the string
01215    representation of a distinguished name, no additional escaping of
01216    this character is performed when a <distinguishedName> is encoded in
01217    a <NameAndOptionalUID>.
01218 
01219       Example:
01220          1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB#'0101'B
01221 
01222    The LDAP definition for the Name and Optional UID syntax is:
01223 
01224       ( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )
01225 
01226    This syntax corresponds to the NameAndOptionalUID ASN.1 type from
01227    [X.520].
01228 
01229  *
01230  * RFC 4512 says:
01231  *
01232 
01233 1.4. Common ABNF Productions
01234 
01235   ...
01236       SHARP   = %x23 ; octothorpe (or sharp sign) ("#")
01237   ...
01238       SQUOTE  = %x27 ; single quote ("'")
01239   ...
01240       
01241  *
01242  * Note:
01243  * RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
01244  * be escaped except when at the beginning of a value, the
01245  * definition of Name and Optional UID appears to be flawed,
01246  * because there is no clear means to determine whether the
01247  * UID part is present or not.
01248  *
01249  * Example:
01250  *
01251  *     cn=Someone,dc=example,dc=com#'1'B
01252  *
01253  * could be either a NameAndOptionalUID with trailing UID, i.e.
01254  *
01255  *     DN = "cn=Someone,dc=example,dc=com"
01256  *     UID = "'1'B"
01257  * 
01258  * or a NameAndOptionalUID with no trailing UID, and the AVA
01259  * in the last RDN made of
01260  *
01261  *     attributeType = dc 
01262  *     attributeValue = com#'1'B
01263  *
01264  * in fact "com#'1'B" is a valid IA5 string.
01265  *
01266  * As a consequence, current slapd code takes the presence of
01267  * #<valid BitString> at the end of the string representation
01268  * of a NameAndOptionalUID to mean this is indeed a BitString.
01269  * This is quite arbitrary - it has changed the past and might
01270  * change in the future.
01271  */
01272 
01273 
01274 static int
01275 nameUIDValidate(
01276        Syntax *syntax,
01277        struct berval *in )
01278 {
01279        int rc;
01280        struct berval dn, uid;
01281 
01282        if( BER_BVISEMPTY( in ) ) return LDAP_SUCCESS;
01283 
01284        ber_dupbv( &dn, in );
01285        if( !dn.bv_val ) return LDAP_OTHER;
01286 
01287        /* if there's a "#", try bitStringValidate()... */
01288        uid.bv_val = strrchr( dn.bv_val, '#' );
01289        if ( !BER_BVISNULL( &uid ) ) {
01290               uid.bv_val++;
01291               uid.bv_len = dn.bv_len - ( uid.bv_val - dn.bv_val );
01292 
01293               rc = bitStringValidate( NULL, &uid );
01294               if ( rc == LDAP_SUCCESS ) {
01295                      /* in case of success, trim the UID,
01296                       * otherwise treat it as part of the DN */
01297                      dn.bv_len -= uid.bv_len + 1;
01298                      uid.bv_val[-1] = '\0';
01299               }
01300        }
01301 
01302        rc = dnValidate( NULL, &dn );
01303 
01304        ber_memfree( dn.bv_val );
01305        return rc;
01306 }
01307 
01308 int
01309 nameUIDPretty(
01310        Syntax *syntax,
01311        struct berval *val,
01312        struct berval *out,
01313        void *ctx )
01314 {
01315        assert( val != NULL );
01316        assert( out != NULL );
01317 
01318 
01319        Debug( LDAP_DEBUG_TRACE, ">>> nameUIDPretty: <%s>\n", val->bv_val, 0, 0 );
01320 
01321        if( BER_BVISEMPTY( val ) ) {
01322               ber_dupbv_x( out, val, ctx );
01323 
01324        } else if ( val->bv_len > SLAP_LDAPDN_MAXLEN ) {
01325               return LDAP_INVALID_SYNTAX;
01326 
01327        } else {
01328               int           rc;
01329               struct berval dnval = *val;
01330               struct berval uidval = BER_BVNULL;
01331 
01332               uidval.bv_val = strrchr( val->bv_val, '#' );
01333               if ( !BER_BVISNULL( &uidval ) ) {
01334                      uidval.bv_val++;
01335                      uidval.bv_len = val->bv_len - ( uidval.bv_val - val->bv_val );
01336 
01337                      rc = bitStringValidate( NULL, &uidval );
01338 
01339                      if ( rc == LDAP_SUCCESS ) {
01340                             ber_dupbv_x( &dnval, val, ctx );
01341                             uidval.bv_val--;
01342                             dnval.bv_len -= ++uidval.bv_len;
01343                             dnval.bv_val[dnval.bv_len] = '\0';
01344 
01345                      } else {
01346                             BER_BVZERO( &uidval );
01347                      }
01348               }
01349 
01350               rc = dnPretty( syntax, &dnval, out, ctx );
01351               if ( dnval.bv_val != val->bv_val ) {
01352                      slap_sl_free( dnval.bv_val, ctx );
01353               }
01354               if( rc != LDAP_SUCCESS ) {
01355                      return rc;
01356               }
01357 
01358               if( !BER_BVISNULL( &uidval ) ) {
01359                      char   *tmp;
01360 
01361                      tmp = slap_sl_realloc( out->bv_val, out->bv_len 
01362                             + uidval.bv_len + 1,
01363                             ctx );
01364                      if( tmp == NULL ) {
01365                             ber_memfree_x( out->bv_val, ctx );
01366                             return LDAP_OTHER;
01367                      }
01368                      out->bv_val = tmp;
01369                      memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
01370                      out->bv_len += uidval.bv_len;
01371                      out->bv_val[out->bv_len] = '\0';
01372               }
01373        }
01374 
01375        Debug( LDAP_DEBUG_TRACE, "<<< nameUIDPretty: <%s>\n", out->bv_val, 0, 0 );
01376 
01377        return LDAP_SUCCESS;
01378 }
01379 
01380 static int
01381 uniqueMemberNormalize(
01382        slap_mask_t usage,
01383        Syntax *syntax,
01384        MatchingRule *mr,
01385        struct berval *val,
01386        struct berval *normalized,
01387        void *ctx )
01388 {
01389        struct berval out;
01390        int rc;
01391 
01392        assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
01393 
01394        ber_dupbv_x( &out, val, ctx );
01395        if ( BER_BVISEMPTY( &out ) ) {
01396               *normalized = out;
01397 
01398        } else {
01399               struct berval uid = BER_BVNULL;
01400 
01401               uid.bv_val = strrchr( out.bv_val, '#' );
01402               if ( !BER_BVISNULL( &uid ) ) {
01403                      uid.bv_val++;
01404                      uid.bv_len = out.bv_len - ( uid.bv_val - out.bv_val );
01405 
01406                      rc = bitStringValidate( NULL, &uid );
01407                      if ( rc == LDAP_SUCCESS ) {
01408                             uid.bv_val[-1] = '\0';
01409                             out.bv_len -= uid.bv_len + 1;
01410                      } else {
01411                             BER_BVZERO( &uid );
01412                      }
01413               }
01414 
01415               rc = dnNormalize( 0, NULL, NULL, &out, normalized, ctx );
01416 
01417               if( rc != LDAP_SUCCESS ) {
01418                      slap_sl_free( out.bv_val, ctx );
01419                      return LDAP_INVALID_SYNTAX;
01420               }
01421 
01422               if( !BER_BVISNULL( &uid ) ) {
01423                      char   *tmp;
01424 
01425                      tmp = ch_realloc( normalized->bv_val,
01426                             normalized->bv_len + uid.bv_len
01427                             + STRLENOF("#") + 1 );
01428                      if ( tmp == NULL ) {
01429                             ber_memfree_x( normalized->bv_val, ctx );
01430                             return LDAP_OTHER;
01431                      }
01432 
01433                      normalized->bv_val = tmp;
01434 
01435                      /* insert the separator */
01436                      normalized->bv_val[normalized->bv_len++] = '#';
01437 
01438                      /* append the UID */
01439                      AC_MEMCPY( &normalized->bv_val[normalized->bv_len],
01440                             uid.bv_val, uid.bv_len );
01441                      normalized->bv_len += uid.bv_len;
01442 
01443                      /* terminate */
01444                      normalized->bv_val[normalized->bv_len] = '\0';
01445               }
01446 
01447               slap_sl_free( out.bv_val, ctx );
01448        }
01449 
01450        return LDAP_SUCCESS;
01451 }
01452 
01453 static int
01454 uniqueMemberMatch(
01455        int *matchp,
01456        slap_mask_t flags,
01457        Syntax *syntax,
01458        MatchingRule *mr,
01459        struct berval *value,
01460        void *assertedValue )
01461 {
01462        int match;
01463        struct berval *asserted = (struct berval *) assertedValue;
01464        struct berval assertedDN = *asserted;
01465        struct berval assertedUID = BER_BVNULL;
01466        struct berval valueDN = *value;
01467        struct berval valueUID = BER_BVNULL;
01468        int approx = ((flags & SLAP_MR_EQUALITY_APPROX) == SLAP_MR_EQUALITY_APPROX);
01469 
01470        if ( !BER_BVISEMPTY( asserted ) ) {
01471               assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
01472               if ( !BER_BVISNULL( &assertedUID ) ) {
01473                      assertedUID.bv_val++;
01474                      assertedUID.bv_len = assertedDN.bv_len
01475                             - ( assertedUID.bv_val - assertedDN.bv_val );
01476 
01477                      if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
01478                             assertedDN.bv_len -= assertedUID.bv_len + 1;
01479 
01480                      } else {
01481                             BER_BVZERO( &assertedUID );
01482                      }
01483               }
01484        }
01485 
01486        if ( !BER_BVISEMPTY( value ) ) {
01487 
01488               valueUID.bv_val = strrchr( valueDN.bv_val, '#' );
01489               if ( !BER_BVISNULL( &valueUID ) ) {
01490                      valueUID.bv_val++;
01491                      valueUID.bv_len = valueDN.bv_len
01492                             - ( valueUID.bv_val - valueDN.bv_val );
01493 
01494                      if ( bitStringValidate( NULL, &valueUID ) == LDAP_SUCCESS ) {
01495                             valueDN.bv_len -= valueUID.bv_len + 1;
01496 
01497                      } else {
01498                             BER_BVZERO( &valueUID );
01499                      }
01500               }
01501        }
01502 
01503        if( valueUID.bv_len && assertedUID.bv_len ) {
01504               ber_slen_t d;
01505               d = (ber_slen_t) valueUID.bv_len - (ber_slen_t) assertedUID.bv_len;
01506               if ( d ) {
01507                      *matchp = sizeof(d) == sizeof(int) ? d : d < 0 ? -1 : 1;
01508                      return LDAP_SUCCESS;
01509               }
01510 
01511               match = memcmp( valueUID.bv_val, assertedUID.bv_val, valueUID.bv_len );
01512               if( match ) {
01513                      *matchp = match;
01514                      return LDAP_SUCCESS;
01515               }
01516 
01517        } else if ( !approx && valueUID.bv_len ) {
01518               match = -1;
01519               *matchp = match;
01520               return LDAP_SUCCESS;
01521 
01522        } else if ( !approx && assertedUID.bv_len ) {
01523               match = 1;
01524               *matchp = match;
01525               return LDAP_SUCCESS;
01526        }
01527 
01528        return dnMatch( matchp, flags, syntax, mr, &valueDN, &assertedDN );
01529 }
01530 
01531 static int 
01532 uniqueMemberIndexer(
01533        slap_mask_t use,
01534        slap_mask_t flags,
01535        Syntax *syntax,
01536        MatchingRule *mr,
01537        struct berval *prefix,
01538        BerVarray values,
01539        BerVarray *keysp,
01540        void *ctx )
01541 {
01542        BerVarray dnvalues;
01543        int rc;
01544        int i;
01545        for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
01546               /* just count them */                 
01547        }
01548        assert( i > 0 );
01549 
01550        dnvalues = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
01551 
01552        for( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
01553               struct berval assertedDN = values[i];
01554               struct berval assertedUID = BER_BVNULL;
01555 
01556               if ( !BER_BVISEMPTY( &assertedDN ) ) {
01557                      assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
01558                      if ( !BER_BVISNULL( &assertedUID ) ) {
01559                             assertedUID.bv_val++;
01560                             assertedUID.bv_len = assertedDN.bv_len
01561                                    - ( assertedUID.bv_val - assertedDN.bv_val );
01562        
01563                             if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
01564                                    assertedDN.bv_len -= assertedUID.bv_len + 1;
01565 
01566                             } else {
01567                                    BER_BVZERO( &assertedUID );
01568                             }
01569                      }
01570               }
01571 
01572               dnvalues[i] = assertedDN;
01573        }
01574        BER_BVZERO( &dnvalues[i] );
01575 
01576        rc = octetStringIndexer( use, flags, syntax, mr, prefix,
01577               dnvalues, keysp, ctx );
01578 
01579        slap_sl_free( dnvalues, ctx );
01580        return rc;
01581 }
01582 
01583 static int 
01584 uniqueMemberFilter(
01585        slap_mask_t use,
01586        slap_mask_t flags,
01587        Syntax *syntax,
01588        MatchingRule *mr,
01589        struct berval *prefix,
01590        void * assertedValue,
01591        BerVarray *keysp,
01592        void *ctx )
01593 {
01594        struct berval *asserted = (struct berval *) assertedValue;
01595        struct berval assertedDN = *asserted;
01596        struct berval assertedUID = BER_BVNULL;
01597 
01598        if ( !BER_BVISEMPTY( asserted ) ) {
01599               assertedUID.bv_val = strrchr( assertedDN.bv_val, '#' );
01600               if ( !BER_BVISNULL( &assertedUID ) ) {
01601                      assertedUID.bv_val++;
01602                      assertedUID.bv_len = assertedDN.bv_len
01603                             - ( assertedUID.bv_val - assertedDN.bv_val );
01604 
01605                      if ( bitStringValidate( NULL, &assertedUID ) == LDAP_SUCCESS ) {
01606                             assertedDN.bv_len -= assertedUID.bv_len + 1;
01607 
01608                      } else {
01609                             BER_BVZERO( &assertedUID );
01610                      }
01611               }
01612        }
01613 
01614        return octetStringFilter( use, flags, syntax, mr, prefix,
01615               &assertedDN, keysp, ctx );
01616 }
01617 
01618 
01619 /*
01620  * Handling boolean syntax and matching is quite rigid.
01621  * A more flexible approach would be to allow a variety
01622  * of strings to be normalized and prettied into TRUE
01623  * and FALSE.
01624  */
01625 static int
01626 booleanValidate(
01627        Syntax *syntax,
01628        struct berval *in )
01629 {
01630        /* very unforgiving validation, requires no normalization
01631         * before simplistic matching
01632         */
01633 
01634        if( in->bv_len == 4 ) {
01635               if( bvmatch( in, &slap_true_bv ) ) {
01636                      return LDAP_SUCCESS;
01637               }
01638        } else if( in->bv_len == 5 ) {
01639               if( bvmatch( in, &slap_false_bv ) ) {
01640                      return LDAP_SUCCESS;
01641               }
01642        }
01643 
01644        return LDAP_INVALID_SYNTAX;
01645 }
01646 
01647 static int
01648 booleanMatch(
01649        int *matchp,
01650        slap_mask_t flags,
01651        Syntax *syntax,
01652        MatchingRule *mr,
01653        struct berval *value,
01654        void *assertedValue )
01655 {
01656        /* simplistic matching allowed by rigid validation */
01657        struct berval *asserted = (struct berval *) assertedValue;
01658        *matchp = (int) asserted->bv_len - (int) value->bv_len;
01659        return LDAP_SUCCESS;
01660 }
01661 
01662 /*-------------------------------------------------------------------
01663 LDAP/X.500 string syntax / matching rules have a few oddities.  This
01664 comment attempts to detail how slapd(8) treats them.
01665 
01666 Summary:
01667   StringSyntax              X.500  LDAP   Matching/Comments
01668   DirectoryString    CHOICE UTF8   i/e + ignore insignificant spaces
01669   PrintableString    subset subset i/e + ignore insignificant spaces
01670   PrintableString    subset subset i/e + ignore insignificant spaces
01671   NumericString             subset subset ignore all spaces
01672   IA5String                 ASCII  ASCII  i/e + ignore insignificant spaces
01673   TeletexString             T.61   T.61   i/e + ignore insignificant spaces
01674 
01675   TelephoneNumber    subset subset i + ignore all spaces and "-"
01676 
01677   See RFC 4518 for details.
01678 
01679 
01680 Directory String -
01681   In X.500(93), a directory string can be either a PrintableString,
01682   a bmpString, or a UniversalString (e.g., UCS (a subset of Unicode)).
01683   In later versions, more CHOICEs were added.  In all cases the string
01684   must be non-empty.
01685 
01686   In LDAPv3, a directory string is a UTF-8 encoded UCS string.
01687   A directory string cannot be zero length.
01688 
01689   For matching, there are both case ignore and exact rules.  Both
01690   also require that "insignificant" spaces be ignored.
01691        spaces before the first non-space are ignored;
01692        spaces after the last non-space are ignored;
01693        spaces after a space are ignored.
01694   Note: by these rules (and as clarified in X.520), a string of only
01695   spaces is to be treated as if held one space, not empty (which
01696   would be a syntax error).
01697 
01698 NumericString
01699   In ASN.1, numeric string is just a string of digits and spaces
01700   and could be empty.  However, in X.500, all attribute values of
01701   numeric string carry a non-empty constraint.  For example:
01702 
01703        internationalISDNNumber ATTRIBUTE ::= {
01704               WITH SYNTAX InternationalISDNNumber
01705               EQUALITY MATCHING RULE numericStringMatch
01706               SUBSTRINGS MATCHING RULE numericStringSubstringsMatch
01707               ID id-at-internationalISDNNumber }
01708        InternationalISDNNumber ::=
01709            NumericString (SIZE(1..ub-international-isdn-number))
01710 
01711   Unforunately, some assertion values are don't carry the same
01712   constraint (but its unclear how such an assertion could ever
01713   be true). In LDAP, there is one syntax (numericString) not two
01714   (numericString with constraint, numericString without constraint).
01715   This should be treated as numericString with non-empty constraint.
01716   Note that while someone may have no ISDN number, there are no ISDN
01717   numbers which are zero length.
01718 
01719   In matching, spaces are ignored.
01720 
01721 PrintableString
01722   In ASN.1, Printable string is just a string of printable characters
01723   and can be empty.  In X.500, semantics much like NumericString (see
01724   serialNumber for a like example) excepting uses insignificant space
01725   handling instead of ignore all spaces.  They must be non-empty.
01726 
01727 IA5String
01728   Basically same as PrintableString.  There are no examples in X.500,
01729   but same logic applies.  Empty strings are allowed.
01730 
01731 -------------------------------------------------------------------*/
01732 
01733 static int
01734 UTF8StringValidate(
01735        Syntax *syntax,
01736        struct berval *in )
01737 {
01738        ber_len_t count;
01739        int len;
01740        unsigned char *u = (unsigned char *)in->bv_val;
01741 
01742        if( BER_BVISEMPTY( in ) && syntax == slap_schema.si_syn_directoryString ) {
01743               /* directory strings cannot be empty */
01744               return LDAP_INVALID_SYNTAX;
01745        }
01746 
01747        for( count = in->bv_len; count > 0; count -= len, u += len ) {
01748               /* get the length indicated by the first byte */
01749               len = LDAP_UTF8_CHARLEN2( u, len );
01750 
01751               /* very basic checks */
01752               switch( len ) {
01753                      case 6:
01754                             if( (u[5] & 0xC0) != 0x80 ) {
01755                                    return LDAP_INVALID_SYNTAX;
01756                             }
01757                      case 5:
01758                             if( (u[4] & 0xC0) != 0x80 ) {
01759                                    return LDAP_INVALID_SYNTAX;
01760                             }
01761                      case 4:
01762                             if( (u[3] & 0xC0) != 0x80 ) {
01763                                    return LDAP_INVALID_SYNTAX;
01764                             }
01765                      case 3:
01766                             if( (u[2] & 0xC0 )!= 0x80 ) {
01767                                    return LDAP_INVALID_SYNTAX;
01768                             }
01769                      case 2:
01770                             if( (u[1] & 0xC0) != 0x80 ) {
01771                                    return LDAP_INVALID_SYNTAX;
01772                             }
01773                      case 1:
01774                             /* CHARLEN already validated it */
01775                             break;
01776                      default:
01777                             return LDAP_INVALID_SYNTAX;
01778               }
01779 
01780               /* make sure len corresponds with the offset
01781                      to the next character */
01782               if( LDAP_UTF8_OFFSET( (char *)u ) != len ) return LDAP_INVALID_SYNTAX;
01783        }
01784 
01785        if( count != 0 ) {
01786               return LDAP_INVALID_SYNTAX;
01787        }
01788 
01789        return LDAP_SUCCESS;
01790 }
01791 
01792 static int
01793 UTF8StringNormalize(
01794        slap_mask_t use,
01795        Syntax *syntax,
01796        MatchingRule *mr,
01797        struct berval *val,
01798        struct berval *normalized,
01799        void *ctx )
01800 {
01801        struct berval tmp, nvalue;
01802        int flags, wasspace;
01803        ber_len_t i;
01804 
01805        assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
01806 
01807        if( BER_BVISNULL( val ) ) {
01808               /* assume we're dealing with a syntax (e.g., UTF8String)
01809                * which allows empty strings
01810                */
01811               BER_BVZERO( normalized );
01812               return LDAP_SUCCESS;
01813        }
01814 
01815        flags = SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseExactMatch )
01816               ? LDAP_UTF8_NOCASEFOLD : LDAP_UTF8_CASEFOLD;
01817        flags |= ( ( use & SLAP_MR_EQUALITY_APPROX ) == SLAP_MR_EQUALITY_APPROX )
01818               ? LDAP_UTF8_APPROX : 0;
01819 
01820        val = UTF8bvnormalize( val, &tmp, flags, ctx );
01821        /* out of memory or syntax error, the former is unlikely */
01822        if( val == NULL ) {
01823               return LDAP_INVALID_SYNTAX;
01824        }
01825        
01826        /* collapse spaces (in place) */
01827        nvalue.bv_len = 0;
01828        nvalue.bv_val = tmp.bv_val;
01829 
01830        /* trim leading spaces? */
01831        wasspace = !((( use & SLAP_MR_SUBSTR_ANY ) == SLAP_MR_SUBSTR_ANY ) ||
01832               (( use & SLAP_MR_SUBSTR_FINAL ) == SLAP_MR_SUBSTR_FINAL ));
01833 
01834        for( i = 0; i < tmp.bv_len; i++) {
01835               if ( ASCII_SPACE( tmp.bv_val[i] )) {
01836                      if( wasspace++ == 0 ) {
01837                             /* trim repeated spaces */
01838                             nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
01839                      }
01840               } else {
01841                      wasspace = 0;
01842                      nvalue.bv_val[nvalue.bv_len++] = tmp.bv_val[i];
01843               }
01844        }
01845 
01846        if( !BER_BVISEMPTY( &nvalue ) ) {
01847               /* trim trailing space? */
01848               if( wasspace && (
01849                      (( use & SLAP_MR_SUBSTR_INITIAL ) != SLAP_MR_SUBSTR_INITIAL ) &&
01850                      ( use & SLAP_MR_SUBSTR_ANY ) != SLAP_MR_SUBSTR_ANY ))
01851               {
01852                      --nvalue.bv_len;
01853               }
01854               nvalue.bv_val[nvalue.bv_len] = '\0';
01855 
01856        } else if ( tmp.bv_len )  {
01857               /* string of all spaces is treated as one space */
01858               nvalue.bv_val[0] = ' ';
01859               nvalue.bv_val[1] = '\0';
01860               nvalue.bv_len = 1;
01861        }      /* should never be entered with 0-length val */
01862 
01863        *normalized = nvalue;
01864        return LDAP_SUCCESS;
01865 }
01866 
01867 static int
01868 directoryStringSubstringsMatch(
01869        int *matchp,
01870        slap_mask_t flags,
01871        Syntax *syntax,
01872        MatchingRule *mr,
01873        struct berval *value,
01874        void *assertedValue )
01875 {
01876        int match = 0;
01877        SubstringsAssertion *sub = assertedValue;
01878        struct berval left = *value;
01879        ber_len_t i;
01880        int priorspace=0;
01881 
01882        if ( !BER_BVISNULL( &sub->sa_initial ) ) {
01883               if ( sub->sa_initial.bv_len > left.bv_len ) {
01884                      /* not enough left */
01885                      match = 1;
01886                      goto done;
01887               }
01888 
01889               match = memcmp( sub->sa_initial.bv_val, left.bv_val,
01890                      sub->sa_initial.bv_len );
01891 
01892               if ( match != 0 ) {
01893                      goto done;
01894               }
01895 
01896               left.bv_val += sub->sa_initial.bv_len;
01897               left.bv_len -= sub->sa_initial.bv_len;
01898 
01899               priorspace = ASCII_SPACE(
01900                      sub->sa_initial.bv_val[sub->sa_initial.bv_len] );
01901        }
01902 
01903        if ( sub->sa_any ) {
01904               for ( i = 0; !BER_BVISNULL( &sub->sa_any[i] ); i++ ) {
01905                      ber_len_t idx;
01906                      char *p;
01907 
01908                      if( priorspace && !BER_BVISEMPTY( &sub->sa_any[i] ) 
01909                             && ASCII_SPACE( sub->sa_any[i].bv_val[0] ))
01910                      { 
01911                             /* allow next space to match */
01912                             left.bv_val--;
01913                             left.bv_len++;
01914                      }
01915                      priorspace=0;
01916 
01917 retry:
01918                      if ( BER_BVISEMPTY( &sub->sa_any[i] ) ) {
01919                             continue;
01920                      }
01921 
01922                      if ( sub->sa_any[i].bv_len > left.bv_len ) {
01923                             /* not enough left */
01924                             match = 1;
01925                             goto done;
01926                      }
01927 
01928                      p = memchr( left.bv_val, *sub->sa_any[i].bv_val, left.bv_len );
01929 
01930                      if( p == NULL ) {
01931                             match = 1;
01932                             goto done;
01933                      }
01934 
01935                      idx = p - left.bv_val;
01936 
01937                      if ( idx >= left.bv_len ) {
01938                             /* this shouldn't happen */
01939                             return LDAP_OTHER;
01940                      }
01941 
01942                      left.bv_val = p;
01943                      left.bv_len -= idx;
01944 
01945                      if ( sub->sa_any[i].bv_len > left.bv_len ) {
01946                             /* not enough left */
01947                             match = 1;
01948                             goto done;
01949                      }
01950 
01951                      match = memcmp( left.bv_val,
01952                             sub->sa_any[i].bv_val,
01953                             sub->sa_any[i].bv_len );
01954 
01955                      if ( match != 0 ) {
01956                             left.bv_val++;
01957                             left.bv_len--;
01958                             goto retry;
01959                      }
01960 
01961                      left.bv_val += sub->sa_any[i].bv_len;
01962                      left.bv_len -= sub->sa_any[i].bv_len;
01963 
01964                      priorspace = ASCII_SPACE(
01965                             sub->sa_any[i].bv_val[sub->sa_any[i].bv_len] );
01966               }
01967        }
01968 
01969        if ( !BER_BVISNULL( &sub->sa_final ) ) {
01970               if( priorspace && !BER_BVISEMPTY( &sub->sa_final ) 
01971                      && ASCII_SPACE( sub->sa_final.bv_val[0] ))
01972               { 
01973                      /* allow next space to match */
01974                      left.bv_val--;
01975                      left.bv_len++;
01976               }
01977 
01978               if ( sub->sa_final.bv_len > left.bv_len ) {
01979                      /* not enough left */
01980                      match = 1;
01981                      goto done;
01982               }
01983 
01984               match = memcmp( sub->sa_final.bv_val,
01985                      &left.bv_val[left.bv_len - sub->sa_final.bv_len],
01986                      sub->sa_final.bv_len );
01987 
01988               if ( match != 0 ) {
01989                      goto done;
01990               }
01991        }
01992 
01993 done:
01994        *matchp = match;
01995        return LDAP_SUCCESS;
01996 }
01997 
01998 #if defined(SLAPD_APPROX_INITIALS)
01999 #      define SLAPD_APPROX_DELIMITER "._ "
02000 #      define SLAPD_APPROX_WORDLEN 2
02001 #else
02002 #      define SLAPD_APPROX_DELIMITER " "
02003 #      define SLAPD_APPROX_WORDLEN 1
02004 #endif
02005 
02006 static int
02007 approxMatch(
02008        int *matchp,
02009        slap_mask_t flags,
02010        Syntax *syntax,
02011        MatchingRule *mr,
02012        struct berval *value,
02013        void *assertedValue )
02014 {
02015        struct berval *nval, *assertv;
02016        char *val, **values, **words, *c;
02017        int i, count, len, nextchunk=0, nextavail=0;
02018 
02019        /* Yes, this is necessary */
02020        nval = UTF8bvnormalize( value, NULL, LDAP_UTF8_APPROX, NULL );
02021        if( nval == NULL ) {
02022               *matchp = 1;
02023               return LDAP_SUCCESS;
02024        }
02025 
02026        /* Yes, this is necessary */
02027        assertv = UTF8bvnormalize( ((struct berval *)assertedValue),
02028               NULL, LDAP_UTF8_APPROX, NULL );
02029        if( assertv == NULL ) {
02030               ber_bvfree( nval );
02031               *matchp = 1;
02032               return LDAP_SUCCESS;
02033        }
02034 
02035        /* Isolate how many words there are */
02036        for ( c = nval->bv_val, count = 1; *c; c++ ) {
02037               c = strpbrk( c, SLAPD_APPROX_DELIMITER );
02038               if ( c == NULL ) break;
02039               *c = '\0';
02040               count++;
02041        }
02042 
02043        /* Get a phonetic copy of each word */
02044        words = (char **)ch_malloc( count * sizeof(char *) );
02045        values = (char **)ch_malloc( count * sizeof(char *) );
02046        for ( c = nval->bv_val, i = 0;  i < count; i++, c += strlen(c) + 1 ) {
02047               words[i] = c;
02048               values[i] = phonetic(c);
02049        }
02050 
02051        /* Work through the asserted value's words, to see if at least some
02052         * of the words are there, in the same order. */
02053        len = 0;
02054        while ( (ber_len_t) nextchunk < assertv->bv_len ) {
02055               len = strcspn( assertv->bv_val + nextchunk, SLAPD_APPROX_DELIMITER);
02056               if( len == 0 ) {
02057                      nextchunk++;
02058                      continue;
02059               }
02060 #if defined(SLAPD_APPROX_INITIALS)
02061               else if( len == 1 ) {
02062                      /* Single letter words need to at least match one word's initial */
02063                      for( i=nextavail; i<count; i++ )
02064                             if( !strncasecmp( assertv->bv_val + nextchunk, words[i], 1 )) {
02065                                    nextavail=i+1;
02066                                    break;
02067                             }
02068               }
02069 #endif
02070               else {
02071                      /* Isolate the next word in the asserted value and phonetic it */
02072                      assertv->bv_val[nextchunk+len] = '\0';
02073                      val = phonetic( assertv->bv_val + nextchunk );
02074 
02075                      /* See if this phonetic chunk is in the remaining words of *value */
02076                      for( i=nextavail; i<count; i++ ){
02077                             if( !strcmp( val, values[i] ) ){
02078                                    nextavail = i+1;
02079                                    break;
02080                             }
02081                      }
02082                      ch_free( val );
02083               }
02084 
02085               /* This chunk in the asserted value was NOT within the *value. */
02086               if( i >= count ) {
02087                      nextavail=-1;
02088                      break;
02089               }
02090 
02091               /* Go on to the next word in the asserted value */
02092               nextchunk += len+1;
02093        }
02094 
02095        /* If some of the words were seen, call it a match */
02096        if( nextavail > 0 ) {
02097               *matchp = 0;
02098        }
02099        else {
02100               *matchp = 1;
02101        }
02102 
02103        /* Cleanup allocs */
02104        ber_bvfree( assertv );
02105        for( i=0; i<count; i++ ) {
02106               ch_free( values[i] );
02107        }
02108        ch_free( values );
02109        ch_free( words );
02110        ber_bvfree( nval );
02111 
02112        return LDAP_SUCCESS;
02113 }
02114 
02115 static int 
02116 approxIndexer(
02117        slap_mask_t use,
02118        slap_mask_t flags,
02119        Syntax *syntax,
02120        MatchingRule *mr,
02121        struct berval *prefix,
02122        BerVarray values,
02123        BerVarray *keysp,
02124        void *ctx )
02125 {
02126        char *c;
02127        int i,j, len, wordcount, keycount=0;
02128        struct berval *newkeys;
02129        BerVarray keys=NULL;
02130 
02131        for( j = 0; !BER_BVISNULL( &values[j] ); j++ ) {
02132               struct berval val = BER_BVNULL;
02133               /* Yes, this is necessary */
02134               UTF8bvnormalize( &values[j], &val, LDAP_UTF8_APPROX, NULL );
02135               assert( !BER_BVISNULL( &val ) );
02136 
02137               /* Isolate how many words there are. There will be a key for each */
02138               for( wordcount = 0, c = val.bv_val; *c; c++) {
02139                      len = strcspn(c, SLAPD_APPROX_DELIMITER);
02140                      if( len >= SLAPD_APPROX_WORDLEN ) wordcount++;
02141                      c+= len;
02142                      if (*c == '\0') break;
02143                      *c = '\0';
02144               }
02145 
02146               /* Allocate/increase storage to account for new keys */
02147               newkeys = (struct berval *)ch_malloc( (keycount + wordcount + 1) 
02148                      * sizeof(struct berval) );
02149               AC_MEMCPY( newkeys, keys, keycount * sizeof(struct berval) );
02150               if( keys ) ch_free( keys );
02151               keys = newkeys;
02152 
02153               /* Get a phonetic copy of each word */
02154               for( c = val.bv_val, i = 0; i < wordcount; c += len + 1 ) {
02155                      len = strlen( c );
02156                      if( len < SLAPD_APPROX_WORDLEN ) continue;
02157                      ber_str2bv( phonetic( c ), 0, 0, &keys[keycount] );
02158                      if( keys[keycount].bv_len ) {
02159                             keycount++;
02160                      } else {
02161                             ch_free( keys[keycount].bv_val );
02162                      }
02163                      i++;
02164               }
02165 
02166               ber_memfree( val.bv_val );
02167        }
02168        BER_BVZERO( &keys[keycount] );
02169        *keysp = keys;
02170 
02171        return LDAP_SUCCESS;
02172 }
02173 
02174 static int 
02175 approxFilter(
02176        slap_mask_t use,
02177        slap_mask_t flags,
02178        Syntax *syntax,
02179        MatchingRule *mr,
02180        struct berval *prefix,
02181        void * assertedValue,
02182        BerVarray *keysp,
02183        void *ctx )
02184 {
02185        char *c;
02186        int i, count, len;
02187        struct berval *val;
02188        BerVarray keys;
02189 
02190        /* Yes, this is necessary */
02191        val = UTF8bvnormalize( ((struct berval *)assertedValue),
02192               NULL, LDAP_UTF8_APPROX, NULL );
02193        if( val == NULL || BER_BVISNULL( val ) ) {
02194               keys = (struct berval *)ch_malloc( sizeof(struct berval) );
02195               BER_BVZERO( &keys[0] );
02196               *keysp = keys;
02197               ber_bvfree( val );
02198               return LDAP_SUCCESS;
02199        }
02200 
02201        /* Isolate how many words there are. There will be a key for each */
02202        for( count = 0,c = val->bv_val; *c; c++) {
02203               len = strcspn(c, SLAPD_APPROX_DELIMITER);
02204               if( len >= SLAPD_APPROX_WORDLEN ) count++;
02205               c+= len;
02206               if (*c == '\0') break;
02207               *c = '\0';
02208        }
02209 
02210        /* Allocate storage for new keys */
02211        keys = (struct berval *)ch_malloc( (count + 1) * sizeof(struct berval) );
02212 
02213        /* Get a phonetic copy of each word */
02214        for( c = val->bv_val, i = 0; i < count; c += len + 1 ) {
02215               len = strlen(c);
02216               if( len < SLAPD_APPROX_WORDLEN ) continue;
02217               ber_str2bv( phonetic( c ), 0, 0, &keys[i] );
02218               i++;
02219        }
02220 
02221        ber_bvfree( val );
02222 
02223        BER_BVZERO( &keys[count] );
02224        *keysp = keys;
02225 
02226        return LDAP_SUCCESS;
02227 }
02228 
02229 /* Remove all spaces and '-' characters */
02230 static int
02231 telephoneNumberNormalize(
02232        slap_mask_t usage,
02233        Syntax *syntax,
02234        MatchingRule *mr,
02235        struct berval *val,
02236        struct berval *normalized,
02237        void *ctx )
02238 {
02239        char *p, *q;
02240 
02241        assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
02242 
02243        /* validator should have refused an empty string */
02244        assert( !BER_BVISEMPTY( val ) );
02245 
02246        q = normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
02247 
02248        for( p = val->bv_val; *p; p++ ) {
02249               if ( ! ( ASCII_SPACE( *p ) || *p == '-' )) {
02250                      *q++ = *p;
02251               }
02252        }
02253        *q = '\0';
02254 
02255        normalized->bv_len = q - normalized->bv_val;
02256 
02257        if( BER_BVISEMPTY( normalized ) ) {
02258               slap_sl_free( normalized->bv_val, ctx );
02259               BER_BVZERO( normalized );
02260               return LDAP_INVALID_SYNTAX;
02261        }
02262 
02263        return LDAP_SUCCESS;
02264 }
02265 
02266 static int
02267 postalAddressValidate(
02268        Syntax *syntax,
02269        struct berval *in )
02270 {
02271        struct berval bv = *in;
02272        ber_len_t c;
02273 
02274        for ( c = 0; c < in->bv_len; c++ ) {
02275               if ( in->bv_val[c] == '\\' ) {
02276                      c++;
02277                      if ( strncasecmp( &in->bv_val[c], "24", STRLENOF( "24" ) ) != 0
02278                             && strncasecmp( &in->bv_val[c], "5C", STRLENOF( "5C" ) ) != 0 )
02279                      {
02280                             return LDAP_INVALID_SYNTAX;
02281                      }
02282                      continue;
02283               }
02284 
02285               if ( in->bv_val[c] == '$' ) {
02286                      bv.bv_len = &in->bv_val[c] - bv.bv_val;
02287                      if ( UTF8StringValidate( NULL, &bv ) != LDAP_SUCCESS ) {
02288                             return LDAP_INVALID_SYNTAX;
02289                      }
02290                      bv.bv_val = &in->bv_val[c] + 1;
02291               }
02292        }
02293 
02294        bv.bv_len = &in->bv_val[c] - bv.bv_val;
02295        return UTF8StringValidate( NULL, &bv );
02296 }
02297 
02298 static int
02299 postalAddressNormalize(
02300        slap_mask_t usage,
02301        Syntax *syntax,
02302        MatchingRule *mr,
02303        struct berval *val,
02304        struct berval *normalized,
02305        void *ctx )
02306 {
02307        BerVarray lines = NULL, nlines = NULL;
02308        ber_len_t l, c;
02309        int rc = LDAP_SUCCESS;
02310        MatchingRule *xmr = NULL;
02311        char *p;
02312 
02313        if ( SLAP_MR_ASSOCIATED( mr, slap_schema.si_mr_caseIgnoreListMatch ) ) {
02314               xmr = slap_schema.si_mr_caseIgnoreMatch;
02315 
02316        } else {
02317               xmr = slap_schema.si_mr_caseExactMatch;
02318        }
02319 
02320        for ( l = 0, c = 0; c < val->bv_len; c++ ) {
02321               if ( val->bv_val[c] == '$' ) {
02322                      l++;
02323               }
02324        }
02325 
02326        lines = slap_sl_calloc( sizeof( struct berval ), 2 * ( l + 2 ), ctx );
02327        nlines = &lines[l + 2];
02328 
02329        lines[0].bv_val = val->bv_val;
02330        for ( l = 0, c = 0; c < val->bv_len; c++ ) {
02331               if ( val->bv_val[c] == '$' ) {
02332                      lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
02333                      l++;
02334                      lines[l].bv_val = &val->bv_val[c + 1];
02335               }
02336        }
02337        lines[l].bv_len = &val->bv_val[c] - lines[l].bv_val;
02338 
02339        normalized->bv_len = c = l;
02340 
02341        for ( l = 0; l <= c; l++ ) {
02342               /* NOTE: we directly normalize each line,
02343                * without unescaping the values, since the special
02344                * values '\24' ('$') and '\5C' ('\') are not affected
02345                * by normalization */
02346               if ( !lines[l].bv_len ) {
02347                      nlines[l].bv_len = 0;
02348                      nlines[l].bv_val = NULL;
02349                      continue;
02350               }
02351               rc = UTF8StringNormalize( usage, NULL, xmr, &lines[l], &nlines[l], ctx );
02352               if ( rc != LDAP_SUCCESS ) {
02353                      rc = LDAP_INVALID_SYNTAX;
02354                      goto done;
02355               }
02356 
02357               normalized->bv_len += nlines[l].bv_len;
02358        }
02359 
02360        normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
02361 
02362        p = normalized->bv_val;
02363        for ( l = 0; l <= c ; l++ ) {
02364               p = lutil_strbvcopy( p, &nlines[l] );
02365               *p++ = '$';
02366        }
02367        *--p = '\0';
02368 
02369        assert( p == &normalized->bv_val[normalized->bv_len] );
02370 
02371 done:;
02372        if ( nlines != NULL ) {
02373               for ( l = 0; !BER_BVISNULL( &nlines[ l ] ); l++ ) {
02374                      slap_sl_free( nlines[l].bv_val, ctx );
02375               }
02376 
02377               slap_sl_free( lines, ctx );
02378        }
02379 
02380        return rc;
02381 }
02382 
02383 int
02384 numericoidValidate(
02385        Syntax *syntax,
02386        struct berval *in )
02387 {
02388        struct berval val = *in;
02389 
02390        if( BER_BVISEMPTY( &val ) ) {
02391               /* disallow empty strings */
02392               return LDAP_INVALID_SYNTAX;
02393        }
02394 
02395        while( OID_LEADCHAR( val.bv_val[0] ) ) {
02396               if ( val.bv_len == 1 ) {
02397                      return LDAP_SUCCESS;
02398               }
02399 
02400               if ( val.bv_val[0] == '0' && !OID_SEPARATOR( val.bv_val[1] )) {
02401                      break;
02402               }
02403 
02404               val.bv_val++;
02405               val.bv_len--;
02406 
02407               while ( OID_LEADCHAR( val.bv_val[0] )) {
02408                      val.bv_val++;
02409                      val.bv_len--;
02410 
02411                      if ( val.bv_len == 0 ) {
02412                             return LDAP_SUCCESS;
02413                      }
02414               }
02415 
02416               if( !OID_SEPARATOR( val.bv_val[0] )) {
02417                      break;
02418               }
02419 
02420               val.bv_val++;
02421               val.bv_len--;
02422        }
02423 
02424        return LDAP_INVALID_SYNTAX;
02425 }
02426 
02427 static int
02428 integerValidate(
02429        Syntax *syntax,
02430        struct berval *in )
02431 {
02432        ber_len_t i;
02433        struct berval val = *in;
02434 
02435        if ( BER_BVISEMPTY( &val ) ) return LDAP_INVALID_SYNTAX;
02436 
02437        if ( val.bv_val[0] == '-' ) {
02438               val.bv_len--;
02439               val.bv_val++;
02440 
02441               if( BER_BVISEMPTY( &val ) ) { /* bare "-" */
02442                      return LDAP_INVALID_SYNTAX;
02443               }
02444 
02445               if( val.bv_val[0] == '0' ) { /* "-0" */
02446                      return LDAP_INVALID_SYNTAX;
02447               }
02448 
02449        } else if ( val.bv_val[0] == '0' ) {
02450               if( val.bv_len > 1 ) { /* "0<more>" */
02451                      return LDAP_INVALID_SYNTAX;
02452               }
02453 
02454               return LDAP_SUCCESS;
02455        }
02456 
02457        for( i=0; i < val.bv_len; i++ ) {
02458               if( !ASCII_DIGIT(val.bv_val[i]) ) {
02459                      return LDAP_INVALID_SYNTAX;
02460               }
02461        }
02462 
02463        return LDAP_SUCCESS;
02464 }
02465 
02466 static int
02467 integerMatch(
02468        int *matchp,
02469        slap_mask_t flags,
02470        Syntax *syntax,
02471        MatchingRule *mr,
02472        struct berval *value,
02473        void *assertedValue )
02474 {
02475        struct berval *asserted = (struct berval *) assertedValue;
02476        int vsign = 1, asign = 1;   /* default sign = '+' */
02477        struct berval v, a;
02478        int match;
02479 
02480        v = *value;
02481        if( v.bv_val[0] == '-' ) {
02482               vsign = -1;
02483               v.bv_val++;
02484               v.bv_len--;
02485        }
02486 
02487        if( BER_BVISEMPTY( &v ) ) vsign = 0;
02488 
02489        a = *asserted;
02490        if( a.bv_val[0] == '-' ) {
02491               asign = -1;
02492               a.bv_val++;
02493               a.bv_len--;
02494        }
02495 
02496        if( BER_BVISEMPTY( &a ) ) vsign = 0;
02497 
02498        match = vsign - asign;
02499        if( match == 0 ) {
02500               match = ( v.bv_len != a.bv_len
02501                      ? ( v.bv_len < a.bv_len ? -1 : 1 )
02502                      : memcmp( v.bv_val, a.bv_val, v.bv_len ));
02503               if( vsign < 0 ) match = -match;
02504        }
02505 
02506        /* Ordering rule used in extensible match filter? */
02507        if ( (flags & SLAP_MR_EXT) && (mr->smr_usage & SLAP_MR_ORDERING) )
02508               match = (match >= 0);
02509 
02510        *matchp = match;
02511        return LDAP_SUCCESS;
02512 }
02513 
02514 /* 10**Chop < 256**Chopbytes and Chop > Chopbytes<<1 (for sign bit and itmp) */
02515 #define INDEX_INTLEN_CHOP 7
02516 #define INDEX_INTLEN_CHOPBYTES 3
02517 
02518 static int
02519 integerVal2Key(
02520        struct berval *in,
02521        struct berval *key,
02522        struct berval *tmp,
02523        void *ctx )
02524 {
02525        /* Integer index key format, designed for memcmp to collate correctly:
02526         * if too large: one's complement sign*<approx exponent=chopped bytes>,
02527         * two's complement value (sign-extended or chopped as needed),
02528         * however in first byte above, the top <number of exponent-bytes + 1>
02529         * bits are the inverse sign and next bit is the sign as delimiter.
02530         */
02531        ber_slen_t k = index_intlen_strlen;
02532        ber_len_t chop = 0;
02533        unsigned signmask = ~0x7fU;
02534        unsigned char lenbuf[sizeof(k) + 2], *lenp, neg = 0xff;
02535        struct berval val = *in, itmp = *tmp;
02536 
02537        if ( val.bv_val[0] != '-' ) {
02538               neg = 0;
02539               --k;
02540        }
02541 
02542        /* Chop least significant digits, increase length instead */
02543        if ( val.bv_len > (ber_len_t) k ) {
02544               chop = (val.bv_len-k+2)/INDEX_INTLEN_CHOP; /* 2 fewer digits */
02545               val.bv_len -= chop * INDEX_INTLEN_CHOP;   /* #digits chopped */
02546               chop *= INDEX_INTLEN_CHOPBYTES;           /* #bytes added */
02547        }
02548 
02549        if ( lutil_str2bin( &val, &itmp, ctx )) {
02550               return LDAP_INVALID_SYNTAX;
02551        }
02552 
02553        /* Omit leading sign byte */
02554        if ( itmp.bv_val[0] == neg ) {
02555               itmp.bv_val++;
02556               itmp.bv_len--;
02557        }
02558 
02559        k = (ber_slen_t) index_intlen - (ber_slen_t) (itmp.bv_len + chop);
02560        if ( k > 0 ) {
02561               assert( chop == 0 );
02562               memset( key->bv_val, neg, k );     /* sign-extend */
02563        } else if ( k != 0 || ((itmp.bv_val[0] ^ neg) & 0xc0) ) {
02564               /* Got exponent -k, or no room for 2 sign bits */
02565               lenp = lenbuf + sizeof(lenbuf);
02566               chop = - (ber_len_t) k;
02567               do {
02568                      *--lenp = ((unsigned char) chop & 0xff) ^ neg;
02569                      signmask >>= 1;
02570               } while ( (chop >>= 8) != 0 || (signmask >> 1) & (*lenp ^ neg) );
02571               /* With n bytes in lenbuf, the top n+1 bits of (signmask&0xff)
02572                * are 1, and the top n+2 bits of lenp[0] are the sign bit. */
02573               k = (lenbuf + sizeof(lenbuf)) - lenp;
02574               if ( k > (ber_slen_t) index_intlen )
02575                      k = index_intlen;
02576               memcpy( key->bv_val, lenp, k );
02577               itmp.bv_len = index_intlen - k;
02578        }
02579        memcpy( key->bv_val + k, itmp.bv_val, itmp.bv_len );
02580        key->bv_val[0] ^= (unsigned char) signmask & 0xff; /* invert sign */
02581        return 0;
02582 }
02583 
02584 /* Index generation function: Ordered index */
02585 static int
02586 integerIndexer(
02587        slap_mask_t use,
02588        slap_mask_t flags,
02589        Syntax *syntax,
02590        MatchingRule *mr,
02591        struct berval *prefix,
02592        BerVarray values,
02593        BerVarray *keysp,
02594        void *ctx )
02595 {
02596        char ibuf[64];
02597        struct berval itmp;
02598        BerVarray keys;
02599        ber_len_t vlen;
02600        int i, rc;
02601        unsigned maxstrlen = index_intlen_strlen + INDEX_INTLEN_CHOP-1;
02602 
02603        /* count the values and find max needed length */
02604        vlen = 0;
02605        for( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
02606               if ( vlen < values[i].bv_len )
02607                      vlen = values[i].bv_len;
02608        }
02609        if ( vlen > maxstrlen )
02610               vlen = maxstrlen;
02611 
02612        /* we should have at least one value at this point */
02613        assert( i > 0 );
02614 
02615        keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
02616        for ( i = 0; !BER_BVISNULL( &values[i] ); i++ ) {
02617               keys[i].bv_len = index_intlen;
02618               keys[i].bv_val = slap_sl_malloc( index_intlen, ctx );
02619        }
02620        keys[i].bv_len = 0;
02621        keys[i].bv_val = NULL;
02622 
02623        if ( vlen > sizeof(ibuf) ) {
02624               itmp.bv_val = slap_sl_malloc( vlen, ctx );
02625        } else {
02626               itmp.bv_val = ibuf;
02627        }
02628        itmp.bv_len = sizeof(ibuf);
02629 
02630        for ( i=0; !BER_BVISNULL( &values[i] ); i++ ) {
02631               if ( itmp.bv_val != ibuf ) {
02632                      itmp.bv_len = values[i].bv_len;
02633                      if ( itmp.bv_len <= sizeof(ibuf) )
02634                             itmp.bv_len = sizeof(ibuf);
02635                      else if ( itmp.bv_len > maxstrlen )
02636                             itmp.bv_len = maxstrlen;
02637               }
02638               rc = integerVal2Key( &values[i], &keys[i], &itmp, ctx );
02639               if ( rc )
02640                      goto func_leave;
02641        }
02642        *keysp = keys;
02643 func_leave:
02644        if ( itmp.bv_val != ibuf ) {
02645               slap_sl_free( itmp.bv_val, ctx );
02646        }
02647        return rc;
02648 }
02649 
02650 /* Index generation function: Ordered index */
02651 static int
02652 integerFilter(
02653        slap_mask_t use,
02654        slap_mask_t flags,
02655        Syntax *syntax,
02656        MatchingRule *mr,
02657        struct berval *prefix,
02658        void * assertedValue,
02659        BerVarray *keysp,
02660        void *ctx )
02661 {
02662        char ibuf[64];
02663        struct berval iv;
02664        BerVarray keys;
02665        struct berval *value;
02666        int rc;
02667 
02668        value = (struct berval *) assertedValue;
02669 
02670        keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
02671 
02672        keys[0].bv_len = index_intlen;
02673        keys[0].bv_val = slap_sl_malloc( index_intlen, ctx );
02674        keys[1].bv_len = 0;
02675        keys[1].bv_val = NULL;
02676 
02677        iv.bv_len = value->bv_len < index_intlen_strlen + INDEX_INTLEN_CHOP-1
02678               ? value->bv_len : index_intlen_strlen + INDEX_INTLEN_CHOP-1;
02679        if ( iv.bv_len > (int) sizeof(ibuf) ) {
02680               iv.bv_val = slap_sl_malloc( iv.bv_len, ctx );
02681        } else {
02682               iv.bv_val = ibuf;
02683               iv.bv_len = sizeof(ibuf);
02684        }
02685 
02686        rc = integerVal2Key( value, keys, &iv, ctx );
02687        if ( rc == 0 )
02688               *keysp = keys;
02689 
02690        if ( iv.bv_val != ibuf ) {
02691               slap_sl_free( iv.bv_val, ctx );
02692        }
02693        return rc;
02694 }
02695 
02696 static int
02697 countryStringValidate(
02698        Syntax *syntax,
02699        struct berval *val )
02700 {
02701        if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
02702 
02703        if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
02704               return LDAP_INVALID_SYNTAX;
02705        }
02706        if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
02707               return LDAP_INVALID_SYNTAX;
02708        }
02709 
02710        return LDAP_SUCCESS;
02711 }
02712 
02713 static int
02714 printableStringValidate(
02715        Syntax *syntax,
02716        struct berval *val )
02717 {
02718        ber_len_t i;
02719 
02720        if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
02721 
02722        for(i=0; i < val->bv_len; i++) {
02723               if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
02724                      return LDAP_INVALID_SYNTAX;
02725               }
02726        }
02727 
02728        return LDAP_SUCCESS;
02729 }
02730 
02731 static int
02732 printablesStringValidate(
02733        Syntax *syntax,
02734        struct berval *val )
02735 {
02736        ber_len_t i, len;
02737 
02738        if( BER_BVISEMPTY( val ) ) return LDAP_INVALID_SYNTAX;
02739 
02740        for(i=0,len=0; i < val->bv_len; i++) {
02741               int c = val->bv_val[i];
02742 
02743               if( c == '$' ) {
02744                      if( len == 0 ) {
02745                             return LDAP_INVALID_SYNTAX;
02746                      }
02747                      len = 0;
02748 
02749               } else if ( SLAP_PRINTABLE(c) ) {
02750                      len++;
02751               } else {
02752                      return LDAP_INVALID_SYNTAX;
02753               }
02754        }
02755 
02756        if( len == 0 ) {
02757               return LDAP_INVALID_SYNTAX;
02758        }
02759 
02760        return LDAP_SUCCESS;
02761 }
02762 
02763 static int
02764 IA5StringValidate(
02765        Syntax *syntax,
02766        struct berval *val )
02767 {
02768        ber_len_t i;
02769 
02770        for(i=0; i < val->bv_len; i++) {
02771               if( !LDAP_ASCII(val->bv_val[i]) ) {
02772                      return LDAP_INVALID_SYNTAX;
02773               }
02774        }
02775 
02776        return LDAP_SUCCESS;
02777 }
02778 
02779 static int
02780 IA5StringNormalize(
02781        slap_mask_t use,
02782        Syntax *syntax,
02783        MatchingRule *mr,
02784        struct berval *val,
02785        struct berval *normalized,
02786        void *ctx )
02787 {
02788        char *p, *q;
02789        int casefold = !SLAP_MR_ASSOCIATED( mr,
02790               slap_schema.si_mr_caseExactIA5Match );
02791 
02792        assert( SLAP_MR_IS_VALUE_OF_SYNTAX( use ) != 0 );
02793 
02794        p = val->bv_val;
02795 
02796        /* Ignore initial whitespace */
02797        while ( ASCII_SPACE( *p ) ) p++;
02798 
02799        normalized->bv_len = val->bv_len - ( p - val->bv_val );
02800        normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
02801        AC_MEMCPY( normalized->bv_val, p, normalized->bv_len );
02802        normalized->bv_val[normalized->bv_len] = '\0';
02803 
02804        p = q = normalized->bv_val;
02805 
02806        while ( *p ) {
02807               if ( ASCII_SPACE( *p ) ) {
02808                      *q++ = *p++;
02809 
02810                      /* Ignore the extra whitespace */
02811                      while ( ASCII_SPACE( *p ) ) {
02812                             p++;
02813                      }
02814 
02815               } else if ( casefold ) {
02816                      /* Most IA5 rules require casefolding */
02817                      *q++ = TOLOWER(*p); p++;
02818 
02819               } else {
02820                      *q++ = *p++;
02821               }
02822        }
02823 
02824        assert( normalized->bv_val <= p );
02825        assert( q <= p );
02826 
02827        /*
02828         * If the string ended in space, backup the pointer one
02829         * position.  One is enough because the above loop collapsed
02830         * all whitespace to a single space.
02831         */
02832        if ( q > normalized->bv_val && ASCII_SPACE( q[-1] ) ) --q;
02833 
02834        /* null terminate */
02835        *q = '\0';
02836 
02837        normalized->bv_len = q - normalized->bv_val;
02838 
02839        return LDAP_SUCCESS;
02840 }
02841 
02842 static int
02843 UUIDValidate(
02844        Syntax *syntax,
02845        struct berval *in )
02846 {
02847        int i;
02848        if( in->bv_len != 36 ) {
02849               return LDAP_INVALID_SYNTAX;
02850        }
02851 
02852        for( i=0; i<36; i++ ) {
02853               switch(i) {
02854                      case 8:
02855                      case 13:
02856                      case 18:
02857                      case 23:
02858                             if( in->bv_val[i] != '-' ) {
02859                                    return LDAP_INVALID_SYNTAX;
02860                             }
02861                             break;
02862                      default:
02863                             if( !ASCII_HEX( in->bv_val[i]) ) {
02864                                    return LDAP_INVALID_SYNTAX;
02865                             }
02866               }
02867        }
02868        
02869        return LDAP_SUCCESS;
02870 }
02871 
02872 static int
02873 UUIDPretty(
02874        Syntax *syntax,
02875        struct berval *in,
02876        struct berval *out,
02877        void *ctx )
02878 {
02879        int i;
02880        int rc=LDAP_INVALID_SYNTAX;
02881 
02882        assert( in != NULL );
02883        assert( out != NULL );
02884 
02885        if( in->bv_len != 36 ) return LDAP_INVALID_SYNTAX;
02886 
02887        out->bv_len = 36;
02888        out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
02889 
02890        for( i=0; i<36; i++ ) {
02891               switch(i) {
02892                      case 8:
02893                      case 13:
02894                      case 18:
02895                      case 23:
02896                             if( in->bv_val[i] != '-' ) {
02897                                    goto handle_error;
02898                             }
02899                             out->bv_val[i] = '-';
02900                             break;
02901 
02902                      default:
02903                             if( !ASCII_HEX( in->bv_val[i]) ) {
02904                                    goto handle_error;
02905                             }
02906                             out->bv_val[i] = TOLOWER( in->bv_val[i] );
02907               }
02908        }
02909 
02910        rc = LDAP_SUCCESS;
02911        out->bv_val[ out->bv_len ] = '\0';
02912 
02913        if( 0 ) {
02914 handle_error:
02915               slap_sl_free( out->bv_val, ctx );
02916               out->bv_val = NULL;
02917        }
02918 
02919        return rc;
02920 }
02921 
02922 int
02923 UUIDNormalize(
02924        slap_mask_t usage,
02925        Syntax *syntax,
02926        MatchingRule *mr,
02927        struct berval *val,
02928        struct berval *normalized,
02929        void *ctx )
02930 {
02931        unsigned char octet = '\0';
02932        int i;
02933        int j;
02934 
02935        if ( SLAP_MR_IS_DENORMALIZE( usage ) ) {
02936               /* NOTE: must be a normalized UUID */
02937               assert( val->bv_len == 16 );
02938 
02939               normalized->bv_val = slap_sl_malloc( LDAP_LUTIL_UUIDSTR_BUFSIZE, ctx );
02940               normalized->bv_len = lutil_uuidstr_from_normalized( val->bv_val,
02941                      val->bv_len, normalized->bv_val, LDAP_LUTIL_UUIDSTR_BUFSIZE );
02942               assert( normalized->bv_len == STRLENOF( "BADBADBA-DBAD-0123-4567-BADBADBADBAD" ) );
02943 
02944               return LDAP_SUCCESS;
02945        }
02946 
02947        normalized->bv_len = 16;
02948        normalized->bv_val = slap_sl_malloc( normalized->bv_len + 1, ctx );
02949 
02950        for( i=0, j=0; i<36; i++ ) {
02951               unsigned char nibble;
02952               if( val->bv_val[i] == '-' ) {
02953                      continue;
02954 
02955               } else if( ASCII_DIGIT( val->bv_val[i] ) ) {
02956                      nibble = val->bv_val[i] - '0';
02957 
02958               } else if( ASCII_HEXLOWER( val->bv_val[i] ) ) {
02959                      nibble = val->bv_val[i] - ('a'-10);
02960 
02961               } else if( ASCII_HEXUPPER( val->bv_val[i] ) ) {
02962                      nibble = val->bv_val[i] - ('A'-10);
02963 
02964               } else {
02965                      slap_sl_free( normalized->bv_val, ctx );
02966                      BER_BVZERO( normalized );
02967                      return LDAP_INVALID_SYNTAX;
02968               }
02969 
02970               if( j & 1 ) {
02971                      octet |= nibble;
02972                      normalized->bv_val[j>>1] = octet;
02973               } else {
02974                      octet = nibble << 4;
02975               }
02976               j++;
02977        }
02978 
02979        normalized->bv_val[normalized->bv_len] = 0;
02980        return LDAP_SUCCESS;
02981 }
02982 
02983 
02984 
02985 int
02986 numericStringValidate(
02987        Syntax *syntax,
02988        struct berval *in )
02989 {
02990        ber_len_t i;
02991 
02992        if( BER_BVISEMPTY( in ) ) return LDAP_INVALID_SYNTAX;
02993 
02994        for(i=0; i < in->bv_len; i++) {
02995               if( !SLAP_NUMERIC(in->bv_val[i]) ) {
02996                      return LDAP_INVALID_SYNTAX;
02997               }
02998        }
02999 
03000        return LDAP_SUCCESS;
03001 }
03002 
03003 static int
03004 numericStringNormalize(
03005        slap_mask_t usage,
03006        Syntax *syntax,
03007        MatchingRule *mr,
03008        struct berval *val,
03009        struct berval *normalized,
03010        void *ctx )
03011 {
03012        /* removal all spaces */
03013        char *p, *q;
03014 
03015        assert( !BER_BVISEMPTY( val ) );
03016 
03017        normalized->bv_val = slap_sl_malloc( val->bv_len + 1, ctx );
03018 
03019        p = val->bv_val;
03020        q = normalized->bv_val;
03021 
03022        while ( *p ) {
03023               if ( ASCII_SPACE( *p ) ) {
03024                      /* Ignore whitespace */
03025                      p++;
03026               } else {
03027                      *q++ = *p++;
03028               }
03029        }
03030 
03031        /* we should have copied no more than is in val */
03032        assert( (q - normalized->bv_val) <= (p - val->bv_val) );
03033 
03034        /* null terminate */
03035        *q = '\0';
03036 
03037        normalized->bv_len = q - normalized->bv_val;
03038 
03039        if( BER_BVISEMPTY( normalized ) ) {
03040               normalized->bv_val = slap_sl_realloc( normalized->bv_val, 2, ctx );
03041               normalized->bv_val[0] = ' ';
03042               normalized->bv_val[1] = '\0';
03043               normalized->bv_len = 1;
03044        }
03045 
03046        return LDAP_SUCCESS;
03047 }
03048 
03049 /*
03050  * Integer conversion macros that will use the largest available
03051  * type.
03052  */
03053 #if defined(HAVE_STRTOLL) && defined(HAVE_LONG_LONG)
03054 # define SLAP_STRTOL(n,e,b)  strtoll(n,e,b) 
03055 # define SLAP_LONG           long long
03056 #else
03057 # define SLAP_STRTOL(n,e,b)  strtol(n,e,b)
03058 # define SLAP_LONG           long
03059 #endif /* HAVE_STRTOLL ... */
03060 
03061 static int
03062 integerBitAndMatch(
03063        int *matchp,
03064        slap_mask_t flags,
03065        Syntax *syntax,
03066        MatchingRule *mr,
03067        struct berval *value,
03068        void *assertedValue )
03069 {
03070        SLAP_LONG lValue, lAssertedValue;
03071 
03072        errno = 0;
03073        /* safe to assume integers are NUL terminated? */
03074        lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
03075        if( errno == ERANGE )
03076        {
03077               return LDAP_CONSTRAINT_VIOLATION;
03078        }
03079 
03080        lAssertedValue = SLAP_STRTOL(((struct berval *)assertedValue)->bv_val,
03081               NULL, 10);
03082        if( errno == ERANGE )
03083        {
03084               return LDAP_CONSTRAINT_VIOLATION;
03085        }
03086 
03087        *matchp = ((lValue & lAssertedValue) == lAssertedValue) ? 0 : 1;
03088        return LDAP_SUCCESS;
03089 }
03090 
03091 static int
03092 integerBitOrMatch(
03093        int *matchp,
03094        slap_mask_t flags,
03095        Syntax *syntax,
03096        MatchingRule *mr,
03097        struct berval *value,
03098        void *assertedValue )
03099 {
03100        SLAP_LONG lValue, lAssertedValue;
03101 
03102        errno = 0;
03103        /* safe to assume integers are NUL terminated? */
03104        lValue = SLAP_STRTOL(value->bv_val, NULL, 10);
03105        if( errno == ERANGE )
03106        {
03107               return LDAP_CONSTRAINT_VIOLATION;
03108        }
03109 
03110        lAssertedValue = SLAP_STRTOL( ((struct berval *)assertedValue)->bv_val,
03111               NULL, 10);
03112        if( errno == ERANGE )
03113        {
03114               return LDAP_CONSTRAINT_VIOLATION;
03115        }
03116 
03117        *matchp = ((lValue & lAssertedValue) != 0) ? 0 : -1;
03118        return LDAP_SUCCESS;
03119 }
03120 
03121 static int
03122 checkNum( struct berval *in, struct berval *out )
03123 {
03124        /* parse serialNumber */
03125        ber_len_t neg = 0, extra = 0;
03126        char first = '\0';
03127 
03128        out->bv_val = in->bv_val;
03129        out->bv_len = 0;
03130 
03131        if ( out->bv_val[0] == '-' ) {
03132               neg++;
03133               out->bv_len++;
03134        }
03135 
03136        if ( strncasecmp( out->bv_val, "0x", STRLENOF("0x") ) == 0 ) {
03137               first = out->bv_val[2];
03138               extra = 2;
03139 
03140               out->bv_len += STRLENOF("0x");
03141               for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
03142                      if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
03143               }
03144 
03145        } else if ( out->bv_val[0] == '\'' ) {
03146               first = out->bv_val[1];
03147               extra = 3;
03148 
03149               out->bv_len += STRLENOF("'");
03150 
03151               for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
03152                      if ( !ASCII_HEX( out->bv_val[out->bv_len] ) ) break;
03153               }
03154               if ( strncmp( &out->bv_val[out->bv_len], "'H", STRLENOF("'H") ) != 0 ) {
03155                      return -1;
03156               }
03157               out->bv_len += STRLENOF("'H");
03158 
03159        } else {
03160               first = out->bv_val[0];
03161               for ( ; out->bv_len < in->bv_len; out->bv_len++ ) {
03162                      if ( !ASCII_DIGIT( out->bv_val[out->bv_len] ) ) break;
03163               }
03164        }
03165 
03166        if ( !( out->bv_len > neg ) ) {
03167               return -1;
03168        }
03169 
03170        if ( ( out->bv_len > extra + 1 + neg ) && ( first == '0' ) ) {
03171               return -1;
03172        }
03173 
03174        return 0;
03175 }
03176 
03177 static int
03178 serialNumberAndIssuerCheck(
03179        struct berval *in,
03180        struct berval *sn,
03181        struct berval *is,
03182        void *ctx )
03183 {
03184        ber_len_t n;
03185 
03186        if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
03187 
03188        if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
03189               /* Parse old format */
03190               is->bv_val = ber_bvchr( in, '$' );
03191               if( BER_BVISNULL( is ) ) return LDAP_INVALID_SYNTAX;
03192 
03193               sn->bv_val = in->bv_val;
03194               sn->bv_len = is->bv_val - in->bv_val;
03195 
03196               is->bv_val++;
03197               is->bv_len = in->bv_len - (sn->bv_len + 1);
03198 
03199               /* eat leading zeros */
03200               for( n=0; n < (sn->bv_len-1); n++ ) {
03201                      if( sn->bv_val[n] != '0' ) break;
03202               }
03203               sn->bv_val += n;
03204               sn->bv_len -= n;
03205 
03206               for( n=0; n < sn->bv_len; n++ ) {
03207                      if( !ASCII_DIGIT(sn->bv_val[n]) ) return LDAP_INVALID_SYNTAX;
03208               }
03209 
03210        } else {
03211               /* Parse GSER format */ 
03212               enum {
03213                      HAVE_NONE = 0x0,
03214                      HAVE_ISSUER = 0x1,
03215                      HAVE_SN = 0x2,
03216                      HAVE_ALL = ( HAVE_ISSUER | HAVE_SN )
03217               } have = HAVE_NONE;
03218 
03219               int numdquotes = 0;
03220               struct berval x = *in;
03221               struct berval ni;
03222               x.bv_val++;
03223               x.bv_len -= 2;
03224 
03225               do {
03226                      /* eat leading spaces */
03227                      for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
03228                             /* empty */;
03229                      }
03230 
03231                      /* should be at issuer or serialNumber NamedValue */
03232                      if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
03233                             if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
03234 
03235                             /* parse issuer */
03236                             x.bv_val += STRLENOF("issuer");
03237                             x.bv_len -= STRLENOF("issuer");
03238 
03239                             if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
03240                             x.bv_val++;
03241                             x.bv_len--;
03242 
03243                             /* eat leading spaces */
03244                             for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
03245                                    /* empty */;
03246                             }
03247 
03248                             /* For backward compatibility, this part is optional */
03249                             if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) == 0 ) {
03250                                    x.bv_val += STRLENOF("rdnSequence:");
03251                                    x.bv_len -= STRLENOF("rdnSequence:");
03252                             }
03253 
03254                             if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
03255                             x.bv_val++;
03256                             x.bv_len--;
03257 
03258                             is->bv_val = x.bv_val;
03259                             is->bv_len = 0;
03260 
03261                             for ( ; is->bv_len < x.bv_len; ) {
03262                                    if ( is->bv_val[is->bv_len] != '"' ) {
03263                                           is->bv_len++;
03264                                           continue;
03265                                    }
03266                                    if ( is->bv_val[is->bv_len+1] == '"' ) {
03267                                           /* double dquote */
03268                                           is->bv_len += 2;
03269                                           continue;
03270                                    }
03271                                    break;
03272                             }
03273                             x.bv_val += is->bv_len + 1;
03274                             x.bv_len -= is->bv_len + 1;
03275 
03276                             have |= HAVE_ISSUER;
03277 
03278                      } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 )
03279                      {
03280                             if ( have & HAVE_SN ) return LDAP_INVALID_SYNTAX;
03281 
03282                             /* parse serialNumber */
03283                             x.bv_val += STRLENOF("serialNumber");
03284                             x.bv_len -= STRLENOF("serialNumber");
03285 
03286                             if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
03287                             x.bv_val++;
03288                             x.bv_len--;
03289 
03290                             /* eat leading spaces */
03291                             for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
03292                                    /* empty */;
03293                             }
03294 
03295                             if ( checkNum( &x, sn ) ) {
03296                                    return LDAP_INVALID_SYNTAX;
03297                             }
03298 
03299                             x.bv_val += sn->bv_len;
03300                             x.bv_len -= sn->bv_len;
03301 
03302                             have |= HAVE_SN;
03303 
03304                      } else {
03305                             return LDAP_INVALID_SYNTAX;
03306                      }
03307 
03308                      /* eat leading spaces */
03309                      for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
03310                             /* empty */;
03311                      }
03312 
03313                      if ( have == HAVE_ALL ) {
03314                             break;
03315                      }
03316 
03317                      if ( x.bv_val[0] != ',' ) {
03318                             return LDAP_INVALID_SYNTAX;
03319                      }
03320 
03321                      x.bv_val++;
03322                      x.bv_len--;
03323               } while ( 1 );
03324 
03325               /* should have no characters left... */
03326               if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
03327 
03328               if ( numdquotes == 0 ) {
03329                      ber_dupbv_x( &ni, is, ctx );
03330 
03331               } else {
03332                      ber_len_t src, dst;
03333 
03334                      ni.bv_len = is->bv_len - numdquotes;
03335                      ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
03336                      for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
03337                             if ( is->bv_val[src] == '"' ) {
03338                                    src++;
03339                             }
03340                             ni.bv_val[dst] = is->bv_val[src];
03341                      }
03342                      ni.bv_val[dst] = '\0';
03343               }
03344                      
03345               *is = ni;
03346        }
03347 
03348        return 0;
03349 }
03350        
03351 static int
03352 serialNumberAndIssuerValidate(
03353        Syntax *syntax,
03354        struct berval *in )
03355 {
03356        int rc;
03357        struct berval sn, i;
03358 
03359        Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerValidate: <%s>\n",
03360               in->bv_val, 0, 0 );
03361 
03362        rc = serialNumberAndIssuerCheck( in, &sn, &i, NULL );
03363        if ( rc ) {
03364               goto done;
03365        }
03366 
03367        /* validate DN -- doesn't handle double dquote */ 
03368        rc = dnValidate( NULL, &i );
03369        if ( rc ) {
03370               rc = LDAP_INVALID_SYNTAX;
03371        }
03372 
03373        if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
03374               slap_sl_free( i.bv_val, NULL );
03375        }
03376 
03377        Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerValidate: <%s> err=%d\n",
03378               in->bv_val, rc, 0 );
03379 
03380 done:;
03381        return rc;
03382 }
03383 
03384 static int
03385 serialNumberAndIssuerPretty(
03386        Syntax *syntax,
03387        struct berval *in,
03388        struct berval *out,
03389        void *ctx )
03390 {
03391        int rc;
03392        struct berval sn, i, ni = BER_BVNULL;
03393        char *p;
03394 
03395        assert( in != NULL );
03396        assert( out != NULL );
03397 
03398        BER_BVZERO( out );
03399 
03400        Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerPretty: <%s>\n",
03401               in->bv_val, 0, 0 );
03402 
03403        rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
03404        if ( rc ) {
03405               goto done;
03406        }
03407 
03408        rc = dnPretty( syntax, &i, &ni, ctx );
03409 
03410        if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
03411               slap_sl_free( i.bv_val, ctx );
03412        }
03413 
03414        if ( rc ) {
03415               rc = LDAP_INVALID_SYNTAX;
03416               goto done;
03417        }
03418 
03419        /* make room from sn + "$" */
03420        out->bv_len = STRLENOF("{ serialNumber , issuer rdnSequence:\"\" }")
03421               + sn.bv_len + ni.bv_len;
03422        out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
03423 
03424        if ( out->bv_val == NULL ) {
03425               out->bv_len = 0;
03426               rc = LDAP_OTHER;
03427               goto done;
03428        }
03429 
03430        p = out->bv_val;
03431        p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
03432        p = lutil_strbvcopy( p, &sn );
03433        p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
03434        p = lutil_strbvcopy( p, &ni );
03435        p = lutil_strcopy( p, /*{*/ "\" }" );
03436 
03437        assert( p == &out->bv_val[out->bv_len] );
03438 
03439 done:;
03440        Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s> => <%s>\n",
03441               in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
03442 
03443        slap_sl_free( ni.bv_val, ctx );
03444 
03445        return LDAP_SUCCESS; 
03446 }
03447 
03448 static int
03449 slap_bin2hex(
03450        struct berval *in,
03451        struct berval *out,
03452        void *ctx )
03453 
03454 {      
03455        /* Use hex format. '123456789abcdef'H */
03456        unsigned char *ptr, zero = '\0';
03457        char *sptr;
03458        int first;
03459        ber_len_t i, len, nlen;
03460 
03461        assert( in != NULL );
03462        assert( !BER_BVISNULL( in ) );
03463        assert( out != NULL );
03464        assert( !BER_BVISNULL( out ) );
03465 
03466        ptr = (unsigned char *)in->bv_val;
03467        len = in->bv_len;
03468 
03469        /* Check for minimal encodings */
03470        if ( len > 1 ) {
03471               if ( ptr[0] & 0x80 ) {
03472                      if ( ( ptr[0] == 0xff ) && ( ptr[1] & 0x80 ) ) {
03473                             return -1;
03474                      }
03475 
03476               } else if ( ptr[0] == 0 ) {
03477                      if ( !( ptr[1] & 0x80 ) ) {
03478                             return -1;
03479                      }
03480                      len--;
03481                      ptr++;
03482               }
03483 
03484        } else if ( len == 0 ) {
03485               /* FIXME: this should not be possible,
03486                * since a value of zero would have length 1 */
03487               len = 1;
03488               ptr = &zero;
03489        }
03490 
03491        first = !( ptr[0] & 0xf0U );
03492        nlen = len * 2 - first + STRLENOF("''H"); /* quotes, H */
03493        if ( nlen >= out->bv_len ) {
03494               out->bv_val = slap_sl_malloc( nlen + 1, ctx );
03495        }
03496        sptr = out->bv_val;
03497        *sptr++ = '\'';
03498        i = 0;
03499        if ( first ) {
03500               sprintf( sptr, "%01X", ( ptr[0] & 0x0fU ) );
03501               sptr++;
03502               i = 1;
03503        }
03504        for ( ; i < len; i++ ) {
03505               sprintf( sptr, "%02X", ptr[i] );
03506               sptr += 2;
03507        }
03508        *sptr++ = '\'';
03509        *sptr++ = 'H';
03510        *sptr = '\0';
03511 
03512        assert( sptr == &out->bv_val[nlen] );
03513 
03514        out->bv_len = nlen;
03515 
03516        return 0;
03517 }
03518 
03519 #define SLAP_SN_BUFLEN      (64)
03520 
03521 /*
03522  * This routine is called by certificateExactNormalize when
03523  * certificateExactNormalize receives a search string instead of
03524  * a certificate. This routine checks if the search value is valid
03525  * and then returns the normalized value
03526  */
03527 static int
03528 serialNumberAndIssuerNormalize(
03529        slap_mask_t usage,
03530        Syntax *syntax,
03531        MatchingRule *mr,
03532        struct berval *in,
03533        struct berval *out,
03534        void *ctx )
03535 {
03536        struct berval sn, sn2, sn3, i, ni;
03537        char sbuf2[SLAP_SN_BUFLEN];
03538        char sbuf3[SLAP_SN_BUFLEN];
03539        char *p;
03540        int rc;
03541 
03542        assert( in != NULL );
03543        assert( out != NULL );
03544 
03545        Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
03546               in->bv_val, 0, 0 );
03547 
03548        rc = serialNumberAndIssuerCheck( in, &sn, &i, ctx );
03549        if ( rc ) {
03550               return rc;
03551        }
03552 
03553        rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
03554 
03555        if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
03556               slap_sl_free( i.bv_val, ctx );
03557        }
03558 
03559        if ( rc ) {
03560               return LDAP_INVALID_SYNTAX;
03561        }
03562 
03563        /* Convert sn to canonical hex */
03564        sn2.bv_val = sbuf2;
03565        if ( sn.bv_len > sizeof( sbuf2 ) ) {
03566               sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
03567        }
03568        sn2.bv_len = sn.bv_len;
03569        sn3.bv_val = sbuf3;
03570        sn3.bv_len = sizeof(sbuf3);
03571        if ( lutil_str2bin( &sn, &sn2, ctx ) || slap_bin2hex( &sn2, &sn3, ctx ) ) {
03572               rc = LDAP_INVALID_SYNTAX;
03573               goto func_leave;
03574        }
03575 
03576        out->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
03577               + sn3.bv_len + ni.bv_len;
03578        out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
03579        if ( out->bv_val == NULL ) {
03580               out->bv_len = 0;
03581               rc = LDAP_OTHER;
03582               goto func_leave;
03583        }
03584 
03585        p = out->bv_val;
03586 
03587        p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
03588        p = lutil_strbvcopy( p, &sn3 );
03589        p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
03590        p = lutil_strbvcopy( p, &ni );
03591        p = lutil_strcopy( p, /*{*/ "\" }" );
03592 
03593        assert( p == &out->bv_val[out->bv_len] );
03594 
03595 func_leave:
03596        Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s> => <%s>\n",
03597               in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
03598 
03599        if ( sn2.bv_val != sbuf2 ) {
03600               slap_sl_free( sn2.bv_val, ctx );
03601        }
03602 
03603        if ( sn3.bv_val != sbuf3 ) {
03604               slap_sl_free( sn3.bv_val, ctx );
03605        }
03606 
03607        slap_sl_free( ni.bv_val, ctx );
03608 
03609        return rc;
03610 }
03611 
03612 static int
03613 certificateExactNormalize(
03614        slap_mask_t usage,
03615        Syntax *syntax,
03616        MatchingRule *mr,
03617        struct berval *val,
03618        struct berval *normalized,
03619        void *ctx )
03620 {
03621        BerElementBuffer berbuf;
03622        BerElement *ber = (BerElement *)&berbuf;
03623        ber_tag_t tag;
03624        ber_len_t len;
03625        ber_int_t i;
03626        char serialbuf2[SLAP_SN_BUFLEN];
03627        struct berval sn, sn2 = BER_BVNULL;
03628        struct berval issuer_dn = BER_BVNULL, bvdn;
03629        char *p;
03630        int rc = LDAP_INVALID_SYNTAX;
03631 
03632        assert( val != NULL );
03633 
03634        Debug( LDAP_DEBUG_TRACE, ">>> certificateExactNormalize: <%p, %lu>\n",
03635               val->bv_val, val->bv_len, 0 );
03636 
03637        if ( BER_BVISEMPTY( val ) ) goto done;
03638 
03639        if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
03640               return serialNumberAndIssuerNormalize( 0, NULL, NULL, val, normalized, ctx );
03641        }
03642 
03643        assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
03644 
03645        ber_init2( ber, val, LBER_USE_DER );
03646        tag = ber_skip_tag( ber, &len );   /* Signed Sequence */
03647        tag = ber_skip_tag( ber, &len );   /* Sequence */
03648        tag = ber_peek_tag( ber, &len );   /* Optional version? */
03649        if ( tag == SLAP_X509_OPT_C_VERSION ) {
03650               tag = ber_skip_tag( ber, &len );
03651               tag = ber_get_int( ber, &i );      /* version */
03652        }
03653 
03654        /* NOTE: move the test here from certificateValidate,
03655         * so that we can validate certs with serial longer
03656         * than sizeof(ber_int_t) */
03657        tag = ber_skip_tag( ber, &len );   /* serial */
03658        sn.bv_len = len;
03659        sn.bv_val = (char *)ber->ber_ptr;
03660        sn2.bv_val = serialbuf2;
03661        sn2.bv_len = sizeof(serialbuf2);
03662        if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
03663               rc = LDAP_INVALID_SYNTAX;
03664               goto done;
03665        }
03666        ber_skip_data( ber, len );
03667 
03668        tag = ber_skip_tag( ber, &len );   /* SignatureAlg */
03669        ber_skip_data( ber, len );
03670        tag = ber_peek_tag( ber, &len );   /* IssuerDN */
03671        len = ber_ptrlen( ber );
03672        bvdn.bv_val = val->bv_val + len;
03673        bvdn.bv_len = val->bv_len - len;
03674 
03675        rc = dnX509normalize( &bvdn, &issuer_dn );
03676        if ( rc != LDAP_SUCCESS ) goto done;
03677 
03678        normalized->bv_len = STRLENOF( "{ serialNumber , issuer rdnSequence:\"\" }" )
03679               + sn2.bv_len + issuer_dn.bv_len;
03680        normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
03681 
03682        p = normalized->bv_val;
03683 
03684        p = lutil_strcopy( p, "{ serialNumber " /*}*/ );
03685        p = lutil_strbvcopy( p, &sn2 );
03686        p = lutil_strcopy( p, ", issuer rdnSequence:\"" );
03687        p = lutil_strbvcopy( p, &issuer_dn );
03688        p = lutil_strcopy( p, /*{*/ "\" }" );
03689 
03690        rc = LDAP_SUCCESS;
03691 
03692 done:
03693        Debug( LDAP_DEBUG_TRACE, "<<< certificateExactNormalize: <%p, %lu> => <%s>\n",
03694               val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
03695 
03696        if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
03697        if ( sn2.bv_val != serialbuf2 ) ber_memfree_x( sn2.bv_val, ctx );
03698 
03699        return rc;
03700 }
03701 
03702 /* X.509 PKI certificateList stuff */
03703 static int
03704 checkTime( struct berval *in, struct berval *out )
03705 {
03706        int rc;
03707        ber_len_t i;
03708        char buf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
03709        struct berval bv;
03710 
03711        assert( in != NULL );
03712        assert( !BER_BVISNULL( in ) );
03713        assert( !BER_BVISEMPTY( in ) );
03714 
03715        if ( in->bv_len < STRLENOF( "YYmmddHHMMSSZ" ) ) {
03716               return -1;
03717        }
03718 
03719        if ( out != NULL ) {
03720               assert( !BER_BVISNULL( out ) );
03721               assert( out->bv_len >= sizeof( buf ) );
03722               bv.bv_val = out->bv_val;
03723 
03724        } else {
03725               bv.bv_val = buf;
03726        }
03727 
03728        for ( i = 0; i < STRLENOF( "YYYYmmddHHMMSS" ); i++ ) {
03729               if ( !ASCII_DIGIT( in->bv_val[i] ) ) break;
03730        }
03731 
03732        if ( in->bv_val[i] != 'Z' ) {
03733               return -1;
03734        }
03735        i++;
03736 
03737        if ( i != in->bv_len ) {
03738               return -1;
03739        }
03740 
03741        if ( i == STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
03742               lutil_strncopy( bv.bv_val, in->bv_val, i );
03743               bv.bv_len = i;
03744               
03745        } else if ( i == STRLENOF( "YYmmddHHMMSSZ" ) ) {
03746               char *p = bv.bv_val;
03747               if ( in->bv_val[0] < '7' ) {
03748                      p = lutil_strcopy( p, "20" );
03749 
03750               } else {
03751                      p = lutil_strcopy( p, "19" );
03752               }
03753               lutil_strncopy( p, in->bv_val, i );
03754               bv.bv_len = 2 + i;
03755 
03756        } else {
03757               return -1;
03758        }
03759 
03760        rc = generalizedTimeValidate( NULL, &bv );
03761        if ( rc == LDAP_SUCCESS && out != NULL ) {
03762               if ( out->bv_len > bv.bv_len ) {
03763                      out->bv_val[ bv.bv_len ] = '\0';
03764               }
03765               out->bv_len = bv.bv_len;
03766        }
03767 
03768        return rc != LDAP_SUCCESS;
03769 }
03770 
03771 static int
03772 issuerAndThisUpdateCheck(
03773        struct berval *in,
03774        struct berval *is,
03775        struct berval *tu,
03776        void *ctx )
03777 {
03778        int numdquotes = 0;
03779        struct berval x = *in;
03780        struct berval ni = BER_BVNULL;
03781        /* Parse GSER format */ 
03782        enum {
03783               HAVE_NONE = 0x0,
03784               HAVE_ISSUER = 0x1,
03785               HAVE_THISUPDATE = 0x2,
03786               HAVE_ALL = ( HAVE_ISSUER | HAVE_THISUPDATE )
03787        } have = HAVE_NONE;
03788 
03789 
03790        if ( in->bv_len < STRLENOF( "{issuer \"\",thisUpdate \"YYMMDDhhmmssZ\"}" ) ) return LDAP_INVALID_SYNTAX;
03791 
03792        if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
03793               return LDAP_INVALID_SYNTAX;
03794        }
03795 
03796        x.bv_val++;
03797        x.bv_len -= STRLENOF("{}");
03798 
03799        do {
03800               /* eat leading spaces */
03801               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
03802                      /* empty */;
03803               }
03804 
03805               /* should be at issuer or thisUpdate */
03806               if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
03807                      if ( have & HAVE_ISSUER ) return LDAP_INVALID_SYNTAX;
03808 
03809                      /* parse issuer */
03810                      x.bv_val += STRLENOF("issuer");
03811                      x.bv_len -= STRLENOF("issuer");
03812 
03813                      if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
03814                      x.bv_val++;
03815                      x.bv_len--;
03816 
03817                      /* eat leading spaces */
03818                      for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
03819                             /* empty */;
03820                      }
03821 
03822                      /* For backward compatibility, this part is optional */
03823                      if ( strncasecmp( x.bv_val, "rdnSequence:", STRLENOF("rdnSequence:") ) != 0 ) {
03824                             return LDAP_INVALID_SYNTAX;
03825                      }
03826                      x.bv_val += STRLENOF("rdnSequence:");
03827                      x.bv_len -= STRLENOF("rdnSequence:");
03828 
03829                      if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
03830                      x.bv_val++;
03831                      x.bv_len--;
03832 
03833                      is->bv_val = x.bv_val;
03834                      is->bv_len = 0;
03835 
03836                      for ( ; is->bv_len < x.bv_len; ) {
03837                             if ( is->bv_val[is->bv_len] != '"' ) {
03838                                    is->bv_len++;
03839                                    continue;
03840                             }
03841                             if ( is->bv_val[is->bv_len+1] == '"' ) {
03842                                    /* double dquote */
03843                                    is->bv_len += 2;
03844                                    continue;
03845                             }
03846                             break;
03847                      }
03848                      x.bv_val += is->bv_len + 1;
03849                      x.bv_len -= is->bv_len + 1;
03850 
03851                      have |= HAVE_ISSUER;
03852 
03853               } else if ( strncasecmp( x.bv_val, "thisUpdate", STRLENOF("thisUpdate") ) == 0 )
03854               {
03855                      if ( have & HAVE_THISUPDATE ) return LDAP_INVALID_SYNTAX;
03856 
03857                      /* parse thisUpdate */
03858                      x.bv_val += STRLENOF("thisUpdate");
03859                      x.bv_len -= STRLENOF("thisUpdate");
03860 
03861                      if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
03862                      x.bv_val++;
03863                      x.bv_len--;
03864 
03865                      /* eat leading spaces */
03866                      for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
03867                             /* empty */;
03868                      }
03869 
03870                      if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
03871                      x.bv_val++;
03872                      x.bv_len--;
03873 
03874                      tu->bv_val = x.bv_val;
03875                      tu->bv_len = 0;
03876 
03877                      for ( ; tu->bv_len < x.bv_len; tu->bv_len++ ) {
03878                             if ( tu->bv_val[tu->bv_len] == '"' ) {
03879                                    break;
03880                             }
03881                      }
03882                      x.bv_val += tu->bv_len + 1;
03883                      x.bv_len -= tu->bv_len + 1;
03884 
03885                      have |= HAVE_THISUPDATE;
03886 
03887               } else {
03888                      return LDAP_INVALID_SYNTAX;
03889               }
03890 
03891               /* eat leading spaces */
03892               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
03893                      /* empty */;
03894               }
03895 
03896               if ( have == HAVE_ALL ) {
03897                      break;
03898               }
03899 
03900               if ( x.bv_val[0] != ',' ) {
03901                      return LDAP_INVALID_SYNTAX;
03902               }
03903 
03904               x.bv_val++;
03905               x.bv_len--;
03906        } while ( 1 );
03907 
03908        /* should have no characters left... */
03909        if ( x.bv_len ) return LDAP_INVALID_SYNTAX;
03910 
03911        if ( numdquotes == 0 ) {
03912               ber_dupbv_x( &ni, is, ctx );
03913 
03914        } else {
03915               ber_len_t src, dst;
03916 
03917               ni.bv_len = is->bv_len - numdquotes;
03918               ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
03919               for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
03920                      if ( is->bv_val[src] == '"' ) {
03921                             src++;
03922                      }
03923                      ni.bv_val[dst] = is->bv_val[src];
03924               }
03925               ni.bv_val[dst] = '\0';
03926        }
03927               
03928        *is = ni;
03929 
03930        return 0;
03931 }
03932 
03933 static int
03934 issuerAndThisUpdateValidate(
03935        Syntax *syntax,
03936        struct berval *in )
03937 {
03938        int rc;
03939        struct berval i, tu;
03940 
03941        Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateValidate: <%s>\n",
03942               in->bv_val, 0, 0 );
03943 
03944        rc = issuerAndThisUpdateCheck( in, &i, &tu, NULL );
03945        if ( rc ) {
03946               goto done;
03947        }
03948 
03949        /* validate DN -- doesn't handle double dquote */ 
03950        rc = dnValidate( NULL, &i );
03951        if ( rc ) {
03952               rc = LDAP_INVALID_SYNTAX;
03953 
03954        } else if ( checkTime( &tu, NULL ) ) {
03955               rc = LDAP_INVALID_SYNTAX;
03956        }
03957 
03958        if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
03959               slap_sl_free( i.bv_val, NULL );
03960        }
03961 
03962        Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateValidate: <%s> err=%d\n",
03963               in->bv_val, rc, 0 );
03964 
03965 done:;
03966        return rc;
03967 }
03968 
03969 static int
03970 issuerAndThisUpdatePretty(
03971        Syntax *syntax,
03972        struct berval *in,
03973        struct berval *out,
03974        void *ctx )
03975 {
03976        int rc;
03977        struct berval i, tu, ni = BER_BVNULL;
03978        char *p;
03979 
03980        assert( in != NULL );
03981        assert( out != NULL );
03982 
03983        BER_BVZERO( out );
03984 
03985        Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdatePretty: <%s>\n",
03986               in->bv_val, 0, 0 );
03987 
03988        rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
03989        if ( rc ) {
03990               goto done;
03991        }
03992 
03993        rc = dnPretty( syntax, &i, &ni, ctx );
03994 
03995        if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
03996               slap_sl_free( i.bv_val, ctx );
03997        }
03998 
03999        if ( rc || checkTime( &tu, NULL ) ) {
04000               rc = LDAP_INVALID_SYNTAX;
04001               goto done;
04002        }
04003 
04004        /* make room */
04005        out->bv_len = STRLENOF("{ issuer rdnSequence:\"\", thisUpdate \"\" }")
04006               + ni.bv_len + tu.bv_len;
04007        out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
04008 
04009        if ( out->bv_val == NULL ) {
04010               out->bv_len = 0;
04011               rc = LDAP_OTHER;
04012               goto done;
04013        }
04014 
04015        p = out->bv_val;
04016        p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
04017        p = lutil_strbvcopy( p, &ni );
04018        p = lutil_strcopy( p, "\", thisUpdate \"" );
04019        p = lutil_strbvcopy( p, &tu );
04020        p = lutil_strcopy( p, /*{*/ "\" }" );
04021 
04022        assert( p == &out->bv_val[out->bv_len] );
04023 
04024 done:;
04025        Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdatePretty: <%s> => <%s>\n",
04026               in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
04027 
04028        slap_sl_free( ni.bv_val, ctx );
04029 
04030        return rc; 
04031 }
04032 
04033 static int
04034 issuerAndThisUpdateNormalize(
04035        slap_mask_t usage,
04036        Syntax *syntax,
04037        MatchingRule *mr,
04038        struct berval *in,
04039        struct berval *out,
04040        void *ctx )
04041 {
04042        struct berval i, ni, tu, tu2;
04043        char sbuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
04044        char *p;
04045        int rc;
04046 
04047        assert( in != NULL );
04048        assert( out != NULL );
04049 
04050        Debug( LDAP_DEBUG_TRACE, ">>> issuerAndThisUpdateNormalize: <%s>\n",
04051               in->bv_val, 0, 0 );
04052 
04053        rc = issuerAndThisUpdateCheck( in, &i, &tu, ctx );
04054        if ( rc ) {
04055               return rc;
04056        }
04057 
04058        rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
04059 
04060        if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
04061               slap_sl_free( i.bv_val, ctx );
04062        }
04063 
04064        tu2.bv_val = sbuf;
04065        tu2.bv_len = sizeof( sbuf );
04066        if ( rc || checkTime( &tu, &tu2 ) ) {
04067               return LDAP_INVALID_SYNTAX;
04068        }
04069 
04070        out->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
04071               + ni.bv_len + tu2.bv_len;
04072        out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
04073 
04074        if ( out->bv_val == NULL ) {
04075               out->bv_len = 0;
04076               rc = LDAP_OTHER;
04077               goto func_leave;
04078        }
04079 
04080        p = out->bv_val;
04081 
04082        p = lutil_strcopy( p, "{ issuer rdnSequence:\"" /*}*/ );
04083        p = lutil_strbvcopy( p, &ni );
04084        p = lutil_strcopy( p, "\", thisUpdate \"" );
04085        p = lutil_strbvcopy( p, &tu2 );
04086        p = lutil_strcopy( p, /*{*/ "\" }" );
04087 
04088        assert( p == &out->bv_val[out->bv_len] );
04089 
04090 func_leave:
04091        Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n",
04092               in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
04093 
04094        slap_sl_free( ni.bv_val, ctx );
04095 
04096        return rc;
04097 }
04098 
04099 static int
04100 certificateListExactNormalize(
04101        slap_mask_t usage,
04102        Syntax *syntax,
04103        MatchingRule *mr,
04104        struct berval *val,
04105        struct berval *normalized,
04106        void *ctx )
04107 {
04108        BerElementBuffer berbuf;
04109        BerElement *ber = (BerElement *)&berbuf;
04110        ber_tag_t tag;
04111        ber_len_t len;
04112        ber_int_t version;
04113        struct berval issuer_dn = BER_BVNULL, bvdn,
04114               thisUpdate, bvtu;
04115        char *p, tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
04116        int rc = LDAP_INVALID_SYNTAX;
04117 
04118        assert( val != NULL );
04119 
04120        Debug( LDAP_DEBUG_TRACE, ">>> certificateListExactNormalize: <%p, %lu>\n",
04121               val->bv_val, val->bv_len, 0 );
04122 
04123        if ( BER_BVISEMPTY( val ) ) goto done;
04124 
04125        if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
04126               return issuerAndThisUpdateNormalize( 0, NULL, NULL, val, normalized, ctx );
04127        }
04128 
04129        assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
04130 
04131        ber_init2( ber, val, LBER_USE_DER );
04132        tag = ber_skip_tag( ber, &len );   /* Signed wrapper */
04133        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
04134        tag = ber_skip_tag( ber, &len );   /* Sequence */
04135        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
04136        tag = ber_peek_tag( ber, &len );
04137        /* Optional version */
04138        if ( tag == LBER_INTEGER ) {
04139               tag = ber_get_int( ber, &version );
04140               assert( tag == LBER_INTEGER );
04141               if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
04142        }
04143        tag = ber_skip_tag( ber, &len );   /* Signature Algorithm */
04144        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
04145        ber_skip_data( ber, len );
04146 
04147        tag = ber_peek_tag( ber, &len );   /* IssuerDN */
04148        if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
04149        len = ber_ptrlen( ber );
04150        bvdn.bv_val = val->bv_val + len;
04151        bvdn.bv_len = val->bv_len - len;
04152        tag = ber_skip_tag( ber, &len );
04153        ber_skip_data( ber, len );
04154 
04155        tag = ber_skip_tag( ber, &len );   /* thisUpdate */
04156        /* Time is a CHOICE { UTCTime, GeneralizedTime } */
04157        if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
04158        bvtu.bv_val = (char *)ber->ber_ptr;
04159        bvtu.bv_len = len;
04160 
04161        rc = dnX509normalize( &bvdn, &issuer_dn );
04162        if ( rc != LDAP_SUCCESS ) goto done;
04163 
04164        thisUpdate.bv_val = tubuf;
04165        thisUpdate.bv_len = sizeof(tubuf);
04166        if ( checkTime( &bvtu, &thisUpdate ) ) {
04167               rc = LDAP_INVALID_SYNTAX;
04168               goto done;
04169        }
04170 
04171        normalized->bv_len = STRLENOF( "{ issuer rdnSequence:\"\", thisUpdate \"\" }" )
04172               + issuer_dn.bv_len + thisUpdate.bv_len;
04173        normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
04174 
04175        p = normalized->bv_val;
04176 
04177        p = lutil_strcopy( p, "{ issuer rdnSequence:\"" );
04178        p = lutil_strbvcopy( p, &issuer_dn );
04179        p = lutil_strcopy( p, "\", thisUpdate \"" );
04180        p = lutil_strbvcopy( p, &thisUpdate );
04181        p = lutil_strcopy( p, /*{*/ "\" }" );
04182 
04183        rc = LDAP_SUCCESS;
04184 
04185 done:
04186        Debug( LDAP_DEBUG_TRACE, "<<< certificateListExactNormalize: <%p, %lu> => <%s>\n",
04187               val->bv_val, val->bv_len, rc == LDAP_SUCCESS ? normalized->bv_val : "(err)" );
04188 
04189        if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
04190 
04191        return rc;
04192 }
04193 
04194 /* X.509 PMI serialNumberAndIssuerSerialCheck
04195 
04196 AttributeCertificateExactAssertion     ::= SEQUENCE {
04197    serialNumber              CertificateSerialNumber,
04198    issuer                    AttCertIssuer }
04199 
04200 CertificateSerialNumber ::= INTEGER
04201 
04202 AttCertIssuer ::=    [0] SEQUENCE {
04203 issuerName                     GeneralNames OPTIONAL,
04204 baseCertificateID         [0] IssuerSerial OPTIONAL,
04205 objectDigestInfo          [1] ObjectDigestInfo OPTIONAL }
04206 -- At least one component shall be present
04207 
04208 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
04209 
04210 GeneralName ::= CHOICE {
04211   otherName                 [0] INSTANCE OF OTHER-NAME,
04212   rfc822Name                [1] IA5String,
04213   dNSName                   [2] IA5String,
04214   x400Address               [3] ORAddress,
04215   directoryName             [4] Name,
04216   ediPartyName              [5] EDIPartyName,
04217   uniformResourceIdentifier [6] IA5String,
04218   iPAddress                 [7] OCTET STRING,
04219   registeredID              [8] OBJECT IDENTIFIER }
04220 
04221 IssuerSerial ::= SEQUENCE {
04222    issuer       GeneralNames,
04223    serial       CertificateSerialNumber,
04224    issuerUID UniqueIdentifier OPTIONAL }
04225 
04226 ObjectDigestInfo ::= SEQUENCE {
04227    digestedObjectType ENUMERATED {
04228       publicKey           (0),
04229       publicKeyCert       (1),
04230       otherObjectTypes    (2) },
04231    otherObjectTypeID      OBJECT IDENTIFIER OPTIONAL,
04232    digestAlgorithm        AlgorithmIdentifier,
04233    objectDigest           BIT STRING }
04234 
04235  * The way I interpret it, an assertion should look like
04236 
04237  { serialNumber 'dd'H,
04238    issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional
04239             baseCertificateID { serial '1d'H,
04240                                 issuer { directoryName:rdnSequence:"cn=zzz" },
04241                                 issuerUID <value>              -- optional
04242                               },                               -- optional
04243             objectDigestInfo { ... }                           -- optional
04244           }
04245  }
04246  
04247  * with issuerName, baseCertificateID and objectDigestInfo optional,
04248  * at least one present; the way it's currently implemented, it is
04249 
04250  { serialNumber 'dd'H,
04251    issuer { baseCertificateID { serial '1d'H,
04252                                 issuer { directoryName:rdnSequence:"cn=zzz" }
04253                               }
04254           }
04255  }
04256 
04257  * with all the above parts mandatory.
04258  */
04259 static int
04260 serialNumberAndIssuerSerialCheck(
04261        struct berval *in,
04262        struct berval *sn,
04263        struct berval *is,
04264        struct berval *i_sn, /* contain serial of baseCertificateID */
04265        void *ctx )
04266 {
04267        /* Parse GSER format */ 
04268        enum {
04269               HAVE_NONE = 0x0,
04270               HAVE_SN = 0x1,
04271               HAVE_ISSUER = 0x2,
04272               HAVE_ALL = ( HAVE_SN | HAVE_ISSUER )
04273        } have = HAVE_NONE, have2 = HAVE_NONE;
04274        int numdquotes = 0;
04275        struct berval x = *in;
04276        struct berval ni;
04277 
04278        if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
04279 
04280        /* no old format */
04281        if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX;
04282 
04283        x.bv_val++;
04284        x.bv_len -= 2;
04285 
04286        do {
04287 
04288               /* eat leading spaces */
04289               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04290                      /* empty */;
04291               }
04292 
04293               /* should be at issuer or serialNumber NamedValue */
04294               if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) {
04295                      if ( have & HAVE_ISSUER ) {
04296                             return LDAP_INVALID_SYNTAX;
04297                      }
04298 
04299                      /* parse IssuerSerial */
04300                      x.bv_val += STRLENOF("issuer");
04301                      x.bv_len -= STRLENOF("issuer");
04302 
04303                      if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
04304                      x.bv_val++;
04305                      x.bv_len--;
04306 
04307                      /* eat leading spaces */
04308                      for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04309                             /* empty */;
04310                      }
04311 
04312                      if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
04313                      x.bv_val++;
04314                      x.bv_len--;
04315 
04316                      /* eat leading spaces */
04317                      for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04318                             /* empty */;
04319                      }
04320 
04321                      if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) {
04322                             return LDAP_INVALID_SYNTAX;
04323                      }
04324                      x.bv_val += STRLENOF("baseCertificateID ");
04325                      x.bv_len -= STRLENOF("baseCertificateID ");
04326 
04327                      /* eat leading spaces */
04328                      for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04329                             /* empty */;
04330                      }
04331 
04332                      if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
04333                      x.bv_val++;
04334                      x.bv_len--;
04335 
04336                      do {
04337                             /* eat leading spaces */
04338                             for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04339                                    /* empty */;
04340                             }
04341 
04342                             /* parse issuer of baseCertificateID */
04343                             if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) {
04344                                    if ( have2 & HAVE_ISSUER ) {
04345                                           return LDAP_INVALID_SYNTAX;
04346                                    }
04347 
04348                                    x.bv_val += STRLENOF("issuer ");
04349                                    x.bv_len -= STRLENOF("issuer ");
04350 
04351                                    /* eat leading spaces */
04352                                    for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04353                                           /* empty */;
04354                                    }
04355 
04356                                    if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX;
04357                                    x.bv_val++;
04358                                    x.bv_len--;
04359 
04360                                    /* eat leading spaces */
04361                                    for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04362                                           /* empty */;
04363                                    }
04364 
04365                                    if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) {
04366                                           return LDAP_INVALID_SYNTAX;
04367                                    }
04368                                    x.bv_val += STRLENOF("directoryName:rdnSequence:");
04369                                    x.bv_len -= STRLENOF("directoryName:rdnSequence:");
04370 
04371                                    if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
04372                                    x.bv_val++;
04373                                    x.bv_len--;
04374 
04375                                    is->bv_val = x.bv_val;
04376                                    is->bv_len = 0;
04377 
04378                                    for ( ; is->bv_len < x.bv_len; ) {
04379                                           if ( is->bv_val[is->bv_len] != '"' ) {
04380                                                  is->bv_len++;
04381                                                  continue;
04382                                           }
04383                                           if ( is->bv_val[is->bv_len + 1] == '"' ) {
04384                                                  /* double dquote */
04385                                                  is->bv_len += 2;
04386                                                  continue;
04387                                           }
04388                                           break;
04389                                    }
04390                                    x.bv_val += is->bv_len + 1;
04391                                    x.bv_len -= is->bv_len + 1;
04392 
04393                                    /* eat leading spaces */
04394                                    for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04395                                           /* empty */;
04396                                    }
04397 
04398                                    if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
04399                                    x.bv_val++;
04400                                    x.bv_len--;
04401 
04402                                    have2 |= HAVE_ISSUER;
04403 
04404                             } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) {
04405                                    if ( have2 & HAVE_SN ) {
04406                                           return LDAP_INVALID_SYNTAX;
04407                                    }
04408 
04409                                    x.bv_val += STRLENOF("serial ");
04410                                    x.bv_len -= STRLENOF("serial ");
04411 
04412                                    /* eat leading spaces */
04413                                    for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
04414                                           /* empty */;
04415                                    }
04416 
04417                                    if ( checkNum( &x, i_sn ) ) {
04418                                           return LDAP_INVALID_SYNTAX;
04419                                    }
04420 
04421                                    x.bv_val += i_sn->bv_len;
04422                                    x.bv_len -= i_sn->bv_len;
04423 
04424                                    have2 |= HAVE_SN;
04425 
04426                             } else {
04427                                    return LDAP_INVALID_SYNTAX;
04428                             }
04429 
04430                             /* eat leading spaces */
04431                             for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04432                                    /* empty */;
04433                             }
04434 
04435                             if ( have2 == HAVE_ALL ) {
04436                                    break;
04437                             }
04438 
04439                             if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
04440                             x.bv_val++;
04441                             x.bv_len--;
04442                      } while ( 1 );
04443 
04444                      if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
04445                      x.bv_val++;
04446                      x.bv_len--;
04447 
04448                      /* eat leading spaces */
04449                      for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04450                             /* empty */;
04451                      }
04452 
04453                      if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX;
04454                      x.bv_val++;
04455                      x.bv_len--;
04456 
04457                      have |= HAVE_ISSUER;
04458 
04459               } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) {
04460                      if ( have & HAVE_SN ) {
04461                             return LDAP_INVALID_SYNTAX;
04462                      }
04463 
04464                      /* parse serialNumber */
04465                      x.bv_val += STRLENOF("serialNumber");
04466                      x.bv_len -= STRLENOF("serialNumber");
04467 
04468                      if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
04469                      x.bv_val++;
04470                      x.bv_len--;
04471 
04472                      /* eat leading spaces */
04473                      for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04474                             /* empty */;
04475                      }
04476                      
04477                      if ( checkNum( &x, sn ) ) {
04478                             return LDAP_INVALID_SYNTAX;
04479                      }
04480 
04481                      x.bv_val += sn->bv_len;
04482                      x.bv_len -= sn->bv_len;
04483 
04484                      have |= HAVE_SN;
04485 
04486               } else {
04487                      return LDAP_INVALID_SYNTAX;
04488               }
04489 
04490               /* eat spaces */
04491               for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) {
04492                      /* empty */;
04493               }
04494 
04495               if ( have == HAVE_ALL ) {
04496                      break;
04497               }
04498 
04499               if ( x.bv_val[0] != ',' ) {
04500                      return LDAP_INVALID_SYNTAX;
04501               }
04502               x.bv_val++ ;
04503               x.bv_len--;
04504        } while ( 1 );
04505 
04506        /* should have no characters left... */
04507        if( x.bv_len ) return LDAP_INVALID_SYNTAX;
04508 
04509        if ( numdquotes == 0 ) {
04510               ber_dupbv_x( &ni, is, ctx );
04511 
04512        } else {
04513               ber_len_t src, dst;
04514 
04515               ni.bv_len = is->bv_len - numdquotes;
04516               ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
04517               for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
04518                      if ( is->bv_val[src] == '"' ) {
04519                             src++;
04520                      }
04521                      ni.bv_val[dst] = is->bv_val[src];
04522               }
04523               ni.bv_val[dst] = '\0';
04524        }
04525 
04526        *is = ni;
04527 
04528        /* need to handle double dquotes here */
04529        return 0;
04530 }
04531 
04532 /* X.509 PMI serialNumberAndIssuerSerialValidate */
04533 static int
04534 serialNumberAndIssuerSerialValidate(
04535        Syntax *syntax,
04536        struct berval *in )
04537 {
04538        int rc;
04539        struct berval sn, i, i_sn;
04540 
04541        Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n",
04542               in->bv_val, 0, 0 );
04543 
04544        rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL );
04545        if ( rc ) {
04546               goto done;
04547        }
04548 
04549        /* validate DN -- doesn't handle double dquote */ 
04550        rc = dnValidate( NULL, &i );
04551        if ( rc ) {
04552               rc = LDAP_INVALID_SYNTAX;
04553        }
04554 
04555        if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
04556               slap_sl_free( i.bv_val, NULL );
04557        }
04558 
04559 done:;
04560        Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n",
04561               in->bv_val, rc, 0 );
04562 
04563        return rc;
04564 }
04565 
04566 /* X.509 PMI serialNumberAndIssuerSerialPretty */
04567 static int
04568 serialNumberAndIssuerSerialPretty(
04569        Syntax *syntax,
04570        struct berval *in,
04571        struct berval *out,
04572        void *ctx )
04573 {
04574        struct berval sn, i, i_sn, ni = BER_BVNULL;
04575        char *p;
04576        int rc;
04577 
04578        assert( in != NULL );
04579        assert( out != NULL );
04580 
04581        Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n",
04582               in->bv_val, 0, 0 );
04583 
04584        rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
04585        if ( rc ) {
04586               goto done;
04587        }
04588 
04589        rc = dnPretty( syntax, &i, &ni, ctx );
04590 
04591        if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
04592               slap_sl_free( i.bv_val, ctx );
04593        }
04594 
04595        if ( rc ) {
04596               rc = LDAP_INVALID_SYNTAX;
04597               goto done;
04598        }
04599 
04600        /* make room from sn + "$" */
04601        out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
04602               + sn.bv_len + ni.bv_len + i_sn.bv_len;
04603        out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
04604 
04605        if ( out->bv_val == NULL ) {
04606               out->bv_len = 0;
04607               rc = LDAP_OTHER;
04608               goto done;
04609        }
04610 
04611        p = out->bv_val;
04612        p = lutil_strcopy( p, "{ serialNumber " );
04613        p = lutil_strbvcopy( p, &sn );
04614        p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
04615        p = lutil_strbvcopy( p, &ni );
04616        p = lutil_strcopy( p, "\" }, serial " );
04617        p = lutil_strbvcopy( p, &i_sn );
04618        p = lutil_strcopy( p, " } } }" );
04619 
04620        assert( p == &out->bv_val[out->bv_len] );
04621 
04622 done:;
04623        Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n",
04624               in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
04625 
04626        slap_sl_free( ni.bv_val, ctx );
04627 
04628        return rc; 
04629 }
04630 
04631 /* X.509 PMI serialNumberAndIssuerSerialNormalize */
04632 /*
04633  * This routine is called by attributeCertificateExactNormalize
04634  * when attributeCertificateExactNormalize receives a search 
04635  * string instead of a attribute certificate. This routine 
04636  * checks if the search value is valid and then returns the 
04637  * normalized value
04638  */
04639 static int
04640 serialNumberAndIssuerSerialNormalize(
04641        slap_mask_t usage,
04642        Syntax *syntax,
04643        MatchingRule *mr,
04644        struct berval *in,
04645        struct berval *out,
04646        void *ctx )
04647 {
04648        struct berval i, ni = BER_BVNULL,
04649               sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL,
04650               i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL;
04651        char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN],
04652               sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN];
04653        char *p;
04654        int rc;
04655 
04656        assert( in != NULL );
04657        assert( out != NULL );
04658 
04659        Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n",
04660               in->bv_val, 0, 0 );
04661 
04662        rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx );
04663        if ( rc ) {
04664               goto func_leave;
04665        }
04666 
04667        rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
04668 
04669        if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
04670               slap_sl_free( i.bv_val, ctx );
04671        }
04672 
04673        if ( rc ) {
04674               rc = LDAP_INVALID_SYNTAX;
04675               goto func_leave;
04676        }
04677 
04678        /* Convert sn to canonical hex */
04679        sn2.bv_val = sbuf2;
04680        sn2.bv_len = sn.bv_len;
04681        if ( sn.bv_len > sizeof( sbuf2 ) ) {
04682               sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx );
04683        }
04684        if ( lutil_str2bin( &sn, &sn2, ctx ) ) {
04685               rc = LDAP_INVALID_SYNTAX;
04686               goto func_leave;
04687        }
04688 
04689         /* Convert i_sn to canonical hex */
04690        i_sn2.bv_val = i_sbuf2;
04691        i_sn2.bv_len = i_sn.bv_len;
04692        if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) {
04693               i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx );
04694        }
04695        if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) {
04696               rc = LDAP_INVALID_SYNTAX;
04697               goto func_leave;
04698        }
04699 
04700        sn3.bv_val = sbuf3;
04701        sn3.bv_len = sizeof(sbuf3);
04702        if ( slap_bin2hex( &sn2, &sn3, ctx ) ) {
04703               rc = LDAP_INVALID_SYNTAX;
04704               goto func_leave;
04705        }
04706 
04707        i_sn3.bv_val = i_sbuf3;
04708        i_sn3.bv_len = sizeof(i_sbuf3);
04709        if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) {
04710               rc = LDAP_INVALID_SYNTAX;
04711               goto func_leave;
04712        }
04713 
04714        out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }")
04715               + sn3.bv_len + ni.bv_len + i_sn3.bv_len;
04716        out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
04717 
04718        if ( out->bv_val == NULL ) {
04719               out->bv_len = 0;
04720               rc = LDAP_OTHER;
04721               goto func_leave;
04722        }
04723 
04724        p = out->bv_val;
04725 
04726        p = lutil_strcopy( p, "{ serialNumber " );
04727        p = lutil_strbvcopy( p, &sn3 );
04728        p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
04729        p = lutil_strbvcopy( p, &ni );
04730        p = lutil_strcopy( p, "\" }, serial " );
04731        p = lutil_strbvcopy( p, &i_sn3 );
04732        p = lutil_strcopy( p, " } } }" );
04733 
04734        assert( p == &out->bv_val[out->bv_len] );
04735 
04736 func_leave:
04737        Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n",
04738               in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 );
04739 
04740        if ( sn2.bv_val != sbuf2 ) {
04741               slap_sl_free( sn2.bv_val, ctx );
04742        }
04743 
04744        if ( i_sn2.bv_val != i_sbuf2 ) {
04745               slap_sl_free( i_sn2.bv_val, ctx );
04746        }
04747 
04748        if ( sn3.bv_val != sbuf3 ) {
04749               slap_sl_free( sn3.bv_val, ctx );
04750        }
04751 
04752        if ( i_sn3.bv_val != i_sbuf3 ) {
04753               slap_sl_free( i_sn3.bv_val, ctx );
04754        }
04755 
04756        slap_sl_free( ni.bv_val, ctx );
04757 
04758        return rc;
04759 }
04760 
04761 /* X.509 PMI attributeCertificateExactNormalize */
04762 static int
04763 attributeCertificateExactNormalize(
04764        slap_mask_t usage,
04765        Syntax *syntax,
04766        MatchingRule *mr,
04767        struct berval *val,
04768        struct berval *normalized,
04769        void *ctx )
04770 {
04771        BerElementBuffer berbuf;
04772        BerElement *ber = (BerElement *)&berbuf;
04773        ber_tag_t tag;
04774        ber_len_t len;
04775        char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN];
04776        struct berval sn, i_sn, sn2 = BER_BVNULL, i_sn2 = BER_BVNULL;
04777        struct berval issuer_dn = BER_BVNULL, bvdn;
04778        char *p;
04779        int rc = LDAP_INVALID_SYNTAX;
04780 
04781        if ( BER_BVISEMPTY( val ) ) {
04782               return rc;
04783        }
04784 
04785        if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
04786               return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx );
04787        }
04788 
04789        assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
04790 
04791        ber_init2( ber, val, LBER_USE_DER );
04792        tag = ber_skip_tag( ber, &len );   /* Signed Sequence */
04793        tag = ber_skip_tag( ber, &len );   /* Sequence */
04794        tag = ber_skip_tag( ber, &len );   /* (Mandatory) version; must be v2(1) */
04795        ber_skip_data( ber, len );
04796        tag = ber_skip_tag( ber, &len );   /* Holder Sequence */
04797        ber_skip_data( ber, len );
04798 
04799        /* Issuer */
04800        tag = ber_skip_tag( ber, &len );   /* Sequence */
04801                                           /* issuerName (GeneralNames sequence; optional)? */
04802        tag = ber_skip_tag( ber, &len );   /* baseCertificateID (sequence; optional)? */
04803        tag = ber_skip_tag( ber, &len );   /* GeneralNames (sequence) */
04804        tag = ber_skip_tag( ber, &len );   /* directoryName (we only accept this form of GeneralName) */
04805        if ( tag != SLAP_X509_GN_DIRECTORYNAME ) { 
04806               return LDAP_INVALID_SYNTAX; 
04807        }
04808        tag = ber_peek_tag( ber, &len );   /* sequence of RDN */
04809        len = ber_ptrlen( ber );
04810        bvdn.bv_val = val->bv_val + len;
04811        bvdn.bv_len = val->bv_len - len;
04812        rc = dnX509normalize( &bvdn, &issuer_dn );
04813        if ( rc != LDAP_SUCCESS ) goto done;
04814        
04815        tag = ber_skip_tag( ber, &len );   /* sequence of RDN */
04816        ber_skip_data( ber, len ); 
04817        tag = ber_skip_tag( ber, &len );   /* serial number */
04818        if ( tag != LBER_INTEGER ) {
04819               rc = LDAP_INVALID_SYNTAX; 
04820               goto done;
04821        }
04822        i_sn.bv_val = (char *)ber->ber_ptr;
04823        i_sn.bv_len = len;
04824        i_sn2.bv_val = issuer_serialbuf;
04825        i_sn2.bv_len = sizeof(issuer_serialbuf);
04826        if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) {
04827               rc = LDAP_INVALID_SYNTAX;
04828               goto done;
04829        }
04830        ber_skip_data( ber, len );
04831 
04832                                           /* issuerUID (bitstring; optional)? */
04833                                           /* objectDigestInfo (sequence; optional)? */
04834 
04835        tag = ber_skip_tag( ber, &len );   /* Signature (sequence) */
04836        ber_skip_data( ber, len );
04837        tag = ber_skip_tag( ber, &len );   /* serial number */ 
04838        if ( tag != LBER_INTEGER ) {
04839               rc = LDAP_INVALID_SYNTAX; 
04840               goto done;
04841        }
04842        sn.bv_val = (char *)ber->ber_ptr;
04843        sn.bv_len = len;
04844        sn2.bv_val = serialbuf;
04845        sn2.bv_len = sizeof(serialbuf);
04846        if ( slap_bin2hex( &sn, &sn2, ctx ) ) {
04847               rc = LDAP_INVALID_SYNTAX;
04848               goto done;
04849        }
04850        ber_skip_data( ber, len );
04851 
04852        normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial  } } }" )
04853               + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len;
04854        normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
04855 
04856        p = normalized->bv_val;
04857 
04858        p = lutil_strcopy( p, "{ serialNumber " );
04859        p = lutil_strbvcopy( p, &sn2 );
04860        p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" );
04861        p = lutil_strbvcopy( p, &issuer_dn );
04862        p = lutil_strcopy( p, "\" }, serial " );
04863        p = lutil_strbvcopy( p, &i_sn2 );
04864        p = lutil_strcopy( p, " } } }" );
04865 
04866        Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n",
04867               normalized->bv_val, NULL, NULL );
04868 
04869        rc = LDAP_SUCCESS;
04870 
04871 done:
04872        if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val );
04873        if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx );
04874        if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx );
04875 
04876        return rc;
04877 }
04878 
04879 
04880 static int
04881 hexValidate(
04882        Syntax *syntax,
04883        struct berval *in )
04884 {
04885        ber_len_t     i;
04886 
04887        assert( in != NULL );
04888        assert( !BER_BVISNULL( in ) );
04889 
04890        for ( i = 0; i < in->bv_len; i++ ) {
04891               if ( !ASCII_HEX( in->bv_val[ i ] ) ) {
04892                      return LDAP_INVALID_SYNTAX;
04893               }
04894        }
04895 
04896        return LDAP_SUCCESS;
04897 }
04898 
04899 /* Normalize a SID as used inside a CSN:
04900  * three-digit numeric string */
04901 static int
04902 hexNormalize(
04903        slap_mask_t usage,
04904        Syntax *syntax,
04905        MatchingRule *mr,
04906        struct berval *val,
04907        struct berval *normalized,
04908        void *ctx )
04909 {
04910        ber_len_t     i;
04911 
04912        assert( val != NULL );
04913        assert( normalized != NULL );
04914 
04915        ber_dupbv_x( normalized, val, ctx );
04916 
04917        for ( i = 0; i < normalized->bv_len; i++ ) {
04918               if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) {
04919                      ber_memfree_x( normalized->bv_val, ctx );
04920                      BER_BVZERO( normalized );
04921                      return LDAP_INVALID_SYNTAX;
04922               }
04923 
04924               normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
04925        }
04926 
04927        return LDAP_SUCCESS;
04928 }
04929 
04930 static int
04931 sidValidate (
04932        Syntax *syntax,
04933        struct berval *in )
04934 {
04935        assert( in != NULL );
04936        assert( !BER_BVISNULL( in ) );
04937 
04938        if ( in->bv_len != 3 ) {
04939               return LDAP_INVALID_SYNTAX;
04940        }
04941 
04942        return hexValidate( NULL, in );
04943 }
04944 
04945 /* Normalize a SID as used inside a CSN:
04946  * three-digit numeric string */
04947 static int
04948 sidNormalize(
04949        slap_mask_t usage,
04950        Syntax *syntax,
04951        MatchingRule *mr,
04952        struct berval *val,
04953        struct berval *normalized,
04954        void *ctx )
04955 {
04956        if ( val->bv_len != 3 ) {
04957               return LDAP_INVALID_SYNTAX;
04958        }
04959 
04960        return hexNormalize( 0, NULL, NULL, val, normalized, ctx );
04961 }
04962 
04963 static int
04964 sidPretty(
04965        Syntax *syntax,
04966        struct berval *val,
04967        struct berval *out,
04968        void *ctx )
04969 {
04970        return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
04971 }
04972 
04973 /* Normalize a SID as used inside a CSN, either as-is
04974  * (assertion value) or extracted from the CSN
04975  * (attribute value) */
04976 static int
04977 csnSidNormalize(
04978        slap_mask_t usage,
04979        Syntax *syntax,
04980        MatchingRule *mr,
04981        struct berval *val,
04982        struct berval *normalized,
04983        void *ctx )
04984 {
04985        struct berval bv;
04986        char          *ptr,
04987                      buf[ 4 ];
04988 
04989 
04990        if ( BER_BVISEMPTY( val ) ) {
04991               return LDAP_INVALID_SYNTAX;
04992        }
04993 
04994        if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
04995               return sidNormalize( 0, NULL, NULL, val, normalized, ctx );
04996        }
04997 
04998        assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
04999 
05000        ptr = ber_bvchr( val, '#' );
05001        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05002               return LDAP_INVALID_SYNTAX;
05003        }
05004 
05005        bv.bv_val = ptr + 1;
05006        bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
05007 
05008        ptr = ber_bvchr( &bv, '#' );
05009        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05010               return LDAP_INVALID_SYNTAX;
05011        }
05012 
05013        bv.bv_val = ptr + 1;
05014        bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val );
05015               
05016        ptr = ber_bvchr( &bv, '#' );
05017        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05018               return LDAP_INVALID_SYNTAX;
05019        }
05020 
05021        bv.bv_len = ptr - bv.bv_val;
05022 
05023        if ( bv.bv_len == 2 ) {
05024               /* OpenLDAP 2.3 SID */
05025               buf[ 0 ] = '0';
05026               buf[ 1 ] = bv.bv_val[ 0 ];
05027               buf[ 2 ] = bv.bv_val[ 1 ];
05028               buf[ 3 ] = '\0';
05029 
05030               bv.bv_val = buf;
05031               bv.bv_len = 3;
05032        }
05033 
05034        return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx );
05035 }
05036 
05037 static int
05038 csnValidate(
05039        Syntax *syntax,
05040        struct berval *in )
05041 {
05042        struct berval bv;
05043        char          *ptr;
05044        int           rc;
05045 
05046        assert( in != NULL );
05047        assert( !BER_BVISNULL( in ) );
05048 
05049        if ( BER_BVISEMPTY( in ) ) {
05050               return LDAP_INVALID_SYNTAX;
05051        }
05052 
05053        bv = *in;
05054 
05055        ptr = ber_bvchr( &bv, '#' );
05056        if ( ptr == NULL || ptr == &bv.bv_val[bv.bv_len] ) {
05057               return LDAP_INVALID_SYNTAX;
05058        }
05059 
05060        bv.bv_len = ptr - bv.bv_val;
05061        if ( bv.bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) &&
05062               bv.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) )
05063        {
05064               return LDAP_INVALID_SYNTAX;
05065        }
05066 
05067        rc = generalizedTimeValidate( NULL, &bv );
05068        if ( rc != LDAP_SUCCESS ) {
05069               return rc;
05070        }
05071 
05072        bv.bv_val = ptr + 1;
05073        bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
05074 
05075        ptr = ber_bvchr( &bv, '#' );
05076        if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
05077               return LDAP_INVALID_SYNTAX;
05078        }
05079 
05080        bv.bv_len = ptr - bv.bv_val;
05081        if ( bv.bv_len != 6 ) {
05082               return LDAP_INVALID_SYNTAX;
05083        }
05084 
05085        rc = hexValidate( NULL, &bv );
05086        if ( rc != LDAP_SUCCESS ) {
05087               return rc;
05088        }
05089 
05090        bv.bv_val = ptr + 1;
05091        bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
05092 
05093        ptr = ber_bvchr( &bv, '#' );
05094        if ( ptr == NULL || ptr == &in->bv_val[in->bv_len] ) {
05095               return LDAP_INVALID_SYNTAX;
05096        }
05097 
05098        bv.bv_len = ptr - bv.bv_val;
05099        if ( bv.bv_len == 2 ) {
05100               /* tolerate old 2-digit replica-id */
05101               rc = hexValidate( NULL, &bv );
05102 
05103        } else {
05104               rc = sidValidate( NULL, &bv );
05105        }
05106        if ( rc != LDAP_SUCCESS ) {
05107               return rc;
05108        }
05109 
05110        bv.bv_val = ptr + 1;
05111        bv.bv_len = in->bv_len - ( bv.bv_val - in->bv_val );
05112 
05113        if ( bv.bv_len != 6 ) {
05114               return LDAP_INVALID_SYNTAX;
05115        }
05116 
05117        return hexValidate( NULL, &bv );
05118 }
05119 
05120 /* Normalize a CSN in OpenLDAP 2.1 format */
05121 static int
05122 csnNormalize21(
05123        slap_mask_t usage,
05124        Syntax *syntax,
05125        MatchingRule *mr,
05126        struct berval *val,
05127        struct berval *normalized,
05128        void *ctx )
05129 {
05130        struct berval gt, cnt, sid, mod;
05131        struct berval bv;
05132        char          buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
05133        char          *ptr;
05134        ber_len_t     i;
05135 
05136        assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
05137        assert( !BER_BVISEMPTY( val ) );
05138 
05139        gt = *val;
05140 
05141        ptr = ber_bvchr( &gt, '#' );
05142        if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
05143               return LDAP_INVALID_SYNTAX;
05144        }
05145 
05146        gt.bv_len = ptr - gt.bv_val;
05147        if ( gt.bv_len != STRLENOF( "YYYYmmddHH:MM:SSZ" ) ) {
05148               return LDAP_INVALID_SYNTAX;
05149        }
05150 
05151        if ( gt.bv_val[ 10 ] != ':' || gt.bv_val[ 13 ] != ':' ) {
05152               return LDAP_INVALID_SYNTAX;
05153        }
05154 
05155        cnt.bv_val = ptr + 1;
05156        cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
05157 
05158        ptr = ber_bvchr( &cnt, '#' );
05159        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05160               return LDAP_INVALID_SYNTAX;
05161        }
05162 
05163        cnt.bv_len = ptr - cnt.bv_val;
05164        if ( cnt.bv_len != STRLENOF( "0x0000" ) ) {
05165               return LDAP_INVALID_SYNTAX;
05166        }
05167 
05168        if ( strncmp( cnt.bv_val, "0x", STRLENOF( "0x" ) ) != 0 ) {
05169               return LDAP_INVALID_SYNTAX;
05170        }
05171 
05172        cnt.bv_val += STRLENOF( "0x" );
05173        cnt.bv_len -= STRLENOF( "0x" );
05174 
05175        sid.bv_val = ptr + 1;
05176        sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
05177               
05178        ptr = ber_bvchr( &sid, '#' );
05179        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05180               return LDAP_INVALID_SYNTAX;
05181        }
05182 
05183        sid.bv_len = ptr - sid.bv_val;
05184        if ( sid.bv_len != STRLENOF( "0" ) ) {
05185               return LDAP_INVALID_SYNTAX;
05186        }
05187 
05188        mod.bv_val = ptr + 1;
05189        mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
05190        if ( mod.bv_len != STRLENOF( "0000" ) ) {
05191               return LDAP_INVALID_SYNTAX;
05192        }
05193 
05194        bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
05195        bv.bv_val = buf;
05196 
05197        ptr = bv.bv_val;
05198        ptr = lutil_strncopy( ptr, gt.bv_val, STRLENOF( "YYYYmmddHH" ) );
05199        ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:" ) ],
05200               STRLENOF( "MM" ) );
05201        ptr = lutil_strncopy( ptr, &gt.bv_val[ STRLENOF( "YYYYmmddHH:MM:" ) ],
05202               STRLENOF( "SS" ) );
05203        ptr = lutil_strcopy( ptr, ".000000Z#00" );
05204        ptr = lutil_strbvcopy( ptr, &cnt );
05205        *ptr++ = '#';
05206        *ptr++ = '0';
05207        *ptr++ = '0';
05208        *ptr++ = sid.bv_val[ 0 ];
05209        *ptr++ = '#';
05210        *ptr++ = '0';
05211        *ptr++ = '0';
05212        for ( i = 0; i < mod.bv_len; i++ ) {
05213               *ptr++ = TOLOWER( mod.bv_val[ i ] );
05214        }
05215        *ptr = '\0';
05216 
05217        assert( ptr == &bv.bv_val[bv.bv_len] );
05218 
05219        if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
05220               return LDAP_INVALID_SYNTAX;
05221        }
05222 
05223        ber_dupbv_x( normalized, &bv, ctx );
05224 
05225        return LDAP_SUCCESS;
05226 }
05227 
05228 /* Normalize a CSN in OpenLDAP 2.3 format */
05229 static int
05230 csnNormalize23(
05231        slap_mask_t usage,
05232        Syntax *syntax,
05233        MatchingRule *mr,
05234        struct berval *val,
05235        struct berval *normalized,
05236        void *ctx )
05237 {
05238        struct berval gt, cnt, sid, mod;
05239        struct berval bv;
05240        char          buf[ STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) + 1 ];
05241        char          *ptr;
05242        ber_len_t     i;
05243 
05244        assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
05245        assert( !BER_BVISEMPTY( val ) );
05246 
05247        gt = *val;
05248 
05249        ptr = ber_bvchr( &gt, '#' );
05250        if ( ptr == NULL || ptr == &gt.bv_val[gt.bv_len] ) {
05251               return LDAP_INVALID_SYNTAX;
05252        }
05253 
05254        gt.bv_len = ptr - gt.bv_val;
05255        if ( gt.bv_len != STRLENOF( "YYYYmmddHHMMSSZ" ) ) {
05256               return LDAP_INVALID_SYNTAX;
05257        }
05258 
05259        cnt.bv_val = ptr + 1;
05260        cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
05261 
05262        ptr = ber_bvchr( &cnt, '#' );
05263        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05264               return LDAP_INVALID_SYNTAX;
05265        }
05266 
05267        cnt.bv_len = ptr - cnt.bv_val;
05268        if ( cnt.bv_len != STRLENOF( "000000" ) ) {
05269               return LDAP_INVALID_SYNTAX;
05270        }
05271 
05272        sid.bv_val = ptr + 1;
05273        sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
05274               
05275        ptr = ber_bvchr( &sid, '#' );
05276        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05277               return LDAP_INVALID_SYNTAX;
05278        }
05279 
05280        sid.bv_len = ptr - sid.bv_val;
05281        if ( sid.bv_len != STRLENOF( "00" ) ) {
05282               return LDAP_INVALID_SYNTAX;
05283        }
05284 
05285        mod.bv_val = ptr + 1;
05286        mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
05287        if ( mod.bv_len != STRLENOF( "000000" ) ) {
05288               return LDAP_INVALID_SYNTAX;
05289        }
05290 
05291        bv.bv_len = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" );
05292        bv.bv_val = buf;
05293 
05294        ptr = bv.bv_val;
05295        ptr = lutil_strncopy( ptr, gt.bv_val, gt.bv_len - 1 );
05296        ptr = lutil_strcopy( ptr, ".000000Z#" );
05297        ptr = lutil_strbvcopy( ptr, &cnt );
05298        *ptr++ = '#';
05299        *ptr++ = '0';
05300        for ( i = 0; i < sid.bv_len; i++ ) {
05301               *ptr++ = TOLOWER( sid.bv_val[ i ] );
05302        }
05303        *ptr++ = '#';
05304        for ( i = 0; i < mod.bv_len; i++ ) {
05305               *ptr++ = TOLOWER( mod.bv_val[ i ] );
05306        }
05307        *ptr = '\0';
05308 
05309        assert( ptr == &bv.bv_val[bv.bv_len] );
05310        if ( csnValidate( syntax, &bv ) != LDAP_SUCCESS ) {
05311               return LDAP_INVALID_SYNTAX;
05312        }
05313 
05314        ber_dupbv_x( normalized, &bv, ctx );
05315 
05316        return LDAP_SUCCESS;
05317 }
05318 
05319 /* Normalize a CSN */
05320 static int
05321 csnNormalize(
05322        slap_mask_t usage,
05323        Syntax *syntax,
05324        MatchingRule *mr,
05325        struct berval *val,
05326        struct berval *normalized,
05327        void *ctx )
05328 {
05329        struct berval cnt, sid, mod;
05330        char          *ptr;
05331        ber_len_t     i;
05332 
05333        assert( val != NULL );
05334        assert( normalized != NULL );
05335 
05336        assert( SLAP_MR_IS_VALUE_OF_SYNTAX( usage ) != 0 );
05337 
05338        if ( BER_BVISEMPTY( val ) ) {
05339               return LDAP_INVALID_SYNTAX;
05340        }
05341 
05342        if ( val->bv_len == STRLENOF( "YYYYmmddHHMMSSZ#SSSSSS#ID#ssssss" ) ) {
05343               /* Openldap <= 2.3 */
05344 
05345               return csnNormalize23( usage, syntax, mr, val, normalized, ctx );
05346        }
05347 
05348        if ( val->bv_len == STRLENOF( "YYYYmmddHH:MM:SSZ#0xSSSS#I#ssss" ) ) {
05349               /* Openldap 2.1 */
05350 
05351               return csnNormalize21( usage, syntax, mr, val, normalized, ctx );
05352        }
05353 
05354        if ( val->bv_len != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#SID#ssssss" ) ) {
05355               return LDAP_INVALID_SYNTAX;
05356        }
05357 
05358        ptr = ber_bvchr( val, '#' );
05359        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05360               return LDAP_INVALID_SYNTAX;
05361        }
05362 
05363        if ( ptr - val->bv_val != STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ" ) ) {
05364               return LDAP_INVALID_SYNTAX;
05365        }
05366 
05367        cnt.bv_val = ptr + 1;
05368        cnt.bv_len = val->bv_len - ( cnt.bv_val - val->bv_val );
05369 
05370        ptr = ber_bvchr( &cnt, '#' );
05371        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05372               return LDAP_INVALID_SYNTAX;
05373        }
05374 
05375        if ( ptr - cnt.bv_val != STRLENOF( "000000" ) ) {
05376               return LDAP_INVALID_SYNTAX;
05377        }
05378 
05379        sid.bv_val = ptr + 1;
05380        sid.bv_len = val->bv_len - ( sid.bv_val - val->bv_val );
05381               
05382        ptr = ber_bvchr( &sid, '#' );
05383        if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) {
05384               return LDAP_INVALID_SYNTAX;
05385        }
05386 
05387        sid.bv_len = ptr - sid.bv_val;
05388        if ( sid.bv_len != STRLENOF( "000" ) ) {
05389               return LDAP_INVALID_SYNTAX;
05390        }
05391 
05392        mod.bv_val = ptr + 1;
05393        mod.bv_len = val->bv_len - ( mod.bv_val - val->bv_val );
05394 
05395        if ( mod.bv_len != STRLENOF( "000000" ) ) {
05396               return LDAP_INVALID_SYNTAX;
05397        }
05398 
05399        ber_dupbv_x( normalized, val, ctx );
05400 
05401        for ( i = STRLENOF( "YYYYmmddHHMMSS.uuuuuuZ#SSSSSS#" );
05402               i < normalized->bv_len; i++ )
05403        {
05404               /* assume it's already validated that's all hex digits */
05405               normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] );
05406        }
05407 
05408        return LDAP_SUCCESS;
05409 }
05410 
05411 static int
05412 csnPretty(
05413        Syntax *syntax,
05414        struct berval *val,
05415        struct berval *out,
05416        void *ctx )
05417 {
05418        return csnNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx );
05419 }
05420 
05421 #ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
05422 /* slight optimization - does not need the start parameter */
05423 #define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
05424 enum { start = 0 };
05425 #endif
05426 
05427 static int
05428 check_time_syntax (struct berval *val,
05429        int start,
05430        int *parts,
05431        struct berval *fraction)
05432 {
05433        /*
05434         * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
05435         * start=1 UTCTime         YYmmddHHMM[SS][Z|(+/-)HHMM]
05436         * GeneralizedTime supports leap seconds, UTCTime does not.
05437         */
05438        static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
05439        static const int mdays[2][12] = {
05440               /* non-leap years */
05441               { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
05442               /* leap years */
05443               { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
05444        };
05445        char *p, *e;
05446        int part, c, c1, c2, tzoffset, leapyear = 0;
05447 
05448        p = val->bv_val;
05449        e = p + val->bv_len;
05450 
05451 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
05452        parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
05453 #endif
05454        for (part = start; part < 7 && p < e; part++) {
05455               c1 = *p;
05456               if (!ASCII_DIGIT(c1)) {
05457                      break;
05458               }
05459               p++;
05460               if (p == e) {
05461                      return LDAP_INVALID_SYNTAX;
05462               }
05463               c = *p++;
05464               if (!ASCII_DIGIT(c)) {
05465                      return LDAP_INVALID_SYNTAX;
05466               }
05467               c += c1 * 10 - '0' * 11;
05468               if ((part | 1) == 3) {
05469                      --c;
05470                      if (c < 0) {
05471                             return LDAP_INVALID_SYNTAX;
05472                      }
05473               }
05474               if (c >= ceiling[part]) {
05475                      if (! (c == 60 && part == 6 && start == 0))
05476                             return LDAP_INVALID_SYNTAX;
05477               }
05478               parts[part] = c;
05479        }
05480        if (part < 5 + start) {
05481               return LDAP_INVALID_SYNTAX;
05482        }
05483        for (; part < 9; part++) {
05484               parts[part] = 0;
05485        }
05486 
05487        /* leapyear check for the Gregorian calendar (year>1581) */
05488        if (parts[parts[1] == 0 ? 0 : 1] % 4 == 0) {
05489               leapyear = 1;
05490        }
05491 
05492        if (parts[3] >= mdays[leapyear][parts[2]]) {
05493               return LDAP_INVALID_SYNTAX;
05494        }
05495 
05496        if (start == 0) {
05497               fraction->bv_val = p;
05498               fraction->bv_len = 0;
05499               if (p < e && (*p == '.' || *p == ',')) {
05500                      char *end_num;
05501                      while (++p < e && ASCII_DIGIT(*p)) {
05502                             /* EMTPY */;
05503                      }
05504                      if (p - fraction->bv_val == 1) {
05505                             return LDAP_INVALID_SYNTAX;
05506                      }
05507                      for (end_num = p; end_num[-1] == '0'; --end_num) {
05508                             /* EMPTY */;
05509                      }
05510                      c = end_num - fraction->bv_val;
05511                      if (c != 1) fraction->bv_len = c;
05512               }
05513        }
05514 
05515        if (p == e) {
05516               /* no time zone */
05517               return start == 0 ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
05518        }
05519 
05520        tzoffset = *p++;
05521        switch (tzoffset) {
05522        default:
05523               return LDAP_INVALID_SYNTAX;
05524        case 'Z':
05525               /* UTC */
05526               break;
05527        case '+':
05528        case '-':
05529               for (part = 7; part < 9 && p < e; part++) {
05530                      c1 = *p;
05531                      if (!ASCII_DIGIT(c1)) {
05532                             break;
05533                      }
05534                      p++;
05535                      if (p == e) {
05536                             return LDAP_INVALID_SYNTAX;
05537                      }
05538                      c2 = *p++;
05539                      if (!ASCII_DIGIT(c2)) {
05540                             return LDAP_INVALID_SYNTAX;
05541                      }
05542                      parts[part] = c1 * 10 + c2 - '0' * 11;
05543                      if (parts[part] >= ceiling[part]) {
05544                             return LDAP_INVALID_SYNTAX;
05545                      }
05546               }
05547               if (part < 8 + start) {
05548                      return LDAP_INVALID_SYNTAX;
05549               }
05550 
05551               if (tzoffset == '-') {
05552                      /* negative offset to UTC, ie west of Greenwich */
05553                      parts[4] += parts[7];
05554                      parts[5] += parts[8];
05555                      /* offset is just hhmm, no seconds */
05556                      for (part = 6; --part >= 0; ) {
05557                             if (part != 3) {
05558                                    c = ceiling[part];
05559                             } else {
05560                                    c = mdays[leapyear][parts[2]];
05561                             }
05562                             if (parts[part] >= c) {
05563                                    if (part == 0) {
05564                                           return LDAP_INVALID_SYNTAX;
05565                                    }
05566                                    parts[part] -= c;
05567                                    parts[part - 1]++;
05568                                    continue;
05569                             } else if (part != 5) {
05570                                    break;
05571                             }
05572                      }
05573               } else {
05574                      /* positive offset to UTC, ie east of Greenwich */
05575                      parts[4] -= parts[7];
05576                      parts[5] -= parts[8];
05577                      for (part = 6; --part >= 0; ) {
05578                             if (parts[part] < 0) {
05579                                    if (part == 0) {
05580                                           return LDAP_INVALID_SYNTAX;
05581                                    }
05582                                    if (part != 3) {
05583                                           c = ceiling[part];
05584                                    } else {
05585                                           /* make first arg to % non-negative */
05586                                           c = mdays[leapyear][(parts[2] - 1 + 12) % 12];
05587                                    }
05588                                    parts[part] += c;
05589                                    parts[part - 1]--;
05590                                    continue;
05591                             } else if (part != 5) {
05592                                    break;
05593                             }
05594                      }
05595               }
05596        }
05597 
05598        return p != e ? LDAP_INVALID_SYNTAX : LDAP_SUCCESS;
05599 }
05600 
05601 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
05602 
05603 #if 0
05604 static int
05605 xutcTimeNormalize(
05606        Syntax *syntax,
05607        struct berval *val,
05608        struct berval *normalized )
05609 {
05610        int parts[9], rc;
05611 
05612        rc = check_time_syntax(val, 1, parts, NULL);
05613        if (rc != LDAP_SUCCESS) {
05614               return rc;
05615        }
05616 
05617        normalized->bv_val = ch_malloc( 14 );
05618        if ( normalized->bv_val == NULL ) {
05619               return LBER_ERROR_MEMORY;
05620        }
05621 
05622        sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02dZ",
05623               parts[1], parts[2] + 1, parts[3] + 1,
05624               parts[4], parts[5], parts[6] );
05625        normalized->bv_len = 13;
05626 
05627        return LDAP_SUCCESS;
05628 }
05629 #endif /* 0 */
05630 
05631 static int
05632 utcTimeValidate(
05633        Syntax *syntax,
05634        struct berval *in )
05635 {
05636        int parts[9];
05637        return check_time_syntax(in, 1, parts, NULL);
05638 }
05639 
05640 #endif /* SUPPORT_OBSOLETE_UTC_SYNTAX */
05641 
05642 static int
05643 generalizedTimeValidate(
05644        Syntax *syntax,
05645        struct berval *in )
05646 {
05647        int parts[9];
05648        struct berval fraction;
05649        return check_time_syntax(in, 0, parts, &fraction);
05650 }
05651 
05652 static int
05653 generalizedTimeNormalize(
05654        slap_mask_t usage,
05655        Syntax *syntax,
05656        MatchingRule *mr,
05657        struct berval *val,
05658        struct berval *normalized,
05659        void *ctx )
05660 {
05661        int parts[9], rc;
05662        unsigned int len;
05663        struct berval fraction;
05664 
05665        rc = check_time_syntax(val, 0, parts, &fraction);
05666        if (rc != LDAP_SUCCESS) {
05667               return rc;
05668        }
05669 
05670        len = STRLENOF("YYYYmmddHHMMSSZ") + fraction.bv_len;
05671        normalized->bv_val = slap_sl_malloc( len + 1, ctx );
05672        if ( BER_BVISNULL( normalized ) ) {
05673               return LBER_ERROR_MEMORY;
05674        }
05675 
05676        sprintf( normalized->bv_val, "%02d%02d%02d%02d%02d%02d%02d",
05677               parts[0], parts[1], parts[2] + 1, parts[3] + 1,
05678               parts[4], parts[5], parts[6] );
05679        if ( !BER_BVISEMPTY( &fraction ) ) {
05680               memcpy( normalized->bv_val + STRLENOF("YYYYmmddHHMMSSZ")-1,
05681                      fraction.bv_val, fraction.bv_len );
05682               normalized->bv_val[STRLENOF("YYYYmmddHHMMSSZ")-1] = '.';
05683        }
05684        strcpy( normalized->bv_val + len-1, "Z" );
05685        normalized->bv_len = len;
05686 
05687        return LDAP_SUCCESS;
05688 }
05689 
05690 static int
05691 generalizedTimeOrderingMatch(
05692        int *matchp,
05693        slap_mask_t flags,
05694        Syntax *syntax,
05695        MatchingRule *mr,
05696        struct berval *value,
05697        void *assertedValue )
05698 {
05699        struct berval *asserted = (struct berval *) assertedValue;
05700        ber_len_t v_len  = value->bv_len;
05701        ber_len_t av_len = asserted->bv_len;
05702 
05703        /* ignore trailing 'Z' when comparing */
05704        int match = memcmp( value->bv_val, asserted->bv_val,
05705               (v_len < av_len ? v_len : av_len) - 1 );
05706        if ( match == 0 ) match = v_len - av_len;
05707 
05708        /* If used in extensible match filter, match if value < asserted */
05709        if ( flags & SLAP_MR_EXT )
05710               match = (match >= 0);
05711 
05712        *matchp = match;
05713        return LDAP_SUCCESS;
05714 }
05715 
05716 /* Index generation function: Ordered index */
05717 int generalizedTimeIndexer(
05718        slap_mask_t use,
05719        slap_mask_t flags,
05720        Syntax *syntax,
05721        MatchingRule *mr,
05722        struct berval *prefix,
05723        BerVarray values,
05724        BerVarray *keysp,
05725        void *ctx )
05726 {
05727        int i, j;
05728        BerVarray keys;
05729        char tmp[5];
05730        BerValue bvtmp; /* 40 bit index */
05731        struct lutil_tm tm;
05732        struct lutil_timet tt;
05733 
05734        bvtmp.bv_len = sizeof(tmp);
05735        bvtmp.bv_val = tmp;
05736        for( i=0; values[i].bv_val != NULL; i++ ) {
05737               /* just count them */
05738        }
05739 
05740        /* we should have at least one value at this point */
05741        assert( i > 0 );
05742 
05743        keys = slap_sl_malloc( sizeof( struct berval ) * (i+1), ctx );
05744 
05745        /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
05746        for( i=0, j=0; values[i].bv_val != NULL; i++ ) {
05747               assert(values[i].bv_val != NULL && values[i].bv_len >= 10);
05748               /* Use 40 bits of time for key */
05749               if ( lutil_parsetime( values[i].bv_val, &tm ) == 0 ) {
05750                      lutil_tm2time( &tm, &tt );
05751                      tmp[0] = tt.tt_gsec & 0xff;
05752                      tmp[4] = tt.tt_sec & 0xff;
05753                      tt.tt_sec >>= 8;
05754                      tmp[3] = tt.tt_sec & 0xff;
05755                      tt.tt_sec >>= 8;
05756                      tmp[2] = tt.tt_sec & 0xff;
05757                      tt.tt_sec >>= 8;
05758                      tmp[1] = tt.tt_sec & 0xff;
05759                      
05760                      ber_dupbv_x(&keys[j++], &bvtmp, ctx );
05761               }
05762        }
05763 
05764        keys[j].bv_val = NULL;
05765        keys[j].bv_len = 0;
05766 
05767        *keysp = keys;
05768 
05769        return LDAP_SUCCESS;
05770 }
05771 
05772 /* Index generation function: Ordered index */
05773 int generalizedTimeFilter(
05774        slap_mask_t use,
05775        slap_mask_t flags,
05776        Syntax *syntax,
05777        MatchingRule *mr,
05778        struct berval *prefix,
05779        void * assertedValue,
05780        BerVarray *keysp,
05781        void *ctx )
05782 {
05783        BerVarray keys;
05784        char tmp[5];
05785        BerValue bvtmp; /* 40 bit index */
05786        BerValue *value = (BerValue *) assertedValue;
05787        struct lutil_tm tm;
05788        struct lutil_timet tt;
05789        
05790        bvtmp.bv_len = sizeof(tmp);
05791        bvtmp.bv_val = tmp;
05792        /* GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM]) */
05793        /* Use 40 bits of time for key */
05794        if ( value->bv_val && value->bv_len >= 10 &&
05795               lutil_parsetime( value->bv_val, &tm ) == 0 ) {
05796 
05797               lutil_tm2time( &tm, &tt );
05798               tmp[0] = tt.tt_gsec & 0xff;
05799               tmp[4] = tt.tt_sec & 0xff;
05800               tt.tt_sec >>= 8;
05801               tmp[3] = tt.tt_sec & 0xff;
05802               tt.tt_sec >>= 8;
05803               tmp[2] = tt.tt_sec & 0xff;
05804               tt.tt_sec >>= 8;
05805               tmp[1] = tt.tt_sec & 0xff;
05806 
05807               keys = slap_sl_malloc( sizeof( struct berval ) * 2, ctx );
05808               ber_dupbv_x(keys, &bvtmp, ctx );
05809               keys[1].bv_val = NULL;
05810               keys[1].bv_len = 0;
05811        } else {
05812               keys = NULL;
05813        }
05814 
05815        *keysp = keys;
05816 
05817        return LDAP_SUCCESS;
05818 }
05819 
05820 static int
05821 deliveryMethodValidate(
05822        Syntax *syntax,
05823        struct berval *val )
05824 {
05825 #undef LENOF
05826 #define LENOF(s) (sizeof(s)-1)
05827        struct berval tmp = *val;
05828        /*
05829      * DeliveryMethod = pdm *( WSP DOLLAR WSP DeliveryMethod )
05830         *     pdm = "any" / "mhs" / "physical" / "telex" / "teletex" /
05831         *            "g3fax" / "g4fax" / "ia5" / "videotex" / "telephone"
05832         */
05833 again:
05834        if( tmp.bv_len < 3 ) return LDAP_INVALID_SYNTAX;
05835 
05836        switch( tmp.bv_val[0] ) {
05837        case 'a':
05838        case 'A':
05839               if(( tmp.bv_len >= LENOF("any") ) &&
05840                      ( strncasecmp(tmp.bv_val, "any", LENOF("any")) == 0 ))
05841               {
05842                      tmp.bv_len -= LENOF("any");
05843                      tmp.bv_val += LENOF("any");
05844                      break;
05845               }
05846               return LDAP_INVALID_SYNTAX;
05847 
05848        case 'm':
05849        case 'M':
05850               if(( tmp.bv_len >= LENOF("mhs") ) &&
05851                      ( strncasecmp(tmp.bv_val, "mhs", LENOF("mhs")) == 0 ))
05852               {
05853                      tmp.bv_len -= LENOF("mhs");
05854                      tmp.bv_val += LENOF("mhs");
05855                      break;
05856               }
05857               return LDAP_INVALID_SYNTAX;
05858 
05859        case 'p':
05860        case 'P':
05861               if(( tmp.bv_len >= LENOF("physical") ) &&
05862                      ( strncasecmp(tmp.bv_val, "physical", LENOF("physical")) == 0 ))
05863               {
05864                      tmp.bv_len -= LENOF("physical");
05865                      tmp.bv_val += LENOF("physical");
05866                      break;
05867               }
05868               return LDAP_INVALID_SYNTAX;
05869 
05870        case 't':
05871        case 'T': /* telex or teletex or telephone */
05872               if(( tmp.bv_len >= LENOF("telex") ) &&
05873                      ( strncasecmp(tmp.bv_val, "telex", LENOF("telex")) == 0 ))
05874               {
05875                      tmp.bv_len -= LENOF("telex");
05876                      tmp.bv_val += LENOF("telex");
05877                      break;
05878               }
05879               if(( tmp.bv_len >= LENOF("teletex") ) &&
05880                      ( strncasecmp(tmp.bv_val, "teletex", LENOF("teletex")) == 0 ))
05881               {
05882                      tmp.bv_len -= LENOF("teletex");
05883                      tmp.bv_val += LENOF("teletex");
05884                      break;
05885               }
05886               if(( tmp.bv_len >= LENOF("telephone") ) &&
05887                      ( strncasecmp(tmp.bv_val, "telephone", LENOF("telephone")) == 0 ))
05888               {
05889                      tmp.bv_len -= LENOF("telephone");
05890                      tmp.bv_val += LENOF("telephone");
05891                      break;
05892               }
05893               return LDAP_INVALID_SYNTAX;
05894 
05895        case 'g':
05896        case 'G': /* g3fax or g4fax */
05897               if(( tmp.bv_len >= LENOF("g3fax") ) && (
05898                      ( strncasecmp(tmp.bv_val, "g3fax", LENOF("g3fax")) == 0 ) ||
05899                      ( strncasecmp(tmp.bv_val, "g4fax", LENOF("g4fax")) == 0 )))
05900               {
05901                      tmp.bv_len -= LENOF("g3fax");
05902                      tmp.bv_val += LENOF("g3fax");
05903                      break;
05904               }
05905               return LDAP_INVALID_SYNTAX;
05906 
05907        case 'i':
05908        case 'I':
05909               if(( tmp.bv_len >= LENOF("ia5") ) &&
05910                      ( strncasecmp(tmp.bv_val, "ia5", LENOF("ia5")) == 0 ))
05911               {
05912                      tmp.bv_len -= LENOF("ia5");
05913                      tmp.bv_val += LENOF("ia5");
05914                      break;
05915               }
05916               return LDAP_INVALID_SYNTAX;
05917 
05918        case 'v':
05919        case 'V':
05920               if(( tmp.bv_len >= LENOF("videotex") ) &&
05921                      ( strncasecmp(tmp.bv_val, "videotex", LENOF("videotex")) == 0 ))
05922               {
05923                      tmp.bv_len -= LENOF("videotex");
05924                      tmp.bv_val += LENOF("videotex");
05925                      break;
05926               }
05927               return LDAP_INVALID_SYNTAX;
05928 
05929        default:
05930               return LDAP_INVALID_SYNTAX;
05931        }
05932 
05933        if( BER_BVISEMPTY( &tmp ) ) return LDAP_SUCCESS;
05934 
05935        while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
05936               tmp.bv_len++;
05937               tmp.bv_val--;
05938        }
05939        if( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == '$' ) ) {
05940               tmp.bv_len++;
05941               tmp.bv_val--;
05942        } else {
05943               return LDAP_INVALID_SYNTAX;
05944        }
05945        while( !BER_BVISEMPTY( &tmp ) && ( tmp.bv_val[0] == ' ' ) ) {
05946               tmp.bv_len++;
05947               tmp.bv_val--;
05948        }
05949 
05950        goto again;
05951 }
05952 
05953 static int
05954 nisNetgroupTripleValidate(
05955        Syntax *syntax,
05956        struct berval *val )
05957 {
05958        char *p, *e;
05959        int commas = 0;
05960 
05961        if ( BER_BVISEMPTY( val ) ) {
05962               return LDAP_INVALID_SYNTAX;
05963        }
05964 
05965        p = (char *)val->bv_val;
05966        e = p + val->bv_len;
05967 
05968        if ( *p != '(' /*')'*/ ) {
05969               return LDAP_INVALID_SYNTAX;
05970        }
05971 
05972        for ( p++; ( p < e ) && ( *p != /*'('*/ ')' ); p++ ) {
05973               if ( *p == ',' ) {
05974                      commas++;
05975                      if ( commas > 2 ) {
05976                             return LDAP_INVALID_SYNTAX;
05977                      }
05978 
05979               } else if ( !AD_CHAR( *p ) ) {
05980                      return LDAP_INVALID_SYNTAX;
05981               }
05982        }
05983 
05984        if ( ( commas != 2 ) || ( *p != /*'('*/ ')' ) ) {
05985               return LDAP_INVALID_SYNTAX;
05986        }
05987 
05988        p++;
05989 
05990        if (p != e) {
05991               return LDAP_INVALID_SYNTAX;
05992        }
05993 
05994        return LDAP_SUCCESS;
05995 }
05996 
05997 static int
05998 bootParameterValidate(
05999        Syntax *syntax,
06000        struct berval *val )
06001 {
06002        char *p, *e;
06003 
06004        if ( BER_BVISEMPTY( val ) ) {
06005               return LDAP_INVALID_SYNTAX;
06006        }
06007 
06008        p = (char *)val->bv_val;
06009        e = p + val->bv_len;
06010 
06011        /* key */
06012        for (; ( p < e ) && ( *p != '=' ); p++ ) {
06013               if ( !AD_CHAR( *p ) ) {
06014                      return LDAP_INVALID_SYNTAX;
06015               }
06016        }
06017 
06018        if ( *p != '=' ) {
06019               return LDAP_INVALID_SYNTAX;
06020        }
06021 
06022        /* server */
06023        for ( p++; ( p < e ) && ( *p != ':' ); p++ ) {
06024               if ( !AD_CHAR( *p ) ) {
06025                      return LDAP_INVALID_SYNTAX;
06026               }
06027        }
06028 
06029        if ( *p != ':' ) {
06030               return LDAP_INVALID_SYNTAX;
06031        }
06032 
06033        /* path */
06034        for ( p++; p < e; p++ ) {
06035               if ( !SLAP_PRINTABLE( *p ) ) {
06036                      return LDAP_INVALID_SYNTAX;
06037               }
06038        }
06039 
06040        return LDAP_SUCCESS;
06041 }
06042 
06043 static int
06044 firstComponentNormalize(
06045        slap_mask_t usage,
06046        Syntax *syntax,
06047        MatchingRule *mr,
06048        struct berval *val,
06049        struct berval *normalized,
06050        void *ctx )
06051 {
06052        int rc;
06053        struct berval comp;
06054        ber_len_t len;
06055 
06056        if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX( usage )) {
06057               ber_dupbv_x( normalized, val, ctx );
06058               return LDAP_SUCCESS;
06059        }
06060 
06061        if( val->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
06062 
06063        if( ! ( val->bv_val[0] == '(' /*')'*/
06064                      && val->bv_val[val->bv_len - 1] == /*'('*/ ')' )
06065               && ! ( val->bv_val[0] == '{' /*'}'*/
06066                      && val->bv_val[val->bv_len - 1] == /*'('*/ '}' ) )
06067        {
06068               return LDAP_INVALID_SYNTAX;
06069        }
06070 
06071        /* trim leading white space */
06072        for( len=1;
06073               len < val->bv_len && ASCII_SPACE(val->bv_val[len]);
06074               len++ )
06075        {
06076               /* empty */
06077        }
06078 
06079        /* grab next word */
06080        comp.bv_val = &val->bv_val[len];
06081        len = val->bv_len - len - STRLENOF(/*"{"*/ "}");
06082        for( comp.bv_len = 0;
06083               !ASCII_SPACE(comp.bv_val[comp.bv_len]) && comp.bv_len < len;
06084               comp.bv_len++ )
06085        {
06086               /* empty */
06087        }
06088 
06089        if( mr == slap_schema.si_mr_objectIdentifierFirstComponentMatch ) {
06090               rc = numericoidValidate( NULL, &comp );
06091        } else if( mr == slap_schema.si_mr_integerFirstComponentMatch ) {
06092               rc = integerValidate( NULL, &comp );
06093        } else {
06094               rc = LDAP_INVALID_SYNTAX;
06095        }
06096        
06097 
06098        if( rc == LDAP_SUCCESS ) {
06099               ber_dupbv_x( normalized, &comp, ctx );
06100        }
06101 
06102        return rc;
06103 }
06104 
06105 static char *country_gen_syn[] = {
06106        "1.3.6.1.4.1.1466.115.121.1.15",   /* Directory String */
06107        "1.3.6.1.4.1.1466.115.121.1.26",   /* IA5 String */
06108        "1.3.6.1.4.1.1466.115.121.1.44",   /* Printable String */
06109        NULL
06110 };
06111 
06112 #define X_BINARY "X-BINARY-TRANSFER-REQUIRED 'TRUE' "
06113 #define X_NOT_H_R "X-NOT-HUMAN-READABLE 'TRUE' "
06114 
06115 static slap_syntax_defs_rec syntax_defs[] = {
06116        {"( 1.3.6.1.4.1.1466.115.121.1.1 DESC 'ACI Item' "
06117               X_BINARY X_NOT_H_R ")",
06118               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, NULL, NULL},
06119        {"( 1.3.6.1.4.1.1466.115.121.1.2 DESC 'Access Point' " X_NOT_H_R ")",
06120               0, NULL, NULL, NULL},
06121        {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'Attribute Type Description' )",
06122               0, NULL, NULL, NULL},
06123        {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' "
06124               X_NOT_H_R ")",
06125               SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
06126        {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' "
06127               X_NOT_H_R ")",
06128               SLAP_SYNTAX_BER, NULL, berValidate, NULL},
06129        {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'Bit String' )",
06130               0, NULL, bitStringValidate, NULL },
06131        {"( 1.3.6.1.4.1.1466.115.121.1.7 DESC 'Boolean' )",
06132               0, NULL, booleanValidate, NULL},
06133        {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' "
06134               X_BINARY X_NOT_H_R ")",
06135               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
06136               NULL, certificateValidate, NULL},
06137        {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'Certificate List' "
06138               X_BINARY X_NOT_H_R ")",
06139               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
06140               NULL, certificateListValidate, NULL},
06141        {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'Certificate Pair' "
06142               X_BINARY X_NOT_H_R ")",
06143               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
06144               NULL, sequenceValidate, NULL},
06145        {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' "
06146               X_BINARY X_NOT_H_R ")",
06147               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER,
06148               NULL, attributeCertificateValidate, NULL},
06149 #if 0  /* need to go __after__ printableString */
06150        {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
06151               0, "1.3.6.1.4.1.1466.115.121.1.44",
06152               countryStringValidate, NULL},
06153 #endif
06154        {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
06155               SLAP_SYNTAX_DN, NULL, dnValidate, dnPretty},
06156        {"( 1.2.36.79672281.1.5.0 DESC 'RDN' )",
06157               0, NULL, rdnValidate, rdnPretty},
06158 #ifdef LDAP_COMP_MATCH
06159        {"( 1.2.36.79672281.1.5.3 DESC 'allComponents' )",
06160               0, NULL, allComponentsValidate, NULL},
06161        {"( 1.2.36.79672281.1.5.2 DESC 'componentFilterMatch assertion') ",
06162               0, NULL, componentFilterValidate, NULL},
06163 #endif
06164        {"( 1.3.6.1.4.1.1466.115.121.1.13 DESC 'Data Quality' )",
06165               0, NULL, NULL, NULL},
06166        {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'Delivery Method' )",
06167               0, NULL, deliveryMethodValidate, NULL},
06168        {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'Directory String' )",
06169               0, NULL, UTF8StringValidate, NULL},
06170        {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DIT Content Rule Description' )",
06171               0, NULL, NULL, NULL},
06172        {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DIT Structure Rule Description' )",
06173               0, NULL, NULL, NULL},
06174        {"( 1.3.6.1.4.1.1466.115.121.1.19 DESC 'DSA Quality' )",
06175               0, NULL, NULL, NULL},
06176        {"( 1.3.6.1.4.1.1466.115.121.1.20 DESC 'DSE Type' )",
06177               0, NULL, NULL, NULL},
06178        {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'Enhanced Guide' )",
06179               0, NULL, NULL, NULL},
06180        {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'Facsimile Telephone Number' )",
06181               0, NULL, printablesStringValidate, NULL},
06182        {"( 1.3.6.1.4.1.1466.115.121.1.23 DESC 'Fax' " X_NOT_H_R ")",
06183               SLAP_SYNTAX_BLOB, NULL, NULL, NULL},
06184        {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'Generalized Time' )",
06185               0, NULL, generalizedTimeValidate, NULL},
06186        {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )",
06187               0, NULL, NULL, NULL},
06188        {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5 String' )",
06189               0, NULL, IA5StringValidate, NULL},
06190        {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )",
06191               0, NULL, integerValidate, NULL},
06192        {"( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " X_NOT_H_R ")",
06193               SLAP_SYNTAX_BLOB, NULL, blobValidate, NULL},
06194        {"( 1.3.6.1.4.1.1466.115.121.1.29 DESC 'Master And Shadow Access Points' )",
06195               0, NULL, NULL, NULL},
06196        {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'Matching Rule Description' )",
06197               0, NULL, NULL, NULL},
06198        {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'Matching Rule Use Description' )",
06199               0, NULL, NULL, NULL},
06200        {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'Mail Preference' )",
06201               0, NULL, NULL, NULL},
06202        {"( 1.3.6.1.4.1.1466.115.121.1.33 DESC 'MHS OR Address' )",
06203               0, NULL, NULL, NULL},
06204        {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'Name And Optional UID' )",
06205               SLAP_SYNTAX_DN, NULL, nameUIDValidate, nameUIDPretty },
06206        {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'Name Form Description' )",
06207               0, NULL, NULL, NULL},
06208        {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'Numeric String' )",
06209               0, NULL, numericStringValidate, NULL},
06210        {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'Object Class Description' )",
06211               0, NULL, NULL, NULL},
06212        {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )",
06213               0, NULL, numericoidValidate, NULL},
06214        {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'Other Mailbox' )",
06215               0, NULL, IA5StringValidate, NULL},
06216        {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'Octet String' )",
06217               0, NULL, blobValidate, NULL},
06218        {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'Postal Address' )",
06219               0, NULL, postalAddressValidate, NULL},
06220        {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'Protocol Information' )",
06221               0, NULL, NULL, NULL},
06222        {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'Presentation Address' )",
06223               0, NULL, NULL, NULL},
06224        {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'Printable String' )",
06225               0, NULL, printableStringValidate, NULL},
06226        /* moved here because now depends on Directory String, IA5 String 
06227         * and Printable String */
06228        {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )",
06229               0, country_gen_syn, countryStringValidate, NULL},
06230        {"( 1.3.6.1.4.1.1466.115.121.1.45 DESC 'SubtreeSpecification' )",
06231 #define subtreeSpecificationValidate UTF8StringValidate /* FIXME */
06232               0, NULL, subtreeSpecificationValidate, NULL},
06233        {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'Supported Algorithm' "
06234               X_BINARY X_NOT_H_R ")",
06235               SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, berValidate, NULL},
06236        {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'Telephone Number' )",
06237               0, NULL, printableStringValidate, NULL},
06238        {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'Teletex Terminal Identifier' )",
06239               0, NULL, NULL, NULL},
06240        {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'Telex Number' )",
06241               0, NULL, printablesStringValidate, NULL},
06242 #ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
06243        {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTC Time' )",
06244               0, NULL, utcTimeValidate, NULL},
06245 #endif
06246        {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAP Syntax Description' )",
06247               0, NULL, NULL, NULL},
06248        {"( 1.3.6.1.4.1.1466.115.121.1.55 DESC 'Modify Rights' )",
06249               0, NULL, NULL, NULL},
06250        {"( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )",
06251               0, NULL, NULL, NULL},
06252        {"( 1.3.6.1.4.1.1466.115.121.1.57 DESC 'LDAP Schema Description' )",
06253               0, NULL, NULL, NULL},
06254        {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'Substring Assertion' )",
06255               0, NULL, NULL, NULL},
06256 
06257        /* RFC 2307 NIS Syntaxes */
06258        {"( 1.3.6.1.1.1.0.0  DESC 'RFC2307 NIS Netgroup Triple' )",
06259               0, NULL, nisNetgroupTripleValidate, NULL},
06260        {"( 1.3.6.1.1.1.0.1  DESC 'RFC2307 Boot Parameter' )",
06261               0, NULL, bootParameterValidate, NULL},
06262 
06263        /* draft-zeilenga-ldap-x509 */
06264        {"( 1.3.6.1.1.15.1 DESC 'Certificate Exact Assertion' )",
06265               SLAP_SYNTAX_HIDE, NULL,
06266               serialNumberAndIssuerValidate,
06267               serialNumberAndIssuerPretty},
06268        {"( 1.3.6.1.1.15.2 DESC 'Certificate Assertion' )",
06269               SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
06270        {"( 1.3.6.1.1.15.3 DESC 'Certificate Pair Exact Assertion' )",
06271               SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
06272        {"( 1.3.6.1.1.15.4 DESC 'Certificate Pair Assertion' )",
06273               SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
06274        {"( 1.3.6.1.1.15.5 DESC 'Certificate List Exact Assertion' )",
06275               SLAP_SYNTAX_HIDE, NULL,
06276               issuerAndThisUpdateValidate,
06277               issuerAndThisUpdatePretty},
06278        {"( 1.3.6.1.1.15.6 DESC 'Certificate List Assertion' )",
06279               SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
06280        {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )",
06281               SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
06282        {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )",
06283               SLAP_SYNTAX_HIDE, NULL,
06284               serialNumberAndIssuerSerialValidate,
06285               serialNumberAndIssuerSerialPretty},
06286        {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )",
06287               SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
06288 
06289 #ifdef SLAPD_AUTHPASSWD
06290        /* needs updating */
06291        {"( 1.3.6.1.4.1.4203.666.2.2 DESC 'OpenLDAP authPassword' )",
06292               SLAP_SYNTAX_HIDE, NULL, NULL, NULL},
06293 #endif
06294 
06295        {"( 1.3.6.1.1.16.1 DESC 'UUID' )",
06296               0, NULL, UUIDValidate, UUIDPretty},
06297 
06298        {"( 1.3.6.1.4.1.4203.666.11.2.1 DESC 'CSN' )",
06299               SLAP_SYNTAX_HIDE, NULL, csnValidate, csnPretty },
06300 
06301        {"( 1.3.6.1.4.1.4203.666.11.2.4 DESC 'CSN SID' )",
06302               SLAP_SYNTAX_HIDE, NULL, sidValidate, sidPretty },
06303 
06304        /* OpenLDAP Void Syntax */
06305        {"( 1.3.6.1.4.1.4203.1.1.1 DESC 'OpenLDAP void' )" ,
06306               SLAP_SYNTAX_HIDE, NULL, inValidate, NULL},
06307 
06308        /* FIXME: OID is unused, but not registered yet */
06309        {"( 1.3.6.1.4.1.4203.666.2.7 DESC 'OpenLDAP authz' )",
06310               SLAP_SYNTAX_HIDE, NULL, authzValidate, authzPretty},
06311 
06312        {NULL, 0, NULL, NULL, NULL}
06313 };
06314 
06315 char *csnSIDMatchSyntaxes[] = {
06316        "1.3.6.1.4.1.4203.666.11.2.1" /* csn */,
06317        NULL
06318 };
06319 char *certificateExactMatchSyntaxes[] = {
06320        "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
06321        NULL
06322 };
06323 char *certificateListExactMatchSyntaxes[] = {
06324        "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
06325        NULL
06326 };
06327 char *attributeCertificateExactMatchSyntaxes[] = {
06328        attributeCertificateSyntaxOID  /* attributeCertificate */,
06329        NULL
06330 };
06331 
06332 #ifdef LDAP_COMP_MATCH
06333 char *componentFilterMatchSyntaxes[] = {
06334        "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */,
06335        "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */,
06336        attributeCertificateSyntaxOID /* attributeCertificate */,
06337        NULL
06338 };
06339 #endif
06340 
06341 char *directoryStringSyntaxes[] = {
06342        "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */,
06343        NULL
06344 };
06345 char *integerFirstComponentMatchSyntaxes[] = {
06346        "1.3.6.1.4.1.1466.115.121.1.27" /* INTEGER */,
06347        "1.3.6.1.4.1.1466.115.121.1.17" /* dITStructureRuleDescription */,
06348        NULL
06349 };
06350 char *objectIdentifierFirstComponentMatchSyntaxes[] = {
06351        "1.3.6.1.4.1.1466.115.121.1.38" /* OID */,
06352        "1.3.6.1.4.1.1466.115.121.1.3"  /* attributeTypeDescription */,
06353        "1.3.6.1.4.1.1466.115.121.1.16" /* dITContentRuleDescription */,
06354        "1.3.6.1.4.1.1466.115.121.1.54" /* ldapSyntaxDescription */,
06355        "1.3.6.1.4.1.1466.115.121.1.30" /* matchingRuleDescription */,
06356        "1.3.6.1.4.1.1466.115.121.1.31" /* matchingRuleUseDescription */,
06357        "1.3.6.1.4.1.1466.115.121.1.35" /* nameFormDescription */,
06358        "1.3.6.1.4.1.1466.115.121.1.37" /* objectClassDescription */,
06359        NULL
06360 };
06361 
06362 /*
06363  * Other matching rules in X.520 that we do not use (yet):
06364  *
06365  * 2.5.13.25  uTCTimeMatch
06366  * 2.5.13.26  uTCTimeOrderingMatch
06367  * 2.5.13.31* directoryStringFirstComponentMatch
06368  * 2.5.13.32* wordMatch
06369  * 2.5.13.33* keywordMatch
06370  * 2.5.13.36+ certificatePairExactMatch
06371  * 2.5.13.37+ certificatePairMatch
06372  * 2.5.13.40+ algorithmIdentifierMatch
06373  * 2.5.13.41* storedPrefixMatch
06374  * 2.5.13.42  attributeCertificateMatch
06375  * 2.5.13.43  readerAndKeyIDMatch
06376  * 2.5.13.44  attributeIntegrityMatch
06377  *
06378  * (*) described in RFC 3698 (LDAP: Additional Matching Rules)
06379  * (+) described in draft-zeilenga-ldap-x509
06380  */
06381 static slap_mrule_defs_rec mrule_defs[] = {
06382        /*
06383         * EQUALITY matching rules must be listed after associated APPROX
06384         * matching rules.  So, we list all APPROX matching rules first.
06385         */
06386        {"( " directoryStringApproxMatchOID " NAME 'directoryStringApproxMatch' "
06387               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
06388               SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
06389               NULL, NULL, directoryStringApproxMatch,
06390               directoryStringApproxIndexer, directoryStringApproxFilter,
06391               NULL},
06392 
06393        {"( " IA5StringApproxMatchOID " NAME 'IA5StringApproxMatch' "
06394               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
06395               SLAP_MR_HIDE | SLAP_MR_EQUALITY_APPROX | SLAP_MR_EXT, NULL,
06396               NULL, NULL, IA5StringApproxMatch,
06397               IA5StringApproxIndexer, IA5StringApproxFilter,
06398               NULL},
06399 
06400        /*
06401         * Other matching rules
06402         */
06403        
06404        {"( 2.5.13.0 NAME 'objectIdentifierMatch' "
06405               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )",
06406               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06407               NULL, NULL, octetStringMatch,
06408               octetStringIndexer, octetStringFilter,
06409               NULL },
06410 
06411        {"( 2.5.13.1 NAME 'distinguishedNameMatch' "
06412               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
06413               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06414               NULL, dnNormalize, dnMatch,
06415               octetStringIndexer, octetStringFilter,
06416               NULL },
06417 
06418        {"( 1.3.6.1.4.1.4203.666.4.9 NAME 'dnSubtreeMatch' "
06419               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
06420               SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
06421               NULL, dnNormalize, dnRelativeMatch,
06422               NULL, NULL,
06423               NULL },
06424 
06425        {"( 1.3.6.1.4.1.4203.666.4.8 NAME 'dnOneLevelMatch' "
06426               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
06427               SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
06428               NULL, dnNormalize, dnRelativeMatch,
06429               NULL, NULL,
06430               NULL },
06431 
06432        {"( 1.3.6.1.4.1.4203.666.4.10 NAME 'dnSubordinateMatch' "
06433               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
06434               SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
06435               NULL, dnNormalize, dnRelativeMatch,
06436               NULL, NULL,
06437               NULL },
06438 
06439        {"( 1.3.6.1.4.1.4203.666.4.11 NAME 'dnSuperiorMatch' "
06440               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
06441               SLAP_MR_HIDE | SLAP_MR_EXT, NULL,
06442               NULL, dnNormalize, dnRelativeMatch,
06443               NULL, NULL,
06444               NULL },
06445 
06446        {"( 1.2.36.79672281.1.13.3 NAME 'rdnMatch' "
06447               "SYNTAX 1.2.36.79672281.1.5.0 )",
06448               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06449               NULL, rdnNormalize, rdnMatch,
06450               octetStringIndexer, octetStringFilter,
06451               NULL },
06452 
06453 #ifdef LDAP_COMP_MATCH
06454        {"( 1.2.36.79672281.1.13.2 NAME 'componentFilterMatch' "
06455               "SYNTAX 1.2.36.79672281.1.5.2 )", /* componentFilterMatch assertion */
06456               SLAP_MR_EXT|SLAP_MR_COMPONENT, componentFilterMatchSyntaxes,
06457               NULL, NULL , componentFilterMatch,
06458               octetStringIndexer, octetStringFilter,
06459               NULL },
06460 
06461         {"( 1.2.36.79672281.1.13.6 NAME 'allComponentsMatch' "
06462                 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
06463                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
06464                 NULL, NULL , allComponentsMatch,
06465                 octetStringIndexer, octetStringFilter,
06466                 NULL },
06467 
06468         {"( 1.2.36.79672281.1.13.7 NAME 'directoryComponentsMatch' "
06469                 "SYNTAX 1.2.36.79672281.1.5.3 )", /* allComponents */
06470                 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_COMPONENT, NULL,
06471                 NULL, NULL , directoryComponentsMatch,
06472                 octetStringIndexer, octetStringFilter,
06473                 NULL },
06474 #endif
06475 
06476        {"( 2.5.13.2 NAME 'caseIgnoreMatch' "
06477               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
06478               SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
06479               NULL, UTF8StringNormalize, octetStringMatch,
06480               octetStringIndexer, octetStringFilter,
06481               directoryStringApproxMatchOID },
06482 
06483        {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' "
06484               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
06485               SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
06486               NULL, UTF8StringNormalize, octetStringOrderingMatch,
06487               NULL, NULL,
06488               "caseIgnoreMatch" },
06489 
06490        {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' "
06491               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
06492               SLAP_MR_SUBSTR, directoryStringSyntaxes,
06493               NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
06494               octetStringSubstringsIndexer, octetStringSubstringsFilter,
06495               "caseIgnoreMatch" },
06496 
06497        {"( 2.5.13.5 NAME 'caseExactMatch' "
06498               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
06499               SLAP_MR_EQUALITY | SLAP_MR_EXT, directoryStringSyntaxes,
06500               NULL, UTF8StringNormalize, octetStringMatch,
06501               octetStringIndexer, octetStringFilter,
06502               directoryStringApproxMatchOID },
06503 
06504        {"( 2.5.13.6 NAME 'caseExactOrderingMatch' "
06505               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
06506               SLAP_MR_ORDERING | SLAP_MR_EXT, directoryStringSyntaxes,
06507               NULL, UTF8StringNormalize, octetStringOrderingMatch,
06508               NULL, NULL,
06509               "caseExactMatch" },
06510 
06511        {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' "
06512               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
06513               SLAP_MR_SUBSTR, directoryStringSyntaxes,
06514               NULL, UTF8StringNormalize, directoryStringSubstringsMatch,
06515               octetStringSubstringsIndexer, octetStringSubstringsFilter,
06516               "caseExactMatch" },
06517 
06518        {"( 2.5.13.8 NAME 'numericStringMatch' "
06519               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
06520               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06521               NULL, numericStringNormalize, octetStringMatch,
06522               octetStringIndexer, octetStringFilter,
06523               NULL },
06524 
06525        {"( 2.5.13.9 NAME 'numericStringOrderingMatch' "
06526               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )",
06527               SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
06528               NULL, numericStringNormalize, octetStringOrderingMatch,
06529               NULL, NULL,
06530               "numericStringMatch" },
06531 
06532        {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' "
06533               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
06534               SLAP_MR_SUBSTR, NULL,
06535               NULL, numericStringNormalize, octetStringSubstringsMatch,
06536               octetStringSubstringsIndexer, octetStringSubstringsFilter,
06537               "numericStringMatch" },
06538 
06539        {"( 2.5.13.11 NAME 'caseIgnoreListMatch' "
06540               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", /* Postal Address */
06541               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06542               NULL, postalAddressNormalize, octetStringMatch,
06543               octetStringIndexer, octetStringFilter,
06544               NULL },
06545 
06546        {"( 2.5.13.12 NAME 'caseIgnoreListSubstringsMatch' "
06547               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
06548               SLAP_MR_SUBSTR, NULL,
06549               NULL, NULL, NULL, NULL, NULL,
06550               "caseIgnoreListMatch" },
06551 
06552        {"( 2.5.13.13 NAME 'booleanMatch' "
06553               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 )",
06554               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06555               NULL, NULL, booleanMatch,
06556               octetStringIndexer, octetStringFilter,
06557               NULL },
06558 
06559        {"( 2.5.13.14 NAME 'integerMatch' "
06560               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
06561               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
06562               NULL, NULL, integerMatch,
06563               integerIndexer, integerFilter,
06564               NULL },
06565 
06566        {"( 2.5.13.15 NAME 'integerOrderingMatch' "
06567               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )",
06568               SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
06569               NULL, NULL, integerMatch,
06570               NULL, NULL,
06571               "integerMatch" },
06572 
06573        {"( 2.5.13.16 NAME 'bitStringMatch' "
06574               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )",
06575               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06576               NULL, NULL, octetStringMatch,
06577               octetStringIndexer, octetStringFilter,
06578               NULL },
06579 
06580        {"( 2.5.13.17 NAME 'octetStringMatch' "
06581               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
06582               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06583               NULL, NULL, octetStringMatch,
06584               octetStringIndexer, octetStringFilter,
06585               NULL },
06586 
06587        {"( 2.5.13.18 NAME 'octetStringOrderingMatch' "
06588               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
06589               SLAP_MR_ORDERING | SLAP_MR_EXT, NULL,
06590               NULL, NULL, octetStringOrderingMatch,
06591               NULL, NULL,
06592               "octetStringMatch" },
06593 
06594        {"( 2.5.13.19 NAME 'octetStringSubstringsMatch' "
06595               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )",
06596               SLAP_MR_SUBSTR, NULL,
06597               NULL, NULL, octetStringSubstringsMatch,
06598               octetStringSubstringsIndexer, octetStringSubstringsFilter,
06599               "octetStringMatch" },
06600 
06601        {"( 2.5.13.20 NAME 'telephoneNumberMatch' "
06602               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )",
06603               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06604               NULL,
06605               telephoneNumberNormalize, octetStringMatch,
06606               octetStringIndexer, octetStringFilter,
06607               NULL },
06608 
06609        {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' "
06610               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", /* Substring Assertion */
06611               SLAP_MR_SUBSTR, NULL,
06612               NULL, telephoneNumberNormalize, octetStringSubstringsMatch,
06613               octetStringSubstringsIndexer, octetStringSubstringsFilter,
06614               "telephoneNumberMatch" },
06615 
06616        {"( 2.5.13.22 NAME 'presentationAddressMatch' "
06617               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )",
06618               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06619               NULL, NULL, NULL, NULL, NULL, NULL },
06620 
06621        {"( 2.5.13.23 NAME 'uniqueMemberMatch' "
06622               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", /* Name And Optional UID */
06623               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06624               NULL, uniqueMemberNormalize, uniqueMemberMatch,
06625               uniqueMemberIndexer, uniqueMemberFilter,
06626               NULL },
06627 
06628        {"( 2.5.13.24 NAME 'protocolInformationMatch' "
06629               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )",
06630               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06631               NULL, NULL, NULL, NULL, NULL, NULL },
06632 
06633        {"( 2.5.13.27 NAME 'generalizedTimeMatch' "
06634               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
06635               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
06636               NULL, generalizedTimeNormalize, octetStringMatch,
06637               generalizedTimeIndexer, generalizedTimeFilter,
06638               NULL },
06639 
06640        {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' "
06641               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )",
06642               SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
06643               NULL, generalizedTimeNormalize, generalizedTimeOrderingMatch,
06644               NULL, NULL,
06645               "generalizedTimeMatch" },
06646 
06647        {"( 2.5.13.29 NAME 'integerFirstComponentMatch' "
06648               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
06649               SLAP_MR_EQUALITY | SLAP_MR_EXT,
06650                      integerFirstComponentMatchSyntaxes,
06651               NULL, firstComponentNormalize, integerMatch,
06652               octetStringIndexer, octetStringFilter,
06653               NULL },
06654 
06655        {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' "
06656               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", /* OID */
06657               SLAP_MR_EQUALITY | SLAP_MR_EXT,
06658                      objectIdentifierFirstComponentMatchSyntaxes,
06659               NULL, firstComponentNormalize, octetStringMatch,
06660               octetStringIndexer, octetStringFilter,
06661               NULL },
06662 
06663        {"( 2.5.13.34 NAME 'certificateExactMatch' "
06664               "SYNTAX 1.3.6.1.1.15.1 )", /* Certificate Exact Assertion */
06665               SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateExactMatchSyntaxes,
06666               NULL, certificateExactNormalize, octetStringMatch,
06667               octetStringIndexer, octetStringFilter,
06668               NULL },
06669 
06670        {"( 2.5.13.35 NAME 'certificateMatch' "
06671               "SYNTAX 1.3.6.1.1.15.2 )", /* Certificate Assertion */
06672               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06673               NULL, NULL, NULL, NULL, NULL,
06674               NULL },
06675 
06676        {"( 2.5.13.38 NAME 'certificateListExactMatch' "
06677               "SYNTAX 1.3.6.1.1.15.5 )", /* Certificate List Exact Assertion */
06678               SLAP_MR_EQUALITY | SLAP_MR_EXT, certificateListExactMatchSyntaxes,
06679               NULL, certificateListExactNormalize, octetStringMatch,
06680               octetStringIndexer, octetStringFilter,
06681               NULL },
06682 
06683        {"( 2.5.13.39 NAME 'certificateListMatch' "
06684               "SYNTAX 1.3.6.1.1.15.6 )", /* Certificate List Assertion */
06685               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06686               NULL, NULL, NULL, NULL, NULL,
06687               NULL },
06688 
06689        {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' "
06690               "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )",
06691               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes,
06692               NULL, attributeCertificateExactNormalize, octetStringMatch,
06693               octetStringIndexer, octetStringFilter,
06694               NULL },
06695 
06696        {"( 2.5.13.46 NAME 'attributeCertificateMatch' "
06697               "SYNTAX " attributeCertificateAssertionSyntaxOID " )",
06698               SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL,
06699               NULL, NULL, NULL, NULL, NULL,
06700               NULL },
06701 
06702        {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' "
06703               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
06704               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06705               NULL, IA5StringNormalize, octetStringMatch,
06706               octetStringIndexer, octetStringFilter,
06707               IA5StringApproxMatchOID },
06708 
06709        {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' "
06710               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
06711               SLAP_MR_EQUALITY | SLAP_MR_EXT, NULL,
06712               NULL, IA5StringNormalize, octetStringMatch,
06713               octetStringIndexer, octetStringFilter,
06714               IA5StringApproxMatchOID },
06715 
06716        {"( 1.3.6.1.4.1.1466.109.114.3 NAME 'caseIgnoreIA5SubstringsMatch' "
06717               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
06718               SLAP_MR_SUBSTR, NULL,
06719               NULL, IA5StringNormalize, directoryStringSubstringsMatch,
06720               octetStringSubstringsIndexer, octetStringSubstringsFilter,
06721               "caseIgnoreIA5Match" },
06722 
06723        {"( 1.3.6.1.4.1.4203.1.2.1 NAME 'caseExactIA5SubstringsMatch' "
06724               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
06725               SLAP_MR_SUBSTR, NULL,
06726               NULL, IA5StringNormalize, directoryStringSubstringsMatch,
06727               octetStringSubstringsIndexer, octetStringSubstringsFilter,
06728               "caseExactIA5Match" },
06729 
06730 #ifdef SLAPD_AUTHPASSWD
06731        /* needs updating */
06732        {"( 1.3.6.1.4.1.4203.666.4.1 NAME 'authPasswordMatch' "
06733               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", /* Octet String */
06734               SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
06735               NULL, NULL, authPasswordMatch,
06736               NULL, NULL,
06737               NULL},
06738 #endif
06739 
06740        {"( 1.2.840.113556.1.4.803 NAME 'integerBitAndMatch' "
06741               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
06742               SLAP_MR_EXT, NULL,
06743               NULL, NULL, integerBitAndMatch,
06744               NULL, NULL,
06745               "integerMatch" },
06746 
06747        {"( 1.2.840.113556.1.4.804 NAME 'integerBitOrMatch' "
06748               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", /* Integer */
06749               SLAP_MR_EXT, NULL,
06750               NULL, NULL, integerBitOrMatch,
06751               NULL, NULL,
06752               "integerMatch" },
06753 
06754        {"( 1.3.6.1.1.16.2 NAME 'UUIDMatch' "
06755               "SYNTAX 1.3.6.1.1.16.1 )",
06756               SLAP_MR_EQUALITY | SLAP_MR_MUTATION_NORMALIZER, NULL,
06757               NULL, UUIDNormalize, octetStringMatch,
06758               octetStringIndexer, octetStringFilter,
06759               NULL},
06760 
06761        {"( 1.3.6.1.1.16.3 NAME 'UUIDOrderingMatch' "
06762               "SYNTAX 1.3.6.1.1.16.1 )",
06763               SLAP_MR_ORDERING | SLAP_MR_MUTATION_NORMALIZER, NULL,
06764               NULL, UUIDNormalize, octetStringOrderingMatch,
06765               octetStringIndexer, octetStringFilter,
06766               "UUIDMatch"},
06767 
06768        {"( 1.3.6.1.4.1.4203.666.11.2.2 NAME 'CSNMatch' "
06769               "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
06770               SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_ORDERED_INDEX, NULL,
06771               NULL, csnNormalize, csnMatch,
06772               csnIndexer, csnFilter,
06773               NULL},
06774 
06775        {"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
06776               "SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
06777               SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_EXT | SLAP_MR_ORDERED_INDEX, NULL,
06778               NULL, csnNormalize, csnOrderingMatch,
06779               NULL, NULL,
06780               "CSNMatch" },
06781 
06782        {"( 1.3.6.1.4.1.4203.666.11.2.5 NAME 'CSNSIDMatch' "
06783               "SYNTAX 1.3.6.1.4.1.4203.666.11.2.4 )",
06784               SLAP_MR_HIDE | SLAP_MR_EQUALITY | SLAP_MR_EXT, csnSIDMatchSyntaxes,
06785               NULL, csnSidNormalize, octetStringMatch,
06786               octetStringIndexer, octetStringFilter,
06787               NULL },
06788 
06789        /* FIXME: OID is unused, but not registered yet */
06790        {"( 1.3.6.1.4.1.4203.666.4.12 NAME 'authzMatch' "
06791               "SYNTAX 1.3.6.1.4.1.4203.666.2.7 )", /* OpenLDAP authz */
06792               SLAP_MR_HIDE | SLAP_MR_EQUALITY, NULL,
06793               NULL, authzNormalize, authzMatch,
06794               NULL, NULL,
06795               NULL},
06796 
06797        {NULL, SLAP_MR_NONE, NULL,
06798               NULL, NULL, NULL, NULL, NULL,
06799               NULL }
06800 };
06801 
06802 int
06803 slap_schema_init( void )
06804 {
06805        int           res;
06806        int           i;
06807 
06808        /* we should only be called once (from main) */
06809        assert( schema_init_done == 0 );
06810 
06811        for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
06812               res = register_syntax( &syntax_defs[i] );
06813 
06814               if ( res ) {
06815                      fprintf( stderr, "slap_schema_init: Error registering syntax %s\n",
06816                              syntax_defs[i].sd_desc );
06817                      return LDAP_OTHER;
06818               }
06819        }
06820 
06821        for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
06822               if( mrule_defs[i].mrd_usage == SLAP_MR_NONE &&
06823                      mrule_defs[i].mrd_compat_syntaxes == NULL )
06824               {
06825                      fprintf( stderr,
06826                             "slap_schema_init: Ignoring unusable matching rule %s\n",
06827                              mrule_defs[i].mrd_desc );
06828                      continue;
06829               }
06830 
06831               res = register_matching_rule( &mrule_defs[i] );
06832 
06833               if ( res ) {
06834                      fprintf( stderr,
06835                             "slap_schema_init: Error registering matching rule %s\n",
06836                              mrule_defs[i].mrd_desc );
06837                      return LDAP_OTHER;
06838               }
06839        }
06840 
06841        res = slap_schema_load();
06842        schema_init_done = 1;
06843        return res;
06844 }
06845 
06846 void
06847 schema_destroy( void )
06848 {
06849        oidm_destroy();
06850        oc_destroy();
06851        at_destroy();
06852        mr_destroy();
06853        mru_destroy();
06854        syn_destroy();
06855 
06856        if( schema_init_done ) {
06857               ldap_pvt_thread_mutex_destroy( &ad_index_mutex );
06858               ldap_pvt_thread_mutex_destroy( &ad_undef_mutex );
06859               ldap_pvt_thread_mutex_destroy( &oc_undef_mutex );
06860        }
06861 }