+ n = 0;
+ AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
+ STRLENOF("{ serialNumber "));
+ n = STRLENOF("{ serialNumber ");
+
+ AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
+ n += sn.bv_len;
+
+ AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF(", issuer \""));
+ n += STRLENOF(", issuer \"");
+
+ AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
+ n += ni.bv_len;
+
+ AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF("\" }"));
+ n += STRLENOF("\" }");
+
+ out->bv_val[n] = '\0';
+
+ assert( n == out->bv_len );
+
+ Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerPretty: <%s>\n",
+ out->bv_val, 0, 0 );
+
+ slap_sl_free( ni.bv_val, ctx );
+
+ return LDAP_SUCCESS;
+}
+
+/*
+ * This routine is called by certificateExactNormalize when
+ * certificateExactNormalize receives a search string instead of
+ * a certificate. This routine checks if the search value is valid
+ * and then returns the normalized value
+ */
+static int
+serialNumberAndIssuerNormalize(
+ slap_mask_t usage,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *in,
+ struct berval *out,
+ void *ctx )
+{
+ int rc;
+ ber_len_t n;
+ struct berval sn, i, ni;
+
+ assert( in != NULL );
+ assert( out != NULL );
+
+ Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerNormalize: <%s>\n",
+ in->bv_val, 0, 0 );
+
+ if( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX;
+
+ if( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) {
+ /* Parse old format */
+ i.bv_val = ber_bvchr( in, '$' );
+ if( BER_BVISNULL( &i ) ) return LDAP_INVALID_SYNTAX;
+
+ sn.bv_val = in->bv_val;
+ sn.bv_len = i.bv_val - in->bv_val;
+
+ i.bv_val++;
+ i.bv_len = in->bv_len - (sn.bv_len + 1);
+
+ /* eat leading zeros */
+ for( n=0; n < (sn.bv_len-1); n++ ) {
+ if( sn.bv_val[n] != '0' ) break;
+ }
+ sn.bv_val += n;
+ sn.bv_len -= n;
+
+ for( n=0; n < sn.bv_len; n++ ) {
+ if( !ASCII_DIGIT(sn.bv_val[n]) ) return LDAP_INVALID_SYNTAX;
+ }
+
+ } else {
+ /* Parse GSER format */
+ int havesn=0,haveissuer=0;
+ struct berval x = *in;
+ x.bv_val++;
+ x.bv_len-=2;
+
+ /* eat leading spaces */
+ for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
+ /* empty */;
+ }
+
+ if ( x.bv_len < STRLENOF("serialNumber 0,issuer \"\"")) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ /* should be at issuer or serialNumber NamedValue */
+ if( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer")) == 0 ) {
+ /* parse issuer */
+ x.bv_val += STRLENOF("issuer");
+ x.bv_len -= STRLENOF("issuer");
+
+ if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
+ x.bv_val++; x.bv_len--;
+
+ /* eat leading spaces */
+ for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
+ /* empty */;
+ }
+
+ if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
+ x.bv_val++; x.bv_len--;
+
+ i.bv_val = x.bv_val;
+ i.bv_len = 0;
+
+ for( ; i.bv_len < x.bv_len; ) {
+ if ( i.bv_val[i.bv_len] != '"' ) {
+ i.bv_len++;
+ continue;
+ }
+ if ( i.bv_val[i.bv_len+1] == '"' ) {
+ /* double dquote */
+ i.bv_len+=2;
+ continue;
+ }
+ break;
+ }
+ x.bv_val += i.bv_len+1;
+ x.bv_len -= i.bv_len+1;
+
+ if ( x.bv_len < STRLENOF(",serialNumber 0")) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ haveissuer++;
+
+ } else if( strncasecmp( x.bv_val, "serialNumber",
+ STRLENOF("serialNumber")) == 0 )
+ {
+ /* parse serialNumber */
+ int neg=0;
+ x.bv_val += STRLENOF("serialNumber");
+ x.bv_len -= STRLENOF("serialNumber");
+
+ if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
+ x.bv_val++; x.bv_len--;
+
+ /* eat leading spaces */
+ for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
+ /* empty */;
+ }
+
+ sn.bv_val = x.bv_val;
+ sn.bv_len = 0;
+
+ if( sn.bv_val[0] == '-' ) {
+ neg++;
+ sn.bv_len++;
+ }
+
+ for( ; sn.bv_len < x.bv_len; sn.bv_len++ ) {
+ if ( !ASCII_DIGIT( sn.bv_val[sn.bv_len] )) break;
+ }
+
+ if (!( sn.bv_len > neg )) return LDAP_INVALID_SYNTAX;
+ if (( sn.bv_len > 1+neg ) && ( sn.bv_val[neg] == '0' )) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ x.bv_val += sn.bv_len; x.bv_len -= sn.bv_len;
+
+ if ( x.bv_len < STRLENOF( ",issuer \"\"" )) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ havesn++;
+
+ } else return LDAP_INVALID_SYNTAX;
+
+ if( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX;
+ x.bv_val++; x.bv_len--;
+
+ /* eat spaces */
+ for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
+ /* empty */;
+ }
+
+ /* should be at remaining NamedValue */
+ if( !haveissuer && (strncasecmp( x.bv_val, "issuer",
+ STRLENOF("issuer" )) == 0 ))
+ {
+ /* parse issuer */
+ x.bv_val += STRLENOF("issuer");
+ x.bv_len -= STRLENOF("issuer");
+
+ if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
+ x.bv_val++; x.bv_len--;
+
+ /* eat leading spaces */
+ for( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) {
+ /* empty */;
+ }
+
+ if( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX;
+ x.bv_val++; x.bv_len--;
+
+ i.bv_val = x.bv_val;
+ i.bv_len = 0;
+
+ for( ; i.bv_len < x.bv_len; ) {
+ if ( i.bv_val[i.bv_len] != '"' ) {
+ i.bv_len++;
+ continue;
+ }
+ if ( i.bv_val[i.bv_len+1] == '"' ) {
+ /* double dquote */
+ i.bv_len+=2;
+ continue;
+ }
+ break;
+ }
+ x.bv_val += i.bv_len+1;
+ x.bv_len -= i.bv_len+1;
+
+ } else if( !havesn && (strncasecmp( x.bv_val, "serialNumber",
+ STRLENOF("serialNumber")) == 0 ))
+ {
+ /* parse serialNumber */
+ int neg=0;
+ x.bv_val += STRLENOF("serialNumber");
+ x.bv_len -= STRLENOF("serialNumber");
+
+ if( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX;
+ x.bv_val++; x.bv_len--;