/* * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jndi.ldap; import javax.naming.*;import javax.naming.directory.*;import javax.naming.spi.*;import javax.naming.event.*;import javax.naming.ldap.*;import javax.naming.ldap.LdapName;import javax.naming.ldap.Rdn; import java.util.Vector;import java.util.Hashtable;import java.util.List;import java.util.StringTokenizer;import java.util.Enumeration; import java.io.IOException;import java.io.OutputStream; import com.sun.jndi.toolkit.ctx.*;import com.sun.jndi.toolkit.dir.HierMemDirCtx;import com.sun.jndi.toolkit.dir.SearchFilter;import com.sun.jndi.ldap.ext.StartTlsResponseImpl; /** * The LDAP context implementation. * * Implementation is not thread-safe. Caller must sync as per JNDI spec. * Members that are used directly or indirectly by internal worker threads * (Connection, EventQueue, NamingEventNotifier) must be thread-safe. * Connection - calls LdapClient.processUnsolicited(), which in turn calls * LdapCtx.convertControls() and LdapCtx.fireUnsolicited(). * convertControls() - no sync; reads envprops and 'this' * fireUnsolicited() - sync on eventSupport for all references to 'unsolicited' * (even those in other methods); don't sync on LdapCtx in case caller * is already sync'ing on it - this would prevent Unsol events from firing * and the Connection thread to block (thus preventing any other data * from being read from the connection) * References to 'eventSupport' need not be sync'ed because these * methods can only be called after eventSupport has been set first * (via addNamingListener()). * EventQueue - no direct or indirect calls to LdapCtx * NamingEventNotifier - calls newInstance() to get instance for run() to use; * no sync needed for methods invoked on new instance; * * LdapAttribute links to LdapCtx in order to process getAttributeDefinition() * and getAttributeSyntaxDefinition() calls. It invokes LdapCtx.getSchema(), * which uses schemaTrees (a Hashtable - already sync). Potential conflict * of duplicating construction of tree for same subschemasubentry * but no inconsistency problems. * * NamingEnumerations link to LdapCtx for the following: * 1. increment/decrement enum count so that ctx doesn't close the * underlying connection * 2. LdapClient handle to get next batch of results * 3. Sets LdapCtx's response controls * 4. Process return code * 5. For narrowing response controls (using ctx's factories) * Since processing of NamingEnumeration by client is treated the same as method * invocation on LdapCtx, caller is responsible for locking. * * @author Vincent Ryan * @author Rosanna Lee */ final public class LdapCtx extends ComponentDirContext implements EventDirContext, LdapContext { /* * Used to store arguments to the search method. */ final static class SearchArgs { Name name; String filter; SearchControls cons; String[] reqAttrs; // those attributes originally requested SearchArgs(Name name, String filter, SearchControls cons, String[] ra) { this.name = name; this.filter = filter; this.cons = cons; this.reqAttrs = ra; } } private static final boolean debug = false; private static final boolean HARD_CLOSE = true; private static final boolean SOFT_CLOSE = false; // ----------------- Constants ----------------- public static final int DEFAULT_PORT = 389; public static final int DEFAULT_SSL_PORT = 636; public static final String DEFAULT_HOST = "localhost"; private static final boolean DEFAULT_DELETE_RDN = true; private static final boolean DEFAULT_TYPES_ONLY = false; private static final int DEFAULT_DEREF_ALIASES = 3; // always deref private static final int DEFAULT_LDAP_VERSION = LdapClient.LDAP_VERSION3_VERSION2; private static final int DEFAULT_BATCH_SIZE = 1; private static final int DEFAULT_REFERRAL_MODE = LdapClient.LDAP_REF_IGNORE; private static final char DEFAULT_REF_SEPARATOR = '#'; // Used by LdapPoolManager static final String DEFAULT_SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; // use Sun's SSL private static final int DEFAULT_REFERRAL_LIMIT = 10; private static final String STARTTLS_REQ_OID = "1.3.6.1.4.1.1466.20037"; // schema operational and user attributes private static final String[] SCHEMA_ATTRIBUTES = { "objectClasses", "attributeTypes", "matchingRules", "ldapSyntaxes" }; // --------------- Environment property names ---------- // LDAP protocol version: "2", "3" private static final String VERSION = "java.naming.ldap.version"; // Binary-valued attributes. Space separated string of attribute names. private static final String BINARY_ATTRIBUTES = "java.naming.ldap.attributes.binary"; // Delete old RDN during modifyDN: "true", "false" private static final String DELETE_RDN = "java.naming.ldap.deleteRDN"; // De-reference aliases: "never", "searching", "finding", "always" private static final String DEREF_ALIASES = "java.naming.ldap.derefAliases"; // Return only attribute types (no values) private static final String TYPES_ONLY = "java.naming.ldap.typesOnly"; // Separator character for encoding Reference's RefAddrs; default is '#' private static final String REF_SEPARATOR = "java.naming.ldap.ref.separator"; // Socket factory private static final String SOCKET_FACTORY = "java.naming.ldap.factory.socket"; // Bind Controls (used by LdapReferralException) static final String BIND_CONTROLS = "java.naming.ldap.control.connect"; private static final String REFERRAL_LIMIT = "java.naming.ldap.referral.limit"; // trace BER (java.io.OutputStream) private static final String TRACE_BER = "com.sun.jndi.ldap.trace.ber"; // Get around Netscape Schema Bugs private static final String NETSCAPE_SCHEMA_BUG = "com.sun.jndi.ldap.netscape.schemaBugs"; // deprecated private static final String OLD_NETSCAPE_SCHEMA_BUG = "com.sun.naming.netscape.schemaBugs"; // for backward compatability // Timeout for socket connect private static final String CONNECT_TIMEOUT = "com.sun.jndi.ldap.connect.timeout"; // Timeout for reading responses private static final String READ_TIMEOUT = "com.sun.jndi.ldap.read.timeout"; // Environment property for connection pooling private static final String ENABLE_POOL = "com.sun.jndi.ldap.connect.pool"; // Environment property for the domain name (derived from this context's DN) private static final String DOMAIN_NAME = "com.sun.jndi.ldap.domainname"; // Block until the first search reply is received private static final String WAIT_FOR_REPLY = "com.sun.jndi.ldap.search.waitForReply"; // Size of the queue of unprocessed search replies private static final String REPLY_QUEUE_SIZE = "com.sun.jndi.ldap.search.replyQueueSize"; // ----------------- Fields that don't change ----------------------- private static final NameParser parser = new LdapNameParser(); // controls that Provider needs private static final ControlFactory myResponseControlFactory = new DefaultResponseControlFactory(); private static final Control manageReferralControl = new ManageReferralControl(false); private static final HierMemDirCtx EMPTY_SCHEMA = new HierMemDirCtx(); static { EMPTY_SCHEMA.setReadOnly( new SchemaViolationException("Cannot update schema object")); } // ------------ Package private instance variables ---------------- // Cannot be private; used by enums // ------- Inherited by derived context instances int port_number; // port number of server String hostname = null; // host name of server (no brackets // for IPv6 literals) LdapClient clnt = null; // connection handle Hashtable envprops = null; // environment properties of context int handleReferrals = DEFAULT_REFERRAL_MODE; // how referral is handled boolean hasLdapsScheme = false; // true if the context was created // using an LDAPS URL. // ------- Not inherited by derived context instances String currentDN; // DN of this context Name currentParsedDN; // DN of this context Vector respCtls = null; // Response controls read Control[] reqCtls = null; // Controls to be sent with each request // ------------- Private instance variables ------------------------ // ------- Inherited by derived context instances private OutputStream trace = null; // output stream for BER debug output private boolean netscapeSchemaBug = false; // workaround private Control[] bindCtls = null; // Controls to be sent with LDAP "bind" private int referralHopLimit = DEFAULT_REFERRAL_LIMIT; // max referral private Hashtable schemaTrees = null; // schema root of this context private int batchSize = DEFAULT_BATCH_SIZE; // batch size for search results private boolean deleteRDN = DEFAULT_DELETE_RDN; // delete the old RDN when modifying DN private boolean typesOnly = DEFAULT_TYPES_ONLY; // return attribute types (no values) private int derefAliases = DEFAULT_DEREF_ALIASES;// de-reference alias entries during searching private char addrEncodingSeparator = DEFAULT_REF_SEPARATOR; // encoding RefAddr private Hashtable binaryAttrs = null; // attr values returned as byte[] private int connectTimeout = -1; // no timeout value private int readTimeout = -1; // no timeout value private boolean waitForReply = true; // wait for search response private int replyQueueSize = -1; // unlimited queue size private boolean useSsl = false; // true if SSL protocol is active private boolean useDefaultPortNumber = false; // no port number was supplied // ------- Not inherited by derived context instances // True if this context was created by another LdapCtx. private boolean parentIsLdapCtx = false; // see composeName() private int hopCount = 1; // current referral hop count private String url = null; // URL of context; see getURL() private EventSupport eventSupport; // Event support helper for this ctx private boolean unsolicited = false; // if there unsolicited listeners private boolean sharable = true; // can share connection with other ctx // -------------- Constructors ----------------------------------- public LdapCtx(String dn, String host, int port_number, Hashtable props, boolean useSsl) throws NamingException { this.useSsl = this.hasLdapsScheme = useSsl; if (props != null) { envprops = (Hashtable) props.clone(); // SSL env prop overrides the useSsl argument if ("ssl".equals(envprops.get(Context.SECURITY_PROTOCOL))) { this.useSsl = true; } // %%% These are only examined when the context is created // %%% because they are only for debugging or workaround purposes. trace = (OutputStream)envprops.get(TRACE_BER); if (props.get(NETSCAPE_SCHEMA_BUG) != null || props.get(OLD_NETSCAPE_SCHEMA_BUG) != null) { netscapeSchemaBug = true; } } currentDN = (dn != null) ? dn : ""; currentParsedDN = parser.parse(currentDN); hostname = (host != null && host.length() > 0) ? host : DEFAULT_HOST; if (hostname.charAt(0) == '[') { hostname = hostname.substring(1, hostname.length() - 1); } if (port_number > 0) { this.port_number = port_number; } else { this.port_number = this.useSsl ? DEFAULT_SSL_PORT : DEFAULT_PORT; this.useDefaultPortNumber = true; } schemaTrees = new Hashtable(11, 0.75f); initEnv(); try { connect(false); } catch (NamingException e) { try { close(); } catch (Exception e2) { // Nothing } throw e; } } LdapCtx(LdapCtx existing, String newDN) throws NamingException { useSsl = existing.useSsl; hasLdapsScheme = existing.hasLdapsScheme; useDefaultPortNumber = existing.useDefaultPortNumber; hostname = existing.hostname; port_number = existing.port_number; currentDN = newDN; if (existing.currentDN == currentDN) { currentParsedDN = existing.currentParsedDN; } else { currentParsedDN = parser.parse(currentDN); } envprops = existing.envprops; schemaTrees = existing.schemaTrees; clnt = existing.clnt; clnt.incRefCount(); parentIsLdapCtx = ((newDN == null || newDN.equals(existing.currentDN)) ? existing.parentIsLdapCtx : true); // inherit these debugging/workaround flags trace = existing.trace; netscapeSchemaBug = existing.netscapeSchemaBug; initEnv(); } public LdapContext newInstance(Control[] reqCtls) throws NamingException { LdapContext clone = new LdapCtx(this, currentDN); // Connection controls are inherited from environment // Set clone's request controls // setRequestControls() will clone reqCtls clone.setRequestControls(reqCtls); return clone; } // --------------- Namespace Updates --------------------- // -- bind/rebind/unbind // -- rename // -- createSubcontext/destroySubcontext protected void c_bind(Name name, Object obj, Continuation cont) throws NamingException { c_bind(name, obj, null, cont); } /* * attrs == null * if obj is DirContext, attrs = obj.getAttributes() * if attrs == null && obj == null * disallow (cannot determine objectclass to use) * if obj == null * just create entry using attrs * else * objAttrs = create attributes for representing obj * attrs += objAttrs * create entry using attrs */ protected void c_bind(Name name, Object obj, Attributes attrs, Continuation cont) throws NamingException { cont.setError(this, name); Attributes inputAttrs = attrs; // Attributes supplied by caller try { ensureOpen(); if (obj == null) { if (attrs == null) { throw new IllegalArgumentException( "cannot bind null object with no attributes"); } } else { attrs = Obj.determineBindAttrs(addrEncodingSeparator, obj, attrs, false, name, this, envprops); // not cloned } String newDN = fullyQualifiedName(name); attrs = addRdnAttributes(newDN, attrs, inputAttrs != attrs); LdapEntry entry = new LdapEntry(newDN, attrs); LdapResult answer = clnt.add(entry, reqCtls); respCtls = answer.resControls; // retrieve response controls if (answer.status != LdapClient.LDAP_SUCCESS) { processReturnCode(answer, name); } } catch (LdapReferralException e) { if (handleReferrals == LdapClient.LDAP_REF_THROW) throw cont.fillInException(e); // process the referrals sequentially while (true) { LdapReferralContext refCtx = (LdapReferralContext)e.getReferralContext(envprops, bindCtls); // repeat the original operation at the new context try { refCtx.bind(name, obj, inputAttrs); return; } catch (LdapReferralException re) { e = re; continue; } finally { // Make sure we close referral context refCtx.close(); } } } catch (IOException e) { NamingException e2 = new CommunicationException(e.getMessage()); e2.setRootCause(e); throw cont.fillInException(e2); } catch (NamingException e) { throw cont.fillInException(e); } } protected void c_rebind(Name name, Object obj, Continuation cont) throws NamingException { c_rebind(name, obj, null, cont); } /* * attrs == null * if obj is DirContext, attrs = obj.getAttributes(). * if attrs == null * leave any existing attributes alone * (set attrs = {objectclass=top} if object doesn't exist) * else * replace all existing attributes with attrs * if obj == null * just create entry using attrs * else * objAttrs = create attributes for representing obj * attrs += objAttrs * create entry using attrs */ protected void c_rebind(Name name, Object obj, Attributes attrs, Continuation cont) throws NamingException { cont.setError(this, name); Attributes inputAttrs = attrs; try { Attributes origAttrs = null; // Check if name is bound try { origAttrs = c_getAttributes(name, null, cont); } catch (NameNotFoundException e) {} // Name not bound, just add it if (origAttrs == null) { c_bind(name, obj, attrs, cont); return; } Lines 1–500 of 3541. Load more
/* * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.jndi.ldap; import javax.naming.*; import javax.naming.directory.*; import javax.naming.spi.*; import javax.naming.event.*; import javax.naming.ldap.*; import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; import java.util.Vector; import java.util.Hashtable; import java.util.List; import java.util.StringTokenizer; import java.util.Enumeration; import java.io.IOException; import java.io.OutputStream; import com.sun.jndi.toolkit.ctx.*; import com.sun.jndi.toolkit.dir.HierMemDirCtx; import com.sun.jndi.toolkit.dir.SearchFilter; import com.sun.jndi.ldap.ext.StartTlsResponseImpl; /** * The LDAP context implementation. * * Implementation is not thread-safe. Caller must sync as per JNDI spec. * Members that are used directly or indirectly by internal worker threads * (Connection, EventQueue, NamingEventNotifier) must be thread-safe. * Connection - calls LdapClient.processUnsolicited(), which in turn calls * LdapCtx.convertControls() and LdapCtx.fireUnsolicited(). * convertControls() - no sync; reads envprops and 'this' * fireUnsolicited() - sync on eventSupport for all references to 'unsolicited' * (even those in other methods); don't sync on LdapCtx in case caller * is already sync'ing on it - this would prevent Unsol events from firing * and the Connection thread to block (thus preventing any other data * from being read from the connection) * References to 'eventSupport' need not be sync'ed because these * methods can only be called after eventSupport has been set first * (via addNamingListener()). * EventQueue - no direct or indirect calls to LdapCtx * NamingEventNotifier - calls newInstance() to get instance for run() to use; * no sync needed for methods invoked on new instance; * * LdapAttribute links to LdapCtx in order to process getAttributeDefinition() * and getAttributeSyntaxDefinition() calls. It invokes LdapCtx.getSchema(), * which uses schemaTrees (a Hashtable - already sync). Potential conflict * of duplicating construction of tree for same subschemasubentry * but no inconsistency problems. * * NamingEnumerations link to LdapCtx for the following: * 1. increment/decrement enum count so that ctx doesn't close the * underlying connection * 2. LdapClient handle to get next batch of results * 3. Sets LdapCtx's response controls * 4. Process return code * 5. For narrowing response controls (using ctx's factories) * Since processing of NamingEnumeration by client is treated the same as method * invocation on LdapCtx, caller is responsible for locking. * * @author Vincent Ryan * @author Rosanna Lee */ final public class LdapCtx extends ComponentDirContext implements EventDirContext, LdapContext { /* * Used to store arguments to the search method. */ final static class SearchArgs { Name name; String filter; SearchControls cons; String[] reqAttrs; // those attributes originally requested SearchArgs(Name name, String filter, SearchControls cons, String[] ra) { this.name = name; this.filter = filter; this.cons = cons; this.reqAttrs = ra; } } private static final boolean debug = false; private static final boolean HARD_CLOSE = true; private static final boolean SOFT_CLOSE = false; // ----------------- Constants ----------------- public static final int DEFAULT_PORT = 389; public static final int DEFAULT_SSL_PORT = 636; public static final String DEFAULT_HOST = "localhost"; private static final boolean DEFAULT_DELETE_RDN = true; private static final boolean DEFAULT_TYPES_ONLY = false; private static final int DEFAULT_DEREF_ALIASES = 3; // always deref private static final int DEFAULT_LDAP_VERSION = LdapClient.LDAP_VERSION3_VERSION2; private static final int DEFAULT_BATCH_SIZE = 1; private static final int DEFAULT_REFERRAL_MODE = LdapClient.LDAP_REF_IGNORE; private static final char DEFAULT_REF_SEPARATOR = '#'; // Used by LdapPoolManager static final String DEFAULT_SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; // use Sun's SSL private static final int DEFAULT_REFERRAL_LIMIT = 10; private static final String STARTTLS_REQ_OID = "1.3.6.1.4.1.1466.20037"; // schema operational and user attributes private static final String[] SCHEMA_ATTRIBUTES = { "objectClasses", "attributeTypes", "matchingRules", "ldapSyntaxes" }; // --------------- Environment property names ---------- // LDAP protocol version: "2", "3" private static final String VERSION = "java.naming.ldap.version"; // Binary-valued attributes. Space separated string of attribute names. private static final String BINARY_ATTRIBUTES = "java.naming.ldap.attributes.binary"; // Delete old RDN during modifyDN: "true", "false" private static final String DELETE_RDN = "java.naming.ldap.deleteRDN"; // De-reference aliases: "never", "searching", "finding", "always" private static final String DEREF_ALIASES = "java.naming.ldap.derefAliases"; // Return only attribute types (no values) private static final String TYPES_ONLY = "java.naming.ldap.typesOnly"; // Separator character for encoding Reference's RefAddrs; default is '#' private static final String REF_SEPARATOR = "java.naming.ldap.ref.separator"; // Socket factory private static final String SOCKET_FACTORY = "java.naming.ldap.factory.socket"; // Bind Controls (used by LdapReferralException) static final String BIND_CONTROLS = "java.naming.ldap.control.connect"; private static final String REFERRAL_LIMIT = "java.naming.ldap.referral.limit"; // trace BER (java.io.OutputStream) private static final String TRACE_BER = "com.sun.jndi.ldap.trace.ber"; // Get around Netscape Schema Bugs private static final String NETSCAPE_SCHEMA_BUG = "com.sun.jndi.ldap.netscape.schemaBugs"; // deprecated private static final String OLD_NETSCAPE_SCHEMA_BUG = "com.sun.naming.netscape.schemaBugs"; // for backward compatability // Timeout for socket connect private static final String CONNECT_TIMEOUT = "com.sun.jndi.ldap.connect.timeout"; // Timeout for reading responses private static final String READ_TIMEOUT = "com.sun.jndi.ldap.read.timeout"; // Environment property for connection pooling private static final String ENABLE_POOL = "com.sun.jndi.ldap.connect.pool"; // Environment property for the domain name (derived from this context's DN) private static final String DOMAIN_NAME = "com.sun.jndi.ldap.domainname"; // Block until the first search reply is received private static final String WAIT_FOR_REPLY = "com.sun.jndi.ldap.search.waitForReply"; // Size of the queue of unprocessed search replies private static final String REPLY_QUEUE_SIZE = "com.sun.jndi.ldap.search.replyQueueSize"; // ----------------- Fields that don't change ----------------------- private static final NameParser parser = new LdapNameParser(); // controls that Provider needs private static final ControlFactory myResponseControlFactory = new DefaultResponseControlFactory(); private static final Control manageReferralControl = new ManageReferralControl(false); private static final HierMemDirCtx EMPTY_SCHEMA = new HierMemDirCtx(); static { EMPTY_SCHEMA.setReadOnly( new SchemaViolationException("Cannot update schema object")); } // ------------ Package private instance variables ---------------- // Cannot be private; used by enums // ------- Inherited by derived context instances int port_number; // port number of server String hostname = null; // host name of server (no brackets // for IPv6 literals) LdapClient clnt = null; // connection handle Hashtable envprops = null; // environment properties of context int handleReferrals = DEFAULT_REFERRAL_MODE; // how referral is handled boolean hasLdapsScheme = false; // true if the context was created // using an LDAPS URL. // ------- Not inherited by derived context instances String currentDN; // DN of this context Name currentParsedDN; // DN of this context Vector respCtls = null; // Response controls read Control[] reqCtls = null; // Controls to be sent with each request // ------------- Private instance variables ------------------------ // ------- Inherited by derived context instances private OutputStream trace = null; // output stream for BER debug output private boolean netscapeSchemaBug = false; // workaround private Control[] bindCtls = null; // Controls to be sent with LDAP "bind" private int referralHopLimit = DEFAULT_REFERRAL_LIMIT; // max referral private Hashtable schemaTrees = null; // schema root of this context private int batchSize = DEFAULT_BATCH_SIZE; // batch size for search results private boolean deleteRDN = DEFAULT_DELETE_RDN; // delete the old RDN when modifying DN private boolean typesOnly = DEFAULT_TYPES_ONLY; // return attribute types (no values) private int derefAliases = DEFAULT_DEREF_ALIASES;// de-reference alias entries during searching private char addrEncodingSeparator = DEFAULT_REF_SEPARATOR; // encoding RefAddr private Hashtable binaryAttrs = null; // attr values returned as byte[] private int connectTimeout = -1; // no timeout value private int readTimeout = -1; // no timeout value private boolean waitForReply = true; // wait for search response private int replyQueueSize = -1; // unlimited queue size private boolean useSsl = false; // true if SSL protocol is active private boolean useDefaultPortNumber = false; // no port number was supplied // ------- Not inherited by derived context instances // True if this context was created by another LdapCtx. private boolean parentIsLdapCtx = false; // see composeName() private int hopCount = 1; // current referral hop count private String url = null; // URL of context; see getURL() private EventSupport eventSupport; // Event support helper for this ctx private boolean unsolicited = false; // if there unsolicited listeners private boolean sharable = true; // can share connection with other ctx // -------------- Constructors ----------------------------------- public LdapCtx(String dn, String host, int port_number, Hashtable props, boolean useSsl) throws NamingException { this.useSsl = this.hasLdapsScheme = useSsl; if (props != null) { envprops = (Hashtable) props.clone(); // SSL env prop overrides the useSsl argument if ("ssl".equals(envprops.get(Context.SECURITY_PROTOCOL))) { this.useSsl = true; } // %%% These are only examined when the context is created // %%% because they are only for debugging or workaround purposes. trace = (OutputStream)envprops.get(TRACE_BER); if (props.get(NETSCAPE_SCHEMA_BUG) != null || props.get(OLD_NETSCAPE_SCHEMA_BUG) != null) { netscapeSchemaBug = true; } } currentDN = (dn != null) ? dn : ""; currentParsedDN = parser.parse(currentDN); hostname = (host != null && host.length() > 0) ? host : DEFAULT_HOST; if (hostname.charAt(0) == '[') { hostname = hostname.substring(1, hostname.length() - 1); } if (port_number > 0) { this.port_number = port_number; } else { this.port_number = this.useSsl ? DEFAULT_SSL_PORT : DEFAULT_PORT; this.useDefaultPortNumber = true; } schemaTrees = new Hashtable(11, 0.75f); initEnv(); try { connect(false); } catch (NamingException e) { try { close(); } catch (Exception e2) { // Nothing } throw e; } } LdapCtx(LdapCtx existing, String newDN) throws NamingException { useSsl = existing.useSsl; hasLdapsScheme = existing.hasLdapsScheme; useDefaultPortNumber = existing.useDefaultPortNumber; hostname = existing.hostname; port_number = existing.port_number; currentDN = newDN; if (existing.currentDN == currentDN) { currentParsedDN = existing.currentParsedDN; } else { currentParsedDN = parser.parse(currentDN); } envprops = existing.envprops; schemaTrees = existing.schemaTrees; clnt = existing.clnt; clnt.incRefCount(); parentIsLdapCtx = ((newDN == null || newDN.equals(existing.currentDN)) ? existing.parentIsLdapCtx : true); // inherit these debugging/workaround flags trace = existing.trace; netscapeSchemaBug = existing.netscapeSchemaBug; initEnv(); } public LdapContext newInstance(Control[] reqCtls) throws NamingException { LdapContext clone = new LdapCtx(this, currentDN); // Connection controls are inherited from environment // Set clone's request controls // setRequestControls() will clone reqCtls clone.setRequestControls(reqCtls); return clone; } // --------------- Namespace Updates --------------------- // -- bind/rebind/unbind // -- rename // -- createSubcontext/destroySubcontext protected void c_bind(Name name, Object obj, Continuation cont) throws NamingException { c_bind(name, obj, null, cont); } /* * attrs == null * if obj is DirContext, attrs = obj.getAttributes() * if attrs == null && obj == null * disallow (cannot determine objectclass to use) * if obj == null * just create entry using attrs * else * objAttrs = create attributes for representing obj * attrs += objAttrs * create entry using attrs */ protected void c_bind(Name name, Object obj, Attributes attrs, Continuation cont) throws NamingException { cont.setError(this, name); Attributes inputAttrs = attrs; // Attributes supplied by caller try { ensureOpen(); if (obj == null) { if (attrs == null) { throw new IllegalArgumentException( "cannot bind null object with no attributes"); } } else { attrs = Obj.determineBindAttrs(addrEncodingSeparator, obj, attrs, false, name, this, envprops); // not cloned } String newDN = fullyQualifiedName(name); attrs = addRdnAttributes(newDN, attrs, inputAttrs != attrs); LdapEntry entry = new LdapEntry(newDN, attrs); LdapResult answer = clnt.add(entry, reqCtls); respCtls = answer.resControls; // retrieve response controls if (answer.status != LdapClient.LDAP_SUCCESS) { processReturnCode(answer, name); } } catch (LdapReferralException e) { if (handleReferrals == LdapClient.LDAP_REF_THROW) throw cont.fillInException(e); // process the referrals sequentially while (true) { LdapReferralContext refCtx = (LdapReferralContext)e.getReferralContext(envprops, bindCtls); // repeat the original operation at the new context try { refCtx.bind(name, obj, inputAttrs); return; } catch (LdapReferralException re) { e = re; continue; } finally { // Make sure we close referral context refCtx.close(); } } } catch (IOException e) { NamingException e2 = new CommunicationException(e.getMessage()); e2.setRootCause(e); throw cont.fillInException(e2); } catch (NamingException e) { throw cont.fillInException(e); } } protected void c_rebind(Name name, Object obj, Continuation cont) throws NamingException { c_rebind(name, obj, null, cont); } /* * attrs == null * if obj is DirContext, attrs = obj.getAttributes(). * if attrs == null * leave any existing attributes alone * (set attrs = {objectclass=top} if object doesn't exist) * else * replace all existing attributes with attrs * if obj == null * just create entry using attrs * else * objAttrs = create attributes for representing obj * attrs += objAttrs * create entry using attrs */ protected void c_rebind(Name name, Object obj, Attributes attrs, Continuation cont) throws NamingException { cont.setError(this, name); Attributes inputAttrs = attrs; try { Attributes origAttrs = null; // Check if name is bound try { origAttrs = c_getAttributes(name, null, cont); } catch (NameNotFoundException e) {} // Name not bound, just add it if (origAttrs == null) { c_bind(name, obj, attrs, cont); return; }