-
Bug
-
Resolution: Won't Fix
-
P4
-
None
-
5.0u16
-
x86
-
windows_2003
FULL PRODUCT VERSION :
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b06-284)
Java HotSpot(TM) Client VM (build 1.5.0_16-133, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]
Darwin dhcp-uaus09-147-105.Central.Sun.COM 9.6.0 Darwin Kernel Version 9.6.0: Mon Nov 24 17:37:00 PST 2008; root:xnu-1228.9.59~1/RELEASE_I386 i386
A DESCRIPTION OF THE PROBLEM :
JNDI LDAP
javax.naming.directory.InitialDirContext#search throws java.lang.IndexOutOfBoundsException when search of LDAP DSA root DSE fails with, e.g., LDAP result code 32 (No Such Object).
1. Issue search on the LDAP DSA root DSE (base context "") with SUBTREE_SCOPE. The name argument for root DSE (base context "") is:
javax.naming.ldap.LdapName
• rdns = {java.util.ArrayList@900} size = 0
• unparsed = {java.lang.String@782}""
2. If the search is issued with a scope other than "base" (e.g., "one" for one-level, or "sub" for subtree), some LDAP DSAs will fail the operation and return an LDAP error result (e.g., Error 32 - No Such Object)
3. When JNDI receives the error result, it tries to augment the javax.naming.NameNotFoundException with the portion of the LDAP name (i.e., DN) that matched at the server. In this case, because the "remaining name" CompositeName has somehow gotten a single element, but the original search base LdapName is empty, the call to getPrefix requests the "-1"th name element, resulting in an IndexOutOfBoundsException.
Note: I have a very vague suspicion the path to the error involves the construction of LdapName(""). In this case, the rdn vector is empty (as expected), but the unparsed field is set to "", rather than null. Subsequently, suppose com.sun.jndi.toolkit.ctx.ComponentContext#p_parseComponent is called - the result will be a CompositeName with a single "" element.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run testcase (supplied below) against, e.g., Sun Directory Server 5.x. Note that OpenDS does not expose the problem, because it accepts subtree scope searches at the rootDSE.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Error: [LDAP: error code 32 - No Such Object]
ACTUAL -
Exception in thread "main" java.lang.IndexOutOfBoundsException: Posn: -1, Size: 0
...
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.IndexOutOfBoundsException: Posn: -1, Size: 0
at javax.naming.ldap.LdapName.getPrefix(LdapName.java:240)
at com.sun.jndi.toolkit.ctx.Continuation.fillInException(Continuation.java:133)
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1859)
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1731)
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:368)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:338)
at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:257)
at LdapRootDseSearch.main(LdapRootDseSearch.java:31)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
/* This test demonstrates a bug in JNDI LDAP handling of non
OBJECT_SCOPE searches against the root DSE (base context ""), when
the LDAP DSA returns an error for the search. Specifically, when
run against an LDAP DSA that returns an LDAP result code 32 (No
Such Object) for a SUBTREE_SCOPE search operation on the root DSE
(expressed as LdapName("")), this test demonstrates JNDI throwing
the runtime exception java.lang.IndexOutOfBoundsException. The
runtime error occurs when JNDI is in the process of producing the
expected javax.naming.NameNotFoundException from the LDAP results.
A workaround is to supply an empty CompositeName in place of the
LdapName.
*/
import javax.naming.directory.*;
import javax.naming.*;
import java.util.Enumeration;
import java.util.Properties;
public class LdapRootDseSearch {
public static void main(String[] args) {
Properties env = new Properties();
env.put(DirContext.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(DirContext.PROVIDER_URL,"ldap://localhost:58389");
try {
DirContext dc = new InitialDirContext(env);
SearchControls sc = new SearchControls();
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
Name name = new javax.naming.ldap.LdapName("");
// name = new javax.naming.CompositeName(); // work-around
NamingEnumeration ne = dc.search(name, "(objectclass=*)", sc);
while (ne.hasMore()) {
SearchResult sr = (SearchResult) ne.next();
System.out.println(sr.toString()+"\n");
}
dc.close();
} catch (NamingException nex) {
System.err.println("Error: " + nex.getMessage());
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use an empty javax.naming.CompositeName for the search name argument. See the test case for the work-around.
Also, I believe passing a String("") works also (perhaps the name argument is internally constructed from a CompositeName?)
To elaborate slightly on my analysis from above:
---
Note: I have a very vague suspicion the path to the error involves the construction of LdapName(""). In this case, the rdn vector is empty (as expected), but the unparsed field is set to "", rather than null. Subsequently, suppose com.sun.jndi.toolkit.ctx.ComponentContext#p_parseComponent is called - the result will be a CompositeName with a single "" element.
---
More specificically, when the LdapName.unparsed is non-null (as in the case LdapName was constructed as LdapName("")), the method LdapName.toString() returns exactly the contents of LdapName.unparsed. That itself seems kind of odd, but the specific problem it leads to in this case, is that the value of Name.toString is used in decomposing the supplied base context. This stack trace shows where I suspect things start to go astray:
main[1] where
[1] javax.naming.ldap.LdapName.toString (LdapName.java:607)
[2] com.sun.jndi.toolkit.ctx.ComponentContext.p_parseComponent (ComponentContext.java:104)
[3] com.sun.jndi.toolkit.ctx.ComponentContext.p_resolveIntermediate (ComponentContext.java:359)
[4] com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search (ComponentDirContext.java:360)
[5] com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search (PartialCompositeDirContext.java:338)
[6] javax.naming.directory.InitialDirContext.search (InitialDirContext.java:257)
[7] LdapRootDseSearch.main (LdapRootDseSearch.java:31)
java version "1.5.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64)
Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b06-284)
Java HotSpot(TM) Client VM (build 1.5.0_16-133, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]
Darwin dhcp-uaus09-147-105.Central.Sun.COM 9.6.0 Darwin Kernel Version 9.6.0: Mon Nov 24 17:37:00 PST 2008; root:xnu-1228.9.59~1/RELEASE_I386 i386
A DESCRIPTION OF THE PROBLEM :
JNDI LDAP
javax.naming.directory.InitialDirContext#search throws java.lang.IndexOutOfBoundsException when search of LDAP DSA root DSE fails with, e.g., LDAP result code 32 (No Such Object).
1. Issue search on the LDAP DSA root DSE (base context "") with SUBTREE_SCOPE. The name argument for root DSE (base context "") is:
javax.naming.ldap.LdapName
• rdns = {java.util.ArrayList@900} size = 0
• unparsed = {java.lang.String@782}""
2. If the search is issued with a scope other than "base" (e.g., "one" for one-level, or "sub" for subtree), some LDAP DSAs will fail the operation and return an LDAP error result (e.g., Error 32 - No Such Object)
3. When JNDI receives the error result, it tries to augment the javax.naming.NameNotFoundException with the portion of the LDAP name (i.e., DN) that matched at the server. In this case, because the "remaining name" CompositeName has somehow gotten a single element, but the original search base LdapName is empty, the call to getPrefix requests the "-1"th name element, resulting in an IndexOutOfBoundsException.
Note: I have a very vague suspicion the path to the error involves the construction of LdapName(""). In this case, the rdn vector is empty (as expected), but the unparsed field is set to "", rather than null. Subsequently, suppose com.sun.jndi.toolkit.ctx.ComponentContext#p_parseComponent is called - the result will be a CompositeName with a single "" element.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run testcase (supplied below) against, e.g., Sun Directory Server 5.x. Note that OpenDS does not expose the problem, because it accepts subtree scope searches at the rootDSE.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Error: [LDAP: error code 32 - No Such Object]
ACTUAL -
Exception in thread "main" java.lang.IndexOutOfBoundsException: Posn: -1, Size: 0
...
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.IndexOutOfBoundsException: Posn: -1, Size: 0
at javax.naming.ldap.LdapName.getPrefix(LdapName.java:240)
at com.sun.jndi.toolkit.ctx.Continuation.fillInException(Continuation.java:133)
at com.sun.jndi.ldap.LdapCtx.searchAux(LdapCtx.java:1859)
at com.sun.jndi.ldap.LdapCtx.c_search(LdapCtx.java:1731)
at com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search(ComponentDirContext.java:368)
at com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search(PartialCompositeDirContext.java:338)
at javax.naming.directory.InitialDirContext.search(InitialDirContext.java:257)
at LdapRootDseSearch.main(LdapRootDseSearch.java:31)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
/* This test demonstrates a bug in JNDI LDAP handling of non
OBJECT_SCOPE searches against the root DSE (base context ""), when
the LDAP DSA returns an error for the search. Specifically, when
run against an LDAP DSA that returns an LDAP result code 32 (No
Such Object) for a SUBTREE_SCOPE search operation on the root DSE
(expressed as LdapName("")), this test demonstrates JNDI throwing
the runtime exception java.lang.IndexOutOfBoundsException. The
runtime error occurs when JNDI is in the process of producing the
expected javax.naming.NameNotFoundException from the LDAP results.
A workaround is to supply an empty CompositeName in place of the
LdapName.
*/
import javax.naming.directory.*;
import javax.naming.*;
import java.util.Enumeration;
import java.util.Properties;
public class LdapRootDseSearch {
public static void main(String[] args) {
Properties env = new Properties();
env.put(DirContext.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(DirContext.PROVIDER_URL,"ldap://localhost:58389");
try {
DirContext dc = new InitialDirContext(env);
SearchControls sc = new SearchControls();
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
Name name = new javax.naming.ldap.LdapName("");
// name = new javax.naming.CompositeName(); // work-around
NamingEnumeration ne = dc.search(name, "(objectclass=*)", sc);
while (ne.hasMore()) {
SearchResult sr = (SearchResult) ne.next();
System.out.println(sr.toString()+"\n");
}
dc.close();
} catch (NamingException nex) {
System.err.println("Error: " + nex.getMessage());
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use an empty javax.naming.CompositeName for the search name argument. See the test case for the work-around.
Also, I believe passing a String("") works also (perhaps the name argument is internally constructed from a CompositeName?)
To elaborate slightly on my analysis from above:
---
Note: I have a very vague suspicion the path to the error involves the construction of LdapName(""). In this case, the rdn vector is empty (as expected), but the unparsed field is set to "", rather than null. Subsequently, suppose com.sun.jndi.toolkit.ctx.ComponentContext#p_parseComponent is called - the result will be a CompositeName with a single "" element.
---
More specificically, when the LdapName.unparsed is non-null (as in the case LdapName was constructed as LdapName("")), the method LdapName.toString() returns exactly the contents of LdapName.unparsed. That itself seems kind of odd, but the specific problem it leads to in this case, is that the value of Name.toString is used in decomposing the supplied base context. This stack trace shows where I suspect things start to go astray:
main[1] where
[1] javax.naming.ldap.LdapName.toString (LdapName.java:607)
[2] com.sun.jndi.toolkit.ctx.ComponentContext.p_parseComponent (ComponentContext.java:104)
[3] com.sun.jndi.toolkit.ctx.ComponentContext.p_resolveIntermediate (ComponentContext.java:359)
[4] com.sun.jndi.toolkit.ctx.ComponentDirContext.p_search (ComponentDirContext.java:360)
[5] com.sun.jndi.toolkit.ctx.PartialCompositeDirContext.search (PartialCompositeDirContext.java:338)
[6] javax.naming.directory.InitialDirContext.search (InitialDirContext.java:257)
[7] LdapRootDseSearch.main (LdapRootDseSearch.java:31)