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;
37 using Mono.Security.Protocol.Tls;
38 using System.Security.Cryptography.X509Certificates;
40 namespace Novell.Directory.Ldap
43 /// <summary> The central class that encapsulates the connection
44 /// to a directory server through the Ldap protocol.
45 /// LdapConnection objects are used to perform common Ldap
46 /// operations such as search, modify and add.
48 /// In addition, LdapConnection objects allow you to bind to an
49 /// Ldap server, set connection and search constraints, and perform
50 /// several other tasks.
52 /// An LdapConnection object is not connected on
53 /// construction and can only be connected to one server at one
54 /// port. Multiple threads may share this single connection, typically
55 /// by cloning the connection object, one for each thread. An
56 /// application may have more than one LdapConnection object, connected
57 /// to the same or different directory servers.
61 public class LdapConnection : System.ICloneable
63 private void InitBlock()
65 defSearchCons = new LdapSearchConstraints();
66 responseCtlSemaphore = new System.Object();
68 /// <summary> Returns the protocol version uses to authenticate.
70 /// 0 is returned if no authentication has been performed.
73 /// <returns> The protol version used for authentication or 0
74 /// not authenticated.
77 virtual public int ProtocolVersion
81 BindProperties prop = conn.BindProperties;
86 return prop.ProtocolVersion;
90 /// <summary> Returns the distinguished name (DN) used for as the bind name during
91 /// the last successful bind operation. <code>null</code> is returned
92 /// if no authentication has been performed or if the bind resulted in
93 /// an aonymous connection.
96 /// <returns> The distinguished name if authenticated; otherwise, null.
99 virtual public System.String AuthenticationDN
103 BindProperties prop = conn.BindProperties;
112 return prop.AuthenticationDN;
116 /// <summary> Returns the method used to authenticate the connection. The return
117 /// value is one of the following:
120 /// <li>"none" indicates the connection is not authenticated.</li>
123 /// <li>"simple" indicates simple authentication was used or that a null
124 /// or empty authentication DN was specified.</li>
126 /// <li>"sasl" indicates that a SASL mechanism was used to authenticate</li>
130 /// <returns> The method used to authenticate the connection.
132 virtual public System.String AuthenticationMethod
136 BindProperties prop = conn.BindProperties;
141 return conn.BindProperties.AuthenticationMethod;
145 /// <summary> Returns the properties if any specified on binding with a
148 /// Null is returned if no authentication has been performed
149 /// or no authentication Map is present.
152 /// <returns> The bind properties Map Object used for SASL bind or null if
153 /// the connection is not present or not authenticated.
156 virtual public System.Collections.IDictionary SaslBindProperties
160 BindProperties prop = conn.BindProperties;
165 return conn.BindProperties.SaslBindProperties;
169 /// <summary> Returns the call back handler if any specified on binding with a
172 /// Null is returned if no authentication has been performed
173 /// or no authentication call back handler is present.
176 /// <returns> The call back handler used for SASL bind or null if the
177 /// object is not present or not authenticated.
180 virtual public System.Object SaslBindCallbackHandler
184 BindProperties prop = conn.BindProperties;
189 return conn.BindProperties.SaslCallbackHandler;
193 /// <summary> Returns a copy of the set of constraints associated with this
194 /// connection. These constraints apply to all operations performed
195 /// through this connection (unless a different set of constraints is
196 /// specified when calling an operation method).
199 /// <returns> The set of default contraints that apply to this connection.
202 /// <summary> Sets the constraints that apply to all operations performed through
203 /// this connection (unless a different set of constraints is specified
204 /// when calling an operation method). An LdapSearchConstraints object
205 /// which is passed to this method sets all constraints, while an
206 /// LdapConstraints object passed to this method sets only base constraints.
209 /// <param name="cons"> An LdapConstraints or LdapSearchConstraints Object
210 /// containing the contstraint values to set.
213 /// <seealso cref="Constraints()">
215 /// <seealso cref="SearchConstraints()">
217 virtual public LdapConstraints Constraints
221 return (LdapConstraints) (this.defSearchCons).Clone();
226 // Set all constraints, replace the object with a new one
227 if (value is LdapSearchConstraints)
229 defSearchCons = (LdapSearchConstraints) value.Clone();
233 // We set the constraints this way, so a thread doesn't get an
234 // conconsistant view of the referrals.
235 LdapSearchConstraints newCons = (LdapSearchConstraints) defSearchCons.Clone();
236 newCons.HopLimit = value.HopLimit;
237 newCons.TimeLimit = value.TimeLimit;
238 newCons.setReferralHandler(value.getReferralHandler());
239 newCons.ReferralFollowing = value.ReferralFollowing;
240 LdapControl[] lsc = value.getControls();
243 newCons.setControls(lsc);
245 System.Collections.Hashtable lp = newCons.Properties;
248 newCons.Properties = lp;
250 defSearchCons = newCons;
255 /// <summary> Returns the host name of the Ldap server to which the object is or
256 /// was last connected, in the format originally specified.
259 /// <returns> The host name of the Ldap server to which the object last
260 /// connected or null if the object has never connected.
263 virtual public System.String Host
271 /// <summary> Returns the port number of the Ldap server to which the object is or
272 /// was last connected.
275 /// <returns> The port number of the Ldap server to which the object last
276 /// connected or -1 if the object has never connected.
279 virtual public int Port
287 /// <summary> Returns a copy of the set of search constraints associated with this
288 /// connection. These constraints apply to search operations performed
289 /// through this connection (unless a different set of
290 /// constraints is specified when calling the search operation method).
293 /// <returns> The set of default search contraints that apply to
297 /// <seealso cref="Constraints">
299 /// <seealso cref="LdapSearchConstraints">
301 virtual public LdapSearchConstraints SearchConstraints
305 return (LdapSearchConstraints) this.defSearchCons.Clone();
311 ///<summary> Indicates whther the perform Secure Operation or not
315 /// True if SSL is on
316 /// False if its not on
318 public bool SecureSocketLayer
333 /// <summary> Indicates whether the object has authenticated to the connected Ldap
337 /// <returns> True if the object has authenticated; false if it has not
341 virtual public bool Bound
349 /// <summary> Indicates whether the connection represented by this object is open
353 /// <returns> True if connection is open; false if the connection is closed.
355 virtual public bool Connected
359 return conn.Connected;
364 /// <summary> Indicatates if the connection is protected by TLS.
367 /// <returns> If startTLS has completed this method returns true.
368 /// If stopTLS has completed or start tls failed, this method returns false.
370 /// <returns> True if the connection is protected by TLS.
373 virtual public bool TLS
383 /// <summary> Returns the Server Controls associated with the most recent response
384 /// to a synchronous request on this connection object, or null
385 /// if the latest response contained no Server Controls. The method
386 /// always returns null for asynchronous requests. For asynchronous
387 /// requests, the response controls are available in LdapMessage.
390 /// <returns> The server controls associated with the most recent response
391 /// to a synchronous request or null if the response contains no server
395 /// <seealso cref="LdapMessage.Controls">
397 virtual public LdapControl[] ResponseControls
401 if (responseCtls == null)
407 // We have to clone the control just in case
408 // we have two client threads that end up retreiving the
410 LdapControl[] clonedControl = new LdapControl[responseCtls.Length];
412 // Also note we synchronize access to the local response
413 // control object just in case another message containing controls
414 // comes in from the server while we are busy duplicating
416 lock (responseCtlSemaphore)
418 for (int i = 0; i < responseCtls.Length; i++)
420 clonedControl[i] = (LdapControl) (responseCtls[i]).Clone();
424 // Return the cloned copy. Note we have still left the
425 // control in the local responseCtls variable just in case
426 // somebody requests it again.
427 return clonedControl;
431 /// <summary> Return the Connection object associated with this LdapConnection
434 /// <returns> the Connection object
436 virtual internal Connection Connection
446 /// <summary> Return the Connection object name associated with this LdapConnection
449 /// <returns> the Connection object name
451 virtual internal System.String ConnectionName
461 private LdapSearchConstraints defSearchCons;
462 private LdapControl[] responseCtls = null;
464 // Synchronization Object used to synchronize access to responseCtls
465 private System.Object responseCtlSemaphore;
467 private Connection conn = null;
469 private static System.Object nameLock; // protect agentNum
470 private static int lConnNum = 0; // Debug, LdapConnection number
471 private System.String name; // String name for debug
473 /// <summary> Used with search to specify that the scope of entrys to search is to
474 /// search only the base obect.
478 public const int SCOPE_BASE = 0;
480 /// <summary> Used with search to specify that the scope of entrys to search is to
481 /// search only the immediate subordinates of the base obect.
485 public const int SCOPE_ONE = 1;
487 /// <summary> Used with search to specify that the scope of entrys to search is to
488 /// search the base object and all entries within its subtree.
492 public const int SCOPE_SUB = 2;
494 /// <summary> Used with search instead of an attribute list to indicate that no
495 /// attributes are to be returned.
499 public const System.String NO_ATTRS = "1.1";
501 /// <summary> Used with search instead of an attribute list to indicate that all
502 /// attributes are to be returned.
504 /// ALL_USER_ATTRS = "*"
506 public const System.String ALL_USER_ATTRS = "*";
508 /// <summary> Specifies the Ldapv3 protocol version when performing a bind operation.
510 /// Specifies Ldap version V3 of the protocol, and is specified
511 /// when performing bind operations.
512 /// You can use this identifier in the version parameter
513 /// of the bind method to specify an Ldapv3 bind.
514 /// Ldap_V3 is the default protocol version
519 public const int Ldap_V3 = 3;
521 /// <summary> The default port number for Ldap servers.
523 /// You can use this identifier to specify the port when establishing
524 /// a clear text connection to a server. This the default port.
526 /// DEFAULT_PORT = 389
529 public const int DEFAULT_PORT = 389;
532 /// <summary> The default SSL port number for Ldap servers.
534 /// DEFAULT_SSL_PORT = 636
536 /// You can use this identifier to specify the port when establishing
537 /// a an SSL connection to a server..
539 public const int DEFAULT_SSL_PORT = 636;
541 /// <summary> A string that can be passed in to the getProperty method.
543 /// Ldap_PROPERTY_SDK = "version.sdk"
545 /// You can use this string to request the version of the SDK.
547 public const System.String Ldap_PROPERTY_SDK = "version.sdk";
549 /// <summary> A string that can be passed in to the getProperty method.
551 /// Ldap_PROPERTY_PROTOCOL = "version.protocol"
553 /// You can use this string to request the version of the
556 public const System.String Ldap_PROPERTY_PROTOCOL = "version.protocol";
558 /// <summary> A string that can be passed in to the getProperty method.
560 /// Ldap_PROPERTY_SECURITY = "version.security"
562 /// You can use this string to request the type of security
565 public const System.String Ldap_PROPERTY_SECURITY = "version.security";
567 /// <summary> A string that corresponds to the server shutdown notification OID.
568 /// This notification may be used by the server to advise the client that
569 /// the server is about to close the connection due to an error
572 /// SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036"
574 public const System.String SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036";
576 /// <summary> The OID string that identifies a StartTLS request and response.</summary>
577 private const System.String START_TLS_OID = "1.3.6.1.4.1.1466.20037";
579 public event CertificateValidationCallback UserDefinedServerCertValidationDelegate
583 this.conn.OnCertificateValidation += value;
588 this.conn.OnCertificateValidation -= value;
596 /// <summary> Constructs a new LdapConnection object, which will use the supplied
597 /// class factory to construct a socket connection during
598 /// LdapConnection.connect method.
601 /// <param name="factory"> An object capable of producing a Socket.
604 public LdapConnection()
607 // Get a unique connection name for debug
608 conn = new Connection();
612 /* public LdapConnection(X509Certificate cert)
615 // Get a unique connection name for debug
616 conn = new Connection();
622 * The following are methods that affect the operation of
623 * LdapConnection, but are not Ldap requests.
626 /// <summary> Returns a copy of the object with a private context, but sharing the
627 /// network connection if there is one.
629 /// The network connection remains open until all clones have
630 /// disconnected or gone out of scope. Any connection opened after
631 /// cloning is private to the object making the connection.
633 /// The clone can issue requests and freely modify options and search
634 /// constraints, and , without affecting the source object or other clones.
635 /// If the clone disconnects or reconnects, it is completely dissociated
636 /// from the source object and other clones. Reauthenticating in a clone,
637 /// however, is a global operation which will affect the source object
638 /// and all associated clones, because it applies to the single shared
639 /// physical connection. Any request by an associated object after one
640 /// has reauthenticated will carry the new identity.
643 /// <returns> A of the object.
645 public System.Object Clone()
647 LdapConnection newClone;
648 System.Object newObj;
651 newObj = base.MemberwiseClone();
652 newClone = (LdapConnection) newObj;
654 catch (System.Exception ce)
656 throw new System.SystemException("Internal error, cannot create clone");
658 newClone.conn = conn; // same underlying connection
660 //now just duplicate the defSearchCons and responseCtls
661 if (defSearchCons != null)
663 newClone.defSearchCons = (LdapSearchConstraints) defSearchCons.Clone();
667 newClone.defSearchCons = null;
669 if (responseCtls != null)
671 newClone.responseCtls = new LdapControl[responseCtls.Length];
672 for (int i = 0; i < responseCtls.Length; i++)
674 newClone.responseCtls[i] = (LdapControl) responseCtls[i].Clone();
679 newClone.responseCtls = null;
681 conn.incrCloneCount(); // Increment the count of clones
685 /// <summary> Closes the connection, if open, and releases any other resources held
689 /// <exception> LdapException A general exception which includes an error
690 /// message and an Ldap error code.
693 /// <seealso cref="Disconnect">
697 // Disconnect did not come from user API call
698 Disconnect(defSearchCons, false);
702 /// <summary> Returns a property of a connection object.
705 /// <param name="name"> Name of the property to be returned.
707 /// The following read-only properties are available
708 /// for any given connection:
710 /// <li>Ldap_PROPERTY_SDK returns the version of this SDK,
711 /// as a Float data type.</li>
713 /// <li>Ldap_PROPERTY_PROTOCOL returns the highest supported version of
714 /// the Ldap protocol, as a Float data type.</li>
716 /// <li>Ldap_PROPERTY_SECURITY returns a comma-separated list of the
717 /// types of authentication supported, as a
721 /// A deep copy of the property is provided where applicable; a
722 /// client does not need to clone the object received.
725 /// <returns> The object associated with the requested property,
726 /// or null if the property is not defined.
729 /// <seealso cref="LdapConstraints.getProperty">
731 /// <seealso cref="Object">
733 public virtual System.Object getProperty(System.String name)
735 if (name.ToUpper().Equals(Ldap_PROPERTY_SDK.ToUpper()))
736 return Connection.sdk;
737 else if (name.ToUpper().Equals(Ldap_PROPERTY_PROTOCOL.ToUpper()))
738 return Connection.protocol;
739 else if (name.ToUpper().Equals(Ldap_PROPERTY_SECURITY.ToUpper()))
740 return Connection.security;
747 /// <summary> Registers an object to be notified on arrival of an unsolicited
748 /// message from a server.
750 /// An unsolicited message has the ID 0. A new thread is created and
751 /// the method "messageReceived" in each registered object is called in
755 /// <param name="listener"> An object to be notified on arrival of an
756 /// unsolicited message from a server. This object must
757 /// implement the LdapUnsolicitedNotificationListener interface.
760 public virtual void AddUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
762 if (listener != null)
763 conn.AddUnsolicitedNotificationListener(listener);
768 /// <summary> Deregisters an object so that it will no longer be notified on
769 /// arrival of an unsolicited message from a server. If the object is
770 /// null or was not previously registered for unsolicited notifications,
771 /// the method does nothing.
775 /// <param name="listener"> An object to no longer be notified on arrival of
776 /// an unsolicited message from a server.
779 public virtual void RemoveUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
782 if (listener != null)
783 conn.RemoveUnsolicitedNotificationListener(listener);
786 /// <summary> Starts Transport Layer Security (TLS) protocol on this connection
787 /// to enable session privacy.
789 /// This affects the LdapConnection object and all cloned objects. A
790 /// socket factory that implements LdapTLSSocketFactory must be set on the
794 /// <exception> LdapException Thrown if TLS cannot be started. If a
795 /// SocketFactory has been specified that does not implement
796 /// LdapTLSSocketFactory an LdapException is thrown.
800 public virtual void startTLS()
803 LdapMessage startTLS = MakeExtendedOperation(new LdapExtendedOperation(LdapConnection.START_TLS_OID, null), null);
805 int tlsID = startTLS.MessageID;
807 conn.acquireWriteSemaphore(tlsID);
810 if (!conn.areMessagesComplete())
812 throw new LdapLocalException(ExceptionMessages.OUTSTANDING_OPERATIONS, LdapException.OPERATIONS_ERROR);
814 // Stop reader when response to startTLS request received
815 conn.stopReaderOnReply(tlsID);
818 LdapResponseQueue queue = SendRequestToServer(startTLS, defSearchCons.TimeLimit, null, null);
820 LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
821 response.chkResultCode();
827 //Free this semaphore no matter what exceptions get thrown
829 conn.freeWriteSemaphore(tlsID);
834 /// <summary> Stops Transport Layer Security(TLS) on the LDAPConnection and reverts
835 /// back to an anonymous state.
837 /// @throws LDAPException This can occur for the following reasons:
839 /// <LI>StartTLS has not been called before stopTLS</LI>
840 /// <LI>There exists outstanding messages that have not received all
842 /// <LI>The sever was not able to support the operation</LI></UL>
844 /// <p>Note: The Sun and IBM implementions of JSSE do not currently allow
845 /// stopping TLS on an open Socket. In order to produce the same results
846 /// this method currently disconnects the socket and reconnects, giving
847 /// the application an anonymous connection to the server, as required
850 public virtual void stopTLS()
855 throw new LdapLocalException(ExceptionMessages.NO_STARTTLS, LdapException.OPERATIONS_ERROR);
858 int semaphoreID = conn.acquireWriteSemaphore();
861 if (!conn.areMessagesComplete())
863 throw new LdapLocalException(ExceptionMessages.OUTSTANDING_OPERATIONS, LdapException.OPERATIONS_ERROR);
865 //stopTLS stops and starts the reader thread for us.
870 conn.freeWriteSemaphore(semaphoreID);
872 /* Now that the TLS socket is closed, reset everything. This next
873 line is temporary until JSSE is fixed to properly handle TLS stop */
874 this.Connect(this.Host, this.Port);
880 //*************************************************************************
881 // Below are all of the Ldap protocol operation methods
882 //*************************************************************************
884 //*************************************************************************
886 //*************************************************************************
890 /// Notifies the server not to send additional results associated with
891 /// this LdapSearchResults object, and discards any results already
895 /// <param name="results"> An object returned from a search.
898 /// <exception> LdapException A general exception which includes an error
899 /// message and an Ldap error code.
901 public virtual void Abandon(LdapSearchResults results)
903 Abandon(results, defSearchCons);
909 /// Notifies the server not to send additional results associated with
910 /// this LdapSearchResults object, and discards any results already
914 /// <param name="results"> An object returned from a search.
917 /// <param name="cons"> The contraints specific to the operation.
920 /// <exception> LdapException A general exception which includes an error
921 /// message and an Ldap error code.
923 public virtual void Abandon(LdapSearchResults results, LdapConstraints cons)
930 /// Abandons an asynchronous operation.
933 /// <param name="id"> The ID of the asynchronous operation to abandon. The ID
934 /// can be obtained from the response queue for the
938 /// <exception> LdapException A general exception which includes an error
939 /// message and an Ldap error code.
941 public virtual void Abandon(int id)
943 Abandon(id, defSearchCons);
947 /// <summary> Abandons an asynchronous operation, using the specified
951 /// <param name="id">The ID of the asynchronous operation to abandon.
952 /// The ID can be obtained from the search
953 /// queue for the operation.
956 /// <param name="cons">The contraints specific to the operation.
959 /// <exception> LdapException A general exception which includes an error
960 /// message and an Ldap error code.
962 public virtual void Abandon(int id, LdapConstraints cons)
964 // We need to inform the Message Agent which owns this messageID to
965 // remove it from the queue.
968 MessageAgent agent = conn.getMessageAgent(id);
969 agent.Abandon(id, cons);
972 catch (System.FieldAccessException ex)
974 return ; // Ignore error
978 /// <summary> Abandons all outstanding operations managed by the queue.
980 /// All operations in progress, which are managed by the specified queue,
984 /// <param name="queue"> The queue returned from an asynchronous request.
985 /// All outstanding operations managed by the queue
986 /// are abandoned, and the queue is emptied.
989 /// <exception> LdapException A general exception which includes an error
990 /// message and an Ldap error code.
992 public virtual void Abandon(LdapMessageQueue queue)
994 Abandon(queue, defSearchCons);
998 /// <summary> Abandons all outstanding operations managed by the queue.
1000 /// All operations in progress, which are managed by the specified
1001 /// queue, are abandoned.
1004 /// <param name="queue"> The queue returned from an asynchronous request.
1005 /// All outstanding operations managed by the queue
1006 /// are abandoned, and the queue is emptied.
1009 /// <param name="cons"> The contraints specific to the operation.
1012 /// <exception> LdapException A general exception which includes an error
1013 /// message and an Ldap error code.
1015 public virtual void Abandon(LdapMessageQueue queue, LdapConstraints cons)
1020 if (queue is LdapSearchQueue)
1022 agent = queue.MessageAgent;
1026 agent = queue.MessageAgent;
1028 int[] msgIds = agent.MessageIDs;
1029 for (int i = 0; i < msgIds.Length; i++)
1031 agent.Abandon(msgIds[i], cons);
1037 //*************************************************************************
1039 //*************************************************************************
1041 /// <summary> Synchronously adds an entry to the directory.
1044 /// <param name="entry"> LdapEntry object specifying the distinguished
1045 /// name and attributes of the new entry.
1048 /// <exception> LdapException A general exception which includes an error
1049 /// message and an Ldap error code.
1051 public virtual void Add(LdapEntry entry)
1053 Add(entry, defSearchCons);
1058 /// Synchronously adds an entry to the directory, using the specified
1062 /// <param name="entry"> LdapEntry object specifying the distinguished
1063 /// name and attributes of the new entry.
1066 /// <param name="cons"> Constraints specific to the operation.
1069 /// <exception> LdapException A general exception which includes an error
1070 /// message and an Ldap error code.
1073 public virtual void Add(LdapEntry entry, LdapConstraints cons)
1075 LdapResponseQueue queue = Add(entry, null, cons);
1077 // Get a handle to the add response
1078 LdapResponse addResponse = (LdapResponse) (queue.getResponse());
1080 // Set local copy of responseControls synchronously if there were any
1081 lock (responseCtlSemaphore)
1083 responseCtls = addResponse.Controls;
1085 chkResultCode(queue, cons, addResponse);
1089 /// <summary> Asynchronously adds an entry to the directory.
1092 /// <param name="entry"> LdapEntry object specifying the distinguished
1093 /// name and attributes of the new entry.
1096 /// <param name="queue"> Handler for messages returned from a server in
1097 /// response to this request. If it is null, a
1098 /// queue object is created internally.
1101 /// <exception> LdapException A general exception which includes an error
1102 /// message and an Ldap error code.
1104 public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue)
1106 return Add(entry, queue, defSearchCons);
1109 /// <summary> Asynchronously adds an entry to the directory, using the specified
1113 /// <param name="entry"> LdapEntry object specifying the distinguished
1114 /// name and attributes of the new entry.
1117 /// <param name="queue"> Handler for messages returned from a server in
1118 /// response to this request. If it is null, a
1119 /// queue object is created internally.
1122 /// <param name="cons"> Constraints specific to the operation.
1125 /// <exception> LdapException A general exception which includes an error
1126 /// message and an Ldap error code.
1128 public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue, LdapConstraints cons)
1131 cons = defSearchCons;
1133 // error check the parameters
1136 throw new System.ArgumentException("The LdapEntry parameter" + " cannot be null");
1138 if ((System.Object) entry.DN == null)
1140 throw new System.ArgumentException("The DN value must be present" + " in the LdapEntry object");
1143 LdapMessage msg = new LdapAddRequest(entry, cons.getControls());
1145 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1148 //*************************************************************************
1150 //*************************************************************************
1152 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1153 /// currently connected to) as an Ldapv3 bind, using the specified name and
1156 /// If the object has been disconnected from an Ldap server,
1157 /// this method attempts to reconnect to the server. If the object
1158 /// has already authenticated, the old authentication is discarded.
1161 /// <param name="dn"> If non-null and non-empty, specifies that the
1162 /// connection and all operations through it should
1163 /// be authenticated with dn as the distinguished
1167 /// <param name="passwd"> If non-null and non-empty, specifies that the
1168 /// connection and all operations through it should
1169 /// be authenticated with dn as the distinguished
1170 /// name and passwd as password.
1172 /// Note: the application should use care in the use
1173 /// of String password objects. These are long lived
1174 /// objects, and may expose a security risk, especially
1175 /// in objects that are serialized. The LdapConnection
1176 /// keeps no long lived instances of these objects.
1179 /// <exception> LdapException A general exception which includes an error
1180 /// message and an Ldap error code.
1183 public virtual void Bind(System.String dn, System.String passwd)
1185 Bind(dn, passwd, AuthenticationTypes.None);
1189 public virtual void Bind(System.String dn, System.String passwd, AuthenticationTypes authenticationTypes)
1191 Bind(Ldap_V3, dn, passwd, defSearchCons);
1196 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1197 /// currently connected to) using the specified name, password,
1198 /// and Ldap version.
1200 /// If the object has been disconnected from an Ldap server,
1201 /// this method attempts to reconnect to the server. If the object
1202 /// has already authenticated, the old authentication is discarded.
1205 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1206 /// Ldap_V2 is not supported.
1209 /// <param name="dn"> If non-null and non-empty, specifies that the
1210 /// connection and all operations through it should
1211 /// be authenticated with dn as the distinguished
1215 /// <param name="passwd"> If non-null and non-empty, specifies that the
1216 /// connection and all operations through it should
1217 /// be authenticated with dn as the distinguished
1218 /// name and passwd as password.
1220 /// Note: the application should use care in the use
1221 /// of String password objects. These are long lived
1222 /// objects, and may expose a security risk, especially
1223 /// in objects that are serialized. The LdapConnection
1224 /// keeps no long lived instances of these objects.
1227 /// <exception> LdapException A general exception which includes an error
1228 /// message and an Ldap error code.
1231 public virtual void Bind(int version, System.String dn, System.String passwd)
1233 Bind(version, dn, passwd, defSearchCons);
1237 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1238 /// currently connected to) as an Ldapv3 bind, using the specified name,
1239 /// password, and constraints.
1241 /// If the object has been disconnected from an Ldap server,
1242 /// this method attempts to reconnect to the server. If the object
1243 /// has already authenticated, the old authentication is discarded.
1246 /// <param name="dn"> If non-null and non-empty, specifies that the
1247 /// connection and all operations through it should
1248 /// be authenticated with dn as the distinguished
1252 /// <param name="passwd"> If non-null and non-empty, specifies that the
1253 /// connection and all operations through it should
1254 /// be authenticated with dn as the distinguished
1255 /// name and passwd as password.
1256 /// Note: the application should use care in the use
1257 /// of String password objects. These are long lived
1258 /// objects, and may expose a security risk, especially
1259 /// in objects that are serialized. The LdapConnection
1260 /// keeps no long lived instances of these objects.
1263 /// <param name="cons"> Constraints specific to the operation.
1266 /// <exception> LdapException A general exception which includes an error
1267 /// message and an Ldap error code.
1270 public virtual void Bind(System.String dn, System.String passwd, LdapConstraints cons)
1272 Bind(Ldap_V3, dn, passwd, cons);
1276 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1277 /// currently connected to) using the specified name, password, Ldap version,
1278 /// and constraints.
1280 /// If the object has been disconnected from an Ldap server,
1281 /// this method attempts to reconnect to the server. If the object
1282 /// has already authenticated, the old authentication is discarded.
1285 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1286 /// Ldap_V2 is not supported.
1289 /// <param name="dn"> If non-null and non-empty, specifies that the
1290 /// connection and all operations through it should
1291 /// be authenticated with dn as the distinguished
1295 /// <param name="passwd"> If non-null and non-empty, specifies that the
1296 /// connection and all operations through it should
1297 /// be authenticated with dn as the distinguished
1298 /// name and passwd as password.
1300 /// Note: the application should use care in the use
1301 /// of String password objects. These are long lived
1302 /// objects, and may expose a security risk, especially
1303 /// in objects that are serialized. The LdapConnection
1304 /// keeps no long lived instances of these objects.
1307 /// <param name="cons"> The constraints specific to the operation.
1310 /// <exception> LdapException A general exception which includes an error
1311 /// message and an Ldap error code.
1314 public virtual void Bind(int version, System.String dn, System.String passwd, LdapConstraints cons)
1317 if ((System.Object) passwd != null)
1321 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
1322 byte[] ibytes = encoder.GetBytes(passwd);
1323 pw=SupportClass.ToSByteArray(ibytes);
1325 // pw = passwd.getBytes("UTF8");
1326 passwd = null; // Keep no reference to String object
1328 catch (System.IO.IOException ex)
1330 passwd = null; // Keep no reference to String object
1331 throw new System.SystemException(ex.ToString());
1334 Bind(version, dn, pw, cons);
1338 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1339 /// currently connected to) using the specified name, password,
1340 /// and Ldap version.
1342 /// If the object has been disconnected from an Ldap server,
1343 /// this method attempts to reconnect to the server. If the object
1344 /// has already authenticated, the old authentication is discarded.
1347 /// <param name="version"> The version of the Ldap protocol to use
1348 /// in the bind, use Ldap_V3. Ldap_V2 is not supported.
1351 /// <param name="dn"> If non-null and non-empty, specifies that the
1352 /// connection and all operations through it should
1353 /// be authenticated with dn as the distinguished
1357 /// <param name="passwd"> If non-null and non-empty, specifies that the
1358 /// connection and all operations through it should
1359 /// be authenticated with dn as the distinguished
1360 /// name and passwd as password.
1363 /// <exception> LdapException A general exception which includes an error
1364 /// message and an Ldap error code.
1366 [CLSCompliantAttribute(false)]
1367 public virtual void Bind(int version, System.String dn, sbyte[] passwd)
1369 Bind(version, dn, passwd, defSearchCons);
1374 /// Synchronously authenticates to the Ldap server (that the object is
1375 /// currently connected to) using the specified name, password, Ldap version,
1376 /// and constraints.
1378 /// If the object has been disconnected from an Ldap server,
1379 /// this method attempts to reconnect to the server. If the object
1380 /// has already authenticated, the old authentication is discarded.
1383 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1384 /// Ldap_V2 is not supported.
1387 /// <param name="dn"> If non-null and non-empty, specifies that the
1388 /// connection and all operations through it should
1389 /// be authenticated with dn as the distinguished
1393 /// <param name="passwd"> If non-null and non-empty, specifies that the
1394 /// connection and all operations through it should
1395 /// be authenticated with dn as the distinguished
1396 /// name and passwd as password.
1399 /// <param name="cons"> The constraints specific to the operation.
1402 /// <exception> LdapException A general exception which includes an error
1403 /// message and an Ldap error code.
1405 [CLSCompliantAttribute(false)]
1406 public virtual void Bind(int version, System.String dn, sbyte[] passwd, LdapConstraints cons)
1408 LdapResponseQueue queue = Bind(version, dn, passwd, null, cons, null);
1409 LdapResponse res = (LdapResponse) queue.getResponse();
1412 // Set local copy of responseControls synchronously if any
1413 lock (responseCtlSemaphore)
1415 responseCtls = res.Controls;
1418 chkResultCode(queue, cons, res);
1423 /// <summary> Asynchronously authenticates to the Ldap server (that the object is
1424 /// currently connected to) using the specified name, password, Ldap
1425 /// version, and queue.
1427 /// If the object has been disconnected from an Ldap server,
1428 /// this method attempts to reconnect to the server. If the object
1429 /// has already authenticated, the old authentication is discarded.
1433 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1434 /// Ldap_V2 is not supported.
1437 /// <param name="dn"> If non-null and non-empty, specifies that the
1438 /// connection and all operations through it should
1439 /// be authenticated with dn as the distinguished
1443 /// <param name="passwd"> If non-null and non-empty, specifies that the
1444 /// connection and all operations through it should
1445 /// be authenticated with dn as the distinguished
1446 /// name and passwd as password.
1449 /// <param name="queue"> Handler for messages returned from a server in
1450 /// response to this request. If it is null, a
1451 /// queue object is created internally.
1454 /// <exception> LdapException A general exception which includes an error
1455 /// message and an Ldap error code.
1457 [CLSCompliantAttribute(false)]
1458 public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue)
1460 return Bind(version, dn, passwd, queue, defSearchCons, null);
1463 /// <summary> Asynchronously authenticates to the Ldap server (that the object is
1464 /// currently connected to) using the specified name, password, Ldap
1465 /// version, queue, and constraints.
1467 /// If the object has been disconnected from an Ldap server,
1468 /// this method attempts to reconnect to the server. If the object
1469 /// had already authenticated, the old authentication is discarded.
1472 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1473 /// Ldap_V2 is not supported.
1476 /// <param name="dn"> If non-null and non-empty, specifies that the
1477 /// connection and all operations through it should
1478 /// be authenticated with dn as the distinguished
1482 /// <param name="passwd"> If non-null and non-empty, specifies that the
1483 /// connection and all operations through it should
1484 /// be authenticated with dn as the distinguished
1485 /// name and passwd as password.
1488 /// <param name="queue"> Handler for messages returned from a server in
1489 /// response to this request. If it is null, a
1490 /// queue object is created internally.
1493 /// <param name="cons"> Constraints specific to the operation.
1496 /// <exception> LdapException A general exception which includes an error
1497 /// message and an Ldap error code.
1499 [CLSCompliantAttribute(false)]
1500 public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue, LdapConstraints cons, string mech)
1503 BindProperties bindProps;
1505 cons = defSearchCons;
1507 if ((System.Object) dn == null)
1517 passwd = new sbyte[]{};
1519 bool anonymous = false;
1520 if (passwd.Length == 0)
1522 anonymous = true; // anonymous, passwd length zero with simple bind
1523 dn = ""; // set to null if anonymous
1527 msg = new LdapBindRequest(version, dn, passwd, cons.getControls());
1529 msgId = msg.MessageID;
1530 bindProps = new BindProperties(version, dn, "simple", anonymous, null, null);
1532 // For bind requests, if not connected, attempt to reconnect
1533 if (!conn.Connected)
1535 if ((System.Object) conn.Host != null)
1537 conn.connect(conn.Host, conn.Port);
1541 throw new LdapException(ExceptionMessages.CONNECTION_IMPOSSIBLE, LdapException.CONNECT_ERROR, null);
1545 // The semaphore is released when the bind response is queued.
1546 conn.acquireWriteSemaphore(msgId);
1548 return SendRequestToServer(msg, cons.TimeLimit, queue, bindProps);
1552 //*************************************************************************
1554 //*************************************************************************
1557 /// Synchronously checks to see if an entry contains an attribute
1558 /// with a specified value.
1561 /// <param name="dn"> The distinguished name of the entry to use in the
1565 /// <param name="attr"> The attribute to compare against the entry. The
1566 /// method checks to see if the entry has an
1567 /// attribute with the same name and value as this
1571 /// <returns> True if the entry has the value,
1572 /// and false if the entry does not
1573 /// have the value or the attribute.
1576 /// <exception> LdapException A general exception which includes an error
1577 /// message and an Ldap error code.
1579 public virtual bool Compare(System.String dn, LdapAttribute attr)
1581 return Compare(dn, attr, defSearchCons);
1585 /// Synchronously checks to see if an entry contains an attribute with a
1586 /// specified value, using the specified constraints.
1589 /// <param name="dn"> The distinguished name of the entry to use in the
1593 /// <param name="attr"> The attribute to compare against the entry. The
1594 /// method checks to see if the entry has an
1595 /// attribute with the same name and value as this
1599 /// <param name="cons"> Constraints specific to the operation.
1602 /// <returns> True if the entry has the value,
1603 /// and false if the entry does not
1604 /// have the value or the attribute.
1607 /// <exception> LdapException A general exception which includes an error
1608 /// message and an Ldap error code.
1610 public virtual bool Compare(System.String dn, LdapAttribute attr, LdapConstraints cons)
1614 LdapResponseQueue queue = Compare(dn, attr, null, cons);
1616 LdapResponse res = (LdapResponse) queue.getResponse();
1618 // Set local copy of responseControls synchronously - if there were any
1619 lock (responseCtlSemaphore)
1621 responseCtls = res.Controls;
1624 if (res.ResultCode == LdapException.COMPARE_TRUE)
1628 else if (res.ResultCode == LdapException.COMPARE_FALSE)
1634 chkResultCode(queue, cons, res);
1639 /// <summary> Asynchronously compares an attribute value with one in the directory,
1640 /// using the specified queue.
1642 /// Please note that a successful completion of this command results in
1643 /// one of two status codes: LdapException.COMPARE_TRUE if the entry
1644 /// has the value, and LdapException.COMPARE_FALSE if the entry
1645 /// does not have the value or the attribute.
1648 /// <param name="dn"> The distinguished name of the entry containing an
1649 /// attribute to compare.
1652 /// <param name="attr"> An attribute to compare.
1655 /// <param name="queue"> The queue for messages returned from a server in
1656 /// response to this request. If it is null, a
1657 /// queue object is created internally.
1660 /// <exception> LdapException A general exception which includes an error
1661 /// message and an Ldap error code.
1664 /// <seealso cref="LdapException.COMPARE_TRUE">
1666 /// <seealso cref="LdapException.COMPARE_FALSE">
1668 public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue)
1670 return Compare(dn, attr, queue, defSearchCons);
1673 /// <summary> Asynchronously compares an attribute value with one in the directory,
1674 /// using the specified queue and contraints.
1676 /// Please note that a successful completion of this command results in
1677 /// one of two status codes: LdapException.COMPARE_TRUE if the entry
1678 /// has the value, and LdapException.COMPARE_FALSE if the entry
1679 /// does not have the value or the attribute.
1682 /// <param name="dn"> The distinguished name of the entry containing an
1683 /// attribute to compare.
1686 /// <param name="attr"> An attribute to compare.
1689 /// <param name="queue"> Handler for messages returned from a server in
1690 /// response to this request. If it is null, a
1691 /// queue object is created internally.
1694 /// <param name="cons"> Constraints specific to the operation.
1697 /// <exception> LdapException A general exception which includes an error
1698 /// message and an Ldap error code.
1701 /// <seealso cref="LdapException.COMPARE_TRUE">
1703 /// <seealso cref="LdapException.COMPARE_FALSE">
1705 public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue, LdapConstraints cons)
1707 if (attr.size() != 1)
1709 throw new System.ArgumentException("compare: Exactly one value " + "must be present in the LdapAttribute");
1712 if ((System.Object) dn == null)
1714 // Invalid parameter
1715 throw new System.ArgumentException("compare: DN cannot be null");
1719 cons = defSearchCons;
1721 LdapMessage msg = new LdapCompareRequest(dn, attr.Name, attr.ByteValue, cons.getControls());
1723 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1726 //*************************************************************************
1728 //*************************************************************************
1731 /// Connects to the specified host and port.
1733 /// If this LdapConnection object represents an open connection, the
1734 /// connection is closed first before the new connection is opened.
1735 /// At this point, there is no authentication, and any operations are
1736 /// conducted as an anonymous client.
1738 /// When more than one host name is specified, each host is contacted
1739 /// in turn until a connection can be established.
1742 /// <param name="host">A host name or a dotted string representing the IP address
1743 /// of a host running an Ldap server. It may also
1744 /// contain a list of host names, space-delimited. Each host
1745 /// name can include a trailing colon and port number.
1748 /// <param name="port">The TCP or UDP port number to connect to or contact.
1749 /// The default Ldap port is 389. The port parameter is
1750 /// ignored for any host hame which includes a colon and
1754 /// <exception> LdapException A general exception which includes an error
1755 /// message and an Ldap error code.
1758 public virtual void Connect(System.String host, int port)
1760 // connect doesn't affect other clones
1761 // If not a clone, destroys old connection.
1762 // Step through the space-delimited list
1763 SupportClass.Tokenizer hostList = new SupportClass.Tokenizer(host, " ");
1764 System.String address = null;
1767 int colonIndex; //after the colon is the port
1768 while (hostList.HasMoreTokens())
1772 specifiedPort = port;
1773 address = hostList.NextToken();
1774 colonIndex = address.IndexOf((System.Char) ':');
1775 if (colonIndex != - 1 && colonIndex + 1 != address.Length)
1777 //parse Port out of address
1780 specifiedPort = System.Int32.Parse(address.Substring(colonIndex + 1));
1781 address = address.Substring(0, (colonIndex) - (0));
1783 catch (System.Exception e)
1785 throw new System.ArgumentException(ExceptionMessages.INVALID_ADDRESS);
1788 // This may return a different conn object
1789 // Disassociate this clone with the underlying connection.
1790 conn = conn.destroyClone(true);
1791 conn.connect(address, specifiedPort);
1794 catch (LdapException LE)
1796 if (!hostList.HasMoreTokens())
1803 //*************************************************************************
1805 //*************************************************************************
1808 /// Synchronously deletes the entry with the specified distinguished name
1809 /// from the directory.
1811 /// Note: A Delete operation will not remove an entry that contains
1812 /// subordinate entries, nor will it dereference alias entries.
1815 /// <param name="dn"> The distinguished name of the entry to delete.
1818 /// <exception> LdapException A general exception which includes an error
1819 /// message and an Ldap error code.
1821 public virtual void Delete(System.String dn)
1823 Delete(dn, defSearchCons);
1828 /// <summary> Synchronously deletes the entry with the specified distinguished name
1829 /// from the directory, using the specified constraints.
1831 /// Note: A Delete operation will not remove an entry that contains
1832 /// subordinate entries, nor will it dereference alias entries.
1835 /// <param name="dn"> The distinguished name of the entry to delete.
1838 /// <param name="cons"> Constraints specific to the operation.
1841 /// <exception> LdapException A general exception which includes an error
1842 /// message and an Ldap error code.
1844 public virtual void Delete(System.String dn, LdapConstraints cons)
1846 LdapResponseQueue queue = Delete(dn, null, cons);
1848 // Get a handle to the delete response
1849 LdapResponse deleteResponse = (LdapResponse) (queue.getResponse());
1851 // Set local copy of responseControls synchronously - if there were any
1852 lock (responseCtlSemaphore)
1854 responseCtls = deleteResponse.Controls;
1856 chkResultCode(queue, cons, deleteResponse);
1860 /// <summary> Asynchronously deletes the entry with the specified distinguished name
1861 /// from the directory and returns the results to the specified queue.
1863 /// Note: A Delete operation will not remove an entry that contains
1864 /// subordinate entries, nor will it dereference alias entries.
1867 /// <param name="dn"> The distinguished name of the entry to modify.
1870 /// <param name="queue"> The queue for messages returned from a server in
1871 /// response to this request. If it is null, a
1872 /// queue object is created internally.
1875 /// <exception> LdapException A general exception which includes an error
1876 /// message and an Ldap error code.
1879 public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue)
1881 return Delete(dn, queue, defSearchCons);
1884 /// <summary> Asynchronously deletes the entry with the specified distinguished name
1885 /// from the directory, using the specified contraints and queue.
1887 /// Note: A Delete operation will not remove an entry that contains
1888 /// subordinate entries, nor will it dereference alias entries.
1891 /// <param name="dn"> The distinguished name of the entry to delete.
1894 /// <param name="queue"> The queue for messages returned from a server in
1895 /// response to this request. If it is null, a
1896 /// queue object is created internally.
1899 /// <param name="cons"> The constraints specific to the operation.
1902 /// <exception> LdapException A general exception which includes an error
1903 /// message and an Ldap error code.
1906 public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue, LdapConstraints cons)
1908 if ((System.Object) dn == null)
1910 // Invalid DN parameter
1911 throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
1915 cons = defSearchCons;
1917 LdapMessage msg = new LdapDeleteRequest(dn, cons.getControls());
1919 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1922 //*************************************************************************
1923 // disconnect method
1924 //*************************************************************************
1927 /// Synchronously disconnects from the Ldap server.
1929 /// Before the object can perform Ldap operations again, it must
1930 /// reconnect to the server by calling connect.
1932 /// The disconnect method abandons any outstanding requests, issues an
1933 /// unbind request to the server, and then closes the socket.
1936 /// <exception> LdapException A general exception which includes an error
1937 /// message and an Ldap error code.
1940 public virtual void Disconnect()
1942 // disconnect from API call
1943 Disconnect(defSearchCons, true);
1947 /// <summary> Synchronously disconnects from the Ldap server.
1949 /// Before the object can perform Ldap operations again, it must
1950 /// reconnect to the server by calling connect.
1952 /// The disconnect method abandons any outstanding requests, issues an
1953 /// unbind request to the server, and then closes the socket.
1956 /// <param name="cons">LDPConstraints to be set with the unbind request
1959 /// <exception> LdapException A general exception which includes an error
1960 /// message and an Ldap error code.
1962 public virtual void Disconnect(LdapConstraints cons)
1964 // disconnect from API call
1965 Disconnect(cons, true);
1969 /// <summary> Synchronously disconnect from the server
1972 /// <param name="how">true if application call disconnect API, false if finalize.
1974 private void Disconnect(LdapConstraints cons, bool how)
1976 // disconnect doesn't affect other clones
1977 // If not a clone, distroys connection
1978 conn = conn.destroyClone(how);
1982 //*************************************************************************
1983 // extendedOperation methods
1984 //*************************************************************************
1986 /// <summary> Provides a synchronous means to access extended, non-mandatory
1987 /// operations offered by a particular Ldapv3 compliant server.
1990 /// <param name="op"> The object which contains (1) an identifier of an extended
1991 /// operation which should be recognized by the particular Ldap
1992 /// server this client is connected to and (2)
1993 /// an operation-specific sequence of octet strings
1994 /// or BER-encoded values.
1997 /// <returns> An operation-specific object, containing an ID and either an octet
1998 /// string or BER-encoded values.
2001 /// <exception> LdapException A general exception which includes an error
2002 /// message and an Ldap error code.
2004 public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op)
2006 return ExtendedOperation(op, defSearchCons);
2010 * Synchronous Ldap extended request with SearchConstraints
2014 /// Provides a synchronous means to access extended, non-mandatory
2015 /// operations offered by a particular Ldapv3 compliant server.
2018 /// <param name="op"> The object which contains (1) an identifier of an extended
2019 /// operation which should be recognized by the particular Ldap
2020 /// server this client is connected to and (2) an
2021 /// operation-specific sequence of octet strings
2022 /// or BER-encoded values.
2025 /// <param name="cons">The constraints specific to the operation.
2028 /// <returns> An operation-specific object, containing an ID and either an
2029 /// octet string or BER-encoded values.
2032 /// <exception> LdapException A general exception which includes an error
2033 /// message and an Ldap error code.
2036 public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
2039 // Call asynchronous API and get back handler to reponse queue
2040 LdapResponseQueue queue = ExtendedOperation(op, cons, null);
2041 LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
2043 // Set local copy of responseControls synchronously - if there were any
2044 lock (responseCtlSemaphore)
2046 responseCtls = response.Controls;
2049 chkResultCode(queue, cons, response);
2055 * Asynchronous Ldap extended request
2058 /// <summary> Provides an asynchronous means to access extended, non-mandatory
2059 /// operations offered by a particular Ldapv3 compliant server.
2062 /// <param name="op"> The object which contains (1) an identifier of an extended
2063 /// operation which should be recognized by the particular Ldap
2064 /// server this client is connected to and (2) an
2065 /// operation-specific sequence of octet strings
2066 /// or BER-encoded values.
2069 /// <param name="queue"> The queue for messages returned from a server in
2070 /// response to this request. If it is null, a queue
2071 /// object is created internally.
2074 /// <returns> An operation-specific object, containing an ID and either an octet
2075 /// string or BER-encoded values.
2078 /// <exception> LdapException A general exception which includes an error
2079 /// message and an Ldap error code.
2082 public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapResponseQueue queue)
2085 return ExtendedOperation(op, defSearchCons, queue);
2090 * Asynchronous Ldap extended request with SearchConstraints
2093 /// <summary> Provides an asynchronous means to access extended, non-mandatory
2094 /// operations offered by a particular Ldapv3 compliant server.
2097 /// <param name="op"> The object which contains (1) an identifier of an extended
2098 /// operation which should be recognized by the particular Ldap
2099 /// server this client is connected to and (2) an operation-
2100 /// specific sequence of octet strings or BER-encoded values.
2103 /// <param name="queue"> The queue for messages returned from a server in
2104 /// response to this request. If it is null, a queue
2105 /// object is created internally.
2108 /// <param name="cons"> The constraints specific to this operation.
2111 /// <returns> An operation-specific object, containing an ID and either an
2112 /// octet string or BER-encoded values.
2115 /// <exception> LdapException A general exception which includes an error
2116 /// message and an Ldap error code.
2119 public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons, LdapResponseQueue queue)
2121 // Use default constraints if none-specified
2123 cons = defSearchCons;
2124 LdapMessage msg = MakeExtendedOperation(op, cons);
2125 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2128 /// <summary> Formulates the extended operation, constraints into an
2129 /// LdapMessage and returns the LdapMessage. This is used by
2130 /// extendedOperation and startTLS which needs the LdapMessage to
2131 /// get the MessageID.
2133 protected internal virtual LdapMessage MakeExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
2135 // Use default constraints if none-specified
2137 cons = defSearchCons;
2139 // error check the parameters
2140 if ((System.Object) op.getID() == null)
2142 // Invalid extended operation parameter, no OID specified
2143 throw new System.ArgumentException(ExceptionMessages.OP_PARAM_ERROR);
2146 return new LdapExtendedRequest(op, cons.getControls());
2149 //*************************************************************************
2150 // getResponseControls method
2151 //*************************************************************************
2153 //*************************************************************************
2155 //*************************************************************************
2157 /// <summary> Synchronously makes a single change to an existing entry in the
2160 /// For example, this modify method changes the value of an attribute,
2161 /// adds a new attribute value, or removes an existing attribute value.
2163 /// The LdapModification object specifies both the change to be made and
2164 /// the LdapAttribute value to be changed.
2166 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2167 /// it is indeterminate whether or not the server made the modification.
2170 /// <param name="dn"> The distinguished name of the entry to modify.
2173 /// <param name="mod"> A single change to be made to the entry.
2176 /// <exception> LdapException A general exception which includes an error
2177 /// message and an Ldap error code.
2179 public virtual void Modify(System.String dn, LdapModification mod)
2181 Modify(dn, mod, defSearchCons);
2186 /// Synchronously makes a single change to an existing entry in the
2187 /// directory, using the specified constraints.
2189 /// For example, this modify method changes the value of an attribute,
2190 /// adds a new attribute value, or removes an existing attribute value.
2192 /// The LdapModification object specifies both the change to be
2193 /// made and the LdapAttribute value to be changed.
2195 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2196 /// it is indeterminate whether or not the server made the modification.
2199 /// <param name="dn"> The distinguished name of the entry to modify.
2202 /// <param name="mod"> A single change to be made to the entry.
2205 /// <param name="cons"> The constraints specific to the operation.
2208 /// <exception> LdapException A general exception which includes an error
2209 /// message and an Ldap error code.
2211 public virtual void Modify(System.String dn, LdapModification mod, LdapConstraints cons)
2213 LdapModification[] mods = new LdapModification[1];
2215 Modify(dn, mods, cons);
2220 /// Synchronously makes a set of changes to an existing entry in the
2223 /// For example, this modify method changes attribute values, adds
2224 /// new attribute values, or removes existing attribute values.
2226 /// Because the server applies all changes in an LdapModification array
2227 /// atomically, the application can expect that no changes
2228 /// have been performed if an error is returned.
2229 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2230 /// it is indeterminate whether or not the server made the modifications.
2233 /// <param name="dn"> Distinguished name of the entry to modify.
2236 /// <param name="mods"> The changes to be made to the entry.
2239 /// <exception> LdapException A general exception which includes an error
2240 /// message and an Ldap error code.
2242 public virtual void Modify(System.String dn, LdapModification[] mods)
2244 Modify(dn, mods, defSearchCons);
2248 /// <summary> Synchronously makes a set of changes to an existing entry in the
2249 /// directory, using the specified constraints.
2251 /// For example, this modify method changes attribute values, adds new
2252 /// attribute values, or removes existing attribute values.
2254 /// Because the server applies all changes in an LdapModification array
2255 /// atomically, the application can expect that no changes
2256 /// have been performed if an error is returned.
2257 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2258 /// it is indeterminate whether or not the server made the modifications.
2261 /// <param name="dn"> The distinguished name of the entry to modify.
2264 /// <param name="mods"> The changes to be made to the entry.
2267 /// <param name="cons"> The constraints specific to the operation.
2270 /// <exception> LdapException A general exception which includes an
2271 /// error message and an Ldap error code.
2273 public virtual void Modify(System.String dn, LdapModification[] mods, LdapConstraints cons)
2275 LdapResponseQueue queue = Modify(dn, mods, null, cons);
2277 // Get a handle to the modify response
2278 LdapResponse modifyResponse = (LdapResponse) (queue.getResponse());
2280 // Set local copy of responseControls synchronously - if there were any
2281 lock (responseCtlSemaphore)
2283 responseCtls = modifyResponse.Controls;
2286 chkResultCode(queue, cons, modifyResponse);
2291 /// <summary> Asynchronously makes a single change to an existing entry in the
2294 /// For example, this modify method can change the value of an attribute,
2295 /// add a new attribute value, or remove an existing attribute value.
2297 /// The LdapModification object specifies both the change to be made and
2298 /// the LdapAttribute value to be changed.
2300 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2301 /// it is indeterminate whether or not the server made the modification.
2304 /// <param name="dn"> Distinguished name of the entry to modify.
2307 /// <param name="mod"> A single change to be made to the entry.
2310 /// <param name="queue"> Handler for messages returned from a server in
2311 /// response to this request. If it is null, a
2312 /// queue object is created internally.
2315 /// <exception> LdapException A general exception which includes an error
2316 /// message and an Ldap error code.
2318 public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue)
2320 return Modify(dn, mod, queue, defSearchCons);
2323 /// <summary> Asynchronously makes a single change to an existing entry in the
2324 /// directory, using the specified constraints and queue.
2326 /// For example, this modify method can change the value of an attribute,
2327 /// add a new attribute value, or remove an existing attribute value.
2329 /// The LdapModification object specifies both the change to be made
2330 /// and the LdapAttribute value to be changed.
2332 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2333 /// it is indeterminate whether or not the server made the modification.
2336 /// <param name="dn"> Distinguished name of the entry to modify.
2339 /// <param name="mod"> A single change to be made to the entry.
2342 /// <param name="queue"> Handler for messages returned from a server in
2343 /// response to this request. If it is null, a
2344 /// queue object is created internally.
2347 /// <param name="cons"> Constraints specific to the operation.
2350 /// <exception> LdapException A general exception which includes an error
2351 /// message and an Ldap error code.
2353 public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue, LdapConstraints cons)
2355 LdapModification[] mods = new LdapModification[1];
2357 return Modify(dn, mods, queue, cons);
2360 /// <summary> Asynchronously makes a set of changes to an existing entry in the
2363 /// For example, this modify method can change attribute values, add new
2364 /// attribute values, or remove existing attribute values.
2366 /// Because the server applies all changes in an LdapModification array
2367 /// atomically, the application can expect that no changes
2368 /// have been performed if an error is returned.
2369 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2370 /// it is indeterminate whether or not the server made the modifications.
2373 /// <param name="dn"> The distinguished name of the entry to modify.
2376 /// <param name="mods"> The changes to be made to the entry.
2379 /// <param name="queue"> The queue for messages returned from a server in
2380 /// response to this request. If it is null, a
2381 /// queue object is created internally.
2384 /// <exception> LdapException A general exception which includes an error
2385 /// message and an Ldap error code.
2387 public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue)
2389 return Modify(dn, mods, queue, defSearchCons);
2392 /// <summary> Asynchronously makes a set of changes to an existing entry in the
2393 /// directory, using the specified constraints and queue.
2395 /// For example, this modify method can change attribute values, add new
2396 /// attribute values, or remove existing attribute values.
2398 /// Because the server applies all changes in an LdapModification array
2399 /// atomically, the application can expect that no changes
2400 /// have been performed if an error is returned.
2401 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2402 /// it is indeterminate whether or not the server made the modifications.
2405 /// <param name="dn"> The distinguished name of the entry to modify.
2408 /// <param name="mods"> The changes to be made to the entry.
2411 /// <param name="queue"> The queue for messages returned from a server in
2412 /// response to this request. If it is null, a
2413 /// queue object is created internally.
2416 /// <param name="cons"> Constraints specific to the operation.
2419 /// <exception> LdapException A general exception which includes an error
2420 /// message and an Ldap error code.
2422 public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue, LdapConstraints cons)
2424 if ((System.Object) dn == null)
2426 // Invalid DN parameter
2427 throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
2431 cons = defSearchCons;
2433 LdapMessage msg = new LdapModifyRequest(dn, mods, cons.getControls());
2435 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2438 //*************************************************************************
2440 //*************************************************************************
2442 /// <summary> Synchronously reads the entry for the specified distiguished name (DN)
2443 /// and retrieves all attributes for the entry.
2446 /// <param name="dn"> The distinguished name of the entry to retrieve.
2449 /// <returns> the LdapEntry read from the server.
2452 /// <exception> LdapException if the object was not found
2454 public virtual LdapEntry Read(System.String dn)
2456 return Read(dn, defSearchCons);
2461 /// Synchronously reads the entry for the specified distiguished name (DN),
2462 /// using the specified constraints, and retrieves all attributes for the
2466 /// <param name="dn"> The distinguished name of the entry to retrieve.
2469 /// <param name="cons"> The constraints specific to the operation.
2472 /// <returns> the LdapEntry read from the server
2475 /// <exception> LdapException if the object was not found
2477 public virtual LdapEntry Read(System.String dn, LdapSearchConstraints cons)
2479 return Read(dn, null, cons);
2483 /// Synchronously reads the entry for the specified distinguished name (DN)
2484 /// and retrieves only the specified attributes from the entry.
2487 /// <param name="dn"> The distinguished name of the entry to retrieve.
2490 /// <param name="attrs"> The names of the attributes to retrieve.
2493 /// <returns> the LdapEntry read from the server
2496 /// <exception> LdapException if the object was not found
2498 public virtual LdapEntry Read(System.String dn, System.String[] attrs)
2500 return Read(dn, attrs, defSearchCons);
2503 /// <summary> Synchronously reads the entry for the specified distinguished name (DN),
2504 /// using the specified constraints, and retrieves only the specified
2505 /// attributes from the entry.
2508 /// <param name="dn"> The distinguished name of the entry to retrieve.
2511 /// <param name="attrs"> The names of the attributes to retrieve.
2514 /// <param name="cons"> The constraints specific to the operation.
2517 /// <returns> the LdapEntry read from the server
2520 /// <exception> LdapException if the object was not found
2522 public virtual LdapEntry Read(System.String dn, System.String[] attrs, LdapSearchConstraints cons)
2524 LdapSearchResults sr = Search(dn, SCOPE_BASE, null, attrs, false, cons);
2526 LdapEntry ret = null;
2532 // "Read response is ambiguous, multiple entries returned"
2533 throw new LdapLocalException(ExceptionMessages.READ_MULTIPLE, LdapException.AMBIGUOUS_RESPONSE);
2539 /// <summary> Synchronously reads the entry specified by the Ldap URL.
2541 /// When this read method is called, a new connection is created
2542 /// automatically, using the host and port specified in the URL. After
2543 /// finding the entry, the method closes the connection (in other words,
2544 /// it disconnects from the Ldap server).
2546 /// If the URL specifies a filter and scope, they are not used. Of the
2547 /// information specified in the URL, this method only uses the Ldap host
2548 /// name and port number, the base distinguished name (DN), and the list
2549 /// of attributes to return.
2552 /// <param name="toGet"> Ldap URL specifying the entry to read.
2555 /// <returns> The entry specified by the base DN.
2558 /// <exception> LdapException if the object was not found
2560 public static LdapEntry Read(LdapUrl toGet)
2562 LdapConnection lconn = new LdapConnection();
2563 lconn.Connect(toGet.Host, toGet.Port);
2564 LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray);
2569 /// <summary> Synchronously reads the entry specified by the Ldap URL, using the
2570 /// specified constraints.
2572 /// When this method is called, a new connection is created
2573 /// automatically, using the host and port specified in the URL. After
2574 /// finding the entry, the method closes the connection (in other words,
2575 /// it disconnects from the Ldap server).
2577 /// If the URL specifies a filter and scope, they are not used. Of the
2578 /// information specified in the URL, this method only uses the Ldap host
2579 /// name and port number, the base distinguished name (DN), and the list
2580 /// of attributes to return.
2583 /// <returns> The entry specified by the base DN.
2586 /// <param name="toGet"> Ldap URL specifying the entry to read.
2589 /// <param name="cons"> Constraints specific to the operation.
2592 /// <exception> LdapException if the object was not found
2594 public static LdapEntry Read(LdapUrl toGet, LdapSearchConstraints cons)
2596 LdapConnection lconn = new LdapConnection();
2597 lconn.Connect(toGet.Host, toGet.Port);
2598 LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray, cons);
2603 //*************************************************************************
2605 //*************************************************************************
2608 /// Synchronously renames an existing entry in the directory.
2611 /// <param name="dn"> The current distinguished name of the entry.
2614 /// <param name="newRdn"> The new relative distinguished name for the entry.
2617 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2618 /// attribute value. If false, the old name is
2619 /// retained as an attribute value.
2622 /// <exception> LdapException A general exception which includes an error
2623 /// message and an Ldap error code.
2625 public virtual void Rename(System.String dn, System.String newRdn, bool deleteOldRdn)
2627 Rename(dn, newRdn, deleteOldRdn, defSearchCons);
2632 /// Synchronously renames an existing entry in the directory, using the
2633 /// specified constraints.
2636 /// <param name="dn"> The current distinguished name of the entry.
2639 /// <param name="newRdn"> The new relative distinguished name for the entry.
2642 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2643 /// attribute value. If false, the old name is
2644 /// retained as an attribute value.
2647 /// <param name="cons"> The constraints specific to the operation.
2650 /// <exception> LdapException A general exception which includes an error
2651 /// message and an Ldap error code.
2653 public virtual void Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapConstraints cons)
2655 // null for newParentdn means that this is originating as an Ldapv2 call
2656 Rename(dn, newRdn, null, deleteOldRdn, cons);
2660 /// <summary> Synchronously renames an existing entry in the directory, possibly
2661 /// repositioning the entry in the directory tree.
2664 /// <param name="dn"> The current distinguished name of the entry.
2667 /// <param name="newRdn"> The new relative distinguished name for the entry.
2670 /// <param name="newParentdn"> The distinguished name of an existing entry which
2671 /// is to be the new parent of the entry.
2674 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2675 /// attribute value. If false, the old name is
2676 /// retained as an attribute value.
2679 /// <exception> LdapException A general exception which includes an error
2680 /// message and an Ldap error code.
2682 public virtual void Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn)
2684 Rename(dn, newRdn, newParentdn, deleteOldRdn, defSearchCons);
2689 /// Synchronously renames an existing entry in the directory, using the
2690 /// specified constraints and possibly repositioning the entry in the
2694 /// <param name="dn"> The current distinguished name of the entry.
2697 /// <param name="newRdn"> The new relative distinguished name for the entry.
2700 /// <param name="newParentdn"> The distinguished name of an existing entry which
2701 /// is to be the new parent of the entry.
2704 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2705 /// attribute value. If false, the old name is
2706 /// retained as an attribute value.
2709 /// <param name="cons"> The constraints specific to the operation.
2712 /// <exception> LdapException A general exception which includes an error
2713 /// message and an Ldap error code.
2715 public virtual void Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapConstraints cons)
2717 LdapResponseQueue queue = Rename(dn, newRdn, newParentdn, deleteOldRdn, null, cons);
2719 // Get a handle to the rename response
2720 LdapResponse renameResponse = (LdapResponse) (queue.getResponse());
2722 // Set local copy of responseControls synchronously - if there were any
2723 lock (responseCtlSemaphore)
2725 responseCtls = renameResponse.Controls;
2728 chkResultCode(queue, cons, renameResponse);
2736 /// <summary> Asynchronously renames an existing entry in the directory.
2739 /// <param name="dn"> The current distinguished name of the entry.
2742 /// <param name="newRdn"> The new relative distinguished name for the entry.
2745 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2746 /// attribute value. If false, the old name is
2747 /// retained as an attribute value.
2750 /// <param name="queue"> The queue for messages returned from a server in
2751 /// response to this request. If it is null, a
2752 /// queue object is created internally.
2755 /// <exception> LdapException A general exception which includes an error
2756 /// message and an Ldap error code.
2758 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue)
2760 return Rename(dn, newRdn, deleteOldRdn, queue, defSearchCons);
2763 /// <summary> Asynchronously renames an existing entry in the directory, using the
2764 /// specified constraints.
2767 /// <param name="dn"> The current distinguished name of the entry.
2770 /// <param name="newRdn"> The new relative distinguished name for the entry.
2773 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2774 /// attribute value. If false, the old name is
2775 /// retained as an attribute value.
2778 /// <param name="queue"> The queue for messages returned from a server in
2779 /// response to this request. If it is null, a
2780 /// queue object is created internally.
2783 /// <param name="cons"> The constraints specific to the operation.
2786 /// <exception> LdapException A general exception which includes an error
2787 /// message and an Ldap error code.
2789 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
2791 return Rename(dn, newRdn, null, deleteOldRdn, queue, cons);
2794 /// <summary> Asynchronously renames an existing entry in the directory, possibly
2795 /// repositioning the entry in the directory.
2798 /// <param name="dn"> The current distinguished name of the entry.
2801 /// <param name="newRdn"> The new relative distinguished name for the entry.
2804 /// <param name="newParentdn"> The distinguished name of an existing entry which
2805 /// is to be the new parent of the entry.
2808 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2809 /// attribute value. If false, the old name is
2810 /// retained as an attribute value.
2813 /// <param name="queue"> The queue for messages returned from a server in
2814 /// response to this request. If it is null, a
2815 /// queue object is created internally.
2818 /// <exception> LdapException A general exception which includes an error
2819 /// message and an Ldap error code.
2821 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue)
2823 return Rename(dn, newRdn, newParentdn, deleteOldRdn, queue, defSearchCons);
2826 /// <summary> Asynchronously renames an existing entry in the directory, using the
2827 /// specified constraints and possibily repositioning the entry in the
2831 /// <param name="dn"> The current distinguished name of the entry.
2834 /// <param name="newRdn"> The new relative distinguished name for the entry.
2837 /// <param name="newParentdn"> The distinguished name of an existing entry which
2838 /// is to be the new parent of the entry.
2841 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2842 /// attribute value. If false, the old name is
2843 /// retained as an attribute value.
2846 /// <param name="queue"> The queue for messages returned from a server in
2847 /// response to this request. If it is null, a
2848 /// queue object is created internally.
2851 /// <param name="cons"> The constraints specific to the operation.
2854 /// <exception> LdapException A general exception which includes an error
2855 /// message and an Ldap error code.
2857 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
2859 if ((System.Object) dn == null || (System.Object) newRdn == null)
2861 // Invalid DN or RDN parameter
2862 throw new System.ArgumentException(ExceptionMessages.RDN_PARAM_ERROR);
2866 cons = defSearchCons;
2868 LdapMessage msg = new LdapModifyDNRequest(dn, newRdn, newParentdn, deleteOldRdn, cons.getControls());
2870 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2873 //*************************************************************************
2875 //*************************************************************************
2878 /// Synchronously performs the search specified by the parameters.
2881 /// <param name="base"> The base distinguished name to search from.
2884 /// <param name="scope"> The scope of the entries to search. The following
2885 /// are the valid options:
2887 /// <li>SCOPE_BASE - searches only the base DN</li>
2889 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2891 /// <li>SCOPE_SUB - searches the base DN and all entries
2892 /// within its subtree</li>
2895 /// <param name="filter"> Search filter specifying the search criteria.
2898 /// <param name="attrs"> Names of attributes to retrieve.
2901 /// <param name="typesOnly"> If true, returns the names but not the values of
2902 /// the attributes found. If false, returns the
2903 /// names and values for attributes found.
2906 /// <exception> LdapException A general exception which includes an error
2907 /// message and an Ldap error code.
2909 public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly)
2911 return Search(base_Renamed, scope, filter, attrs, typesOnly, defSearchCons);
2915 /// Synchronously performs the search specified by the parameters,
2916 /// using the specified search constraints (such as the
2917 /// maximum number of entries to find or the maximum time to wait for
2918 /// search results).
2920 /// As part of the search constraints, the method allows specifying
2921 /// whether or not the results are to be delivered all at once or in
2922 /// smaller batches. If specified that the results are to be delivered in
2923 /// smaller batches, each iteration blocks only until the next batch of
2924 /// results is returned.
2927 /// <param name="base"> The base distinguished name to search from.
2930 /// <param name="scope"> The scope of the entries to search. The following
2931 /// are the valid options:
2933 /// <li>SCOPE_BASE - searches only the base DN</li>
2935 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2937 /// <li>SCOPE_SUB - searches the base DN and all entries
2938 /// within its subtree</li>
2941 /// <param name="filter"> The search filter specifying the search criteria.
2944 /// <param name="attrs"> The names of attributes to retrieve.
2947 /// <param name="typesOnly"> If true, returns the names but not the values of
2948 /// the attributes found. If false, returns the
2949 /// names and values for attributes found.
2952 /// <param name="cons"> The constraints specific to the search.
2955 /// <exception> LdapException A general exception which includes an error
2956 /// message and an Ldap error code.
2958 public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchConstraints cons)
2960 LdapSearchQueue queue = Search(base_Renamed, scope, filter, attrs, typesOnly, null, cons);
2963 cons = defSearchCons;
2964 return new LdapSearchResults(this, queue, cons);
2967 /// <summary> Asynchronously performs the search specified by the parameters.
2970 /// <param name="base"> The base distinguished name to search from.
2973 /// <param name="scope"> The scope of the entries to search. The following
2974 /// are the valid options:
2976 /// <li>SCOPE_BASE - searches only the base DN</li>
2978 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2980 /// <li>SCOPE_SUB - searches the base DN and all entries
2981 /// within its subtree</li>
2984 /// <param name="filter"> Search filter specifying the search criteria.
2987 /// <param name="attrs"> Names of attributes to retrieve.
2990 /// <param name="typesOnly"> If true, returns the names but not the values of
2991 /// the attributes found. If false, returns the
2992 /// names and values for attributes found.
2995 /// <param name="queue"> Handler for messages returned from a server in
2996 /// response to this request. If it is null, a
2997 /// queue object is created internally.
3000 /// <exception> LdapException A general exception which includes an error
3001 /// message and an Ldap error code.
3003 public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue)
3005 return Search(base_Renamed, scope, filter, attrs, typesOnly, queue, defSearchCons);
3008 /// <summary> Asynchronously performs the search specified by the parameters,
3009 /// also allowing specification of constraints for the search (such
3010 /// as the maximum number of entries to find or the maximum time to
3011 /// wait for search results).
3014 /// <param name="base"> The base distinguished name to search from.
3017 /// <param name="scope"> The scope of the entries to search. The following
3018 /// are the valid options:
3020 /// <li>SCOPE_BASE - searches only the base DN</li>
3022 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
3024 /// <li>SCOPE_SUB - searches the base DN and all entries
3025 /// within its subtree</li>
3028 /// <param name="filter"> The search filter specifying the search criteria.
3031 /// <param name="attrs"> The names of attributes to retrieve.
3034 /// <param name="typesOnly"> If true, returns the names but not the values of
3035 /// the attributes found. If false, returns the
3036 /// names and values for attributes found.
3039 /// <param name="queue"> The queue for messages returned from a server in
3040 /// response to this request. If it is null, a
3041 /// queue object is created internally.
3044 /// <param name="cons"> The constraints specific to the search.
3047 /// <exception> LdapException A general exception which includes an error
3048 /// message and an Ldap error code.
3050 public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue, LdapSearchConstraints cons)
3052 if ((System.Object) filter == null)
3054 filter = "objectclass=*";
3057 cons = defSearchCons;
3059 LdapMessage msg = new LdapSearchRequest(base_Renamed, scope, filter, attrs, cons.Dereference, cons.MaxResults, cons.ServerTimeLimit, typesOnly, cons.getControls());
3061 LdapSearchQueue myqueue = queue;
3062 if (myqueue == null)
3064 agent = new MessageAgent();
3065 myqueue = new LdapSearchQueue(agent);
3069 agent = queue.MessageAgent;
3074 agent.sendMessage(conn, msg, cons.TimeLimit, myqueue, null);
3076 catch (LdapException lex)
3087 /// <summary> Synchronously performs the search specified by the Ldap URL, returning
3088 /// an enumerable LdapSearchResults object.
3091 /// <param name="toGet">The Ldap URL specifying the entry to read.
3094 /// <exception> LdapException A general exception which includes an error
3095 /// message and an Ldap error code.
3097 public static LdapSearchResults Search(LdapUrl toGet)
3099 // Get a clone of default search constraints, method alters batchSize
3100 return Search(toGet, null);
3107 /// <summary> Synchronously perfoms the search specified by the Ldap URL, using
3108 /// the specified search constraints (such as the maximum number of
3109 /// entries to find or the maximum time to wait for search results).
3111 /// When this method is called, a new connection is created
3112 /// automatically, using the host and port specified in the URL. After
3113 /// all search results have been received from the server, the method
3114 /// closes the connection (in other words, it disconnects from the Ldap
3117 /// As part of the search constraints, a choice can be made as to whether
3118 /// to have the results delivered all at once or in smaller batches. If
3119 /// the results are to be delivered in smaller batches, each iteration
3120 /// blocks only until the next batch of results is returned.
3124 /// <param name="toGet"> Ldap URL specifying the entry to read.
3127 /// <param name="cons"> The constraints specific to the search.
3130 /// <exception> LdapException A general exception which includes an error
3131 /// message and an Ldap error code.
3133 public static LdapSearchResults Search(LdapUrl toGet, LdapSearchConstraints cons)
3135 LdapConnection lconn = new LdapConnection();
3136 lconn.Connect(toGet.Host, toGet.Port);
3139 // This is a clone, so we already have our own copy
3140 cons = lconn.SearchConstraints;
3144 // get our own copy of user's constraints because we modify it
3145 cons = (LdapSearchConstraints) cons.Clone();
3147 cons.BatchSize = 0; // Must wait until all results arrive
3148 LdapSearchResults toReturn = lconn.Search(toGet.getDN(), toGet.Scope, toGet.Filter, toGet.AttributeArray, false, cons);
3153 /// <summary> Sends an Ldap request to a directory server.
3155 /// The specified the Ldap request is sent to the directory server
3156 /// associated with this connection using default constraints. An Ldap
3157 /// request object is a subclass {@link LdapMessage} with the operation
3158 /// type set to one of the request types. You can build a request by using
3159 /// the request classes found in this package
3161 /// You should note that, since Ldap requests sent to the server
3162 /// using sendRequest are asynchronous, automatic referral following
3163 /// does not apply to these requests.
3166 /// <param name="request">The Ldap request to send to the directory server.
3168 /// <param name="queue"> The queue for messages returned from a server in
3169 /// response to this request. If it is null, a
3170 /// queue object is created internally.
3172 /// <exception> LdapException A general exception which includes an error
3173 /// message and an Ldap error code.
3176 /// <seealso cref="LdapMessage.Type">
3178 /// <seealso cref="RfcLdapMessage.isRequest">
3180 public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue)
3182 return SendRequest(request, queue, null);
3185 /// <summary> Sends an Ldap request to a directory server.
3187 /// The specified the Ldap request is sent to the directory server
3188 /// associated with this connection. An Ldap request object is an
3189 /// {@link LdapMessage} with the operation type set to one of the request
3190 /// types. You can build a request by using the request classes found in this
3193 /// You should note that, since Ldap requests sent to the server
3194 /// using sendRequest are asynchronous, automatic referral following
3195 /// does not apply to these requests.
3198 /// <param name="request">The Ldap request to send to the directory server.
3200 /// <param name="queue"> The queue for messages returned from a server in
3201 /// response to this request. If it is null, a
3202 /// queue object is created internally.
3204 /// <param name="cons"> The constraints that apply to this request
3206 /// <exception> LdapException A general exception which includes an error
3207 /// message and an Ldap error code.
3210 /// <seealso cref="LdapMessage.Type">
3212 /// <seealso cref="RfcLdapMessage.isRequest">
3214 public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue, LdapConstraints cons)
3218 if (!request.Request)
3220 throw new System.SystemException("Object is not a request message");
3225 cons = defSearchCons;
3228 // Get the correct queue for a search request
3230 LdapMessageQueue myqueue = queue;
3231 if (myqueue == null)
3233 agent = new MessageAgent();
3234 if (request.Type == LdapMessage.SEARCH_REQUEST)
3236 myqueue = new LdapSearchQueue(agent);
3240 myqueue = new LdapResponseQueue(agent);
3245 if (request.Type == LdapMessage.SEARCH_REQUEST)
3247 agent = queue.MessageAgent;
3251 agent = queue.MessageAgent;
3257 agent.sendMessage(conn, request, cons.TimeLimit, myqueue, null);
3259 catch (LdapException lex)
3266 //*************************************************************************
3268 //*************************************************************************
3270 /// <summary> Locates the appropriate message agent and sends
3271 /// the Ldap request to a directory server.
3274 /// <param name="msg">the message to send
3277 /// <param name="timeout">the timeout value
3280 /// <param name="queue">the response queue or null
3283 /// <returns> the LdapResponseQueue for this request
3286 /// <exception> LdapException A general exception which includes an error
3287 /// message and an Ldap error code.
3289 private LdapResponseQueue SendRequestToServer(LdapMessage msg, int timeout, LdapResponseQueue queue, BindProperties bindProps)
3294 agent = new MessageAgent();
3295 queue = new LdapResponseQueue(agent);
3299 agent = queue.MessageAgent;
3302 agent.sendMessage(conn, msg, timeout, queue, bindProps);
3306 /// <summary> get an LdapConnection object so that we can follow a referral.
3307 /// This function is never called if cons.getReferralFollowing() returns
3311 /// <param name="referrals">the array of referral strings
3315 /// <returns> The referralInfo object
3318 /// <exception> LdapReferralException A general exception which includes
3319 /// an error message and an Ldap error code.
3321 private ReferralInfo getReferralConnection(System.String[] referrals)
3323 ReferralInfo refInfo = null;
3324 System.Exception ex = null;
3325 LdapConnection rconn = null;
3326 LdapReferralHandler rh = defSearchCons.getReferralHandler();
3328 // Check if we use LdapRebind to get authentication credentials
3329 if ((rh == null) || (rh is LdapAuthHandler))
3331 for (i = 0; i < referrals.Length; i++)
3333 // dn, pw are null in the default case (anonymous bind)
3334 System.String dn = null;
3338 rconn = new LdapConnection();
3339 rconn.Constraints = defSearchCons;
3340 LdapUrl url = new LdapUrl(referrals[i]);
3341 rconn.Connect(url.Host, url.Port);
3344 if (rh is LdapAuthHandler)
3346 // Get application supplied dn and pw
3347 LdapAuthProvider ap = ((LdapAuthHandler) rh).getAuthProvider(url.Host, url.Port);
3352 rconn.Bind(Ldap_V3, dn, pw);
3354 refInfo = new ReferralInfo(rconn, referrals, url);
3355 // Indicate this connection created to follow referral
3356 rconn.Connection.ActiveReferral = refInfo;
3359 catch (System.Exception lex)
3369 catch (LdapException e)
3377 // Check if application gets connection and does bind
3380 // rh instanceof LdapBind
3383 rconn = ((LdapBindHandler) rh).Bind(referrals, this);
3386 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR);
3387 rex.setReferrals(referrals);
3390 // Figure out which Url belongs to the connection
3391 for (int idx = 0; idx < referrals.Length; idx++)
3395 LdapUrl url = new LdapUrl(referrals[idx]);
3396 if (url.Host.ToUpper().Equals(rconn.Host.ToUpper()) && (url.Port == rconn.Port))
3398 refInfo = new ReferralInfo(rconn, referrals, url);
3402 catch (System.Exception e)
3407 if (refInfo == null)
3409 // Could not match LdapBind.bind() connecction with URL list
3410 ex = new LdapLocalException(ExceptionMessages.REFERRAL_BIND_MATCH, LdapException.CONNECT_ERROR);
3413 catch (System.Exception lex)
3421 // Could not connect to any server, throw an exception
3422 LdapException ldapex;
3423 if (ex is LdapReferralException)
3425 throw (LdapReferralException) ex;
3427 else if (ex is LdapException)
3429 ldapex = (LdapException) ex;
3433 ldapex = new LdapLocalException(ExceptionMessages.SERVER_CONNECT_ERROR, new System.Object[]{conn.Host}, LdapException.CONNECT_ERROR, ex);
3435 // Error attempting to follow a referral
3436 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ldapex);
3437 rex.setReferrals(referrals);
3438 // Use last URL string for the failed referral
3439 rex.FailedReferral = referrals[referrals.Length - 1];
3443 // We now have an authenticated connection
3444 // to be used to follow the referral.
3448 /// <summary> Check the result code and throw an exception if needed.
3450 /// If referral following is enabled, checks if we need to
3451 /// follow a referral
3454 /// <param name="queue">- the message queue of the current response
3457 /// <param name="cons">- the constraints that apply to the request
3460 /// <param name="response">- the LdapResponse to check
3462 private void chkResultCode(LdapMessageQueue queue, LdapConstraints cons, LdapResponse response)
3464 if ((response.ResultCode == LdapException.REFERRAL) && cons.ReferralFollowing)
3466 // Perform referral following and return
3467 System.Collections.ArrayList refConn = null;
3470 chaseReferral(queue, cons, response, response.Referrals, 0, false, null);
3474 releaseReferralConnections(refConn);
3479 // Throws exception for non success result
3480 response.chkResultCode();
3485 /// <summary> Follow referrals if necessary referral following enabled.
3486 /// This function is called only by synchronous requests.
3487 /// Search responses come here only if referral following is
3488 /// enabled and if we are processing a SearchResultReference
3489 /// or a Response with a status of REFERRAL, i.e. we are
3490 /// going to follow a referral.
3492 /// This functions recursively follows a referral until a result
3493 /// is returned or until the hop limit is reached.
3496 /// <param name="queue">The LdapResponseQueue for this request
3499 /// <param name="cons">The constraints that apply to the request
3502 /// <param name="msg">The referral or search reference response message
3505 /// <param name="initialReferrals">The referral array returned from the
3506 /// initial request.
3509 /// <param name="hopCount">the number of hops already used while
3510 /// following this referral
3513 /// <param name="searchReference">true if the message is a search reference
3516 /// <param name="connectionList">An optional array list used to store
3517 /// the LdapConnection objects used in following the referral.
3520 /// <returns> The array list used to store the all LdapConnection objects
3521 /// used in following the referral. The list will be empty
3522 /// if there were none.
3525 /// <exception> LdapException A general exception which includes an error
3526 /// message and an Ldap error code.
3529 internal virtual System.Collections.ArrayList chaseReferral(LdapMessageQueue queue, LdapConstraints cons, LdapMessage msg, System.String[] initialReferrals, int hopCount, bool searchReference, System.Collections.ArrayList connectionList)
3531 System.Collections.ArrayList connList = connectionList;
3532 LdapConnection rconn = null; // new conn for following referral
3533 ReferralInfo rinfo = null; // referral info
3534 LdapMessage origMsg;
3536 // Get a place to store new connections
3537 if (connList == null)
3539 connList = new System.Collections.ArrayList(cons.HopLimit);
3541 // Following referrals or search reference
3542 System.String[] refs; // referral list
3543 if (initialReferrals != null)
3545 // Search continuation reference from a search request
3546 refs = initialReferrals;
3547 origMsg = msg.RequestingMessage;
3551 // Not a search request
3552 LdapResponse resp = (LdapResponse) queue.getResponse();
3553 if (resp.ResultCode != LdapException.REFERRAL)
3555 // Not referral result,throw Exception if nonzero result
3556 resp.chkResultCode();
3559 // We have a referral response
3560 refs = resp.Referrals;
3561 origMsg = resp.RequestingMessage;
3563 LdapUrl refUrl; // referral represented as URL
3566 // increment hop count, check max hops
3567 if (hopCount++ > cons.HopLimit)
3569 throw new LdapLocalException("Max hops exceeded", LdapException.REFERRAL_LIMIT_EXCEEDED);
3571 // Get a connection to follow the referral
3572 rinfo = getReferralConnection(refs);
3573 rconn = rinfo.ReferralConnection;
3574 refUrl = rinfo.ReferralUrl;
3575 connList.Add(rconn);
3578 // rebuild msg into new msg changing msgID,dn,scope,filter
3579 LdapMessage newMsg = rebuildRequest(origMsg, refUrl, searchReference);
3582 // Send new message on new connection
3586 if (queue is LdapResponseQueue)
3588 agent = queue.MessageAgent;
3592 agent = queue.MessageAgent;
3594 agent.sendMessage(rconn.Connection, newMsg, defSearchCons.TimeLimit, queue, null);
3596 catch (InterThreadException ex)
3598 // Error ending request to referred server
3599 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_SEND, LdapException.CONNECT_ERROR, null, ex);
3600 rex.setReferrals(initialReferrals);
3601 ReferralInfo ref_Renamed = rconn.Connection.ActiveReferral;
3602 rex.FailedReferral = ref_Renamed.ReferralUrl.ToString();
3606 if (initialReferrals == null)
3608 // For operation results, when all responses are complete,
3609 // the stack unwinds back to the original and returns
3610 // to the application.
3611 // An exception is thrown for an error
3612 connList = chaseReferral(queue, cons, null, null, hopCount, false, connList);
3616 // For search, just return to LdapSearchResults object
3620 catch (System.Exception ex)
3623 if (ex is LdapReferralException)
3625 throw (LdapReferralException) ex;
3630 // Set referral list and failed referral
3631 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ex);
3632 rex.setReferrals(refs);
3635 rex.FailedReferral = rinfo.ReferralUrl.ToString();
3639 rex.FailedReferral = refs[refs.Length - 1];
3647 /// <summary> Builds a new request replacing dn, scope, and filter where approprate
3650 /// <param name="msg">the original LdapMessage to build the new request from
3653 /// <param name="url">the referral url
3656 /// <returns> a new LdapMessage with appropriate information replaced
3659 /// <exception> LdapException A general exception which includes an error
3660 /// message and an Ldap error code.
3662 private LdapMessage rebuildRequest(LdapMessage msg, LdapUrl url, bool reference)
3665 System.String dn = url.getDN(); // new base
3666 System.String filter = null;
3671 case LdapMessage.SEARCH_REQUEST:
3674 filter = url.Filter;
3677 // We are allowed to get a referral for the following
3679 case LdapMessage.ADD_REQUEST:
3680 case LdapMessage.BIND_REQUEST:
3681 case LdapMessage.COMPARE_REQUEST:
3682 case LdapMessage.DEL_REQUEST:
3683 case LdapMessage.EXTENDED_REQUEST:
3684 case LdapMessage.MODIFY_RDN_REQUEST:
3685 case LdapMessage.MODIFY_REQUEST:
3687 // The following return no response
3689 case LdapMessage.ABANDON_REQUEST:
3690 case LdapMessage.UNBIND_REQUEST:
3692 throw new LdapLocalException(ExceptionMessages.IMPROPER_REFERRAL, new System.Object[]{msg.Type}, LdapException.LOCAL_ERROR);
3695 return msg.Clone(dn, filter, reference);
3699 * Release connections acquired by following referrals
3701 * @param list the list of the connections
3704 internal virtual void releaseReferralConnections(System.Collections.ArrayList list)
3710 // Release referral connections
3711 for (int i = list.Count - 1; i >= 0; i--)
3713 LdapConnection rconn = null;
3716 rconn=(LdapConnection)list[i];
3718 // rconn = (LdapConnection) list.RemoveAt(i);
3721 catch (System.IndexOutOfRangeException ex)
3725 catch (LdapException lex)
3733 //*************************************************************************
3734 // Schema Related methods
3735 //*************************************************************************
3737 /// <summary> Retrieves the schema associated with a particular schema DN in the
3738 /// directory server.
3739 /// The schema DN for a particular entry is obtained by calling the
3740 /// getSchemaDN method of LDAPConnection
3743 /// <param name="schemaDN">The schema DN used to fetch the schema.
3746 /// <returns> An LDAPSchema entry containing schema attributes. If the
3747 /// entry contains no schema attributes then the returned LDAPSchema object
3751 /// <exception> LDAPException This exception occurs if the schema entry
3752 /// cannot be retrieved with this connection.
3754 /// <seealso cref="GetSchemaDN()">
3756 /// <seealso cref="GetSchemaDN(String)">
3758 public virtual LdapSchema FetchSchema(System.String schemaDN)
3760 LdapEntry ent = Read(schemaDN, LdapSchema.schemaTypeNames);
3761 return new LdapSchema(ent);
3764 /// <summary> Retrieves the Distiguished Name (DN) for the schema advertised in the
3765 /// root DSE of the Directory Server.
3767 /// The DN can be used with the methods fetchSchema and modify to retreive
3768 /// and extend schema definitions. The schema entry is located by reading
3769 /// subschemaSubentry attribute of the root DSE. This is equivalent to
3770 /// calling {@link #getSchemaDN(String) } with the DN parameter as an empty
3771 /// string: <code>getSchemaDN("")</code>.
3775 /// <returns> Distinguished Name of a schema entry in effect for the
3778 /// <exception> LDAPException This exception occurs if the schema DN
3779 /// cannot be retrieved, or if the subschemaSubentry attribute associated
3780 /// with the root DSE contains multiple values.
3783 /// <seealso cref="FetchSchema">
3785 /// <seealso cref="Modify">
3787 public virtual System.String GetSchemaDN()
3789 return GetSchemaDN("");
3792 /// <summary> Retrieves the Distiguished Name (DN) of the schema associated with a
3793 /// entry in the Directory.
3795 /// The DN can be used with the methods fetchSchema and modify to retreive
3796 /// and extend schema definitions. Reads the subschemaSubentry of the entry
3800 /// <param name="dn"> Distinguished Name of any entry. The subschemaSubentry
3801 /// attribute is queried from this entry.
3804 /// <returns> Distinguished Name of a schema entry in effect for the entry
3805 /// identified by <code>dn</code>.
3808 /// <exception> LDAPException This exception occurs if a null or empty
3809 /// value is passed as dn, if the subschemasubentry attribute cannot
3810 /// be retrieved, or the subschemasubentry contains multiple values.
3813 /// <seealso cref="FetchSchema">
3815 /// <seealso cref="Modify">
3817 public virtual System.String GetSchemaDN(System.String dn)
3819 System.String[] attrSubSchema = new System.String[]{"subschemaSubentry"};
3821 /* Read the entries subschemaSubentry attribute. Throws an exception if
3822 * no entries are returned. */
3823 LdapEntry ent = this.Read(dn, attrSubSchema);
3825 LdapAttribute attr = ent.getAttribute(attrSubSchema[0]);
3826 System.String[] values = attr.StringValueArray;
3827 if (values == null || values.Length < 1)
3829 throw new LdapLocalException(ExceptionMessages.NO_SCHEMA, new System.Object[]{dn}, LdapException.NO_RESULTS_RETURNED);
3831 else if (values.Length > 1)
3833 throw new LdapLocalException(ExceptionMessages.MULTIPLE_SCHEMA, new System.Object[]{dn}, LdapException.CONSTRAINT_VIOLATION);