1 /******************************************************************************
3 * Copyright (c) 2003 Novell Inc. www.novell.com
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the Software), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 *******************************************************************************/
24 // Novell.Directory.Ldap.LdapConnection.cs
27 // Sunil Kumar (Sunilk@novell.com)
29 // (C) 2003 Novell, Inc (http://www.novell.com)
33 using Novell.Directory.Ldap;
34 using Novell.Directory.Ldap.Asn1;
35 using Novell.Directory.Ldap.Rfc2251;
36 using Novell.Directory.Ldap.Utilclass;
38 using Mono.Security.Protocol.Tls;
41 using javax.security.auth;
42 using javax.security.auth.login;
45 using Novell.Directory.Ldap.Security;
46 using System.Collections.Specialized;
47 using System.Configuration;
49 using System.Security.Cryptography.X509Certificates;
51 namespace Novell.Directory.Ldap
54 /// <summary> The central class that encapsulates the connection
55 /// to a directory server through the Ldap protocol.
56 /// LdapConnection objects are used to perform common Ldap
57 /// operations such as search, modify and add.
59 /// In addition, LdapConnection objects allow you to bind to an
60 /// Ldap server, set connection and search constraints, and perform
61 /// several other tasks.
63 /// An LdapConnection object is not connected on
64 /// construction and can only be connected to one server at one
65 /// port. Multiple threads may share this single connection, typically
66 /// by cloning the connection object, one for each thread. An
67 /// application may have more than one LdapConnection object, connected
68 /// to the same or different directory servers.
72 public class LdapConnection : System.ICloneable
74 private void InitBlock()
76 defSearchCons = new LdapSearchConstraints();
77 responseCtlSemaphore = new System.Object();
79 /// <summary> Returns the protocol version uses to authenticate.
81 /// 0 is returned if no authentication has been performed.
84 /// <returns> The protol version used for authentication or 0
85 /// not authenticated.
88 virtual public int ProtocolVersion
92 BindProperties prop = conn.BindProperties;
97 return prop.ProtocolVersion;
101 /// <summary> Returns the distinguished name (DN) used for as the bind name during
102 /// the last successful bind operation. <code>null</code> is returned
103 /// if no authentication has been performed or if the bind resulted in
104 /// an aonymous connection.
107 /// <returns> The distinguished name if authenticated; otherwise, null.
110 virtual public System.String AuthenticationDN
114 BindProperties prop = conn.BindProperties;
123 return prop.AuthenticationDN;
127 /// <summary> Returns the method used to authenticate the connection. The return
128 /// value is one of the following:
131 /// <li>"none" indicates the connection is not authenticated.</li>
134 /// <li>"simple" indicates simple authentication was used or that a null
135 /// or empty authentication DN was specified.</li>
137 /// <li>"sasl" indicates that a SASL mechanism was used to authenticate</li>
141 /// <returns> The method used to authenticate the connection.
143 virtual public System.String AuthenticationMethod
147 BindProperties prop = conn.BindProperties;
152 return conn.BindProperties.AuthenticationMethod;
156 /// <summary> Returns the properties if any specified on binding with a
159 /// Null is returned if no authentication has been performed
160 /// or no authentication Map is present.
163 /// <returns> The bind properties Map Object used for SASL bind or null if
164 /// the connection is not present or not authenticated.
167 virtual public System.Collections.IDictionary SaslBindProperties
171 BindProperties prop = conn.BindProperties;
176 return conn.BindProperties.SaslBindProperties;
180 /// <summary> Returns the call back handler if any specified on binding with a
183 /// Null is returned if no authentication has been performed
184 /// or no authentication call back handler is present.
187 /// <returns> The call back handler used for SASL bind or null if the
188 /// object is not present or not authenticated.
191 virtual public System.Object SaslBindCallbackHandler
195 BindProperties prop = conn.BindProperties;
200 return conn.BindProperties.SaslCallbackHandler;
204 /// <summary> Returns a copy of the set of constraints associated with this
205 /// connection. These constraints apply to all operations performed
206 /// through this connection (unless a different set of constraints is
207 /// specified when calling an operation method).
210 /// <returns> The set of default contraints that apply to this connection.
213 /// <summary> Sets the constraints that apply to all operations performed through
214 /// this connection (unless a different set of constraints is specified
215 /// when calling an operation method). An LdapSearchConstraints object
216 /// which is passed to this method sets all constraints, while an
217 /// LdapConstraints object passed to this method sets only base constraints.
220 /// <param name="cons"> An LdapConstraints or LdapSearchConstraints Object
221 /// containing the contstraint values to set.
224 /// <seealso cref="Constraints()">
226 /// <seealso cref="SearchConstraints()">
228 virtual public LdapConstraints Constraints
232 return (LdapConstraints) (this.defSearchCons).Clone();
237 // Set all constraints, replace the object with a new one
238 if (value is LdapSearchConstraints)
240 defSearchCons = (LdapSearchConstraints) value.Clone();
244 // We set the constraints this way, so a thread doesn't get an
245 // conconsistant view of the referrals.
246 LdapSearchConstraints newCons = (LdapSearchConstraints) defSearchCons.Clone();
247 newCons.HopLimit = value.HopLimit;
248 newCons.TimeLimit = value.TimeLimit;
249 newCons.setReferralHandler(value.getReferralHandler());
250 newCons.ReferralFollowing = value.ReferralFollowing;
251 LdapControl[] lsc = value.getControls();
254 newCons.setControls(lsc);
256 System.Collections.Hashtable lp = newCons.Properties;
259 newCons.Properties = lp;
261 defSearchCons = newCons;
266 /// <summary> Returns the host name of the Ldap server to which the object is or
267 /// was last connected, in the format originally specified.
270 /// <returns> The host name of the Ldap server to which the object last
271 /// connected or null if the object has never connected.
274 virtual public System.String Host
282 /// <summary> Returns the port number of the Ldap server to which the object is or
283 /// was last connected.
286 /// <returns> The port number of the Ldap server to which the object last
287 /// connected or -1 if the object has never connected.
290 virtual public int Port
298 /// <summary> Returns a copy of the set of search constraints associated with this
299 /// connection. These constraints apply to search operations performed
300 /// through this connection (unless a different set of
301 /// constraints is specified when calling the search operation method).
304 /// <returns> The set of default search contraints that apply to
308 /// <seealso cref="Constraints">
310 /// <seealso cref="LdapSearchConstraints">
312 virtual public LdapSearchConstraints SearchConstraints
316 return (LdapSearchConstraints) this.defSearchCons.Clone();
322 ///<summary> Indicates whther the perform Secure Operation or not
326 /// True if SSL is on
327 /// False if its not on
329 public bool SecureSocketLayer
344 /// <summary> Indicates whether the object has authenticated to the connected Ldap
348 /// <returns> True if the object has authenticated; false if it has not
352 virtual public bool Bound
360 /// <summary> Indicates whether the connection represented by this object is open
364 /// <returns> True if connection is open; false if the connection is closed.
366 virtual public bool Connected
370 return conn.Connected;
375 /// <summary> Indicatates if the connection is protected by TLS.
378 /// <returns> If startTLS has completed this method returns true.
379 /// If stopTLS has completed or start tls failed, this method returns false.
381 /// <returns> True if the connection is protected by TLS.
384 virtual public bool TLS
394 /// <summary> Returns the Server Controls associated with the most recent response
395 /// to a synchronous request on this connection object, or null
396 /// if the latest response contained no Server Controls. The method
397 /// always returns null for asynchronous requests. For asynchronous
398 /// requests, the response controls are available in LdapMessage.
401 /// <returns> The server controls associated with the most recent response
402 /// to a synchronous request or null if the response contains no server
406 /// <seealso cref="LdapMessage.Controls">
408 virtual public LdapControl[] ResponseControls
412 if (responseCtls == null)
418 // We have to clone the control just in case
419 // we have two client threads that end up retreiving the
421 LdapControl[] clonedControl = new LdapControl[responseCtls.Length];
423 // Also note we synchronize access to the local response
424 // control object just in case another message containing controls
425 // comes in from the server while we are busy duplicating
427 lock (responseCtlSemaphore)
429 for (int i = 0; i < responseCtls.Length; i++)
431 clonedControl[i] = (LdapControl) (responseCtls[i]).Clone();
435 // Return the cloned copy. Note we have still left the
436 // control in the local responseCtls variable just in case
437 // somebody requests it again.
438 return clonedControl;
442 /// <summary> Return the Connection object associated with this LdapConnection
445 /// <returns> the Connection object
447 virtual internal Connection Connection
457 /// <summary> Return the Connection object name associated with this LdapConnection
460 /// <returns> the Connection object name
462 virtual internal System.String ConnectionName
472 private LdapSearchConstraints defSearchCons;
473 private LdapControl[] responseCtls = null;
475 // Synchronization Object used to synchronize access to responseCtls
476 private System.Object responseCtlSemaphore;
478 private Connection conn = null;
480 private static System.Object nameLock; // protect agentNum
481 private static int lConnNum = 0; // Debug, LdapConnection number
482 private System.String name; // String name for debug
484 /// <summary> Used with search to specify that the scope of entrys to search is to
485 /// search only the base obect.
489 public const int SCOPE_BASE = 0;
491 /// <summary> Used with search to specify that the scope of entrys to search is to
492 /// search only the immediate subordinates of the base obect.
496 public const int SCOPE_ONE = 1;
498 /// <summary> Used with search to specify that the scope of entrys to search is to
499 /// search the base object and all entries within its subtree.
503 public const int SCOPE_SUB = 2;
505 /// <summary> Used with search instead of an attribute list to indicate that no
506 /// attributes are to be returned.
510 public const System.String NO_ATTRS = "1.1";
512 /// <summary> Used with search instead of an attribute list to indicate that all
513 /// attributes are to be returned.
515 /// ALL_USER_ATTRS = "*"
517 public const System.String ALL_USER_ATTRS = "*";
519 /// <summary> Specifies the Ldapv3 protocol version when performing a bind operation.
521 /// Specifies Ldap version V3 of the protocol, and is specified
522 /// when performing bind operations.
523 /// You can use this identifier in the version parameter
524 /// of the bind method to specify an Ldapv3 bind.
525 /// Ldap_V3 is the default protocol version
530 public const int Ldap_V3 = 3;
532 /// <summary> The default port number for Ldap servers.
534 /// You can use this identifier to specify the port when establishing
535 /// a clear text connection to a server. This the default port.
537 /// DEFAULT_PORT = 389
540 public const int DEFAULT_PORT = 389;
543 /// <summary> The default SSL port number for Ldap servers.
545 /// DEFAULT_SSL_PORT = 636
547 /// You can use this identifier to specify the port when establishing
548 /// a an SSL connection to a server..
550 public const int DEFAULT_SSL_PORT = 636;
552 /// <summary> A string that can be passed in to the getProperty method.
554 /// Ldap_PROPERTY_SDK = "version.sdk"
556 /// You can use this string to request the version of the SDK.
558 public const System.String Ldap_PROPERTY_SDK = "version.sdk";
560 /// <summary> A string that can be passed in to the getProperty method.
562 /// Ldap_PROPERTY_PROTOCOL = "version.protocol"
564 /// You can use this string to request the version of the
567 public const System.String Ldap_PROPERTY_PROTOCOL = "version.protocol";
569 /// <summary> A string that can be passed in to the getProperty method.
571 /// Ldap_PROPERTY_SECURITY = "version.security"
573 /// You can use this string to request the type of security
576 public const System.String Ldap_PROPERTY_SECURITY = "version.security";
578 /// <summary> A string that corresponds to the server shutdown notification OID.
579 /// This notification may be used by the server to advise the client that
580 /// the server is about to close the connection due to an error
583 /// SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036"
585 public const System.String SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036";
587 /// <summary> The OID string that identifies a StartTLS request and response.</summary>
588 private const System.String START_TLS_OID = "1.3.6.1.4.1.1466.20037";
590 public event CertificateValidationCallback UserDefinedServerCertValidationDelegate
594 this.conn.OnCertificateValidation += value;
599 this.conn.OnCertificateValidation -= value;
607 /// <summary> Constructs a new LdapConnection object, which will use the supplied
608 /// class factory to construct a socket connection during
609 /// LdapConnection.connect method.
612 /// <param name="factory"> An object capable of producing a Socket.
615 public LdapConnection()
618 // Get a unique connection name for debug
619 conn = new Connection();
623 /* public LdapConnection(X509Certificate cert)
626 // Get a unique connection name for debug
627 conn = new Connection();
633 * The following are methods that affect the operation of
634 * LdapConnection, but are not Ldap requests.
637 /// <summary> Returns a copy of the object with a private context, but sharing the
638 /// network connection if there is one.
640 /// The network connection remains open until all clones have
641 /// disconnected or gone out of scope. Any connection opened after
642 /// cloning is private to the object making the connection.
644 /// The clone can issue requests and freely modify options and search
645 /// constraints, and , without affecting the source object or other clones.
646 /// If the clone disconnects or reconnects, it is completely dissociated
647 /// from the source object and other clones. Reauthenticating in a clone,
648 /// however, is a global operation which will affect the source object
649 /// and all associated clones, because it applies to the single shared
650 /// physical connection. Any request by an associated object after one
651 /// has reauthenticated will carry the new identity.
654 /// <returns> A of the object.
656 public System.Object Clone()
658 LdapConnection newClone;
659 System.Object newObj;
662 newObj = base.MemberwiseClone();
663 newClone = (LdapConnection) newObj;
665 catch (System.Exception ce)
667 throw new System.SystemException("Internal error, cannot create clone");
669 newClone.conn = conn; // same underlying connection
671 //now just duplicate the defSearchCons and responseCtls
672 if (defSearchCons != null)
674 newClone.defSearchCons = (LdapSearchConstraints) defSearchCons.Clone();
678 newClone.defSearchCons = null;
680 if (responseCtls != null)
682 newClone.responseCtls = new LdapControl[responseCtls.Length];
683 for (int i = 0; i < responseCtls.Length; i++)
685 newClone.responseCtls[i] = (LdapControl) responseCtls[i].Clone();
690 newClone.responseCtls = null;
692 conn.incrCloneCount(); // Increment the count of clones
696 /// <summary> Closes the connection, if open, and releases any other resources held
700 /// <exception> LdapException A general exception which includes an error
701 /// message and an Ldap error code.
704 /// <seealso cref="Disconnect">
708 // Disconnect did not come from user API call
709 Disconnect(defSearchCons, false);
713 /// <summary> Returns a property of a connection object.
716 /// <param name="name"> Name of the property to be returned.
718 /// The following read-only properties are available
719 /// for any given connection:
721 /// <li>Ldap_PROPERTY_SDK returns the version of this SDK,
722 /// as a Float data type.</li>
724 /// <li>Ldap_PROPERTY_PROTOCOL returns the highest supported version of
725 /// the Ldap protocol, as a Float data type.</li>
727 /// <li>Ldap_PROPERTY_SECURITY returns a comma-separated list of the
728 /// types of authentication supported, as a
732 /// A deep copy of the property is provided where applicable; a
733 /// client does not need to clone the object received.
736 /// <returns> The object associated with the requested property,
737 /// or null if the property is not defined.
740 /// <seealso cref="LdapConstraints.getProperty">
742 /// <seealso cref="Object">
744 public virtual System.Object getProperty(System.String name)
746 if (name.ToUpper().Equals(Ldap_PROPERTY_SDK.ToUpper()))
747 return Connection.sdk;
748 else if (name.ToUpper().Equals(Ldap_PROPERTY_PROTOCOL.ToUpper()))
749 return Connection.protocol;
750 else if (name.ToUpper().Equals(Ldap_PROPERTY_SECURITY.ToUpper()))
751 return Connection.security;
758 /// <summary> Registers an object to be notified on arrival of an unsolicited
759 /// message from a server.
761 /// An unsolicited message has the ID 0. A new thread is created and
762 /// the method "messageReceived" in each registered object is called in
766 /// <param name="listener"> An object to be notified on arrival of an
767 /// unsolicited message from a server. This object must
768 /// implement the LdapUnsolicitedNotificationListener interface.
771 public virtual void AddUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
773 if (listener != null)
774 conn.AddUnsolicitedNotificationListener(listener);
779 /// <summary> Deregisters an object so that it will no longer be notified on
780 /// arrival of an unsolicited message from a server. If the object is
781 /// null or was not previously registered for unsolicited notifications,
782 /// the method does nothing.
786 /// <param name="listener"> An object to no longer be notified on arrival of
787 /// an unsolicited message from a server.
790 public virtual void RemoveUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
793 if (listener != null)
794 conn.RemoveUnsolicitedNotificationListener(listener);
797 /// <summary> Starts Transport Layer Security (TLS) protocol on this connection
798 /// to enable session privacy.
800 /// This affects the LdapConnection object and all cloned objects. A
801 /// socket factory that implements LdapTLSSocketFactory must be set on the
805 /// <exception> LdapException Thrown if TLS cannot be started. If a
806 /// SocketFactory has been specified that does not implement
807 /// LdapTLSSocketFactory an LdapException is thrown.
811 public virtual void startTLS()
814 LdapMessage startTLS = MakeExtendedOperation(new LdapExtendedOperation(LdapConnection.START_TLS_OID, null), null);
816 int tlsID = startTLS.MessageID;
818 conn.acquireWriteSemaphore(tlsID);
821 if (!conn.areMessagesComplete())
823 throw new LdapLocalException(ExceptionMessages.OUTSTANDING_OPERATIONS, LdapException.OPERATIONS_ERROR);
825 // Stop reader when response to startTLS request received
826 conn.stopReaderOnReply(tlsID);
829 LdapResponseQueue queue = SendRequestToServer(startTLS, defSearchCons.TimeLimit, null, null);
831 LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
832 response.chkResultCode();
838 //Free this semaphore no matter what exceptions get thrown
840 conn.freeWriteSemaphore(tlsID);
845 /// <summary> Stops Transport Layer Security(TLS) on the LDAPConnection and reverts
846 /// back to an anonymous state.
848 /// @throws LDAPException This can occur for the following reasons:
850 /// <LI>StartTLS has not been called before stopTLS</LI>
851 /// <LI>There exists outstanding messages that have not received all
853 /// <LI>The sever was not able to support the operation</LI></UL>
855 /// <p>Note: The Sun and IBM implementions of JSSE do not currently allow
856 /// stopping TLS on an open Socket. In order to produce the same results
857 /// this method currently disconnects the socket and reconnects, giving
858 /// the application an anonymous connection to the server, as required
861 public virtual void stopTLS()
866 throw new LdapLocalException(ExceptionMessages.NO_STARTTLS, LdapException.OPERATIONS_ERROR);
869 int semaphoreID = conn.acquireWriteSemaphore();
872 if (!conn.areMessagesComplete())
874 throw new LdapLocalException(ExceptionMessages.OUTSTANDING_OPERATIONS, LdapException.OPERATIONS_ERROR);
876 //stopTLS stops and starts the reader thread for us.
881 conn.freeWriteSemaphore(semaphoreID);
883 /* Now that the TLS socket is closed, reset everything. This next
884 line is temporary until JSSE is fixed to properly handle TLS stop */
885 this.Connect(this.Host, this.Port);
891 //*************************************************************************
892 // Below are all of the Ldap protocol operation methods
893 //*************************************************************************
895 //*************************************************************************
897 //*************************************************************************
901 /// Notifies the server not to send additional results associated with
902 /// this LdapSearchResults object, and discards any results already
906 /// <param name="results"> An object returned from a search.
909 /// <exception> LdapException A general exception which includes an error
910 /// message and an Ldap error code.
912 public virtual void Abandon(LdapSearchResults results)
914 Abandon(results, defSearchCons);
920 /// Notifies the server not to send additional results associated with
921 /// this LdapSearchResults object, and discards any results already
925 /// <param name="results"> An object returned from a search.
928 /// <param name="cons"> The contraints specific to the operation.
931 /// <exception> LdapException A general exception which includes an error
932 /// message and an Ldap error code.
934 public virtual void Abandon(LdapSearchResults results, LdapConstraints cons)
941 /// Abandons an asynchronous operation.
944 /// <param name="id"> The ID of the asynchronous operation to abandon. The ID
945 /// can be obtained from the response queue for the
949 /// <exception> LdapException A general exception which includes an error
950 /// message and an Ldap error code.
952 public virtual void Abandon(int id)
954 Abandon(id, defSearchCons);
958 /// <summary> Abandons an asynchronous operation, using the specified
962 /// <param name="id">The ID of the asynchronous operation to abandon.
963 /// The ID can be obtained from the search
964 /// queue for the operation.
967 /// <param name="cons">The contraints specific to the operation.
970 /// <exception> LdapException A general exception which includes an error
971 /// message and an Ldap error code.
973 public virtual void Abandon(int id, LdapConstraints cons)
975 // We need to inform the Message Agent which owns this messageID to
976 // remove it from the queue.
979 MessageAgent agent = conn.getMessageAgent(id);
980 agent.Abandon(id, cons);
983 catch (System.FieldAccessException ex)
985 return ; // Ignore error
989 /// <summary> Abandons all outstanding operations managed by the queue.
991 /// All operations in progress, which are managed by the specified queue,
995 /// <param name="queue"> The queue returned from an asynchronous request.
996 /// All outstanding operations managed by the queue
997 /// are abandoned, and the queue is emptied.
1000 /// <exception> LdapException A general exception which includes an error
1001 /// message and an Ldap error code.
1003 public virtual void Abandon(LdapMessageQueue queue)
1005 Abandon(queue, defSearchCons);
1009 /// <summary> Abandons all outstanding operations managed by the queue.
1011 /// All operations in progress, which are managed by the specified
1012 /// queue, are abandoned.
1015 /// <param name="queue"> The queue returned from an asynchronous request.
1016 /// All outstanding operations managed by the queue
1017 /// are abandoned, and the queue is emptied.
1020 /// <param name="cons"> The contraints specific to the operation.
1023 /// <exception> LdapException A general exception which includes an error
1024 /// message and an Ldap error code.
1026 public virtual void Abandon(LdapMessageQueue queue, LdapConstraints cons)
1031 if (queue is LdapSearchQueue)
1033 agent = queue.MessageAgent;
1037 agent = queue.MessageAgent;
1039 int[] msgIds = agent.MessageIDs;
1040 for (int i = 0; i < msgIds.Length; i++)
1042 agent.Abandon(msgIds[i], cons);
1048 //*************************************************************************
1050 //*************************************************************************
1052 /// <summary> Synchronously adds an entry to the directory.
1055 /// <param name="entry"> LdapEntry object specifying the distinguished
1056 /// name and attributes of the new entry.
1059 /// <exception> LdapException A general exception which includes an error
1060 /// message and an Ldap error code.
1062 public virtual void Add(LdapEntry entry)
1064 Add(entry, defSearchCons);
1069 /// Synchronously adds an entry to the directory, using the specified
1073 /// <param name="entry"> LdapEntry object specifying the distinguished
1074 /// name and attributes of the new entry.
1077 /// <param name="cons"> Constraints specific to the operation.
1080 /// <exception> LdapException A general exception which includes an error
1081 /// message and an Ldap error code.
1084 public virtual void Add(LdapEntry entry, LdapConstraints cons)
1086 LdapResponseQueue queue = Add(entry, null, cons);
1088 // Get a handle to the add response
1089 LdapResponse addResponse = (LdapResponse) (queue.getResponse());
1091 // Set local copy of responseControls synchronously if there were any
1092 lock (responseCtlSemaphore)
1094 responseCtls = addResponse.Controls;
1096 chkResultCode(queue, cons, addResponse);
1100 /// <summary> Asynchronously adds an entry to the directory.
1103 /// <param name="entry"> LdapEntry object specifying the distinguished
1104 /// name and attributes of the new entry.
1107 /// <param name="queue"> Handler for messages returned from a server in
1108 /// response to this request. If it is null, a
1109 /// queue object is created internally.
1112 /// <exception> LdapException A general exception which includes an error
1113 /// message and an Ldap error code.
1115 public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue)
1117 return Add(entry, queue, defSearchCons);
1120 /// <summary> Asynchronously adds an entry to the directory, using the specified
1124 /// <param name="entry"> LdapEntry object specifying the distinguished
1125 /// name and attributes of the new entry.
1128 /// <param name="queue"> Handler for messages returned from a server in
1129 /// response to this request. If it is null, a
1130 /// queue object is created internally.
1133 /// <param name="cons"> Constraints specific to the operation.
1136 /// <exception> LdapException A general exception which includes an error
1137 /// message and an Ldap error code.
1139 public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue, LdapConstraints cons)
1142 cons = defSearchCons;
1144 // error check the parameters
1147 throw new System.ArgumentException("The LdapEntry parameter" + " cannot be null");
1149 if ((System.Object) entry.DN == null)
1151 throw new System.ArgumentException("The DN value must be present" + " in the LdapEntry object");
1154 LdapMessage msg = new LdapAddRequest(entry, cons.getControls());
1156 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1159 //*************************************************************************
1161 //*************************************************************************
1163 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1164 /// currently connected to) as an Ldapv3 bind, using the specified name and
1167 /// If the object has been disconnected from an Ldap server,
1168 /// this method attempts to reconnect to the server. If the object
1169 /// has already authenticated, the old authentication is discarded.
1172 /// <param name="dn"> If non-null and non-empty, specifies that the
1173 /// connection and all operations through it should
1174 /// be authenticated with dn as the distinguished
1178 /// <param name="passwd"> If non-null and non-empty, specifies that the
1179 /// connection and all operations through it should
1180 /// be authenticated with dn as the distinguished
1181 /// name and passwd as password.
1183 /// Note: the application should use care in the use
1184 /// of String password objects. These are long lived
1185 /// objects, and may expose a security risk, especially
1186 /// in objects that are serialized. The LdapConnection
1187 /// keeps no long lived instances of these objects.
1190 /// <exception> LdapException A general exception which includes an error
1191 /// message and an Ldap error code.
1194 public virtual void Bind(System.String dn, System.String passwd)
1196 Bind(dn, passwd, AuthenticationTypes.None);
1200 public virtual void Bind(System.String dn, System.String passwd, AuthenticationTypes authenticationTypes)
1203 if (authenticationTypes != AuthenticationTypes.None &&
1204 authenticationTypes != AuthenticationTypes.ServerBind &&
1205 authenticationTypes != AuthenticationTypes.Anonymous)
1206 BindSecure(dn, passwd, authenticationTypes);
1209 Bind(Ldap_V3, dn, passwd, defSearchCons);
1214 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1215 /// currently connected to) using the specified name, password,
1216 /// and Ldap version.
1218 /// If the object has been disconnected from an Ldap server,
1219 /// this method attempts to reconnect to the server. If the object
1220 /// has already authenticated, the old authentication is discarded.
1223 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1224 /// Ldap_V2 is not supported.
1227 /// <param name="dn"> If non-null and non-empty, specifies that the
1228 /// connection and all operations through it should
1229 /// be authenticated with dn as the distinguished
1233 /// <param name="passwd"> If non-null and non-empty, specifies that the
1234 /// connection and all operations through it should
1235 /// be authenticated with dn as the distinguished
1236 /// name and passwd as password.
1238 /// Note: the application should use care in the use
1239 /// of String password objects. These are long lived
1240 /// objects, and may expose a security risk, especially
1241 /// in objects that are serialized. The LdapConnection
1242 /// keeps no long lived instances of these objects.
1245 /// <exception> LdapException A general exception which includes an error
1246 /// message and an Ldap error code.
1249 public virtual void Bind(int version, System.String dn, System.String passwd)
1251 Bind(version, dn, passwd, defSearchCons);
1255 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1256 /// currently connected to) as an Ldapv3 bind, using the specified name,
1257 /// password, and constraints.
1259 /// If the object has been disconnected from an Ldap server,
1260 /// this method attempts to reconnect to the server. If the object
1261 /// has already authenticated, the old authentication is discarded.
1264 /// <param name="dn"> If non-null and non-empty, specifies that the
1265 /// connection and all operations through it should
1266 /// be authenticated with dn as the distinguished
1270 /// <param name="passwd"> If non-null and non-empty, specifies that the
1271 /// connection and all operations through it should
1272 /// be authenticated with dn as the distinguished
1273 /// name and passwd as password.
1274 /// Note: the application should use care in the use
1275 /// of String password objects. These are long lived
1276 /// objects, and may expose a security risk, especially
1277 /// in objects that are serialized. The LdapConnection
1278 /// keeps no long lived instances of these objects.
1281 /// <param name="cons"> Constraints specific to the operation.
1284 /// <exception> LdapException A general exception which includes an error
1285 /// message and an Ldap error code.
1288 public virtual void Bind(System.String dn, System.String passwd, LdapConstraints cons)
1290 Bind(Ldap_V3, dn, passwd, cons);
1294 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1295 /// currently connected to) using the specified name, password, Ldap version,
1296 /// and constraints.
1298 /// If the object has been disconnected from an Ldap server,
1299 /// this method attempts to reconnect to the server. If the object
1300 /// has already authenticated, the old authentication is discarded.
1303 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1304 /// Ldap_V2 is not supported.
1307 /// <param name="dn"> If non-null and non-empty, specifies that the
1308 /// connection and all operations through it should
1309 /// be authenticated with dn as the distinguished
1313 /// <param name="passwd"> If non-null and non-empty, specifies that the
1314 /// connection and all operations through it should
1315 /// be authenticated with dn as the distinguished
1316 /// name and passwd as password.
1318 /// Note: the application should use care in the use
1319 /// of String password objects. These are long lived
1320 /// objects, and may expose a security risk, especially
1321 /// in objects that are serialized. The LdapConnection
1322 /// keeps no long lived instances of these objects.
1325 /// <param name="cons"> The constraints specific to the operation.
1328 /// <exception> LdapException A general exception which includes an error
1329 /// message and an Ldap error code.
1332 public virtual void Bind(int version, System.String dn, System.String passwd, LdapConstraints cons)
1335 if ((System.Object) passwd != null)
1339 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
1340 byte[] ibytes = encoder.GetBytes(passwd);
1341 pw=SupportClass.ToSByteArray(ibytes);
1343 // pw = passwd.getBytes("UTF8");
1344 passwd = null; // Keep no reference to String object
1346 catch (System.IO.IOException ex)
1348 passwd = null; // Keep no reference to String object
1349 throw new System.SystemException(ex.ToString());
1352 Bind(version, dn, pw, cons);
1356 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1357 /// currently connected to) using the specified name, password,
1358 /// and Ldap version.
1360 /// If the object has been disconnected from an Ldap server,
1361 /// this method attempts to reconnect to the server. If the object
1362 /// has already authenticated, the old authentication is discarded.
1365 /// <param name="version"> The version of the Ldap protocol to use
1366 /// in the bind, use Ldap_V3. Ldap_V2 is not supported.
1369 /// <param name="dn"> If non-null and non-empty, specifies that the
1370 /// connection and all operations through it should
1371 /// be authenticated with dn as the distinguished
1375 /// <param name="passwd"> If non-null and non-empty, specifies that the
1376 /// connection and all operations through it should
1377 /// be authenticated with dn as the distinguished
1378 /// name and passwd as password.
1381 /// <exception> LdapException A general exception which includes an error
1382 /// message and an Ldap error code.
1384 [CLSCompliantAttribute(false)]
1385 public virtual void Bind(int version, System.String dn, sbyte[] passwd)
1387 Bind(version, dn, passwd, defSearchCons);
1392 /// Synchronously authenticates to the Ldap server (that the object is
1393 /// currently connected to) using the specified name, password, Ldap version,
1394 /// and constraints.
1396 /// If the object has been disconnected from an Ldap server,
1397 /// this method attempts to reconnect to the server. If the object
1398 /// has already authenticated, the old authentication is discarded.
1401 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1402 /// Ldap_V2 is not supported.
1405 /// <param name="dn"> If non-null and non-empty, specifies that the
1406 /// connection and all operations through it should
1407 /// be authenticated with dn as the distinguished
1411 /// <param name="passwd"> If non-null and non-empty, specifies that the
1412 /// connection and all operations through it should
1413 /// be authenticated with dn as the distinguished
1414 /// name and passwd as password.
1417 /// <param name="cons"> The constraints specific to the operation.
1420 /// <exception> LdapException A general exception which includes an error
1421 /// message and an Ldap error code.
1423 [CLSCompliantAttribute(false)]
1424 public virtual void Bind(int version, System.String dn, sbyte[] passwd, LdapConstraints cons)
1426 LdapResponseQueue queue = Bind(version, dn, passwd, null, cons, null);
1427 LdapResponse res = (LdapResponse) queue.getResponse();
1430 // Set local copy of responseControls synchronously if any
1431 lock (responseCtlSemaphore)
1433 responseCtls = res.Controls;
1436 chkResultCode(queue, cons, res);
1441 /// <summary> Asynchronously authenticates to the Ldap server (that the object is
1442 /// currently connected to) using the specified name, password, Ldap
1443 /// version, and queue.
1445 /// If the object has been disconnected from an Ldap server,
1446 /// this method attempts to reconnect to the server. If the object
1447 /// has already authenticated, the old authentication is discarded.
1451 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1452 /// Ldap_V2 is not supported.
1455 /// <param name="dn"> If non-null and non-empty, specifies that the
1456 /// connection and all operations through it should
1457 /// be authenticated with dn as the distinguished
1461 /// <param name="passwd"> If non-null and non-empty, specifies that the
1462 /// connection and all operations through it should
1463 /// be authenticated with dn as the distinguished
1464 /// name and passwd as password.
1467 /// <param name="queue"> Handler for messages returned from a server in
1468 /// response to this request. If it is null, a
1469 /// queue object is created internally.
1472 /// <exception> LdapException A general exception which includes an error
1473 /// message and an Ldap error code.
1475 [CLSCompliantAttribute(false)]
1476 public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue)
1478 return Bind(version, dn, passwd, queue, defSearchCons, null);
1481 /// <summary> Asynchronously authenticates to the Ldap server (that the object is
1482 /// currently connected to) using the specified name, password, Ldap
1483 /// version, queue, and constraints.
1485 /// If the object has been disconnected from an Ldap server,
1486 /// this method attempts to reconnect to the server. If the object
1487 /// had already authenticated, the old authentication is discarded.
1490 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1491 /// Ldap_V2 is not supported.
1494 /// <param name="dn"> If non-null and non-empty, specifies that the
1495 /// connection and all operations through it should
1496 /// be authenticated with dn as the distinguished
1500 /// <param name="passwd"> If non-null and non-empty, specifies that the
1501 /// connection and all operations through it should
1502 /// be authenticated with dn as the distinguished
1503 /// name and passwd as password.
1506 /// <param name="queue"> Handler for messages returned from a server in
1507 /// response to this request. If it is null, a
1508 /// queue object is created internally.
1511 /// <param name="cons"> Constraints specific to the operation.
1514 /// <exception> LdapException A general exception which includes an error
1515 /// message and an Ldap error code.
1517 [CLSCompliantAttribute(false)]
1518 public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue, LdapConstraints cons, string mech)
1521 BindProperties bindProps;
1523 cons = defSearchCons;
1525 if ((System.Object) dn == null)
1535 passwd = new sbyte[]{};
1537 bool anonymous = false;
1538 if (passwd.Length == 0)
1540 anonymous = true; // anonymous, passwd length zero with simple bind
1541 dn = ""; // set to null if anonymous
1547 msg = new LdapBindRequest(version, "", mech, passwd, cons.getControls());
1550 msg = new LdapBindRequest(version, dn, passwd, cons.getControls());
1552 msgId = msg.MessageID;
1553 bindProps = new BindProperties(version, dn, "simple", anonymous, null, null);
1555 // For bind requests, if not connected, attempt to reconnect
1556 if (!conn.Connected)
1558 if ((System.Object) conn.Host != null)
1560 conn.connect(conn.Host, conn.Port);
1564 throw new LdapException(ExceptionMessages.CONNECTION_IMPOSSIBLE, LdapException.CONNECT_ERROR, null);
1569 // stopping reader to enable stream replace after secure binding is complete, see Connection.ReplaceStreams()
1572 if (conn.BindSemIdClear) {
1573 // need to acquire a semaphore only if bindSemId is clear
1574 // because if we receive SASL_BIND_IN_PROGRESS the semaphore is not
1575 // released when the response is queued
1576 conn.acquireWriteSemaphore(msgId);
1577 conn.BindSemId = msgId;
1579 conn.stopReaderOnReply(msgId);
1583 // The semaphore is released when the bind response is queued.
1584 conn.acquireWriteSemaphore(msgId);
1586 return SendRequestToServer(msg, cons.TimeLimit, queue, bindProps);
1590 private void BindSecure(System.String username, System.String password, AuthenticationTypes authenticationTypes)
1592 if ((authenticationTypes & AuthenticationTypes.Secure) != 0) {
1593 LoginContext loginContext = null;
1595 if (username != null && password != null) {
1596 AuthenticationCallbackHandler callbackHandler = new AuthenticationCallbackHandler (username,password);
1597 loginContext = new LoginContext (SecurityAppName, callbackHandler);
1600 loginContext = new LoginContext (SecurityAppName);
1602 loginContext.login ();
1604 catch (Exception e) {
1605 throw new LdapException ("Failed to create login security context", 80, "", e);
1608 Krb5Helper krb5Helper = null;
1610 krb5Helper = new Krb5Helper ("ldap@" + conn.Host, username, loginContext.getSubject (), authenticationTypes, SecurityMech);
1613 loginContext.logout();
1615 sbyte [] token = krb5Helper.ExchangeTokens (Krb5Helper.EmptyToken);
1618 LdapResponseQueue queue = Bind(LdapConnection.Ldap_V3, username, token, null, null, AuthenticationMech);
1619 LdapResponse res = (LdapResponse) queue.getResponse ();
1620 if (res.ResultCode != LdapException.SASL_BIND_IN_PROGRESS &&
1621 res.ResultCode != LdapException.SUCCESS) {
1622 krb5Helper.Dispose();
1623 throw new LdapException(ExceptionMessages.CONNECTION_ERROR, res.ResultCode, res.ErrorMessage);
1625 Asn1OctetString serverSaslCreds = ((RfcBindResponse)res.Asn1Object.Response).ServerSaslCreds;
1626 token = serverSaslCreds != null ? serverSaslCreds.byteValue () : null;
1628 token = krb5Helper.ExchangeTokens(token == null ? Krb5Helper.EmptyToken : token);
1630 if (res.ResultCode != LdapException.SASL_BIND_IN_PROGRESS)
1633 conn.ReplaceStreams (conn.InputStream,conn.OutputStream);
1636 System.IO.Stream inStream = conn.InputStream;
1637 System.IO.Stream newIn = new SecureStream (inStream, krb5Helper);
1638 System.IO.Stream outStream = conn.OutputStream;
1639 System.IO.Stream newOut = new SecureStream (outStream, krb5Helper);
1640 conn.ReplaceStreams (newIn,newOut);
1644 static string SecurityMech
1647 string securityMech = null;
1648 NameValueCollection config = (NameValueCollection) ConfigurationSettings.GetConfig ("System.DirectoryServices/Settings");
1650 securityMech = config ["securitymech"];
1652 if (securityMech == null)
1653 throw new ArgumentException("Security mechanism id not found in application settings");
1655 return securityMech;
1659 static string SecurityAppName
1662 string securityAppName = null;
1663 NameValueCollection config = (NameValueCollection) ConfigurationSettings.GetConfig ("System.DirectoryServices/Settings");
1665 securityAppName = config ["securityappname"];
1667 if (securityAppName == null)
1668 throw new ArgumentException("Application section name not found in application settings");
1670 return securityAppName;
1674 static string AuthenticationMech
1677 string authenticationMech = null;
1678 NameValueCollection config = (NameValueCollection) ConfigurationSettings.GetConfig ("System.DirectoryServices/Settings");
1680 authenticationMech = config ["authenticationmech"];
1682 if (authenticationMech == null)
1683 throw new ArgumentException("Authentication mechanism not found in application settings");
1685 return authenticationMech;
1690 //*************************************************************************
1692 //*************************************************************************
1695 /// Synchronously checks to see if an entry contains an attribute
1696 /// with a specified value.
1699 /// <param name="dn"> The distinguished name of the entry to use in the
1703 /// <param name="attr"> The attribute to compare against the entry. The
1704 /// method checks to see if the entry has an
1705 /// attribute with the same name and value as this
1709 /// <returns> True if the entry has the value,
1710 /// and false if the entry does not
1711 /// have the value or the attribute.
1714 /// <exception> LdapException A general exception which includes an error
1715 /// message and an Ldap error code.
1717 public virtual bool Compare(System.String dn, LdapAttribute attr)
1719 return Compare(dn, attr, defSearchCons);
1723 /// Synchronously checks to see if an entry contains an attribute with a
1724 /// specified value, using the specified constraints.
1727 /// <param name="dn"> The distinguished name of the entry to use in the
1731 /// <param name="attr"> The attribute to compare against the entry. The
1732 /// method checks to see if the entry has an
1733 /// attribute with the same name and value as this
1737 /// <param name="cons"> Constraints specific to the operation.
1740 /// <returns> True if the entry has the value,
1741 /// and false if the entry does not
1742 /// have the value or the attribute.
1745 /// <exception> LdapException A general exception which includes an error
1746 /// message and an Ldap error code.
1748 public virtual bool Compare(System.String dn, LdapAttribute attr, LdapConstraints cons)
1752 LdapResponseQueue queue = Compare(dn, attr, null, cons);
1754 LdapResponse res = (LdapResponse) queue.getResponse();
1756 // Set local copy of responseControls synchronously - if there were any
1757 lock (responseCtlSemaphore)
1759 responseCtls = res.Controls;
1762 if (res.ResultCode == LdapException.COMPARE_TRUE)
1766 else if (res.ResultCode == LdapException.COMPARE_FALSE)
1772 chkResultCode(queue, cons, res);
1777 /// <summary> Asynchronously compares an attribute value with one in the directory,
1778 /// using the specified queue.
1780 /// Please note that a successful completion of this command results in
1781 /// one of two status codes: LdapException.COMPARE_TRUE if the entry
1782 /// has the value, and LdapException.COMPARE_FALSE if the entry
1783 /// does not have the value or the attribute.
1786 /// <param name="dn"> The distinguished name of the entry containing an
1787 /// attribute to compare.
1790 /// <param name="attr"> An attribute to compare.
1793 /// <param name="queue"> The queue for messages returned from a server in
1794 /// response to this request. If it is null, a
1795 /// queue object is created internally.
1798 /// <exception> LdapException A general exception which includes an error
1799 /// message and an Ldap error code.
1802 /// <seealso cref="LdapException.COMPARE_TRUE">
1804 /// <seealso cref="LdapException.COMPARE_FALSE">
1806 public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue)
1808 return Compare(dn, attr, queue, defSearchCons);
1811 /// <summary> Asynchronously compares an attribute value with one in the directory,
1812 /// using the specified queue and contraints.
1814 /// Please note that a successful completion of this command results in
1815 /// one of two status codes: LdapException.COMPARE_TRUE if the entry
1816 /// has the value, and LdapException.COMPARE_FALSE if the entry
1817 /// does not have the value or the attribute.
1820 /// <param name="dn"> The distinguished name of the entry containing an
1821 /// attribute to compare.
1824 /// <param name="attr"> An attribute to compare.
1827 /// <param name="queue"> Handler for messages returned from a server in
1828 /// response to this request. If it is null, a
1829 /// queue object is created internally.
1832 /// <param name="cons"> Constraints specific to the operation.
1835 /// <exception> LdapException A general exception which includes an error
1836 /// message and an Ldap error code.
1839 /// <seealso cref="LdapException.COMPARE_TRUE">
1841 /// <seealso cref="LdapException.COMPARE_FALSE">
1843 public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue, LdapConstraints cons)
1845 if (attr.size() != 1)
1847 throw new System.ArgumentException("compare: Exactly one value " + "must be present in the LdapAttribute");
1850 if ((System.Object) dn == null)
1852 // Invalid parameter
1853 throw new System.ArgumentException("compare: DN cannot be null");
1857 cons = defSearchCons;
1859 LdapMessage msg = new LdapCompareRequest(dn, attr.Name, attr.ByteValue, cons.getControls());
1861 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1864 //*************************************************************************
1866 //*************************************************************************
1869 /// Connects to the specified host and port.
1871 /// If this LdapConnection object represents an open connection, the
1872 /// connection is closed first before the new connection is opened.
1873 /// At this point, there is no authentication, and any operations are
1874 /// conducted as an anonymous client.
1876 /// When more than one host name is specified, each host is contacted
1877 /// in turn until a connection can be established.
1880 /// <param name="host">A host name or a dotted string representing the IP address
1881 /// of a host running an Ldap server. It may also
1882 /// contain a list of host names, space-delimited. Each host
1883 /// name can include a trailing colon and port number.
1886 /// <param name="port">The TCP or UDP port number to connect to or contact.
1887 /// The default Ldap port is 389. The port parameter is
1888 /// ignored for any host hame which includes a colon and
1892 /// <exception> LdapException A general exception which includes an error
1893 /// message and an Ldap error code.
1896 public virtual void Connect(System.String host, int port)
1898 // connect doesn't affect other clones
1899 // If not a clone, destroys old connection.
1900 // Step through the space-delimited list
1901 SupportClass.Tokenizer hostList = new SupportClass.Tokenizer(host, " ");
1902 System.String address = null;
1905 int colonIndex; //after the colon is the port
1906 while (hostList.HasMoreTokens())
1910 specifiedPort = port;
1911 address = hostList.NextToken();
1912 colonIndex = address.IndexOf((System.Char) ':');
1913 if (colonIndex != - 1 && colonIndex + 1 != address.Length)
1915 //parse Port out of address
1918 specifiedPort = System.Int32.Parse(address.Substring(colonIndex + 1));
1919 address = address.Substring(0, (colonIndex) - (0));
1921 catch (System.Exception e)
1923 throw new System.ArgumentException(ExceptionMessages.INVALID_ADDRESS);
1926 // This may return a different conn object
1927 // Disassociate this clone with the underlying connection.
1928 conn = conn.destroyClone(true);
1929 conn.connect(address, specifiedPort);
1932 catch (LdapException LE)
1934 if (!hostList.HasMoreTokens())
1941 //*************************************************************************
1943 //*************************************************************************
1946 /// Synchronously deletes the entry with the specified distinguished name
1947 /// from the directory.
1949 /// Note: A Delete operation will not remove an entry that contains
1950 /// subordinate entries, nor will it dereference alias entries.
1953 /// <param name="dn"> The distinguished name of the entry to delete.
1956 /// <exception> LdapException A general exception which includes an error
1957 /// message and an Ldap error code.
1959 public virtual void Delete(System.String dn)
1961 Delete(dn, defSearchCons);
1966 /// <summary> Synchronously deletes the entry with the specified distinguished name
1967 /// from the directory, using the specified constraints.
1969 /// Note: A Delete operation will not remove an entry that contains
1970 /// subordinate entries, nor will it dereference alias entries.
1973 /// <param name="dn"> The distinguished name of the entry to delete.
1976 /// <param name="cons"> Constraints specific to the operation.
1979 /// <exception> LdapException A general exception which includes an error
1980 /// message and an Ldap error code.
1982 public virtual void Delete(System.String dn, LdapConstraints cons)
1984 LdapResponseQueue queue = Delete(dn, null, cons);
1986 // Get a handle to the delete response
1987 LdapResponse deleteResponse = (LdapResponse) (queue.getResponse());
1989 // Set local copy of responseControls synchronously - if there were any
1990 lock (responseCtlSemaphore)
1992 responseCtls = deleteResponse.Controls;
1994 chkResultCode(queue, cons, deleteResponse);
1998 /// <summary> Asynchronously deletes the entry with the specified distinguished name
1999 /// from the directory and returns the results to the specified queue.
2001 /// Note: A Delete operation will not remove an entry that contains
2002 /// subordinate entries, nor will it dereference alias entries.
2005 /// <param name="dn"> The distinguished name of the entry to modify.
2008 /// <param name="queue"> The queue for messages returned from a server in
2009 /// response to this request. If it is null, a
2010 /// queue object is created internally.
2013 /// <exception> LdapException A general exception which includes an error
2014 /// message and an Ldap error code.
2017 public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue)
2019 return Delete(dn, queue, defSearchCons);
2022 /// <summary> Asynchronously deletes the entry with the specified distinguished name
2023 /// from the directory, using the specified contraints and queue.
2025 /// Note: A Delete operation will not remove an entry that contains
2026 /// subordinate entries, nor will it dereference alias entries.
2029 /// <param name="dn"> The distinguished name of the entry to delete.
2032 /// <param name="queue"> The queue for messages returned from a server in
2033 /// response to this request. If it is null, a
2034 /// queue object is created internally.
2037 /// <param name="cons"> The constraints specific to the operation.
2040 /// <exception> LdapException A general exception which includes an error
2041 /// message and an Ldap error code.
2044 public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue, LdapConstraints cons)
2046 if ((System.Object) dn == null)
2048 // Invalid DN parameter
2049 throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
2053 cons = defSearchCons;
2055 LdapMessage msg = new LdapDeleteRequest(dn, cons.getControls());
2057 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2060 //*************************************************************************
2061 // disconnect method
2062 //*************************************************************************
2065 /// Synchronously disconnects from the Ldap server.
2067 /// Before the object can perform Ldap operations again, it must
2068 /// reconnect to the server by calling connect.
2070 /// The disconnect method abandons any outstanding requests, issues an
2071 /// unbind request to the server, and then closes the socket.
2074 /// <exception> LdapException A general exception which includes an error
2075 /// message and an Ldap error code.
2078 public virtual void Disconnect()
2080 // disconnect from API call
2081 Disconnect(defSearchCons, true);
2085 /// <summary> Synchronously disconnects from the Ldap server.
2087 /// Before the object can perform Ldap operations again, it must
2088 /// reconnect to the server by calling connect.
2090 /// The disconnect method abandons any outstanding requests, issues an
2091 /// unbind request to the server, and then closes the socket.
2094 /// <param name="cons">LDPConstraints to be set with the unbind request
2097 /// <exception> LdapException A general exception which includes an error
2098 /// message and an Ldap error code.
2100 public virtual void Disconnect(LdapConstraints cons)
2102 // disconnect from API call
2103 Disconnect(cons, true);
2107 /// <summary> Synchronously disconnect from the server
2110 /// <param name="how">true if application call disconnect API, false if finalize.
2112 private void Disconnect(LdapConstraints cons, bool how)
2114 // disconnect doesn't affect other clones
2115 // If not a clone, distroys connection
2116 conn = conn.destroyClone(how);
2120 //*************************************************************************
2121 // extendedOperation methods
2122 //*************************************************************************
2124 /// <summary> Provides a synchronous means to access extended, non-mandatory
2125 /// operations offered by a particular Ldapv3 compliant server.
2128 /// <param name="op"> The object which contains (1) an identifier of an extended
2129 /// operation which should be recognized by the particular Ldap
2130 /// server this client is connected to and (2)
2131 /// an operation-specific sequence of octet strings
2132 /// or BER-encoded values.
2135 /// <returns> An operation-specific object, containing an ID and either an octet
2136 /// string or BER-encoded values.
2139 /// <exception> LdapException A general exception which includes an error
2140 /// message and an Ldap error code.
2142 public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op)
2144 return ExtendedOperation(op, defSearchCons);
2148 * Synchronous Ldap extended request with SearchConstraints
2152 /// Provides a synchronous means to access extended, non-mandatory
2153 /// operations offered by a particular Ldapv3 compliant server.
2156 /// <param name="op"> The object which contains (1) an identifier of an extended
2157 /// operation which should be recognized by the particular Ldap
2158 /// server this client is connected to and (2) an
2159 /// operation-specific sequence of octet strings
2160 /// or BER-encoded values.
2163 /// <param name="cons">The constraints specific to the operation.
2166 /// <returns> An operation-specific object, containing an ID and either an
2167 /// octet string or BER-encoded values.
2170 /// <exception> LdapException A general exception which includes an error
2171 /// message and an Ldap error code.
2174 public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
2177 // Call asynchronous API and get back handler to reponse queue
2178 LdapResponseQueue queue = ExtendedOperation(op, cons, null);
2179 LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
2181 // Set local copy of responseControls synchronously - if there were any
2182 lock (responseCtlSemaphore)
2184 responseCtls = response.Controls;
2187 chkResultCode(queue, cons, response);
2193 * Asynchronous Ldap extended request
2196 /// <summary> Provides an asynchronous means to access extended, non-mandatory
2197 /// operations offered by a particular Ldapv3 compliant server.
2200 /// <param name="op"> The object which contains (1) an identifier of an extended
2201 /// operation which should be recognized by the particular Ldap
2202 /// server this client is connected to and (2) an
2203 /// operation-specific sequence of octet strings
2204 /// or BER-encoded values.
2207 /// <param name="queue"> The queue for messages returned from a server in
2208 /// response to this request. If it is null, a queue
2209 /// object is created internally.
2212 /// <returns> An operation-specific object, containing an ID and either an octet
2213 /// string or BER-encoded values.
2216 /// <exception> LdapException A general exception which includes an error
2217 /// message and an Ldap error code.
2220 public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapResponseQueue queue)
2223 return ExtendedOperation(op, defSearchCons, queue);
2228 * Asynchronous Ldap extended request with SearchConstraints
2231 /// <summary> Provides an asynchronous means to access extended, non-mandatory
2232 /// operations offered by a particular Ldapv3 compliant server.
2235 /// <param name="op"> The object which contains (1) an identifier of an extended
2236 /// operation which should be recognized by the particular Ldap
2237 /// server this client is connected to and (2) an operation-
2238 /// specific sequence of octet strings or BER-encoded values.
2241 /// <param name="queue"> The queue for messages returned from a server in
2242 /// response to this request. If it is null, a queue
2243 /// object is created internally.
2246 /// <param name="cons"> The constraints specific to this operation.
2249 /// <returns> An operation-specific object, containing an ID and either an
2250 /// octet string or BER-encoded values.
2253 /// <exception> LdapException A general exception which includes an error
2254 /// message and an Ldap error code.
2257 public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons, LdapResponseQueue queue)
2259 // Use default constraints if none-specified
2261 cons = defSearchCons;
2262 LdapMessage msg = MakeExtendedOperation(op, cons);
2263 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2266 /// <summary> Formulates the extended operation, constraints into an
2267 /// LdapMessage and returns the LdapMessage. This is used by
2268 /// extendedOperation and startTLS which needs the LdapMessage to
2269 /// get the MessageID.
2271 protected internal virtual LdapMessage MakeExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
2273 // Use default constraints if none-specified
2275 cons = defSearchCons;
2277 // error check the parameters
2278 if ((System.Object) op.getID() == null)
2280 // Invalid extended operation parameter, no OID specified
2281 throw new System.ArgumentException(ExceptionMessages.OP_PARAM_ERROR);
2284 return new LdapExtendedRequest(op, cons.getControls());
2287 //*************************************************************************
2288 // getResponseControls method
2289 //*************************************************************************
2291 //*************************************************************************
2293 //*************************************************************************
2295 /// <summary> Synchronously makes a single change to an existing entry in the
2298 /// For example, this modify method changes the value of an attribute,
2299 /// adds a new attribute value, or removes an existing attribute value.
2301 /// The LdapModification object specifies both the change to be made and
2302 /// the LdapAttribute value to be changed.
2304 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2305 /// it is indeterminate whether or not the server made the modification.
2308 /// <param name="dn"> The distinguished name of the entry to modify.
2311 /// <param name="mod"> A single change to be made to the entry.
2314 /// <exception> LdapException A general exception which includes an error
2315 /// message and an Ldap error code.
2317 public virtual void Modify(System.String dn, LdapModification mod)
2319 Modify(dn, mod, defSearchCons);
2324 /// Synchronously makes a single change to an existing entry in the
2325 /// directory, using the specified constraints.
2327 /// For example, this modify method changes the value of an attribute,
2328 /// adds a new attribute value, or removes an existing attribute value.
2330 /// The LdapModification object specifies both the change to be
2331 /// made and the LdapAttribute value to be changed.
2333 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2334 /// it is indeterminate whether or not the server made the modification.
2337 /// <param name="dn"> The distinguished name of the entry to modify.
2340 /// <param name="mod"> A single change to be made to the entry.
2343 /// <param name="cons"> The constraints specific to the operation.
2346 /// <exception> LdapException A general exception which includes an error
2347 /// message and an Ldap error code.
2349 public virtual void Modify(System.String dn, LdapModification mod, LdapConstraints cons)
2351 LdapModification[] mods = new LdapModification[1];
2353 Modify(dn, mods, cons);
2358 /// Synchronously makes a set of changes to an existing entry in the
2361 /// For example, this modify method changes attribute values, adds
2362 /// new attribute values, or removes existing attribute values.
2364 /// Because the server applies all changes in an LdapModification array
2365 /// atomically, the application can expect that no changes
2366 /// have been performed if an error is returned.
2367 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2368 /// it is indeterminate whether or not the server made the modifications.
2371 /// <param name="dn"> Distinguished name of the entry to modify.
2374 /// <param name="mods"> The changes to be made to the entry.
2377 /// <exception> LdapException A general exception which includes an error
2378 /// message and an Ldap error code.
2380 public virtual void Modify(System.String dn, LdapModification[] mods)
2382 Modify(dn, mods, defSearchCons);
2386 /// <summary> Synchronously makes a set of changes to an existing entry in the
2387 /// directory, using the specified constraints.
2389 /// For example, this modify method changes attribute values, adds new
2390 /// attribute values, or removes existing attribute values.
2392 /// Because the server applies all changes in an LdapModification array
2393 /// atomically, the application can expect that no changes
2394 /// have been performed if an error is returned.
2395 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2396 /// it is indeterminate whether or not the server made the modifications.
2399 /// <param name="dn"> The distinguished name of the entry to modify.
2402 /// <param name="mods"> The changes to be made to the entry.
2405 /// <param name="cons"> The constraints specific to the operation.
2408 /// <exception> LdapException A general exception which includes an
2409 /// error message and an Ldap error code.
2411 public virtual void Modify(System.String dn, LdapModification[] mods, LdapConstraints cons)
2413 LdapResponseQueue queue = Modify(dn, mods, null, cons);
2415 // Get a handle to the modify response
2416 LdapResponse modifyResponse = (LdapResponse) (queue.getResponse());
2418 // Set local copy of responseControls synchronously - if there were any
2419 lock (responseCtlSemaphore)
2421 responseCtls = modifyResponse.Controls;
2424 chkResultCode(queue, cons, modifyResponse);
2429 /// <summary> Asynchronously makes a single change to an existing entry in the
2432 /// For example, this modify method can change the value of an attribute,
2433 /// add a new attribute value, or remove an existing attribute value.
2435 /// The LdapModification object specifies both the change to be made and
2436 /// the LdapAttribute value to be changed.
2438 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2439 /// it is indeterminate whether or not the server made the modification.
2442 /// <param name="dn"> Distinguished name of the entry to modify.
2445 /// <param name="mod"> A single change to be made to the entry.
2448 /// <param name="queue"> Handler for messages returned from a server in
2449 /// response to this request. If it is null, a
2450 /// queue object is created internally.
2453 /// <exception> LdapException A general exception which includes an error
2454 /// message and an Ldap error code.
2456 public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue)
2458 return Modify(dn, mod, queue, defSearchCons);
2461 /// <summary> Asynchronously makes a single change to an existing entry in the
2462 /// directory, using the specified constraints and queue.
2464 /// For example, this modify method can change the value of an attribute,
2465 /// add a new attribute value, or remove an existing attribute value.
2467 /// The LdapModification object specifies both the change to be made
2468 /// and the LdapAttribute value to be changed.
2470 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2471 /// it is indeterminate whether or not the server made the modification.
2474 /// <param name="dn"> Distinguished name of the entry to modify.
2477 /// <param name="mod"> A single change to be made to the entry.
2480 /// <param name="queue"> Handler for messages returned from a server in
2481 /// response to this request. If it is null, a
2482 /// queue object is created internally.
2485 /// <param name="cons"> Constraints specific to the operation.
2488 /// <exception> LdapException A general exception which includes an error
2489 /// message and an Ldap error code.
2491 public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue, LdapConstraints cons)
2493 LdapModification[] mods = new LdapModification[1];
2495 return Modify(dn, mods, queue, cons);
2498 /// <summary> Asynchronously makes a set of changes to an existing entry in the
2501 /// For example, this modify method can change attribute values, add new
2502 /// attribute values, or remove existing attribute values.
2504 /// Because the server applies all changes in an LdapModification array
2505 /// atomically, the application can expect that no changes
2506 /// have been performed if an error is returned.
2507 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2508 /// it is indeterminate whether or not the server made the modifications.
2511 /// <param name="dn"> The distinguished name of the entry to modify.
2514 /// <param name="mods"> The changes to be made to the entry.
2517 /// <param name="queue"> The queue for messages returned from a server in
2518 /// response to this request. If it is null, a
2519 /// queue object is created internally.
2522 /// <exception> LdapException A general exception which includes an error
2523 /// message and an Ldap error code.
2525 public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue)
2527 return Modify(dn, mods, queue, defSearchCons);
2530 /// <summary> Asynchronously makes a set of changes to an existing entry in the
2531 /// directory, using the specified constraints and queue.
2533 /// For example, this modify method can change attribute values, add new
2534 /// attribute values, or remove existing attribute values.
2536 /// Because the server applies all changes in an LdapModification array
2537 /// atomically, the application can expect that no changes
2538 /// have been performed if an error is returned.
2539 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2540 /// it is indeterminate whether or not the server made the modifications.
2543 /// <param name="dn"> The distinguished name of the entry to modify.
2546 /// <param name="mods"> The changes to be made to the entry.
2549 /// <param name="queue"> The queue for messages returned from a server in
2550 /// response to this request. If it is null, a
2551 /// queue object is created internally.
2554 /// <param name="cons"> Constraints specific to the operation.
2557 /// <exception> LdapException A general exception which includes an error
2558 /// message and an Ldap error code.
2560 public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue, LdapConstraints cons)
2562 if ((System.Object) dn == null)
2564 // Invalid DN parameter
2565 throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
2569 cons = defSearchCons;
2571 LdapMessage msg = new LdapModifyRequest(dn, mods, cons.getControls());
2573 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2576 //*************************************************************************
2578 //*************************************************************************
2580 /// <summary> Synchronously reads the entry for the specified distiguished name (DN)
2581 /// and retrieves all attributes for the entry.
2584 /// <param name="dn"> The distinguished name of the entry to retrieve.
2587 /// <returns> the LdapEntry read from the server.
2590 /// <exception> LdapException if the object was not found
2592 public virtual LdapEntry Read(System.String dn)
2594 return Read(dn, defSearchCons);
2599 /// Synchronously reads the entry for the specified distiguished name (DN),
2600 /// using the specified constraints, and retrieves all attributes for the
2604 /// <param name="dn"> The distinguished name of the entry to retrieve.
2607 /// <param name="cons"> The constraints specific to the operation.
2610 /// <returns> the LdapEntry read from the server
2613 /// <exception> LdapException if the object was not found
2615 public virtual LdapEntry Read(System.String dn, LdapSearchConstraints cons)
2617 return Read(dn, null, cons);
2621 /// Synchronously reads the entry for the specified distinguished name (DN)
2622 /// and retrieves only the specified attributes from the entry.
2625 /// <param name="dn"> The distinguished name of the entry to retrieve.
2628 /// <param name="attrs"> The names of the attributes to retrieve.
2631 /// <returns> the LdapEntry read from the server
2634 /// <exception> LdapException if the object was not found
2636 public virtual LdapEntry Read(System.String dn, System.String[] attrs)
2638 return Read(dn, attrs, defSearchCons);
2641 /// <summary> Synchronously reads the entry for the specified distinguished name (DN),
2642 /// using the specified constraints, and retrieves only the specified
2643 /// attributes from the entry.
2646 /// <param name="dn"> The distinguished name of the entry to retrieve.
2649 /// <param name="attrs"> The names of the attributes to retrieve.
2652 /// <param name="cons"> The constraints specific to the operation.
2655 /// <returns> the LdapEntry read from the server
2658 /// <exception> LdapException if the object was not found
2660 public virtual LdapEntry Read(System.String dn, System.String[] attrs, LdapSearchConstraints cons)
2662 LdapSearchResults sr = Search(dn, SCOPE_BASE, null, attrs, false, cons);
2664 LdapEntry ret = null;
2670 // "Read response is ambiguous, multiple entries returned"
2671 throw new LdapLocalException(ExceptionMessages.READ_MULTIPLE, LdapException.AMBIGUOUS_RESPONSE);
2677 /// <summary> Synchronously reads the entry specified by the Ldap URL.
2679 /// When this read method is called, a new connection is created
2680 /// automatically, using the host and port specified in the URL. After
2681 /// finding the entry, the method closes the connection (in other words,
2682 /// it disconnects from the Ldap server).
2684 /// If the URL specifies a filter and scope, they are not used. Of the
2685 /// information specified in the URL, this method only uses the Ldap host
2686 /// name and port number, the base distinguished name (DN), and the list
2687 /// of attributes to return.
2690 /// <param name="toGet"> Ldap URL specifying the entry to read.
2693 /// <returns> The entry specified by the base DN.
2696 /// <exception> LdapException if the object was not found
2698 public static LdapEntry Read(LdapUrl toGet)
2700 LdapConnection lconn = new LdapConnection();
2701 lconn.Connect(toGet.Host, toGet.Port);
2702 LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray);
2707 /// <summary> Synchronously reads the entry specified by the Ldap URL, using the
2708 /// specified constraints.
2710 /// When this method is called, a new connection is created
2711 /// automatically, using the host and port specified in the URL. After
2712 /// finding the entry, the method closes the connection (in other words,
2713 /// it disconnects from the Ldap server).
2715 /// If the URL specifies a filter and scope, they are not used. Of the
2716 /// information specified in the URL, this method only uses the Ldap host
2717 /// name and port number, the base distinguished name (DN), and the list
2718 /// of attributes to return.
2721 /// <returns> The entry specified by the base DN.
2724 /// <param name="toGet"> Ldap URL specifying the entry to read.
2727 /// <param name="cons"> Constraints specific to the operation.
2730 /// <exception> LdapException if the object was not found
2732 public static LdapEntry Read(LdapUrl toGet, LdapSearchConstraints cons)
2734 LdapConnection lconn = new LdapConnection();
2735 lconn.Connect(toGet.Host, toGet.Port);
2736 LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray, cons);
2741 //*************************************************************************
2743 //*************************************************************************
2746 /// Synchronously renames an existing entry in the directory.
2749 /// <param name="dn"> The current distinguished name of the entry.
2752 /// <param name="newRdn"> The new relative distinguished name for the entry.
2755 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2756 /// attribute value. If false, the old name is
2757 /// retained as an attribute value.
2760 /// <exception> LdapException A general exception which includes an error
2761 /// message and an Ldap error code.
2763 public virtual void Rename(System.String dn, System.String newRdn, bool deleteOldRdn)
2765 Rename(dn, newRdn, deleteOldRdn, defSearchCons);
2770 /// Synchronously renames an existing entry in the directory, using the
2771 /// specified constraints.
2774 /// <param name="dn"> The current distinguished name of the entry.
2777 /// <param name="newRdn"> The new relative distinguished name for the entry.
2780 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2781 /// attribute value. If false, the old name is
2782 /// retained as an attribute value.
2785 /// <param name="cons"> The constraints specific to the operation.
2788 /// <exception> LdapException A general exception which includes an error
2789 /// message and an Ldap error code.
2791 public virtual void Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapConstraints cons)
2793 // null for newParentdn means that this is originating as an Ldapv2 call
2794 Rename(dn, newRdn, null, deleteOldRdn, cons);
2798 /// <summary> Synchronously renames an existing entry in the directory, possibly
2799 /// repositioning the entry in the directory tree.
2802 /// <param name="dn"> The current distinguished name of the entry.
2805 /// <param name="newRdn"> The new relative distinguished name for the entry.
2808 /// <param name="newParentdn"> The distinguished name of an existing entry which
2809 /// is to be the new parent of the entry.
2812 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2813 /// attribute value. If false, the old name is
2814 /// retained as an attribute value.
2817 /// <exception> LdapException A general exception which includes an error
2818 /// message and an Ldap error code.
2820 public virtual void Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn)
2822 Rename(dn, newRdn, newParentdn, deleteOldRdn, defSearchCons);
2827 /// Synchronously renames an existing entry in the directory, using the
2828 /// specified constraints and possibly repositioning the entry in the
2832 /// <param name="dn"> The current distinguished name of the entry.
2835 /// <param name="newRdn"> The new relative distinguished name for the entry.
2838 /// <param name="newParentdn"> The distinguished name of an existing entry which
2839 /// is to be the new parent of the entry.
2842 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2843 /// attribute value. If false, the old name is
2844 /// retained as an attribute value.
2847 /// <param name="cons"> The constraints specific to the operation.
2850 /// <exception> LdapException A general exception which includes an error
2851 /// message and an Ldap error code.
2853 public virtual void Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapConstraints cons)
2855 LdapResponseQueue queue = Rename(dn, newRdn, newParentdn, deleteOldRdn, null, cons);
2857 // Get a handle to the rename response
2858 LdapResponse renameResponse = (LdapResponse) (queue.getResponse());
2860 // Set local copy of responseControls synchronously - if there were any
2861 lock (responseCtlSemaphore)
2863 responseCtls = renameResponse.Controls;
2866 chkResultCode(queue, cons, renameResponse);
2874 /// <summary> Asynchronously renames an existing entry in the directory.
2877 /// <param name="dn"> The current distinguished name of the entry.
2880 /// <param name="newRdn"> The new relative distinguished name for the entry.
2883 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2884 /// attribute value. If false, the old name is
2885 /// retained as an attribute value.
2888 /// <param name="queue"> The queue for messages returned from a server in
2889 /// response to this request. If it is null, a
2890 /// queue object is created internally.
2893 /// <exception> LdapException A general exception which includes an error
2894 /// message and an Ldap error code.
2896 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue)
2898 return Rename(dn, newRdn, deleteOldRdn, queue, defSearchCons);
2901 /// <summary> Asynchronously renames an existing entry in the directory, using the
2902 /// specified constraints.
2905 /// <param name="dn"> The current distinguished name of the entry.
2908 /// <param name="newRdn"> The new relative distinguished name for the entry.
2911 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2912 /// attribute value. If false, the old name is
2913 /// retained as an attribute value.
2916 /// <param name="queue"> The queue for messages returned from a server in
2917 /// response to this request. If it is null, a
2918 /// queue object is created internally.
2921 /// <param name="cons"> The constraints specific to the operation.
2924 /// <exception> LdapException A general exception which includes an error
2925 /// message and an Ldap error code.
2927 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
2929 return Rename(dn, newRdn, null, deleteOldRdn, queue, cons);
2932 /// <summary> Asynchronously renames an existing entry in the directory, possibly
2933 /// repositioning the entry in the directory.
2936 /// <param name="dn"> The current distinguished name of the entry.
2939 /// <param name="newRdn"> The new relative distinguished name for the entry.
2942 /// <param name="newParentdn"> The distinguished name of an existing entry which
2943 /// is to be the new parent of the entry.
2946 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2947 /// attribute value. If false, the old name is
2948 /// retained as an attribute value.
2951 /// <param name="queue"> The queue for messages returned from a server in
2952 /// response to this request. If it is null, a
2953 /// queue object is created internally.
2956 /// <exception> LdapException A general exception which includes an error
2957 /// message and an Ldap error code.
2959 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue)
2961 return Rename(dn, newRdn, newParentdn, deleteOldRdn, queue, defSearchCons);
2964 /// <summary> Asynchronously renames an existing entry in the directory, using the
2965 /// specified constraints and possibily repositioning the entry in the
2969 /// <param name="dn"> The current distinguished name of the entry.
2972 /// <param name="newRdn"> The new relative distinguished name for the entry.
2975 /// <param name="newParentdn"> The distinguished name of an existing entry which
2976 /// is to be the new parent of the entry.
2979 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2980 /// attribute value. If false, the old name is
2981 /// retained as an attribute value.
2984 /// <param name="queue"> The queue for messages returned from a server in
2985 /// response to this request. If it is null, a
2986 /// queue object is created internally.
2989 /// <param name="cons"> The constraints specific to the operation.
2992 /// <exception> LdapException A general exception which includes an error
2993 /// message and an Ldap error code.
2995 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
2997 if ((System.Object) dn == null || (System.Object) newRdn == null)
2999 // Invalid DN or RDN parameter
3000 throw new System.ArgumentException(ExceptionMessages.RDN_PARAM_ERROR);
3004 cons = defSearchCons;
3006 LdapMessage msg = new LdapModifyDNRequest(dn, newRdn, newParentdn, deleteOldRdn, cons.getControls());
3008 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
3011 //*************************************************************************
3013 //*************************************************************************
3016 /// Synchronously performs the search specified by the parameters.
3019 /// <param name="base"> The base distinguished name to search from.
3022 /// <param name="scope"> The scope of the entries to search. The following
3023 /// are the valid options:
3025 /// <li>SCOPE_BASE - searches only the base DN</li>
3027 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
3029 /// <li>SCOPE_SUB - searches the base DN and all entries
3030 /// within its subtree</li>
3033 /// <param name="filter"> Search filter specifying the search criteria.
3036 /// <param name="attrs"> Names of attributes to retrieve.
3039 /// <param name="typesOnly"> If true, returns the names but not the values of
3040 /// the attributes found. If false, returns the
3041 /// names and values for attributes found.
3044 /// <exception> LdapException A general exception which includes an error
3045 /// message and an Ldap error code.
3047 public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly)
3049 return Search(base_Renamed, scope, filter, attrs, typesOnly, defSearchCons);
3053 /// Synchronously performs the search specified by the parameters,
3054 /// using the specified search constraints (such as the
3055 /// maximum number of entries to find or the maximum time to wait for
3056 /// search results).
3058 /// As part of the search constraints, the method allows specifying
3059 /// whether or not the results are to be delivered all at once or in
3060 /// smaller batches. If specified that the results are to be delivered in
3061 /// smaller batches, each iteration blocks only until the next batch of
3062 /// results is returned.
3065 /// <param name="base"> The base distinguished name to search from.
3068 /// <param name="scope"> The scope of the entries to search. The following
3069 /// are the valid options:
3071 /// <li>SCOPE_BASE - searches only the base DN</li>
3073 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
3075 /// <li>SCOPE_SUB - searches the base DN and all entries
3076 /// within its subtree</li>
3079 /// <param name="filter"> The search filter specifying the search criteria.
3082 /// <param name="attrs"> The names of attributes to retrieve.
3085 /// <param name="typesOnly"> If true, returns the names but not the values of
3086 /// the attributes found. If false, returns the
3087 /// names and values for attributes found.
3090 /// <param name="cons"> The constraints specific to the search.
3093 /// <exception> LdapException A general exception which includes an error
3094 /// message and an Ldap error code.
3096 public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchConstraints cons)
3098 LdapSearchQueue queue = Search(base_Renamed, scope, filter, attrs, typesOnly, null, cons);
3101 cons = defSearchCons;
3102 return new LdapSearchResults(this, queue, cons);
3105 /// <summary> Asynchronously performs the search specified by the parameters.
3108 /// <param name="base"> The base distinguished name to search from.
3111 /// <param name="scope"> The scope of the entries to search. The following
3112 /// are the valid options:
3114 /// <li>SCOPE_BASE - searches only the base DN</li>
3116 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
3118 /// <li>SCOPE_SUB - searches the base DN and all entries
3119 /// within its subtree</li>
3122 /// <param name="filter"> Search filter specifying the search criteria.
3125 /// <param name="attrs"> Names of attributes to retrieve.
3128 /// <param name="typesOnly"> If true, returns the names but not the values of
3129 /// the attributes found. If false, returns the
3130 /// names and values for attributes found.
3133 /// <param name="queue"> Handler for messages returned from a server in
3134 /// response to this request. If it is null, a
3135 /// queue object is created internally.
3138 /// <exception> LdapException A general exception which includes an error
3139 /// message and an Ldap error code.
3141 public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue)
3143 return Search(base_Renamed, scope, filter, attrs, typesOnly, queue, defSearchCons);
3146 /// <summary> Asynchronously performs the search specified by the parameters,
3147 /// also allowing specification of constraints for the search (such
3148 /// as the maximum number of entries to find or the maximum time to
3149 /// wait for search results).
3152 /// <param name="base"> The base distinguished name to search from.
3155 /// <param name="scope"> The scope of the entries to search. The following
3156 /// are the valid options:
3158 /// <li>SCOPE_BASE - searches only the base DN</li>
3160 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
3162 /// <li>SCOPE_SUB - searches the base DN and all entries
3163 /// within its subtree</li>
3166 /// <param name="filter"> The search filter specifying the search criteria.
3169 /// <param name="attrs"> The names of attributes to retrieve.
3172 /// <param name="typesOnly"> If true, returns the names but not the values of
3173 /// the attributes found. If false, returns the
3174 /// names and values for attributes found.
3177 /// <param name="queue"> The queue for messages returned from a server in
3178 /// response to this request. If it is null, a
3179 /// queue object is created internally.
3182 /// <param name="cons"> The constraints specific to the search.
3185 /// <exception> LdapException A general exception which includes an error
3186 /// message and an Ldap error code.
3188 public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue, LdapSearchConstraints cons)
3190 if ((System.Object) filter == null)
3192 filter = "objectclass=*";
3195 cons = defSearchCons;
3197 LdapMessage msg = new LdapSearchRequest(base_Renamed, scope, filter, attrs, cons.Dereference, cons.MaxResults, cons.ServerTimeLimit, typesOnly, cons.getControls());
3199 LdapSearchQueue myqueue = queue;
3200 if (myqueue == null)
3202 agent = new MessageAgent();
3203 myqueue = new LdapSearchQueue(agent);
3207 agent = queue.MessageAgent;
3212 agent.sendMessage(conn, msg, cons.TimeLimit, myqueue, null);
3214 catch (LdapException lex)
3225 /// <summary> Synchronously performs the search specified by the Ldap URL, returning
3226 /// an enumerable LdapSearchResults object.
3229 /// <param name="toGet">The Ldap URL specifying the entry to read.
3232 /// <exception> LdapException A general exception which includes an error
3233 /// message and an Ldap error code.
3235 public static LdapSearchResults Search(LdapUrl toGet)
3237 // Get a clone of default search constraints, method alters batchSize
3238 return Search(toGet, null);
3245 /// <summary> Synchronously perfoms the search specified by the Ldap URL, using
3246 /// the specified search constraints (such as the maximum number of
3247 /// entries to find or the maximum time to wait for search results).
3249 /// When this method is called, a new connection is created
3250 /// automatically, using the host and port specified in the URL. After
3251 /// all search results have been received from the server, the method
3252 /// closes the connection (in other words, it disconnects from the Ldap
3255 /// As part of the search constraints, a choice can be made as to whether
3256 /// to have the results delivered all at once or in smaller batches. If
3257 /// the results are to be delivered in smaller batches, each iteration
3258 /// blocks only until the next batch of results is returned.
3262 /// <param name="toGet"> Ldap URL specifying the entry to read.
3265 /// <param name="cons"> The constraints specific to the search.
3268 /// <exception> LdapException A general exception which includes an error
3269 /// message and an Ldap error code.
3271 public static LdapSearchResults Search(LdapUrl toGet, LdapSearchConstraints cons)
3273 LdapConnection lconn = new LdapConnection();
3274 lconn.Connect(toGet.Host, toGet.Port);
3277 // This is a clone, so we already have our own copy
3278 cons = lconn.SearchConstraints;
3282 // get our own copy of user's constraints because we modify it
3283 cons = (LdapSearchConstraints) cons.Clone();
3285 cons.BatchSize = 0; // Must wait until all results arrive
3286 LdapSearchResults toReturn = lconn.Search(toGet.getDN(), toGet.Scope, toGet.Filter, toGet.AttributeArray, false, cons);
3291 /// <summary> Sends an Ldap request to a directory server.
3293 /// The specified the Ldap request is sent to the directory server
3294 /// associated with this connection using default constraints. An Ldap
3295 /// request object is a subclass {@link LdapMessage} with the operation
3296 /// type set to one of the request types. You can build a request by using
3297 /// the request classes found in this package
3299 /// You should note that, since Ldap requests sent to the server
3300 /// using sendRequest are asynchronous, automatic referral following
3301 /// does not apply to these requests.
3304 /// <param name="request">The Ldap request to send to the directory server.
3306 /// <param name="queue"> The queue for messages returned from a server in
3307 /// response to this request. If it is null, a
3308 /// queue object is created internally.
3310 /// <exception> LdapException A general exception which includes an error
3311 /// message and an Ldap error code.
3314 /// <seealso cref="LdapMessage.Type">
3316 /// <seealso cref="RfcLdapMessage.isRequest">
3318 public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue)
3320 return SendRequest(request, queue, null);
3323 /// <summary> Sends an Ldap request to a directory server.
3325 /// The specified the Ldap request is sent to the directory server
3326 /// associated with this connection. An Ldap request object is an
3327 /// {@link LdapMessage} with the operation type set to one of the request
3328 /// types. You can build a request by using the request classes found in this
3331 /// You should note that, since Ldap requests sent to the server
3332 /// using sendRequest are asynchronous, automatic referral following
3333 /// does not apply to these requests.
3336 /// <param name="request">The Ldap request to send to the directory server.
3338 /// <param name="queue"> The queue for messages returned from a server in
3339 /// response to this request. If it is null, a
3340 /// queue object is created internally.
3342 /// <param name="cons"> The constraints that apply to this request
3344 /// <exception> LdapException A general exception which includes an error
3345 /// message and an Ldap error code.
3348 /// <seealso cref="LdapMessage.Type">
3350 /// <seealso cref="RfcLdapMessage.isRequest">
3352 public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue, LdapConstraints cons)
3356 if (!request.Request)
3358 throw new System.SystemException("Object is not a request message");
3363 cons = defSearchCons;
3366 // Get the correct queue for a search request
3368 LdapMessageQueue myqueue = queue;
3369 if (myqueue == null)
3371 agent = new MessageAgent();
3372 if (request.Type == LdapMessage.SEARCH_REQUEST)
3374 myqueue = new LdapSearchQueue(agent);
3378 myqueue = new LdapResponseQueue(agent);
3383 if (request.Type == LdapMessage.SEARCH_REQUEST)
3385 agent = queue.MessageAgent;
3389 agent = queue.MessageAgent;
3395 agent.sendMessage(conn, request, cons.TimeLimit, myqueue, null);
3397 catch (LdapException lex)
3404 //*************************************************************************
3406 //*************************************************************************
3408 /// <summary> Locates the appropriate message agent and sends
3409 /// the Ldap request to a directory server.
3412 /// <param name="msg">the message to send
3415 /// <param name="timeout">the timeout value
3418 /// <param name="queue">the response queue or null
3421 /// <returns> the LdapResponseQueue for this request
3424 /// <exception> LdapException A general exception which includes an error
3425 /// message and an Ldap error code.
3427 private LdapResponseQueue SendRequestToServer(LdapMessage msg, int timeout, LdapResponseQueue queue, BindProperties bindProps)
3432 agent = new MessageAgent();
3433 queue = new LdapResponseQueue(agent);
3437 agent = queue.MessageAgent;
3440 agent.sendMessage(conn, msg, timeout, queue, bindProps);
3444 /// <summary> get an LdapConnection object so that we can follow a referral.
3445 /// This function is never called if cons.getReferralFollowing() returns
3449 /// <param name="referrals">the array of referral strings
3453 /// <returns> The referralInfo object
3456 /// <exception> LdapReferralException A general exception which includes
3457 /// an error message and an Ldap error code.
3459 private ReferralInfo getReferralConnection(System.String[] referrals)
3461 ReferralInfo refInfo = null;
3462 System.Exception ex = null;
3463 LdapConnection rconn = null;
3464 LdapReferralHandler rh = defSearchCons.getReferralHandler();
3466 // Check if we use LdapRebind to get authentication credentials
3467 if ((rh == null) || (rh is LdapAuthHandler))
3469 for (i = 0; i < referrals.Length; i++)
3471 // dn, pw are null in the default case (anonymous bind)
3472 System.String dn = null;
3476 rconn = new LdapConnection();
3477 rconn.Constraints = defSearchCons;
3478 LdapUrl url = new LdapUrl(referrals[i]);
3479 rconn.Connect(url.Host, url.Port);
3482 if (rh is LdapAuthHandler)
3484 // Get application supplied dn and pw
3485 LdapAuthProvider ap = ((LdapAuthHandler) rh).getAuthProvider(url.Host, url.Port);
3490 rconn.Bind(Ldap_V3, dn, pw);
3492 refInfo = new ReferralInfo(rconn, referrals, url);
3493 // Indicate this connection created to follow referral
3494 rconn.Connection.ActiveReferral = refInfo;
3497 catch (System.Exception lex)
3507 catch (LdapException e)
3515 // Check if application gets connection and does bind
3518 // rh instanceof LdapBind
3521 rconn = ((LdapBindHandler) rh).Bind(referrals, this);
3524 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR);
3525 rex.setReferrals(referrals);
3528 // Figure out which Url belongs to the connection
3529 for (int idx = 0; idx < referrals.Length; idx++)
3533 LdapUrl url = new LdapUrl(referrals[idx]);
3534 if (url.Host.ToUpper().Equals(rconn.Host.ToUpper()) && (url.Port == rconn.Port))
3536 refInfo = new ReferralInfo(rconn, referrals, url);
3540 catch (System.Exception e)
3545 if (refInfo == null)
3547 // Could not match LdapBind.bind() connecction with URL list
3548 ex = new LdapLocalException(ExceptionMessages.REFERRAL_BIND_MATCH, LdapException.CONNECT_ERROR);
3551 catch (System.Exception lex)
3559 // Could not connect to any server, throw an exception
3560 LdapException ldapex;
3561 if (ex is LdapReferralException)
3563 throw (LdapReferralException) ex;
3565 else if (ex is LdapException)
3567 ldapex = (LdapException) ex;
3571 ldapex = new LdapLocalException(ExceptionMessages.SERVER_CONNECT_ERROR, new System.Object[]{conn.Host}, LdapException.CONNECT_ERROR, ex);
3573 // Error attempting to follow a referral
3574 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ldapex);
3575 rex.setReferrals(referrals);
3576 // Use last URL string for the failed referral
3577 rex.FailedReferral = referrals[referrals.Length - 1];
3581 // We now have an authenticated connection
3582 // to be used to follow the referral.
3586 /// <summary> Check the result code and throw an exception if needed.
3588 /// If referral following is enabled, checks if we need to
3589 /// follow a referral
3592 /// <param name="queue">- the message queue of the current response
3595 /// <param name="cons">- the constraints that apply to the request
3598 /// <param name="response">- the LdapResponse to check
3600 private void chkResultCode(LdapMessageQueue queue, LdapConstraints cons, LdapResponse response)
3602 if ((response.ResultCode == LdapException.REFERRAL) && cons.ReferralFollowing)
3604 // Perform referral following and return
3605 System.Collections.ArrayList refConn = null;
3608 chaseReferral(queue, cons, response, response.Referrals, 0, false, null);
3612 releaseReferralConnections(refConn);
3617 // Throws exception for non success result
3618 response.chkResultCode();
3623 /// <summary> Follow referrals if necessary referral following enabled.
3624 /// This function is called only by synchronous requests.
3625 /// Search responses come here only if referral following is
3626 /// enabled and if we are processing a SearchResultReference
3627 /// or a Response with a status of REFERRAL, i.e. we are
3628 /// going to follow a referral.
3630 /// This functions recursively follows a referral until a result
3631 /// is returned or until the hop limit is reached.
3634 /// <param name="queue">The LdapResponseQueue for this request
3637 /// <param name="cons">The constraints that apply to the request
3640 /// <param name="msg">The referral or search reference response message
3643 /// <param name="initialReferrals">The referral array returned from the
3644 /// initial request.
3647 /// <param name="hopCount">the number of hops already used while
3648 /// following this referral
3651 /// <param name="searchReference">true if the message is a search reference
3654 /// <param name="connectionList">An optional array list used to store
3655 /// the LdapConnection objects used in following the referral.
3658 /// <returns> The array list used to store the all LdapConnection objects
3659 /// used in following the referral. The list will be empty
3660 /// if there were none.
3663 /// <exception> LdapException A general exception which includes an error
3664 /// message and an Ldap error code.
3667 internal virtual System.Collections.ArrayList chaseReferral(LdapMessageQueue queue, LdapConstraints cons, LdapMessage msg, System.String[] initialReferrals, int hopCount, bool searchReference, System.Collections.ArrayList connectionList)
3669 System.Collections.ArrayList connList = connectionList;
3670 LdapConnection rconn = null; // new conn for following referral
3671 ReferralInfo rinfo = null; // referral info
3672 LdapMessage origMsg;
3674 // Get a place to store new connections
3675 if (connList == null)
3677 connList = new System.Collections.ArrayList(cons.HopLimit);
3679 // Following referrals or search reference
3680 System.String[] refs; // referral list
3681 if (initialReferrals != null)
3683 // Search continuation reference from a search request
3684 refs = initialReferrals;
3685 origMsg = msg.RequestingMessage;
3689 // Not a search request
3690 LdapResponse resp = (LdapResponse) queue.getResponse();
3691 if (resp.ResultCode != LdapException.REFERRAL)
3693 // Not referral result,throw Exception if nonzero result
3694 resp.chkResultCode();
3697 // We have a referral response
3698 refs = resp.Referrals;
3699 origMsg = resp.RequestingMessage;
3701 LdapUrl refUrl; // referral represented as URL
3704 // increment hop count, check max hops
3705 if (hopCount++ > cons.HopLimit)
3707 throw new LdapLocalException("Max hops exceeded", LdapException.REFERRAL_LIMIT_EXCEEDED);
3709 // Get a connection to follow the referral
3710 rinfo = getReferralConnection(refs);
3711 rconn = rinfo.ReferralConnection;
3712 refUrl = rinfo.ReferralUrl;
3713 connList.Add(rconn);
3716 // rebuild msg into new msg changing msgID,dn,scope,filter
3717 LdapMessage newMsg = rebuildRequest(origMsg, refUrl, searchReference);
3720 // Send new message on new connection
3724 if (queue is LdapResponseQueue)
3726 agent = queue.MessageAgent;
3730 agent = queue.MessageAgent;
3732 agent.sendMessage(rconn.Connection, newMsg, defSearchCons.TimeLimit, queue, null);
3734 catch (InterThreadException ex)
3736 // Error ending request to referred server
3737 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_SEND, LdapException.CONNECT_ERROR, null, ex);
3738 rex.setReferrals(initialReferrals);
3739 ReferralInfo ref_Renamed = rconn.Connection.ActiveReferral;
3740 rex.FailedReferral = ref_Renamed.ReferralUrl.ToString();
3744 if (initialReferrals == null)
3746 // For operation results, when all responses are complete,
3747 // the stack unwinds back to the original and returns
3748 // to the application.
3749 // An exception is thrown for an error
3750 connList = chaseReferral(queue, cons, null, null, hopCount, false, connList);
3754 // For search, just return to LdapSearchResults object
3758 catch (System.Exception ex)
3761 if (ex is LdapReferralException)
3763 throw (LdapReferralException) ex;
3768 // Set referral list and failed referral
3769 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ex);
3770 rex.setReferrals(refs);
3773 rex.FailedReferral = rinfo.ReferralUrl.ToString();
3777 rex.FailedReferral = refs[refs.Length - 1];
3785 /// <summary> Builds a new request replacing dn, scope, and filter where approprate
3788 /// <param name="msg">the original LdapMessage to build the new request from
3791 /// <param name="url">the referral url
3794 /// <returns> a new LdapMessage with appropriate information replaced
3797 /// <exception> LdapException A general exception which includes an error
3798 /// message and an Ldap error code.
3800 private LdapMessage rebuildRequest(LdapMessage msg, LdapUrl url, bool reference)
3803 System.String dn = url.getDN(); // new base
3804 System.String filter = null;
3809 case LdapMessage.SEARCH_REQUEST:
3812 filter = url.Filter;
3815 // We are allowed to get a referral for the following
3817 case LdapMessage.ADD_REQUEST:
3818 case LdapMessage.BIND_REQUEST:
3819 case LdapMessage.COMPARE_REQUEST:
3820 case LdapMessage.DEL_REQUEST:
3821 case LdapMessage.EXTENDED_REQUEST:
3822 case LdapMessage.MODIFY_RDN_REQUEST:
3823 case LdapMessage.MODIFY_REQUEST:
3825 // The following return no response
3827 case LdapMessage.ABANDON_REQUEST:
3828 case LdapMessage.UNBIND_REQUEST:
3830 throw new LdapLocalException(ExceptionMessages.IMPROPER_REFERRAL, new System.Object[]{msg.Type}, LdapException.LOCAL_ERROR);
3833 return msg.Clone(dn, filter, reference);
3837 * Release connections acquired by following referrals
3839 * @param list the list of the connections
3842 internal virtual void releaseReferralConnections(System.Collections.ArrayList list)
3848 // Release referral connections
3849 for (int i = list.Count - 1; i >= 0; i--)
3851 LdapConnection rconn = null;
3854 rconn=(LdapConnection)list[i];
3856 // rconn = (LdapConnection) list.RemoveAt(i);
3859 catch (System.IndexOutOfRangeException ex)
3863 catch (LdapException lex)
3871 //*************************************************************************
3872 // Schema Related methods
3873 //*************************************************************************
3875 /// <summary> Retrieves the schema associated with a particular schema DN in the
3876 /// directory server.
3877 /// The schema DN for a particular entry is obtained by calling the
3878 /// getSchemaDN method of LDAPConnection
3881 /// <param name="schemaDN">The schema DN used to fetch the schema.
3884 /// <returns> An LDAPSchema entry containing schema attributes. If the
3885 /// entry contains no schema attributes then the returned LDAPSchema object
3889 /// <exception> LDAPException This exception occurs if the schema entry
3890 /// cannot be retrieved with this connection.
3892 /// <seealso cref="GetSchemaDN()">
3894 /// <seealso cref="GetSchemaDN(String)">
3896 public virtual LdapSchema FetchSchema(System.String schemaDN)
3898 LdapEntry ent = Read(schemaDN, LdapSchema.schemaTypeNames);
3899 return new LdapSchema(ent);
3902 /// <summary> Retrieves the Distiguished Name (DN) for the schema advertised in the
3903 /// root DSE of the Directory Server.
3905 /// The DN can be used with the methods fetchSchema and modify to retreive
3906 /// and extend schema definitions. The schema entry is located by reading
3907 /// subschemaSubentry attribute of the root DSE. This is equivalent to
3908 /// calling {@link #getSchemaDN(String) } with the DN parameter as an empty
3909 /// string: <code>getSchemaDN("")</code>.
3913 /// <returns> Distinguished Name of a schema entry in effect for the
3916 /// <exception> LDAPException This exception occurs if the schema DN
3917 /// cannot be retrieved, or if the subschemaSubentry attribute associated
3918 /// with the root DSE contains multiple values.
3921 /// <seealso cref="FetchSchema">
3923 /// <seealso cref="Modify">
3925 public virtual System.String GetSchemaDN()
3927 return GetSchemaDN("");
3930 /// <summary> Retrieves the Distiguished Name (DN) of the schema associated with a
3931 /// entry in the Directory.
3933 /// The DN can be used with the methods fetchSchema and modify to retreive
3934 /// and extend schema definitions. Reads the subschemaSubentry of the entry
3938 /// <param name="dn"> Distinguished Name of any entry. The subschemaSubentry
3939 /// attribute is queried from this entry.
3942 /// <returns> Distinguished Name of a schema entry in effect for the entry
3943 /// identified by <code>dn</code>.
3946 /// <exception> LDAPException This exception occurs if a null or empty
3947 /// value is passed as dn, if the subschemasubentry attribute cannot
3948 /// be retrieved, or the subschemasubentry contains multiple values.
3951 /// <seealso cref="FetchSchema">
3953 /// <seealso cref="Modify">
3955 public virtual System.String GetSchemaDN(System.String dn)
3957 System.String[] attrSubSchema = new System.String[]{"subschemaSubentry"};
3959 /* Read the entries subschemaSubentry attribute. Throws an exception if
3960 * no entries are returned. */
3961 LdapEntry ent = this.Read(dn, attrSubSchema);
3963 LdapAttribute attr = ent.getAttribute(attrSubSchema[0]);
3964 System.String[] values = attr.StringValueArray;
3965 if (values == null || values.Length < 1)
3967 throw new LdapLocalException(ExceptionMessages.NO_SCHEMA, new System.Object[]{dn}, LdapException.NO_RESULTS_RETURNED);
3969 else if (values.Length > 1)
3971 throw new LdapLocalException(ExceptionMessages.MULTIPLE_SCHEMA, new System.Object[]{dn}, LdapException.CONSTRAINT_VIOLATION);