+ *q = '\0';
+
+ normalized->bv_len = q - normalized->bv_val;
+
+ if( normalized->bv_len == 0 ) {
+ free( normalized->bv_val );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+oidValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ ber_len_t i;
+
+ if( val->bv_len == 0 ) {
+ /* disallow empty strings */
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ if( OID_LEADCHAR(val->bv_val[0]) ) {
+ int dot = 0;
+ for(i=1; i < val->bv_len; i++) {
+ if( OID_SEPARATOR( val->bv_val[i] ) ) {
+ if( dot++ ) return 1;
+ } else if ( OID_CHAR( val->bv_val[i] ) ) {
+ dot = 0;
+ } else {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ return !dot ? LDAP_SUCCESS : LDAP_INVALID_SYNTAX;
+
+ } else if( DESC_LEADCHAR(val->bv_val[0]) ) {
+ for(i=1; i < val->bv_len; i++) {
+ if( !DESC_CHAR(val->bv_val[i] ) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ return LDAP_SUCCESS;
+ }
+
+ return LDAP_INVALID_SYNTAX;
+}
+
+static int
+integerMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ char *v, *av;
+ int vsign = 1, avsign = 1; /* default sign = '+' */
+ struct berval *asserted;
+ ber_len_t vlen, avlen;
+ int match;
+
+ /* Skip leading space/sign/zeroes, and get the sign of the *value number */
+ v = value->bv_val;
+ vlen = value->bv_len;
+ if( mr == integerFirstComponentMatchingRule ) {
+ char *tmp = memchr( v, '$', vlen );
+ if( tmp )
+ vlen = tmp - v;
+ while( vlen && ASCII_SPACE( v[vlen-1] ))
+ vlen--;
+ }
+ for( ; vlen && ( *v < '1' || '9' < *v ); v++, vlen-- ) /* ANSI 2.2.1 */
+ if( *v == '-' )
+ vsign = -1;
+ if( vlen == 0 )
+ vsign = 0;
+
+ /* Do the same with the *assertedValue number */
+ asserted = (struct berval *) assertedValue;
+ av = asserted->bv_val;
+ avlen = asserted->bv_len;
+ for( ; avlen && ( *av < '1' || '9' < *av ); av++, avlen-- )
+ if( *av == '-' )
+ avsign = -1;
+ if( avlen == 0 )
+ avsign = 0;
+
+ match = vsign - avsign;
+ if( match == 0 ) {
+ match = (vlen != avlen
+ ? ( vlen < avlen ? -1 : 1 )
+ : memcmp( v, av, vlen ));
+ if( vsign < 0 )
+ match = -match;
+ }
+
+ *matchp = match;
+ return LDAP_SUCCESS;
+}
+
+static int
+integerValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ ber_len_t i;
+
+ if( !val->bv_len ) return LDAP_INVALID_SYNTAX;
+
+ if(( val->bv_val[0] == '+' ) || ( val->bv_val[0] == '-' )) {
+ if( val->bv_len < 2 ) return LDAP_INVALID_SYNTAX;
+ } else if( !ASCII_DIGIT(val->bv_val[0]) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ for( i=1; i < val->bv_len; i++ ) {
+ if( !ASCII_DIGIT(val->bv_val[i]) ) return LDAP_INVALID_SYNTAX;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+integerNormalize(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *normalized )
+{
+ char *p;
+ int negative=0;
+ ber_len_t len;
+
+
+ p = val->bv_val;
+ len = val->bv_len;
+
+ /* Ignore leading spaces */
+ while ( len && ( *p == ' ' )) {
+ p++;
+ len--;
+ }
+
+ /* save sign */
+ if( len ) {
+ negative = ( *p == '-' );
+ if(( *p == '-' ) || ( *p == '+' )) {
+ p++;
+ len--;
+ }
+ }
+
+ /* Ignore leading zeros */
+ while ( len && ( *p == '0' )) {
+ p++;
+ len--;
+ }
+
+ /* If there are no non-zero digits left, the number is zero, otherwise
+ allocate space for the number and copy it into the buffer */
+ if( len == 0 ) {
+ normalized->bv_val = ch_strdup("0");
+ normalized->bv_len = 1;
+ }
+ else {
+ normalized->bv_len = len+negative;
+ normalized->bv_val = ch_malloc( normalized->bv_len + 1 );
+ if( negative ) {
+ normalized->bv_val[0] = '-';
+ }
+ AC_MEMCPY( normalized->bv_val + negative, p, len );
+ normalized->bv_val[len+negative] = '\0';
+ }
+
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int integerIndexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ int i;
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* empty - just count them */
+ }
+
+ /* we should have at least one value at this point */
+ assert( i > 0 );
+
+ keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ struct berval norm;
+ integerNormalize( syntax, &values[i], &norm );
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ norm.bv_val, norm.bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[i], &digest );
+ ch_free( norm.bv_val );
+ }
+
+ keys[i].bv_val = NULL;
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int integerFilter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval norm;
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ integerNormalize( syntax, assertValue, &norm );
+
+ keys = ch_malloc( sizeof( struct berval ) * 2 );
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ norm.bv_val, norm.bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[0], &digest );
+ keys[1].bv_val = NULL;
+ ch_free( norm.bv_val );
+
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+
+static int
+countryStringValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ if( val->bv_len != 2 ) return LDAP_INVALID_SYNTAX;
+
+ if( !SLAP_PRINTABLE(val->bv_val[0]) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ if( !SLAP_PRINTABLE(val->bv_val[1]) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+printableStringValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ ber_len_t i;
+
+ if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
+
+ for(i=0; i < val->bv_len; i++) {
+ if( !SLAP_PRINTABLE(val->bv_val[i]) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+printablesStringValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ ber_len_t i, len;
+
+ if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
+
+ for(i=0,len=0; i < val->bv_len; i++) {
+ int c = val->bv_val[i];
+
+ if( c == '$' ) {
+ if( len == 0 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ len = 0;
+
+ } else if ( SLAP_PRINTABLE(c) ) {
+ len++;
+ } else {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ if( len == 0 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+IA5StringValidate(
+ Syntax *syntax,
+ struct berval *val )
+{
+ ber_len_t i;
+
+ if( val->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
+
+ for(i=0; i < val->bv_len; i++) {
+ if( !LDAP_ASCII(val->bv_val[i]) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+IA5StringNormalize(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *normalized )
+{
+ char *p, *q;
+
+ assert( val->bv_len );
+
+ p = val->bv_val;
+
+ /* Ignore initial whitespace */
+ while ( ASCII_SPACE( *p ) ) {
+ p++;
+ }
+
+ normalized->bv_val = ch_strdup( p );
+ p = q = normalized->bv_val;
+
+ while ( *p ) {
+ if ( ASCII_SPACE( *p ) ) {
+ *q++ = *p++;
+
+ /* Ignore the extra whitespace */
+ while ( ASCII_SPACE( *p ) ) {
+ p++;
+ }
+ } else {
+ *q++ = *p++;
+ }
+ }
+
+ assert( normalized->bv_val <= p );
+ assert( q <= p );
+
+ /*
+ * If the string ended in space, backup the pointer one
+ * position. One is enough because the above loop collapsed
+ * all whitespace to a single space.
+ */
+
+ if ( ASCII_SPACE( q[-1] ) ) {
+ --q;
+ }
+
+ /* null terminate */
+ *q = '\0';
+
+ normalized->bv_len = q - normalized->bv_val;
+
+ if( normalized->bv_len == 0 ) {
+ normalized->bv_val = ch_realloc( normalized->bv_val, 2 );
+ normalized->bv_val[0] = ' ';
+ normalized->bv_val[1] = '\0';
+ normalized->bv_len = 1;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+caseExactIA5Match(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
+
+ if( match == 0 ) {
+ match = strncmp( value->bv_val,
+ ((struct berval *) assertedValue)->bv_val,
+ value->bv_len );
+ }
+
+ *matchp = match;
+ return LDAP_SUCCESS;
+}
+
+static int
+caseExactIA5SubstringsMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ int match = 0;
+ SubstringsAssertion *sub = assertedValue;
+ struct berval left = *value;
+ int i;
+ ber_len_t inlen=0;
+
+ /* Add up asserted input length */
+ if( sub->sa_initial.bv_val ) {
+ inlen += sub->sa_initial.bv_len;
+ }
+ if( sub->sa_any ) {
+ for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
+ inlen += sub->sa_any[i].bv_len;
+ }
+ }
+ if( sub->sa_final.bv_val ) {
+ inlen += sub->sa_final.bv_len;
+ }
+
+ if( sub->sa_initial.bv_val ) {
+ if( inlen > left.bv_len ) {
+ match = 1;
+ goto done;
+ }
+
+ match = strncmp( sub->sa_initial.bv_val, left.bv_val,
+ sub->sa_initial.bv_len );
+
+ if( match != 0 ) {
+ goto done;
+ }
+
+ left.bv_val += sub->sa_initial.bv_len;
+ left.bv_len -= sub->sa_initial.bv_len;
+ inlen -= sub->sa_initial.bv_len;
+ }
+
+ if( sub->sa_final.bv_val ) {
+ if( inlen > left.bv_len ) {
+ match = 1;
+ goto done;
+ }
+
+ match = strncmp( sub->sa_final.bv_val,
+ &left.bv_val[left.bv_len - sub->sa_final.bv_len],
+ sub->sa_final.bv_len );
+
+ if( match != 0 ) {
+ goto done;
+ }
+
+ left.bv_len -= sub->sa_final.bv_len;
+ inlen -= sub->sa_final.bv_len;
+ }
+
+ if( sub->sa_any ) {
+ for(i=0; sub->sa_any[i].bv_val; i++) {
+ ber_len_t idx;
+ char *p;
+
+retry:
+ if( inlen > left.bv_len ) {
+ /* not enough length */
+ match = 1;
+ goto done;
+ }
+
+ if( sub->sa_any[i].bv_len == 0 ) {
+ continue;
+ }
+
+ p = strchr( left.bv_val, *sub->sa_any[i].bv_val );
+
+ if( p == NULL ) {
+ match = 1;
+ goto done;
+ }
+
+ idx = p - left.bv_val;
+
+ if( idx >= left.bv_len ) {
+ /* this shouldn't happen */
+ return LDAP_OTHER;
+ }
+
+ left.bv_val = p;
+ left.bv_len -= idx;
+
+ if( sub->sa_any[i].bv_len > left.bv_len ) {
+ /* not enough left */
+ match = 1;
+ goto done;
+ }
+
+ match = strncmp( left.bv_val,
+ sub->sa_any[i].bv_val,
+ sub->sa_any[i].bv_len );
+
+ if( match != 0 ) {
+ left.bv_val++;
+ left.bv_len--;
+ goto retry;
+ }
+
+ left.bv_val += sub->sa_any[i].bv_len;
+ left.bv_len -= sub->sa_any[i].bv_len;
+ inlen -= sub->sa_any[i].bv_len;
+ }
+ }
+
+done:
+ *matchp = match;
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseExactIA5Indexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ int i;
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* empty - just count them */
+ }
+
+ /* we should have at least one value at this point */
+ assert( i > 0 );
+
+ keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ struct berval *value = &values[i];
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value->bv_val, value->bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[i], &digest );
+ }
+
+ keys[i].bv_val = NULL;
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseExactIA5Filter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval *value;
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ value = (struct berval *) assertValue;
+
+ keys = ch_malloc( sizeof( struct berval ) * 2 );
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value->bv_val, value->bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[0], &digest );
+ keys[1].bv_val = NULL;
+
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+/* Substrings Index generation function */
+static int caseExactIA5SubstringsIndexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ ber_len_t i, nkeys;
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ /* we should have at least one value at this point */
+ assert( values != NULL && values[0].bv_val != NULL );
+
+ nkeys=0;
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* count number of indices to generate */
+ if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
+ continue;
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+ if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+ ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+ } else {
+ nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_ANY ) {
+ if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+ if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+ ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+ } else {
+ nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+ }
+ }
+ }
+
+ if( nkeys == 0 ) {
+ /* no keys to generate */
+ *keysp = NULL;
+ return LDAP_SUCCESS;
+ }
+
+ keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ nkeys=0;
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ ber_len_t j,max;
+ struct berval *value;
+
+ value = &values[i];
+ if( value->bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
+
+ if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
+ ( value->bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
+ {
+ char pre = SLAP_INDEX_SUBSTR_PREFIX;
+ max = value->bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
+
+ for( j=0; j<max; j++ ) {
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value->bv_val[j],
+ SLAP_INDEX_SUBSTR_MAXLEN );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+ }
+
+ max = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+ ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+ for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
+ char pre;
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+ pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value->bv_val, j );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+ pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value->bv_val[value->bv_len-j], j );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ }
+ }
+
+ if( nkeys > 0 ) {
+ keys[nkeys].bv_val = NULL;
+ *keysp = keys;
+ } else {
+ ch_free( keys );
+ *keysp = NULL;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int caseExactIA5SubstringsFilter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ SubstringsAssertion *sa = assertValue;
+ char pre;
+ ber_len_t nkeys = 0;
+ size_t slen, mlen, klen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval *value;
+ struct berval digest;
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
+ sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ nkeys++;
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
+ ber_len_t i;
+ for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+ if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ /* don't bother accounting for stepping */
+ nkeys += sa->sa_any[i].bv_len -
+ ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+ }
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
+ sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ nkeys++;
+ }
+
+ if( nkeys == 0 ) {
+ *keysp = NULL;
+ return LDAP_SUCCESS;
+ }
+
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+ nkeys = 0;
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL && sa->sa_initial.bv_val != NULL &&
+ sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+ value = &sa->sa_initial;
+
+ klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+ ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value->bv_val, klen );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_ANY && sa->sa_any != NULL ) {
+ ber_len_t i, j;
+ pre = SLAP_INDEX_SUBSTR_PREFIX;
+ klen = SLAP_INDEX_SUBSTR_MAXLEN;
+
+ for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+ if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
+ continue;
+ }
+
+ value = &sa->sa_any[i];
+
+ for(j=0;
+ j <= value->bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
+ j += SLAP_INDEX_SUBSTR_STEP )
+ {
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value->bv_val[j], klen );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL && sa->sa_final.bv_val != NULL &&
+ sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+ value = &sa->sa_final;
+
+ klen = SLAP_INDEX_SUBSTR_MAXLEN < value->bv_len
+ ? SLAP_INDEX_SUBSTR_MAXLEN : value->bv_len;
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value->bv_val[value->bv_len-klen], klen );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ if( nkeys > 0 ) {
+ keys[nkeys].bv_val = NULL;
+ *keysp = keys;
+ } else {
+ ch_free( keys );
+ *keysp = NULL;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+caseIgnoreIA5Match(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ int match = value->bv_len - ((struct berval *) assertedValue)->bv_len;
+
+ if( match == 0 && value->bv_len ) {
+ match = strncasecmp( value->bv_val,
+ ((struct berval *) assertedValue)->bv_val,
+ value->bv_len );
+ }
+
+ *matchp = match;
+ return LDAP_SUCCESS;
+}
+
+static int
+caseIgnoreIA5SubstringsMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ int match = 0;
+ SubstringsAssertion *sub = assertedValue;
+ struct berval left = *value;
+ int i;
+ ber_len_t inlen=0;
+
+ /* Add up asserted input length */
+ if( sub->sa_initial.bv_val ) {
+ inlen += sub->sa_initial.bv_len;
+ }
+ if( sub->sa_any ) {
+ for(i=0; sub->sa_any[i].bv_val != NULL; i++) {
+ inlen += sub->sa_any[i].bv_len;
+ }
+ }
+ if( sub->sa_final.bv_val ) {
+ inlen += sub->sa_final.bv_len;
+ }
+
+ if( sub->sa_initial.bv_val ) {
+ if( inlen > left.bv_len ) {
+ match = 1;
+ goto done;
+ }
+
+ match = strncasecmp( sub->sa_initial.bv_val, left.bv_val,
+ sub->sa_initial.bv_len );
+
+ if( match != 0 ) {
+ goto done;
+ }
+
+ left.bv_val += sub->sa_initial.bv_len;
+ left.bv_len -= sub->sa_initial.bv_len;
+ inlen -= sub->sa_initial.bv_len;
+ }
+
+ if( sub->sa_final.bv_val ) {
+ if( inlen > left.bv_len ) {
+ match = 1;
+ goto done;
+ }
+
+ match = strncasecmp( sub->sa_final.bv_val,
+ &left.bv_val[left.bv_len - sub->sa_final.bv_len],
+ sub->sa_final.bv_len );
+
+ if( match != 0 ) {
+ goto done;
+ }
+
+ left.bv_len -= sub->sa_final.bv_len;
+ inlen -= sub->sa_final.bv_len;
+ }
+
+ if( sub->sa_any ) {
+ for(i=0; sub->sa_any[i].bv_val; i++) {
+ ber_len_t idx;
+ char *p;
+
+retry:
+ if( inlen > left.bv_len ) {
+ /* not enough length */
+ match = 1;
+ goto done;
+ }
+
+ if( sub->sa_any[i].bv_len == 0 ) {
+ continue;
+ }
+
+ p = bvcasechr( &left, *sub->sa_any[i].bv_val, &idx );
+
+ if( p == NULL ) {
+ match = 1;
+ goto done;
+ }
+
+ assert( idx < left.bv_len );
+ if( idx >= left.bv_len ) {
+ /* this shouldn't happen */
+ return LDAP_OTHER;
+ }
+
+ left.bv_val = p;
+ left.bv_len -= idx;
+
+ if( sub->sa_any[i].bv_len > left.bv_len ) {
+ /* not enough left */
+ match = 1;
+ goto done;
+ }
+
+ match = strncasecmp( left.bv_val,
+ sub->sa_any[i].bv_val,
+ sub->sa_any[i].bv_len );
+
+ if( match != 0 ) {
+ left.bv_val++;
+ left.bv_len--;
+
+ goto retry;
+ }
+
+ left.bv_val += sub->sa_any[i].bv_len;
+ left.bv_len -= sub->sa_any[i].bv_len;
+ inlen -= sub->sa_any[i].bv_len;
+ }
+ }
+
+done:
+ *matchp = match;
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+static int caseIgnoreIA5Indexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ int i;
+ int rc = LDAP_SUCCESS;
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ /* we should have at least one value at this point */
+ assert( values != NULL && values[0].bv_val != NULL );
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* just count them */
+ }
+
+ keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ struct berval value;
+
+ if( mr->smr_normalize ) {
+ rc = (mr->smr_normalize)( use, syntax, mr, &values[i], &value );
+ if( rc != LDAP_SUCCESS ) {
+ break;
+ }
+ } else if ( mr->smr_syntax->ssyn_normalize ) {
+ rc = (mr->smr_syntax->ssyn_normalize)( syntax, &values[i], &value );
+ if( rc != LDAP_SUCCESS ) {
+ break;
+ }
+ } else {
+ ber_dupbv( &value, &values[i] );
+ }
+
+ ldap_pvt_str2lower( value.bv_val );
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value.bv_val, value.bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ free( value.bv_val );
+
+ ber_dupbv( &keys[i], &digest );
+ }
+
+ keys[i].bv_val = NULL;
+ if( rc != LDAP_SUCCESS ) {
+ ber_bvarray_free( keys );
+ keys = NULL;
+ }
+ *keysp = keys;
+ return rc;
+}
+
+/* Index generation function */
+static int caseIgnoreIA5Filter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval value;
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ ber_dupbv( &value, (struct berval *) assertValue );
+ ldap_pvt_str2lower( value.bv_val );
+
+ keys = ch_malloc( sizeof( struct berval ) * 2 );
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value.bv_val, value.bv_len );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[0], &digest );
+ keys[1].bv_val = NULL;
+
+ free( value.bv_val );
+
+ *keysp = keys;
+
+ return LDAP_SUCCESS;
+}
+
+/* Substrings Index generation function */
+static int caseIgnoreIA5SubstringsIndexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ ber_len_t i, nkeys;
+ size_t slen, mlen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval digest;
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ /* we should have at least one value at this point */
+ assert( values != NULL && values[0].bv_val != NULL );
+
+ nkeys=0;
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* count number of indices to generate */
+ if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) {
+ continue;
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+ if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+ ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+ } else {
+ nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_ANY ) {
+ if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+ }
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+ if( values[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ nkeys += SLAP_INDEX_SUBSTR_MAXLEN -
+ ( SLAP_INDEX_SUBSTR_MINLEN - 1);
+ } else {
+ nkeys += values[i].bv_len - ( SLAP_INDEX_SUBSTR_MINLEN - 1 );
+ }
+ }
+ }
+
+ if( nkeys == 0 ) {
+ /* no keys to generate */
+ *keysp = NULL;
+ return LDAP_SUCCESS;
+ }
+
+ keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ nkeys=0;
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ int j,max;
+ struct berval value;
+
+ if( values[i].bv_len < SLAP_INDEX_SUBSTR_MINLEN ) continue;
+
+ ber_dupbv( &value, &values[i] );
+ ldap_pvt_str2lower( value.bv_val );
+
+ if( ( flags & SLAP_INDEX_SUBSTR_ANY ) &&
+ ( value.bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) )
+ {
+ char pre = SLAP_INDEX_SUBSTR_PREFIX;
+ max = value.bv_len - ( SLAP_INDEX_SUBSTR_MAXLEN - 1);
+
+ for( j=0; j<max; j++ ) {
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value.bv_val[j],
+ SLAP_INDEX_SUBSTR_MAXLEN );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+ }
+
+ max = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len
+ ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len;
+
+ for( j=SLAP_INDEX_SUBSTR_MINLEN; j<=max; j++ ) {
+ char pre;
+
+ if( flags & SLAP_INDEX_SUBSTR_INITIAL ) {
+ pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value.bv_val, j );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ if( flags & SLAP_INDEX_SUBSTR_FINAL ) {
+ pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value.bv_val[value.bv_len-j], j );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ }
+
+ free( value.bv_val );
+ }
+
+ if( nkeys > 0 ) {
+ keys[nkeys].bv_val = NULL;
+ *keysp = keys;
+ } else {
+ ch_free( keys );
+ *keysp = NULL;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int caseIgnoreIA5SubstringsFilter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ SubstringsAssertion *sa = assertValue;
+ char pre;
+ ber_len_t nkeys = 0;
+ size_t slen, mlen, klen;
+ BerVarray keys;
+ HASH_CONTEXT HASHcontext;
+ unsigned char HASHdigest[HASH_BYTES];
+ struct berval value;
+ struct berval digest;
+
+ if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial.bv_val != NULL &&
+ sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ nkeys++;
+ }
+
+ if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
+ ber_len_t i;
+ for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+ if( sa->sa_any[i].bv_len >= SLAP_INDEX_SUBSTR_MAXLEN ) {
+ /* don't bother accounting for stepping */
+ nkeys += sa->sa_any[i].bv_len -
+ ( SLAP_INDEX_SUBSTR_MAXLEN - 1 );
+ }
+ }
+ }
+
+ if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final.bv_val != NULL &&
+ sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ nkeys++;
+ }
+
+ if( nkeys == 0 ) {
+ *keysp = NULL;
+ return LDAP_SUCCESS;
+ }
+
+ digest.bv_val = HASHdigest;
+ digest.bv_len = sizeof(HASHdigest);
+
+ slen = syntax->ssyn_oidlen;
+ mlen = mr->smr_oidlen;
+
+ keys = ch_malloc( sizeof( struct berval ) * (nkeys+1) );
+ nkeys = 0;
+
+ if((flags & SLAP_INDEX_SUBSTR_INITIAL) && sa->sa_initial.bv_val != NULL &&
+ sa->sa_initial.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ pre = SLAP_INDEX_SUBSTR_INITIAL_PREFIX;
+ ber_dupbv( &value, &sa->sa_initial );
+ ldap_pvt_str2lower( value.bv_val );
+
+ klen = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len
+ ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len;
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ value.bv_val, klen );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ free( value.bv_val );
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ if((flags & SLAP_INDEX_SUBSTR_ANY) && sa->sa_any != NULL ) {
+ ber_len_t i, j;
+ pre = SLAP_INDEX_SUBSTR_PREFIX;
+ klen = SLAP_INDEX_SUBSTR_MAXLEN;
+
+ for( i=0; sa->sa_any[i].bv_val != NULL; i++ ) {
+ if( sa->sa_any[i].bv_len < SLAP_INDEX_SUBSTR_MAXLEN ) {
+ continue;
+ }
+
+ ber_dupbv( &value, &sa->sa_any[i] );
+ ldap_pvt_str2lower( value.bv_val );
+
+ for(j=0;
+ j <= value.bv_len - SLAP_INDEX_SUBSTR_MAXLEN;
+ j += SLAP_INDEX_SUBSTR_STEP )
+ {
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value.bv_val[j], klen );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ free( value.bv_val );
+ }
+ }
+
+ if((flags & SLAP_INDEX_SUBSTR_FINAL) && sa->sa_final.bv_val != NULL &&
+ sa->sa_final.bv_len >= SLAP_INDEX_SUBSTR_MINLEN )
+ {
+ pre = SLAP_INDEX_SUBSTR_FINAL_PREFIX;
+ ber_dupbv( &value, &sa->sa_final );
+ ldap_pvt_str2lower( value.bv_val );
+
+ klen = SLAP_INDEX_SUBSTR_MAXLEN < value.bv_len
+ ? SLAP_INDEX_SUBSTR_MAXLEN : value.bv_len;
+
+ HASH_Init( &HASHcontext );
+ if( prefix != NULL && prefix->bv_len > 0 ) {
+ HASH_Update( &HASHcontext,
+ prefix->bv_val, prefix->bv_len );
+ }
+ HASH_Update( &HASHcontext,
+ &pre, sizeof( pre ) );
+ HASH_Update( &HASHcontext,
+ syntax->ssyn_oid, slen );
+ HASH_Update( &HASHcontext,
+ mr->smr_oid, mlen );
+ HASH_Update( &HASHcontext,
+ &value.bv_val[value.bv_len-klen], klen );
+ HASH_Final( HASHdigest, &HASHcontext );
+
+ free( value.bv_val );
+ ber_dupbv( &keys[nkeys++], &digest );
+ }
+
+ if( nkeys > 0 ) {
+ keys[nkeys].bv_val = NULL;
+ *keysp = keys;
+ } else {
+ ch_free( keys );
+ *keysp = NULL;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+numericStringValidate(
+ Syntax *syntax,
+ struct berval *in )
+{
+ ber_len_t i;
+
+ if( in->bv_len == 0 ) return LDAP_INVALID_SYNTAX;
+
+ for(i=0; i < in->bv_len; i++) {
+ if( !SLAP_NUMERIC(in->bv_val[i]) ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+numericStringNormalize(
+ Syntax *syntax,
+ struct berval *val,
+ struct berval *normalized )
+{
+ /* removal all spaces */
+ char *p, *q;
+
+ assert( val->bv_len );
+
+ normalized->bv_val = ch_malloc( val->bv_len + 1 );
+
+ p = val->bv_val;
+ q = normalized->bv_val;
+
+ while ( *p ) {
+ if ( ASCII_SPACE( *p ) ) {
+ /* Ignore whitespace */
+ p++;
+ } else {
+ *q++ = *p++;
+ }
+ }
+
+ /* we should have copied no more then is in val */
+ assert( (q - normalized->bv_val) <= (p - val->bv_val) );
+
+ /* null terminate */
+ *q = '\0';
+
+ normalized->bv_len = q - normalized->bv_val;
+
+ if( normalized->bv_len == 0 ) {
+ normalized->bv_val = ch_realloc( normalized->bv_val, 2 );
+ normalized->bv_val[0] = ' ';
+ normalized->bv_val[1] = '\0';
+ normalized->bv_len = 1;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+objectIdentifierFirstComponentMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ int rc = LDAP_SUCCESS;
+ int match;
+ struct berval *asserted = (struct berval *) assertedValue;
+ ber_len_t i;
+ struct berval oid;
+
+ if( value->bv_len == 0 || value->bv_val[0] != '(' /*')'*/ ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* trim leading white space */
+ for( i=1; ASCII_SPACE(value->bv_val[i]) && i < value->bv_len; i++ ) {
+ /* empty */
+ }
+
+ /* grab next word */
+ oid.bv_val = &value->bv_val[i];
+ oid.bv_len = value->bv_len - i;
+ for( i=1; ASCII_SPACE(value->bv_val[i]) && i < oid.bv_len; i++ ) {
+ /* empty */
+ }
+ oid.bv_len = i;
+
+ /* insert attributeTypes, objectclass check here */
+ if( OID_LEADCHAR(asserted->bv_val[0]) ) {
+ rc = objectIdentifierMatch( &match, flags, syntax, mr, &oid, asserted );
+
+ } else {
+ if ( !strcmp( syntax->ssyn_oid, SLAP_SYNTAX_MATCHINGRULES_OID ) ) {
+ MatchingRule *asserted_mr = mr_bvfind( asserted );
+ MatchingRule *stored_mr = mr_bvfind( &oid );
+
+ if( asserted_mr == NULL ) {
+ rc = SLAPD_COMPARE_UNDEFINED;
+ } else {
+ match = asserted_mr != stored_mr;
+ }
+
+ } else if ( !strcmp( syntax->ssyn_oid,
+ SLAP_SYNTAX_ATTRIBUTETYPES_OID ) )
+ {
+ AttributeType *asserted_at = at_bvfind( asserted );
+ AttributeType *stored_at = at_bvfind( &oid );
+
+ if( asserted_at == NULL ) {
+ rc = SLAPD_COMPARE_UNDEFINED;
+ } else {
+ match = asserted_at != stored_at;
+ }
+
+ } else if ( !strcmp( syntax->ssyn_oid,
+ SLAP_SYNTAX_OBJECTCLASSES_OID ) )
+ {
+ ObjectClass *asserted_oc = oc_bvfind( asserted );
+ ObjectClass *stored_oc = oc_bvfind( &oid );
+
+ if( asserted_oc == NULL ) {
+ rc = SLAPD_COMPARE_UNDEFINED;
+ } else {
+ match = asserted_oc != stored_oc;
+ }
+ }
+ }
+
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ENTRY,
+ "objectIdentifierFirstComponentMatch: %d\n %s\n %s\n",
+ match, value->bv_val, asserted->bv_val );
+#else
+ Debug( LDAP_DEBUG_ARGS, "objectIdentifierFirstComponentMatch "
+ "%d\n\t\"%s\"\n\t\"%s\"\n",
+ match, value->bv_val, asserted->bv_val );
+#endif
+
+
+ if( rc == LDAP_SUCCESS ) *matchp = match;
+ return rc;
+}
+
+static int
+integerBitAndMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ long lValue, lAssertedValue;
+
+ /* safe to assume integers are NUL terminated? */
+ lValue = strtoul(value->bv_val, NULL, 10);
+ if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE )
+ return LDAP_CONSTRAINT_VIOLATION;
+
+ lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
+ if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX) && errno == ERANGE )
+ return LDAP_CONSTRAINT_VIOLATION;
+
+ *matchp = (lValue & lAssertedValue);
+ return LDAP_SUCCESS;
+}
+
+static int
+integerBitOrMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ long lValue, lAssertedValue;
+
+ /* safe to assume integers are NUL terminated? */
+ lValue = strtoul(value->bv_val, NULL, 10);
+ if(( lValue == LONG_MIN || lValue == LONG_MAX) && errno == ERANGE )
+ return LDAP_CONSTRAINT_VIOLATION;
+
+ lAssertedValue = strtol(((struct berval *)assertedValue)->bv_val, NULL, 10);
+ if(( lAssertedValue == LONG_MIN || lAssertedValue == LONG_MAX) && errno == ERANGE )
+ return LDAP_CONSTRAINT_VIOLATION;
+
+ *matchp = (lValue | lAssertedValue);
+ return LDAP_SUCCESS;
+}
+
+#ifdef HAVE_TLS
+#include <openssl/x509.h>
+#include <openssl/err.h>
+char digit[] = "0123456789";
+
+/*
+ * Next function returns a string representation of a ASN1_INTEGER.
+ * It works for unlimited lengths.
+ */
+
+static struct berval *
+asn1_integer2str(ASN1_INTEGER *a, struct berval *bv)
+{
+ char buf[256];
+ char *p;
+
+ /* We work backwards, make it fill from the end of buf */
+ p = buf + sizeof(buf) - 1;
+ *p = '\0';
+
+ if ( a == NULL || a->length == 0 ) {
+ *--p = '0';
+ } else {
+ int i;
+ int n = a->length;
+ int base = 0;
+ unsigned int *copy;
+
+ /* We want to preserve the original */
+ copy = ch_malloc(n*sizeof(unsigned int));
+ for (i = 0; i<n; i++) {
+ copy[i] = a->data[i];
+ }
+
+ /*
+ * base indicates the index of the most significant
+ * byte that might be nonzero. When it goes off the
+ * end, we now there is nothing left to do.
+ */
+ while (base < n) {
+ unsigned int carry;
+
+ carry = 0;
+ for (i = base; i<n; i++ ) {
+ copy[i] += carry*256;
+ carry = copy[i] % 10;
+ copy[i] /= 10;
+ }
+ if (p <= buf+1) {
+ /*
+ * Way too large, we need to leave
+ * room for sign if negative
+ */
+ free(copy);
+ return NULL;
+ }
+ *--p = digit[carry];
+ if (copy[base] == 0)
+ base++;
+ }
+ free(copy);
+ }
+
+ if ( a->type == V_ASN1_NEG_INTEGER ) {
+ *--p = '-';
+ }
+
+ return ber_str2bv( p, 0, 1, bv );
+}
+
+/*
+ * Given a certificate in DER format, extract the corresponding
+ * assertion value for certificateExactMatch
+ */
+static int
+certificateExactConvert(
+ struct berval * in,
+ struct berval * out )
+{
+ X509 *xcert;
+ unsigned char *p = in->bv_val;
+ struct berval serial;
+ struct berval issuer_dn;
+
+ xcert = d2i_X509(NULL, &p, in->bv_len);
+ if ( !xcert ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ENTRY,
+ "certificateExactConvert: error parsing cert: %s\n",
+ ERR_error_string(ERR_get_error(),NULL), 0, 0 );
+#else
+ Debug( LDAP_DEBUG_ARGS, "certificateExactConvert: "
+ "error parsing cert: %s\n",
+ ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
+#endif
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ if ( !asn1_integer2str(xcert->cert_info->serialNumber, &serial) ) {
+ X509_free(xcert);
+ return LDAP_INVALID_SYNTAX;
+ }
+ if ( dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn ) != LDAP_SUCCESS ) {
+ X509_free(xcert);
+ ber_memfree(serial.bv_val);
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ X509_free(xcert);
+
+ out->bv_len = serial.bv_len + issuer_dn.bv_len + sizeof(" $ ");
+ out->bv_val = ch_malloc(out->bv_len);
+ p = out->bv_val;
+ AC_MEMCPY(p, serial.bv_val, serial.bv_len);
+ p += serial.bv_len;
+ AC_MEMCPY(p, " $ ", sizeof(" $ ")-1);
+ p += 3;
+ AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
+ p += issuer_dn.bv_len;
+ *p++ = '\0';
+
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ARGS,
+ "certificateExactConvert: \n %s\n", out->bv_val, 0, 0 );
+#else
+ Debug( LDAP_DEBUG_ARGS, "certificateExactConvert "
+ "\n\t\"%s\"\n",
+ out->bv_val, NULL, NULL );
+#endif
+
+ ber_memfree(serial.bv_val);
+ ber_memfree(issuer_dn.bv_val);
+
+ return LDAP_SUCCESS;
+}
+
+static int
+serial_and_issuer_parse(
+ struct berval *assertion,
+ struct berval *serial,
+ struct berval *issuer_dn
+)
+{
+ char *begin;
+ char *end;
+ char *p;
+ struct berval bv;
+
+ begin = assertion->bv_val;
+ end = assertion->bv_val+assertion->bv_len-1;
+ for (p=begin; p<=end && *p != '$'; p++)
+ ;
+ if ( p > end )
+ return LDAP_INVALID_SYNTAX;
+
+ /* p now points at the $ sign, now use begin and end to delimit the
+ serial number */
+ while (ASCII_SPACE(*begin))
+ begin++;
+ end = p-1;
+ while (ASCII_SPACE(*end))
+ end--;
+
+ bv.bv_len = end-begin+1;
+ bv.bv_val = begin;
+ ber_dupbv(serial, &bv);
+
+ /* now extract the issuer, remember p was at the dollar sign */
+ if ( issuer_dn ) {
+ begin = p+1;
+ end = assertion->bv_val+assertion->bv_len-1;
+ while (ASCII_SPACE(*begin))
+ begin++;
+ /* should we trim spaces at the end too? is it safe always? */
+
+ bv.bv_len = end-begin+1;
+ bv.bv_val = begin;
+ dnNormalize2( NULL, &bv, issuer_dn );
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+certificateExactMatch(
+ int *matchp,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *value,
+ void *assertedValue )
+{
+ X509 *xcert;
+ unsigned char *p = value->bv_val;
+ struct berval serial;
+ struct berval issuer_dn;
+ struct berval asserted_serial;
+ struct berval asserted_issuer_dn;
+ int ret;
+
+ xcert = d2i_X509(NULL, &p, value->bv_len);
+ if ( !xcert ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ENTRY,
+ "certificateExactMatch: error parsing cert: %s\n",
+ ERR_error_string(ERR_get_error(),NULL), 0, 0 );
+#else
+ Debug( LDAP_DEBUG_ARGS, "certificateExactMatch: "
+ "error parsing cert: %s\n",
+ ERR_error_string(ERR_get_error(),NULL), NULL, NULL );
+#endif
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ asn1_integer2str(xcert->cert_info->serialNumber, &serial);
+ dnX509normalize(X509_get_issuer_name(xcert), &issuer_dn);
+
+ X509_free(xcert);
+
+ serial_and_issuer_parse(assertedValue,
+ &asserted_serial,
+ &asserted_issuer_dn);
+
+ ret = integerMatch(
+ matchp,
+ flags,
+ slap_schema.si_syn_integer,
+ slap_schema.si_mr_integerMatch,
+ &serial,
+ &asserted_serial);
+ if ( ret == LDAP_SUCCESS ) {
+ if ( *matchp == 0 ) {
+ /* We need to normalize everything for dnMatch */
+ ret = dnMatch(
+ matchp,
+ flags,
+ slap_schema.si_syn_distinguishedName,
+ slap_schema.si_mr_distinguishedNameMatch,
+ &issuer_dn,
+ &asserted_issuer_dn);
+ }
+ }
+
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ARGS, "certificateExactMatch "
+ "%d\n\t\"%s $ %s\"\n",
+ *matchp, serial.bv_val, issuer_dn.bv_val );
+ LDAP_LOG( CONFIG, ARGS, "\t\"%s $ %s\"\n",
+ asserted_serial.bv_val, asserted_issuer_dn.bv_val,
+ 0 );
+#else
+ Debug( LDAP_DEBUG_ARGS, "certificateExactMatch "
+ "%d\n\t\"%s $ %s\"\n",
+ *matchp, serial.bv_val, issuer_dn.bv_val );
+ Debug( LDAP_DEBUG_ARGS, "\t\"%s $ %s\"\n",
+ asserted_serial.bv_val, asserted_issuer_dn.bv_val,
+ NULL );
+#endif
+
+ ber_memfree(serial.bv_val);
+ ber_memfree(issuer_dn.bv_val);
+ ber_memfree(asserted_serial.bv_val);
+ ber_memfree(asserted_issuer_dn.bv_val);
+
+ return ret;
+}
+
+/*
+ * Index generation function
+ * We just index the serials, in most scenarios the issuer DN is one of
+ * a very small set of values.
+ */
+static int certificateExactIndexer(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ BerVarray values,
+ BerVarray *keysp )
+{
+ int i;
+ BerVarray keys;
+ X509 *xcert;
+ unsigned char *p;
+ struct berval serial;
+
+ /* we should have at least one value at this point */
+ assert( values != NULL && values[0].bv_val != NULL );
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ /* empty -- just count them */
+ }
+
+ keys = ch_malloc( sizeof( struct berval ) * (i+1) );
+
+ for( i=0; values[i].bv_val != NULL; i++ ) {
+ p = values[i].bv_val;
+ xcert = d2i_X509(NULL, &p, values[i].bv_len);
+ if ( !xcert ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ENTRY,
+ "certificateExactIndexer: error parsing cert: %s\n",
+ ERR_error_string(ERR_get_error(),NULL), 0, 0);
+#else
+ Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
+ "error parsing cert: %s\n",
+ ERR_error_string(ERR_get_error(),NULL),
+ NULL, NULL );
+#endif
+ /* Do we leak keys on error? */
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ asn1_integer2str(xcert->cert_info->serialNumber, &serial);
+ X509_free(xcert);
+ integerNormalize( slap_schema.si_syn_integer,
+ &serial,
+ &keys[i] );
+ ber_memfree(serial.bv_val);
+#ifdef NEW_LOGGING
+ LDAP_LOG( CONFIG, ENTRY,
+ "certificateExactIndexer: returning: %s\n", keys[i].bv_val, 0, 0);
+#else
+ Debug( LDAP_DEBUG_ARGS, "certificateExactIndexer: "
+ "returning: %s\n",
+ keys[i].bv_val,
+ NULL, NULL );
+#endif
+ }
+
+ keys[i].bv_val = NULL;
+ *keysp = keys;
+ return LDAP_SUCCESS;
+}
+
+/* Index generation function */
+/* We think this is always called with a value in matching rule syntax */
+static int certificateExactFilter(
+ slap_mask_t use,
+ slap_mask_t flags,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *prefix,
+ void * assertValue,
+ BerVarray *keysp )
+{
+ BerVarray keys;
+ struct berval asserted_serial;
+
+ serial_and_issuer_parse(assertValue,
+ &asserted_serial,
+ NULL);
+
+ keys = ch_malloc( sizeof( struct berval ) * 2 );
+ integerNormalize( syntax, &asserted_serial, &keys[0] );
+ keys[1].bv_val = NULL;
+ *keysp = keys;
+
+ ber_memfree(asserted_serial.bv_val);
+ return LDAP_SUCCESS;
+}
+#endif
+
+static int
+check_time_syntax (struct berval *val,
+ int start,
+ int *parts)
+{
+ static int ceiling[9] = { 99, 99, 11, 30, 23, 59, 59, 12, 59 };
+ static int mdays[2][12] = {
+ /* non-leap years */
+ { 30, 27, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 },
+ /* leap years */
+ { 30, 28, 30, 29, 30, 29, 30, 30, 29, 30, 29, 30 }
+ };
+ char *p, *e;
+ int part, c, tzoffset, leapyear = 0 ;
+
+ if( val->bv_len == 0 ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ p = (char *)val->bv_val;
+ e = p + val->bv_len;
+
+ /* Ignore initial whitespace */
+ while ( ( p < e ) && ASCII_SPACE( *p ) ) {
+ p++;
+ }
+
+ if (e - p < 13 - (2 * start)) {
+ return LDAP_INVALID_SYNTAX;