String type, value;
int valueStart, valueEnd, typeStart, typeEnd;
int eq;
if ((eq = indexOf(filter, '=', filtStart, filtEnd)) == -1) {
throw new InvalidSearchFilterException("Missing 'equals'");
}
valueStart = eq + 1; // value starts after equal sign
valueEnd = filtEnd;
typeStart = filtStart; // beginning of string
int ftype;
switch (filter[eq - 1]) {
case '<':
ftype = LDAP_FILTER_LE;
typeEnd = eq - 1;
break;
case '>':
ftype = LDAP_FILTER_GE;
typeEnd = eq - 1;
break;
case '~':
ftype = LDAP_FILTER_APPROX;
typeEnd = eq - 1;
break;
case ':':
ftype = LDAP_FILTER_EXT;
typeEnd = eq - 1;
break;
default:
typeEnd = eq;
//initializing ftype to make the compiler happy
ftype = 0x00;
break;
}
if (dbg) {
System.err.println("type: " + typeStart + ", " + typeEnd);
System.err.println("value: " + valueStart + ", " + valueEnd);
}
// check validity of type
//
// RFC4512 defines the type as the following ABNF:
// attr = attributedescription
// attributedescription = attributetype options
// attributetype = oid
// oid = descr / numericoid
// descr = keystring
// keystring = leadkeychar *keychar
// leadkeychar = ALPHA
// keychar = ALPHA / DIGIT / HYPHEN
// numericoid = number 1*( DOT number )
// number = DIGIT / ( LDIGIT 1*DIGIT )
// options = *( SEMI option )
// option = 1*keychar
//
// And RFC4515 defines the extensible type as the following ABNF:
// attr [dnattrs] [matchingrule] / [dnattrs] matchingrule
int optionsStart = -1;
int extensibleStart = -1;
if ((filter[typeStart] >= '0' && filter[typeStart] <= '9') ||
(filter[typeStart] >= 'A' && filter[typeStart] <= 'Z') ||
(filter[typeStart] >= 'a' && filter[typeStart] <= 'z')) {
boolean isNumericOid =
filter[typeStart] >= '0' && filter[typeStart] <= '9';
for (int i = typeStart + 1; i < typeEnd; i++) {
// ';' is an indicator of attribute options
if (filter[i] == ';') {
if (isNumericOid && filter[i - 1] == '.') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
// attribute options
optionsStart = i;
break;
}
// ':' is an indicator of extensible rules
if (filter[i] == ':' && ftype == LDAP_FILTER_EXT) {
if (isNumericOid && filter[i - 1] == '.') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
// extensible matching
extensibleStart = i;
break;
}
if (isNumericOid) {
// numeric object identifier
if ((filter[i] == '.' && filter[i - 1] == '.') ||
(filter[i] != '.' &&
!(filter[i] >= '0' && filter[i] <= '9'))) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
} else {
// descriptor
// The underscore ("_") character is not allowed by
// the LDAP specification. We allow it here to
// tolerate the incorrect use in practice.
if (filter[i] != '-' && filter[i] != '_' &&
!(filter[i] >= '0' && filter[i] <= '9') &&
!(filter[i] >= 'A' && filter[i] <= 'Z') &&
!(filter[i] >= 'a' && filter[i] <= 'z')) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
}
}
} else if (ftype == LDAP_FILTER_EXT && filter[typeStart] == ':') {
// extensible matching
extensibleStart = typeStart;
} else {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
// check attribute options
if (optionsStart > 0) {
for (int i = optionsStart + 1; i < typeEnd; i++) {
if (filter[i] == ';') {
if (filter[i - 1] == ';') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
continue;
}
// ':' is an indicator of extensible rules
if (filter[i] == ':' && ftype == LDAP_FILTER_EXT) {
if (filter[i - 1] == ';') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
// extensible matching
extensibleStart = i;
break;
}
// The underscore ("_") character is not allowed by
// the LDAP specification. We allow it here to
// tolerate the incorrect use in practice.
if (filter[i] != '-' && filter[i] != '_' &&
!(filter[i] >= '0' && filter[i] <= '9') &&
!(filter[i] >= 'A' && filter[i] <= 'Z') &&
!(filter[i] >= 'a' && filter[i] <= 'z')) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
}
}
// check extensible matching
if (extensibleStart > 0) {
boolean isMatchingRule = false;
for (int i = extensibleStart + 1; i < typeEnd; i++) {
if (filter[i] == ':') {
throw new InvalidSearchFilterException(
"invalid attribute description");
} else if ((filter[i] >= '0' && filter[i] <= '9') ||
(filter[i] >= 'A' && filter[i] <= 'Z') ||
(filter[i] >= 'a' && filter[i] <= 'z')) {
boolean isNumericOid = filter[i] >= '0' && filter[i] <= '9';
i++;
for (int j = i; j < typeEnd; j++, i++) {
// allows no more than two extensible rules
if (filter[j] == ':') {
if (isMatchingRule) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
if (isNumericOid && filter[j - 1] == '.') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
isMatchingRule = true;
break;
}
if (isNumericOid) {
// numeric object identifier
if ((filter[j] == '.' && filter[j - 1] == '.') ||
(filter[j] != '.' &&
!(filter[j] >= '0' && filter[j] <= '9'))) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
} else {
// descriptor
// The underscore ("_") character is not allowed by
// the LDAP specification. We allow it here to
// tolerate the incorrect use in practice.
if (filter[j] != '-' && filter[j] != '_' &&
!(filter[j] >= '0' && filter[j] <= '9') &&
!(filter[j] >= 'A' && filter[j] <= 'Z') &&
!(filter[j] >= 'a' && filter[j] <= 'z')) {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
}
}
} else {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
}
}
// ensure the latest byte is not isolated
if (filter[typeEnd - 1] == '.' || filter[typeEnd - 1] == ';' ||
filter[typeEnd - 1] == ':') {
throw new InvalidSearchFilterException(
"invalid attribute description");
}
if (typeEnd == eq) { // filter type is of "equal"
if (findUnescaped(filter, '*', valueStart, valueEnd) == -1) {