PageRenderTime 36ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/Novell.Directory.Ldap/Novell.Directory.Ldap/LdapConnection.cs

https://bitbucket.org/danipen/mono
C# | 3977 lines | 1403 code | 279 blank | 2295 comment | 204 complexity | 7f94a346a1157c05f6fce05a193a72e1 MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. /******************************************************************************
  2. * The MIT License
  3. * Copyright (c) 2003 Novell Inc. www.novell.com
  4. *
  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:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  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
  21. * SOFTWARE.
  22. *******************************************************************************/
  23. //
  24. // Novell.Directory.Ldap.LdapConnection.cs
  25. //
  26. // Author:
  27. // Sunil Kumar (Sunilk@novell.com)
  28. //
  29. // (C) 2003 Novell, Inc (http://www.novell.com)
  30. //
  31. using System;
  32. using Novell.Directory.Ldap;
  33. using Novell.Directory.Ldap.Asn1;
  34. using Novell.Directory.Ldap.Rfc2251;
  35. using Novell.Directory.Ldap.Utilclass;
  36. #if !TARGET_JVM
  37. using Mono.Security.Protocol.Tls;
  38. #else
  39. using org.ietf.jgss;
  40. using javax.security.auth;
  41. using javax.security.auth.login;
  42. using java.security;
  43. using Novell.Directory.Ldap.Security;
  44. using System.Collections.Specialized;
  45. using System.Configuration;
  46. #endif
  47. using System.Security.Cryptography.X509Certificates;
  48. namespace Novell.Directory.Ldap
  49. {
  50. /// <summary> The central class that encapsulates the connection
  51. /// to a directory server through the Ldap protocol.
  52. /// LdapConnection objects are used to perform common Ldap
  53. /// operations such as search, modify and add.
  54. ///
  55. /// In addition, LdapConnection objects allow you to bind to an
  56. /// Ldap server, set connection and search constraints, and perform
  57. /// several other tasks.
  58. ///
  59. /// An LdapConnection object is not connected on
  60. /// construction and can only be connected to one server at one
  61. /// port. Multiple threads may share this single connection, typically
  62. /// by cloning the connection object, one for each thread. An
  63. /// application may have more than one LdapConnection object, connected
  64. /// to the same or different directory servers.
  65. ///
  66. ///
  67. /// </summary>
  68. public class LdapConnection : System.ICloneable
  69. {
  70. private void InitBlock()
  71. {
  72. defSearchCons = new LdapSearchConstraints();
  73. responseCtlSemaphore = new System.Object();
  74. }
  75. /// <summary> Returns the protocol version uses to authenticate.
  76. ///
  77. /// 0 is returned if no authentication has been performed.
  78. ///
  79. /// </summary>
  80. /// <returns> The protol version used for authentication or 0
  81. /// not authenticated.
  82. ///
  83. /// </returns>
  84. virtual public int ProtocolVersion
  85. {
  86. get
  87. {
  88. BindProperties prop = conn.BindProperties;
  89. if (prop == null)
  90. {
  91. return Ldap_V3;
  92. }
  93. return prop.ProtocolVersion;
  94. }
  95. }
  96. /// <summary> Returns the distinguished name (DN) used for as the bind name during
  97. /// the last successful bind operation. <code>null</code> is returned
  98. /// if no authentication has been performed or if the bind resulted in
  99. /// an aonymous connection.
  100. ///
  101. /// </summary>
  102. /// <returns> The distinguished name if authenticated; otherwise, null.
  103. ///
  104. /// </returns>
  105. virtual public System.String AuthenticationDN
  106. {
  107. get
  108. {
  109. BindProperties prop = conn.BindProperties;
  110. if (prop == null)
  111. {
  112. return null;
  113. }
  114. if (prop.Anonymous)
  115. {
  116. return null;
  117. }
  118. return prop.AuthenticationDN;
  119. }
  120. }
  121. /// <summary> Returns the method used to authenticate the connection. The return
  122. /// value is one of the following:
  123. ///
  124. /// <ul>
  125. /// <li>"none" indicates the connection is not authenticated.</li>
  126. ///
  127. ///
  128. /// <li>"simple" indicates simple authentication was used or that a null
  129. /// or empty authentication DN was specified.</li>
  130. ///
  131. /// <li>"sasl" indicates that a SASL mechanism was used to authenticate</li>
  132. /// </ul>
  133. ///
  134. /// </summary>
  135. /// <returns> The method used to authenticate the connection.
  136. /// </returns>
  137. virtual public System.String AuthenticationMethod
  138. {
  139. get
  140. {
  141. BindProperties prop = conn.BindProperties;
  142. if (prop == null)
  143. {
  144. return "simple";
  145. }
  146. return conn.BindProperties.AuthenticationMethod;
  147. }
  148. }
  149. /// <summary> Returns the properties if any specified on binding with a
  150. /// SASL mechanism.
  151. ///
  152. /// Null is returned if no authentication has been performed
  153. /// or no authentication Map is present.
  154. ///
  155. /// </summary>
  156. /// <returns> The bind properties Map Object used for SASL bind or null if
  157. /// the connection is not present or not authenticated.
  158. ///
  159. /// </returns>
  160. virtual public System.Collections.IDictionary SaslBindProperties
  161. {
  162. get
  163. {
  164. BindProperties prop = conn.BindProperties;
  165. if (prop == null)
  166. {
  167. return null;
  168. }
  169. return conn.BindProperties.SaslBindProperties;
  170. }
  171. }
  172. /// <summary> Returns the call back handler if any specified on binding with a
  173. /// SASL mechanism.
  174. ///
  175. /// Null is returned if no authentication has been performed
  176. /// or no authentication call back handler is present.
  177. ///
  178. /// </summary>
  179. /// <returns> The call back handler used for SASL bind or null if the
  180. /// object is not present or not authenticated.
  181. ///
  182. /// </returns>
  183. virtual public System.Object SaslBindCallbackHandler
  184. {
  185. get
  186. {
  187. BindProperties prop = conn.BindProperties;
  188. if (prop == null)
  189. {
  190. return null;
  191. }
  192. return conn.BindProperties.SaslCallbackHandler;
  193. }
  194. }
  195. /// <summary> Returns a copy of the set of constraints associated with this
  196. /// connection. These constraints apply to all operations performed
  197. /// through this connection (unless a different set of constraints is
  198. /// specified when calling an operation method).
  199. ///
  200. /// </summary>
  201. /// <returns> The set of default contraints that apply to this connection.
  202. ///
  203. /// </returns>
  204. /// <summary> Sets the constraints that apply to all operations performed through
  205. /// this connection (unless a different set of constraints is specified
  206. /// when calling an operation method). An LdapSearchConstraints object
  207. /// which is passed to this method sets all constraints, while an
  208. /// LdapConstraints object passed to this method sets only base constraints.
  209. ///
  210. /// </summary>
  211. /// <param name="cons"> An LdapConstraints or LdapSearchConstraints Object
  212. /// containing the contstraint values to set.
  213. ///
  214. /// </param>
  215. /// <seealso cref="Constraints()">
  216. /// </seealso>
  217. /// <seealso cref="SearchConstraints()">
  218. /// </seealso>
  219. virtual public LdapConstraints Constraints
  220. {
  221. get
  222. {
  223. return (LdapConstraints) (this.defSearchCons).Clone();
  224. }
  225. set
  226. {
  227. // Set all constraints, replace the object with a new one
  228. if (value is LdapSearchConstraints)
  229. {
  230. defSearchCons = (LdapSearchConstraints) value.Clone();
  231. return ;
  232. }
  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();
  241. if (lsc != null)
  242. {
  243. newCons.setControls(lsc);
  244. }
  245. System.Collections.Hashtable lp = newCons.Properties;
  246. if (lp != null)
  247. {
  248. newCons.Properties = lp;
  249. }
  250. defSearchCons = newCons;
  251. return ;
  252. }
  253. }
  254. /// <summary> Returns the host name of the Ldap server to which the object is or
  255. /// was last connected, in the format originally specified.
  256. ///
  257. /// </summary>
  258. /// <returns> The host name of the Ldap server to which the object last
  259. /// connected or null if the object has never connected.
  260. ///
  261. /// </returns>
  262. virtual public System.String Host
  263. {
  264. get
  265. {
  266. return conn.Host;
  267. }
  268. }
  269. /// <summary> Returns the port number of the Ldap server to which the object is or
  270. /// was last connected.
  271. ///
  272. /// </summary>
  273. /// <returns> The port number of the Ldap server to which the object last
  274. /// connected or -1 if the object has never connected.
  275. ///
  276. /// </returns>
  277. virtual public int Port
  278. {
  279. get
  280. {
  281. return conn.Port;
  282. }
  283. }
  284. /// <summary> Returns a copy of the set of search constraints associated with this
  285. /// connection. These constraints apply to search operations performed
  286. /// through this connection (unless a different set of
  287. /// constraints is specified when calling the search operation method).
  288. ///
  289. /// </summary>
  290. /// <returns> The set of default search contraints that apply to
  291. /// this connection.
  292. ///
  293. /// </returns>
  294. /// <seealso cref="Constraints">
  295. /// </seealso>
  296. /// <seealso cref="LdapSearchConstraints">
  297. /// </seealso>
  298. virtual public LdapSearchConstraints SearchConstraints
  299. {
  300. get
  301. {
  302. return (LdapSearchConstraints) this.defSearchCons.Clone();
  303. }
  304. }
  305. ///<summary> Indicates whther the perform Secure Operation or not
  306. ///</summary>
  307. ///
  308. ///<returns>
  309. /// True if SSL is on
  310. /// False if its not on
  311. ///</returns>
  312. public bool SecureSocketLayer
  313. {
  314. get
  315. {
  316. return conn.Ssl;
  317. }
  318. set
  319. {
  320. conn.Ssl=value;
  321. }
  322. }
  323. /// <summary> Indicates whether the object has authenticated to the connected Ldap
  324. /// server.
  325. ///
  326. /// </summary>
  327. /// <returns> True if the object has authenticated; false if it has not
  328. /// authenticated.
  329. ///
  330. /// </returns>
  331. virtual public bool Bound
  332. {
  333. get
  334. {
  335. return conn.Bound;
  336. }
  337. }
  338. /// <summary> Indicates whether the connection represented by this object is open
  339. /// at this time.
  340. ///
  341. /// </summary>
  342. /// <returns> True if connection is open; false if the connection is closed.
  343. /// </returns>
  344. virtual public bool Connected
  345. {
  346. get
  347. {
  348. return conn.Connected;
  349. }
  350. }
  351. /// <summary> Indicatates if the connection is protected by TLS.
  352. ///
  353. /// </summary>
  354. /// <returns> If startTLS has completed this method returns true.
  355. /// If stopTLS has completed or start tls failed, this method returns false.
  356. /// </returns>
  357. /// <returns> True if the connection is protected by TLS.
  358. ///
  359. /// </returns>
  360. virtual public bool TLS
  361. {
  362. get
  363. {
  364. return conn.TLS;
  365. }
  366. }
  367. /// <summary> Returns the Server Controls associated with the most recent response
  368. /// to a synchronous request on this connection object, or null
  369. /// if the latest response contained no Server Controls. The method
  370. /// always returns null for asynchronous requests. For asynchronous
  371. /// requests, the response controls are available in LdapMessage.
  372. ///
  373. /// </summary>
  374. /// <returns> The server controls associated with the most recent response
  375. /// to a synchronous request or null if the response contains no server
  376. /// controls.
  377. ///
  378. /// </returns>
  379. /// <seealso cref="LdapMessage.Controls">
  380. /// </seealso>
  381. virtual public LdapControl[] ResponseControls
  382. {
  383. get
  384. {
  385. if (responseCtls == null)
  386. {
  387. return null;
  388. }
  389. // We have to clone the control just in case
  390. // we have two client threads that end up retreiving the
  391. // same control.
  392. LdapControl[] clonedControl = new LdapControl[responseCtls.Length];
  393. // Also note we synchronize access to the local response
  394. // control object just in case another message containing controls
  395. // comes in from the server while we are busy duplicating
  396. // this one.
  397. lock (responseCtlSemaphore)
  398. {
  399. for (int i = 0; i < responseCtls.Length; i++)
  400. {
  401. clonedControl[i] = (LdapControl) (responseCtls[i]).Clone();
  402. }
  403. }
  404. // Return the cloned copy. Note we have still left the
  405. // control in the local responseCtls variable just in case
  406. // somebody requests it again.
  407. return clonedControl;
  408. }
  409. }
  410. /// <summary> Return the Connection object associated with this LdapConnection
  411. ///
  412. /// </summary>
  413. /// <returns> the Connection object
  414. /// </returns>
  415. virtual internal Connection Connection
  416. {
  417. /* package */
  418. get
  419. {
  420. return conn;
  421. }
  422. }
  423. /// <summary> Return the Connection object name associated with this LdapConnection
  424. ///
  425. /// </summary>
  426. /// <returns> the Connection object name
  427. /// </returns>
  428. virtual internal System.String ConnectionName
  429. {
  430. /* package */
  431. get
  432. {
  433. return name;
  434. }
  435. }
  436. private LdapSearchConstraints defSearchCons;
  437. private LdapControl[] responseCtls = null;
  438. // Synchronization Object used to synchronize access to responseCtls
  439. private System.Object responseCtlSemaphore;
  440. private Connection conn = null;
  441. private static System.Object nameLock; // protect agentNum
  442. private static int lConnNum = 0; // Debug, LdapConnection number
  443. private System.String name; // String name for debug
  444. /// <summary> Used with search to specify that the scope of entrys to search is to
  445. /// search only the base obect.
  446. ///
  447. /// SCOPE_BASE = 0
  448. /// </summary>
  449. public const int SCOPE_BASE = 0;
  450. /// <summary> Used with search to specify that the scope of entrys to search is to
  451. /// search only the immediate subordinates of the base obect.
  452. ///
  453. /// SCOPE_ONE = 1
  454. /// </summary>
  455. public const int SCOPE_ONE = 1;
  456. /// <summary> Used with search to specify that the scope of entrys to search is to
  457. /// search the base object and all entries within its subtree.
  458. ///
  459. /// SCOPE_ONE = 2
  460. /// </summary>
  461. public const int SCOPE_SUB = 2;
  462. /// <summary> Used with search instead of an attribute list to indicate that no
  463. /// attributes are to be returned.
  464. ///
  465. /// NO_ATTRS = "1.1"
  466. /// </summary>
  467. public const System.String NO_ATTRS = "1.1";
  468. /// <summary> Used with search instead of an attribute list to indicate that all
  469. /// attributes are to be returned.
  470. ///
  471. /// ALL_USER_ATTRS = "*"
  472. /// </summary>
  473. public const System.String ALL_USER_ATTRS = "*";
  474. /// <summary> Specifies the Ldapv3 protocol version when performing a bind operation.
  475. ///
  476. /// Specifies Ldap version V3 of the protocol, and is specified
  477. /// when performing bind operations.
  478. /// You can use this identifier in the version parameter
  479. /// of the bind method to specify an Ldapv3 bind.
  480. /// Ldap_V3 is the default protocol version
  481. ///
  482. /// Ldap_V3 = 3
  483. ///
  484. /// </summary>
  485. public const int Ldap_V3 = 3;
  486. /// <summary> The default port number for Ldap servers.
  487. ///
  488. /// You can use this identifier to specify the port when establishing
  489. /// a clear text connection to a server. This the default port.
  490. ///
  491. /// DEFAULT_PORT = 389
  492. ///
  493. /// </summary>
  494. public const int DEFAULT_PORT = 389;
  495. /// <summary> The default SSL port number for Ldap servers.
  496. ///
  497. /// DEFAULT_SSL_PORT = 636
  498. ///
  499. /// You can use this identifier to specify the port when establishing
  500. /// a an SSL connection to a server..
  501. /// </summary>
  502. public const int DEFAULT_SSL_PORT = 636;
  503. /// <summary> A string that can be passed in to the getProperty method.
  504. ///
  505. /// Ldap_PROPERTY_SDK = "version.sdk"
  506. ///
  507. /// You can use this string to request the version of the SDK.
  508. /// </summary>
  509. public const System.String Ldap_PROPERTY_SDK = "version.sdk";
  510. /// <summary> A string that can be passed in to the getProperty method.
  511. ///
  512. /// Ldap_PROPERTY_PROTOCOL = "version.protocol"
  513. ///
  514. /// You can use this string to request the version of the
  515. /// Ldap protocol.
  516. /// </summary>
  517. public const System.String Ldap_PROPERTY_PROTOCOL = "version.protocol";
  518. /// <summary> A string that can be passed in to the getProperty method.
  519. ///
  520. /// Ldap_PROPERTY_SECURITY = "version.security"
  521. ///
  522. /// You can use this string to request the type of security
  523. /// being used.
  524. /// </summary>
  525. public const System.String Ldap_PROPERTY_SECURITY = "version.security";
  526. /// <summary> A string that corresponds to the server shutdown notification OID.
  527. /// This notification may be used by the server to advise the client that
  528. /// the server is about to close the connection due to an error
  529. /// condition.
  530. ///
  531. /// SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036"
  532. /// </summary>
  533. public const System.String SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036";
  534. /// <summary> The OID string that identifies a StartTLS request and response.</summary>
  535. private const System.String START_TLS_OID = "1.3.6.1.4.1.1466.20037";
  536. public event CertificateValidationCallback UserDefinedServerCertValidationDelegate
  537. {
  538. add
  539. {
  540. this.conn.OnCertificateValidation += value;
  541. }
  542. remove
  543. {
  544. this.conn.OnCertificateValidation -= value;
  545. }
  546. }
  547. /*
  548. * Constructors
  549. */
  550. /// <summary> Constructs a new LdapConnection object, which will use the supplied
  551. /// class factory to construct a socket connection during
  552. /// LdapConnection.connect method.
  553. ///
  554. /// </summary>
  555. /// <param name="factory"> An object capable of producing a Socket.
  556. ///
  557. /// </param>
  558. public LdapConnection()
  559. {
  560. InitBlock();
  561. // Get a unique connection name for debug
  562. conn = new Connection();
  563. return ;
  564. }
  565. /* public LdapConnection(X509Certificate cert)
  566. {
  567. InitBlock();
  568. // Get a unique connection name for debug
  569. conn = new Connection();
  570. conn.Cert = cert;
  571. return ;
  572. }
  573. */
  574. /*
  575. * The following are methods that affect the operation of
  576. * LdapConnection, but are not Ldap requests.
  577. */
  578. /// <summary> Returns a copy of the object with a private context, but sharing the
  579. /// network connection if there is one.
  580. ///
  581. /// The network connection remains open until all clones have
  582. /// disconnected or gone out of scope. Any connection opened after
  583. /// cloning is private to the object making the connection.
  584. ///
  585. /// The clone can issue requests and freely modify options and search
  586. /// constraints, and , without affecting the source object or other clones.
  587. /// If the clone disconnects or reconnects, it is completely dissociated
  588. /// from the source object and other clones. Reauthenticating in a clone,
  589. /// however, is a global operation which will affect the source object
  590. /// and all associated clones, because it applies to the single shared
  591. /// physical connection. Any request by an associated object after one
  592. /// has reauthenticated will carry the new identity.
  593. ///
  594. /// </summary>
  595. /// <returns> A of the object.
  596. /// </returns>
  597. public System.Object Clone()
  598. {
  599. LdapConnection newClone;
  600. System.Object newObj;
  601. try
  602. {
  603. newObj = base.MemberwiseClone();
  604. newClone = (LdapConnection) newObj;
  605. }
  606. catch (System.Exception ce)
  607. {
  608. throw new System.SystemException("Internal error, cannot create clone");
  609. }
  610. newClone.conn = conn; // same underlying connection
  611. //now just duplicate the defSearchCons and responseCtls
  612. if (defSearchCons != null)
  613. {
  614. newClone.defSearchCons = (LdapSearchConstraints) defSearchCons.Clone();
  615. }
  616. else
  617. {
  618. newClone.defSearchCons = null;
  619. }
  620. if (responseCtls != null)
  621. {
  622. newClone.responseCtls = new LdapControl[responseCtls.Length];
  623. for (int i = 0; i < responseCtls.Length; i++)
  624. {
  625. newClone.responseCtls[i] = (LdapControl) responseCtls[i].Clone();
  626. }
  627. }
  628. else
  629. {
  630. newClone.responseCtls = null;
  631. }
  632. conn.incrCloneCount(); // Increment the count of clones
  633. return newObj;
  634. }
  635. /// <summary> Closes the connection, if open, and releases any other resources held
  636. /// by the object.
  637. ///
  638. /// </summary>
  639. /// <exception> LdapException A general exception which includes an error
  640. /// message and an Ldap error code.
  641. ///
  642. /// </exception>
  643. /// <seealso cref="Disconnect">
  644. /// </seealso>
  645. ~LdapConnection()
  646. {
  647. // Disconnect did not come from user API call
  648. Disconnect(defSearchCons, false);
  649. return ;
  650. }
  651. /// <summary> Returns a property of a connection object.
  652. ///
  653. /// </summary>
  654. /// <param name="name"> Name of the property to be returned.
  655. ///
  656. /// The following read-only properties are available
  657. /// for any given connection:
  658. /// <ul>
  659. /// <li>Ldap_PROPERTY_SDK returns the version of this SDK,
  660. /// as a Float data type.</li>
  661. ///
  662. /// <li>Ldap_PROPERTY_PROTOCOL returns the highest supported version of
  663. /// the Ldap protocol, as a Float data type.</li>
  664. ///
  665. /// <li>Ldap_PROPERTY_SECURITY returns a comma-separated list of the
  666. /// types of authentication supported, as a
  667. /// string.</li>
  668. /// </ul>
  669. ///
  670. /// A deep copy of the property is provided where applicable; a
  671. /// client does not need to clone the object received.
  672. ///
  673. /// </param>
  674. /// <returns> The object associated with the requested property,
  675. /// or null if the property is not defined.
  676. ///
  677. /// </returns>
  678. /// <seealso cref="LdapConstraints.getProperty">
  679. /// </seealso>
  680. /// <seealso cref="Object">
  681. /// </seealso>
  682. public virtual System.Object getProperty(System.String name)
  683. {
  684. if (name.ToUpper().Equals(Ldap_PROPERTY_SDK.ToUpper()))
  685. return Connection.sdk;
  686. else if (name.ToUpper().Equals(Ldap_PROPERTY_PROTOCOL.ToUpper()))
  687. return Connection.protocol;
  688. else if (name.ToUpper().Equals(Ldap_PROPERTY_SECURITY.ToUpper()))
  689. return Connection.security;
  690. else
  691. {
  692. return null;
  693. }
  694. }
  695. /// <summary> Registers an object to be notified on arrival of an unsolicited
  696. /// message from a server.
  697. ///
  698. /// An unsolicited message has the ID 0. A new thread is created and
  699. /// the method "messageReceived" in each registered object is called in
  700. /// turn.
  701. ///
  702. /// </summary>
  703. /// <param name="listener"> An object to be notified on arrival of an
  704. /// unsolicited message from a server. This object must
  705. /// implement the LdapUnsolicitedNotificationListener interface.
  706. ///
  707. /// </param>
  708. public virtual void AddUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
  709. {
  710. if (listener != null)
  711. conn.AddUnsolicitedNotificationListener(listener);
  712. }
  713. /// <summary> Deregisters an object so that it will no longer be notified on
  714. /// arrival of an unsolicited message from a server. If the object is
  715. /// null or was not previously registered for unsolicited notifications,
  716. /// the method does nothing.
  717. ///
  718. ///
  719. /// </summary>
  720. /// <param name="listener"> An object to no longer be notified on arrival of
  721. /// an unsolicited message from a server.
  722. ///
  723. /// </param>
  724. public virtual void RemoveUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
  725. {
  726. if (listener != null)
  727. conn.RemoveUnsolicitedNotificationListener(listener);
  728. }
  729. /// <summary> Starts Transport Layer Security (TLS) protocol on this connection
  730. /// to enable session privacy.
  731. ///
  732. /// This affects the LdapConnection object and all cloned objects. A
  733. /// socket factory that implements LdapTLSSocketFactory must be set on the
  734. /// connection.
  735. ///
  736. /// </summary>
  737. /// <exception> LdapException Thrown if TLS cannot be started. If a
  738. /// SocketFactory has been specified that does not implement
  739. /// LdapTLSSocketFactory an LdapException is thrown.
  740. ///
  741. /// </exception>
  742. public virtual void startTLS()
  743. {
  744. LdapMessage startTLS = MakeExtendedOperation(new LdapExtendedOperation(LdapConnection.START_TLS_OID, null), null);
  745. int tlsID = startTLS.MessageID;
  746. conn.acquireWriteSemaphore(tlsID);
  747. try
  748. {
  749. if (!conn.areMessagesComplete())
  750. {
  751. throw new LdapLocalException(ExceptionMessages.OUTSTANDING_OPERATIONS, LdapException.OPERATIONS_ERROR);
  752. }
  753. // Stop reader when response to startTLS request received
  754. conn.stopReaderOnReply(tlsID);
  755. // send tls message
  756. LdapResponseQueue queue = SendRequestToServer(startTLS, defSearchCons.TimeLimit, null, null);
  757. LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
  758. response.chkResultCode();
  759. conn.startTLS();
  760. }
  761. finally
  762. {
  763. //Free this semaphore no matter what exceptions get thrown
  764. conn.startReader();
  765. conn.freeWriteSemaphore(tlsID);
  766. }
  767. return ;
  768. }
  769. /// <summary> Stops Transport Layer Security(TLS) on the LDAPConnection and reverts
  770. /// back to an anonymous state.
  771. ///
  772. /// @throws LDAPException This can occur for the following reasons:
  773. /// <UL>
  774. /// <LI>StartTLS has not been called before stopTLS</LI>
  775. /// <LI>There exists outstanding messages that have not received all
  776. /// responses</LI>
  777. /// <LI>The sever was not able to support the operation</LI></UL>
  778. ///
  779. /// <p>Note: The Sun and IBM implementions of JSSE do not currently allow
  780. /// stopping TLS on an open Socket. In order to produce the same results
  781. /// this method currently disconnects the socket and reconnects, giving
  782. /// the application an anonymous connection to the server, as required
  783. /// by StopTLS</p>
  784. /// </summary>
  785. public virtual void stopTLS()
  786. {
  787. if (!TLS)
  788. {
  789. throw new LdapLocalException(ExceptionMessages.NO_STARTTLS, LdapException.OPERATIONS_ERROR);
  790. }
  791. int semaphoreID = conn.acquireWriteSemaphore();
  792. try
  793. {
  794. if (!conn.areMessagesComplete())
  795. {
  796. throw new LdapLocalException(ExceptionMessages.OUTSTANDING_OPERATIONS, LdapException.OPERATIONS_ERROR);
  797. }
  798. //stopTLS stops and starts the reader thread for us.
  799. conn.stopTLS();
  800. }
  801. finally
  802. {
  803. conn.freeWriteSemaphore(semaphoreID);
  804. /* Now that the TLS socket is closed, reset everything. This next
  805. line is temporary until JSSE is fixed to properly handle TLS stop */
  806. this.Connect(this.Host, this.Port);
  807. }
  808. return ;
  809. }
  810. //*************************************************************************
  811. // Below are all of the Ldap protocol operation methods
  812. //*************************************************************************
  813. //*************************************************************************
  814. // abandon methods
  815. //*************************************************************************
  816. /// <summary>
  817. ///
  818. /// Notifies the server not to send additional results associated with
  819. /// this LdapSearchResults object, and discards any results already
  820. /// received.
  821. ///
  822. /// </summary>
  823. /// <param name="results"> An object returned from a search.
  824. ///
  825. /// </param>
  826. /// <exception> LdapException A general exception which includes an error
  827. /// message and an Ldap error code.
  828. /// </exception>
  829. public virtual void Abandon(LdapSearchResults results)
  830. {
  831. Abandon(results, defSearchCons);
  832. return ;
  833. }
  834. /// <summary>
  835. ///
  836. /// Notifies the server not to send additional results associated with
  837. /// this LdapSearchResults object, and discards any results already
  838. /// received.
  839. ///
  840. /// </summary>
  841. /// <param name="results"> An object returned from a search.
  842. ///
  843. /// </param>
  844. /// <param name="cons"> The contraints specific to the operation.
  845. ///
  846. /// </param>
  847. /// <exception> LdapException A general exception which includes an error
  848. /// message and an Ldap error code.
  849. /// </exception>
  850. public virtual void Abandon(LdapSearchResults results, LdapConstraints cons)
  851. {
  852. results.Abandon();
  853. return ;
  854. }
  855. /// <summary>
  856. /// Abandons an asynchronous operation.
  857. ///
  858. /// </summary>
  859. /// <param name="id"> The ID of the asynchronous operation to abandon. The ID
  860. /// can be obtained from the response queue for the
  861. /// operation.
  862. ///
  863. /// </param>
  864. /// <exception> LdapException A general exception which includes an error
  865. /// message and an Ldap error code.
  866. /// </exception>
  867. public virtual void Abandon(int id)
  868. {
  869. Abandon(id, defSearchCons);
  870. return ;
  871. }
  872. /// <summary> Abandons an asynchronous operation, using the specified
  873. /// constraints.
  874. ///
  875. /// </summary>
  876. /// <param name="id">The ID of the asynchronous operation to abandon.
  877. /// The ID can be obtained from the search
  878. /// queue for the operation.
  879. ///
  880. /// </param>
  881. /// <param name="cons">The contraints specific to the operation.
  882. ///
  883. /// </param>
  884. /// <exception> LdapException A general exception which includes an error
  885. /// message and an Ldap error code.
  886. /// </exception>
  887. public virtual void Abandon(int id, LdapConstraints cons)
  888. {
  889. // We need to inform the Message Agent which owns this messageID to
  890. // remove it from the queue.
  891. try
  892. {
  893. MessageAgent agent = conn.getMessageAgent(id);
  894. agent.Abandon(id, cons);
  895. return ;
  896. }
  897. catch (System.FieldAccessException ex)
  898. {
  899. return ; // Ignore error
  900. }
  901. }
  902. /// <summary> Abandons all outstanding operations managed by the queue.
  903. ///
  904. /// All operations in progress, which are managed by the specified queue,
  905. /// are abandoned.
  906. ///
  907. /// </summary>
  908. /// <param name="queue"> The queue returned from an asynchronous request.
  909. /// All outstanding operations managed by the queue
  910. /// are abandoned, and the queue is emptied.
  911. ///
  912. /// </param>
  913. /// <exception> LdapException A general exception which includes an error
  914. /// message and an Ldap error code.
  915. /// </exception>
  916. public virtual void Abandon(LdapMessageQueue queue)
  917. {
  918. Abandon(queue, defSearchCons);
  919. return ;
  920. }
  921. /// <summary> Abandons all outstanding operations managed by the queue.
  922. ///
  923. /// All operations in progress, which are managed by the specified
  924. /// queue, are abandoned.
  925. ///
  926. /// </summary>
  927. /// <param name="queue"> The queue returned from an asynchronous request.
  928. /// All outstanding operations managed by the queue
  929. /// are abandoned, and the queue is emptied.
  930. ///
  931. /// </param>
  932. /// <param name="cons"> The contraints specific to the operation.
  933. ///
  934. /// </param>
  935. /// <exception> LdapException A general exception which includes an error
  936. /// message and an Ldap error code.
  937. /// </exception>
  938. public virtual void Abandon(LdapMessageQueue queue, LdapConstraints cons)
  939. {
  940. if (queue != null)
  941. {
  942. MessageAgent agent;
  943. if (queue is LdapSearchQueue)
  944. {
  945. agent = queue.MessageAgent;
  946. }
  947. else
  948. {
  949. agent = queue.MessageAgent;
  950. }
  951. int[] msgIds = agent.MessageIDs;
  952. for (int i = 0; i < msgIds.Length; i++)
  953. {
  954. agent.Abandon(msgIds[i], cons);
  955. }
  956. }
  957. return ;
  958. }
  959. //*************************************************************************
  960. // add methods
  961. //*************************************************************************
  962. /// <summary> Synchronously adds an entry to the directory.
  963. ///
  964. /// </summary>
  965. /// <param name="entry"> LdapEntry object specifying the distinguished
  966. /// name and attributes of the new entry.
  967. ///
  968. /// </param>
  969. /// <exception> LdapException A general exception which includes an error
  970. /// message and an Ldap error code.
  971. /// </exception>
  972. public virtual void Add(LdapEntry entry)
  973. {
  974. Add(entry, defSearchCons);
  975. return ;
  976. }
  977. /// <summary>
  978. /// Synchronously adds an entry to the directory, using the specified
  979. /// constraints.
  980. ///
  981. /// </summary>
  982. /// <param name="entry"> LdapEntry object specifying the distinguished
  983. /// name and attributes of the new entry.
  984. ///
  985. /// </param>
  986. /// <param name="cons"> Constraints specific to the operation.
  987. ///
  988. /// </param>
  989. /// <exception> LdapException A general exception which includes an error
  990. /// message and an Ldap error code.
  991. /// </exception>
  992. public virtual void Add(LdapEntry entry, LdapConstraints cons)
  993. {
  994. LdapResponseQueue queue = Add(entry, null, cons);
  995. // Get a handle to the add response
  996. LdapResponse addResponse = (LdapResponse) (queue.getResponse());
  997. // Set local copy of responseControls synchronously if there were any
  998. lock (responseCtlSemaphore)
  999. {
  1000. responseCtls = addResponse.Controls;
  1001. }
  1002. chkResultCode(queue, cons, addResponse);
  1003. return ;
  1004. }
  1005. /// <summary> Asynchronously adds an entry to the directory.
  1006. ///
  1007. /// </summary>
  1008. /// <param name="entry"> LdapEntry object specifying the distinguished
  1009. /// name and attributes of the new entry.
  1010. ///
  1011. /// </param>
  1012. /// <param name="queue"> Handler for messages returned from a server in
  1013. /// response to this request. If it is null, a
  1014. /// queue object is created internally.
  1015. ///
  1016. /// </param>
  1017. /// <exception> LdapException A general exception which includes an error
  1018. /// message and an Ldap error code.
  1019. /// </exception>
  1020. public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue)
  1021. {
  1022. return Add(entry, queue, defSearchCons);
  1023. }
  1024. /// <summary> Asynchronously adds an entry to the directory, using the specified
  1025. /// constraints.
  1026. ///
  1027. /// </summary>
  1028. /// <param name="entry"> LdapEntry object specifying the distinguished
  1029. /// name and attributes of the new entry.
  1030. ///
  1031. /// </param>
  1032. /// <param name="queue"> Handler for messages returned from a server in
  1033. /// response to this request. If it is null, a
  1034. /// queue object is created internally.
  1035. ///
  1036. /// </param>
  1037. /// <param name="cons"> Constraints specific to the operation.
  1038. ///
  1039. /// </param>
  1040. /// <exception> LdapException A general exception which includes an error
  1041. /// message and an Ldap error code.
  1042. /// </exception>
  1043. public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue, LdapConstraints cons)
  1044. {
  1045. if (cons == null)
  1046. cons = defSearchCons;
  1047. // error check the parameters
  1048. if (entry == null)
  1049. {
  1050. throw new System.ArgumentException("The LdapEntry parameter" + " cannot be null");
  1051. }
  1052. if ((System.Object) entry.DN == null)
  1053. {
  1054. throw new System.ArgumentException("The DN value must be present" + " in the LdapEntry object");
  1055. }
  1056. LdapMessage msg = new LdapAddRequest(entry, cons.getControls());
  1057. return SendRequestToServer(msg, cons.TimeLimit, queue, null);
  1058. }
  1059. //*************************************************************************
  1060. // bind methods
  1061. //*************************************************************************
  1062. /// <summary> Synchronously authenticates to the Ldap server (that the object is
  1063. /// currently connected to) as an Ldapv3 bind, using the specified name and
  1064. /// password.
  1065. ///
  1066. /// If the object has been disconnected from an Ldap server,
  1067. /// this method attempts to reconnect to the server. If the object
  1068. /// has already authenticated, the old authentication is discarded.
  1069. ///
  1070. /// </summary>
  1071. /// <param name="dn"> If non-null and non-empty, specifies that the
  1072. /// connection and all operations through it should
  1073. /// be authenticated with dn as the distinguished
  1074. /// name.
  1075. ///
  1076. /// </param>
  1077. /// <param name="passwd"> If non-null and non-empty, specifies that the
  1078. /// connection and all operations through it should
  1079. /// be authenticated with dn as the distinguished
  1080. /// name and passwd as password.
  1081. ///
  1082. /// Note: the application should use care in the use
  1083. /// of String password objects. These are long lived
  1084. /// objects, and may expose a security risk, especially
  1085. /// in objects that are serialized. The LdapConnection
  1086. /// keeps no long lived instances of these objects.
  1087. ///
  1088. /// </param>
  1089. /// <exception> LdapException A general exception which includes an error
  1090. /// message and an Ldap error code.
  1091. ///
  1092. /// </exception>
  1093. public virtual void Bind(System.String dn, System.String passwd)
  1094. {
  1095. Bind(dn, passwd, AuthenticationTypes.None);
  1096. return ;
  1097. }
  1098. public virtual void Bind(System.String dn, System.String passwd, AuthenticationTypes authenticationTypes)
  1099. {
  1100. #if TARGET_JVM
  1101. if (authenticationTypes != AuthenticationTypes.None &&
  1102. authenticationTypes != AuthenticationTypes.ServerBind &&
  1103. authenticationTypes != AuthenticationTypes.Anonymous)
  1104. BindSecure(dn, passwd, authenticationTypes);
  1105. else
  1106. #endif
  1107. Bind(Ldap_V3, dn, passwd, defSearchCons);
  1108. return ;
  1109. }
  1110. /// <summary> Synchronously authenticates to the Ldap server (that the object is
  1111. /// currently connected to) using the specified name, password,
  1112. /// and Ldap version.
  1113. ///
  1114. /// If the object has been disconnected from an Ldap server,
  1115. /// this method attempts to reconnect to the server. If the object
  1116. /// has already authenticated, the old authentication is discarded.
  1117. ///
  1118. /// </summary>
  1119. /// <param name="version"> The Ldap protocol version, use Ldap_V3.
  1120. /// Ldap_V2 is not supported.
  1121. ///
  1122. /// </param>
  1123. /// <param name="dn"> If non-null and non-empty, specifies that the
  1124. /// connection and all operations through it should
  1125. /// be authenticated with dn as the distinguished
  1126. /// name.
  1127. ///
  1128. /// </param>
  1129. /// <param name="passwd"> If non-null and non-empty, specifies that the
  1130. /// connection and all operations through it should
  1131. /// be authenticated with dn as the distinguished
  1132. /// name and passwd as password.
  1133. ///
  1134. /// Note: the application should use care in the use
  1135. /// of String password objects. These are long lived
  1136. /// objects, and may expose a security risk, especially
  1137. /// in objects that are serialized. The LdapConnection
  1138. /// keeps no long lived instances of these objects.
  1139. ///
  1140. /// </param>
  1141. /// <exception> LdapException A general exception which includes an error
  1142. /// message and an Ldap error code.
  1143. ///
  1144. /// </exception>
  1145. public virtual void Bind(int version, System.String dn, System.String passwd)
  1146. {
  1147. Bind(version, dn, passwd, defSearchCons);
  1148. return ;
  1149. }
  1150. /// <summary> Synchronously authenticates to the Ldap server (that the object is
  1151. /// currently connected to) as an Ldapv3 bind, using the specified name,
  1152. /// password, and constraints.
  1153. ///
  1154. /// If the object has been disconnected from an Ldap server,
  1155. /// this method attempts to reconnect to the server. If the object
  1156. /// has already authenticated, the old authentication is discarded.
  1157. ///
  1158. /// </summary>
  1159. /// <param name="dn"> If non-null and non-empty, specifies that the
  1160. /// connection and all operations through it should
  1161. /// be authenticated with dn as the distinguished
  1162. /// name.
  1163. ///
  1164. /// </param>
  1165. /// <param name="passwd"> If non-null and non-empty, specifies that the
  1166. /// connection and all operations through it should
  1167. /// be authenticated with dn as the distinguished
  1168. /// name and passwd as password.
  1169. /// Note: the application should use care in the use
  1170. /// of String password objects. These are long lived
  1171. /// objects, and may expose a security risk, especially
  1172. /// in objects that are serialized. The LdapConnection
  1173. /// keeps no long lived instances of these objects.
  1174. ///
  1175. /// </param>
  1176. /// <param name="cons"> Constraints specific to the operation.
  1177. ///
  1178. /// </param>
  1179. /// <exception> LdapException A general exception which includes an error
  1180. /// message and an Ldap error code.
  1181. ///
  1182. /// </exception>
  1183. public virtual void Bind(System.String dn, System.String passwd, LdapConstraints cons)
  1184. {
  1185. Bind(Ldap_V3, dn, passwd, cons);
  1186. return ;
  1187. }
  1188. /// <summary> Synchronously authenticates to the Ldap server (that the object is
  1189. /// currently connected to) using the specified name, password, Ldap version,
  1190. /// and constraints.
  1191. ///
  1192. /// If the object has been disconnected from an Ldap server,
  1193. /// this method attempts to reconnect to the server. If the object
  1194. /// has already authenticated, the old authentication is discarded.
  1195. ///
  1196. /// </summary>
  1197. /// <param name="version"> The Ldap protocol version, use Ldap_V3.
  1198. /// Ldap_V2 is not supported.
  1199. ///
  1200. /// </param>
  1201. /// <param name="dn"> If non-null and non-empty, specifies that the
  1202. /// connection and all operations through it should
  1203. /// be authenticated with dn as the distinguished
  1204. /// name.
  1205. ///
  1206. /// </param>
  1207. /// <param name="passwd"> If non-null and non-empty, specifies that the
  1208. /// connection and all operations through it should
  1209. /// be authenticated with dn as the distinguished
  1210. /// name and passwd as password.
  1211. ///
  1212. /// Note: the application should use care in the use
  1213. /// of String password objects. These are long lived
  1214. /// objects, and may expose a security risk, especially
  1215. /// in objects that are serialized. The LdapConnection
  1216. /// keeps no long lived instances of these objects.
  1217. ///
  1218. /// </param>
  1219. /// <param name="cons"> The constraints specific to the operation.
  1220. ///
  1221. /// </param>
  1222. /// <exception> LdapException A general exception which includes an error
  1223. /// message and an Ldap error code.
  1224. ///
  1225. /// </exception>
  1226. public virtual void Bind(int version, System.String dn, System.String passwd, LdapConstraints cons)
  1227. {
  1228. sbyte[] pw = null;
  1229. if ((System.Object) passwd != null)
  1230. {
  1231. try
  1232. {
  1233. System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
  1234. byte[] ibytes = encoder.GetBytes(passwd);
  1235. pw=SupportClass.ToSByteArray(ibytes);
  1236. // pw = passwd.getBytes("UTF8");
  1237. passwd = null; // Keep no reference to String object
  1238. }
  1239. catch (System.IO.IOException ex)
  1240. {
  1241. passwd = null; // Keep no reference to String object
  1242. throw new System.SystemException(ex.ToString());
  1243. }
  1244. }
  1245. Bind(version, dn, pw, cons);
  1246. return ;
  1247. }
  1248. /// <summary> Synchronously authenticates to the Ldap server (that the object is
  1249. /// currently connected to) using the specified name, password,
  1250. /// and Ldap version.
  1251. ///
  1252. /// If the object has been disconnected from an Ldap server,
  1253. /// this method attempts to reconnect to the server. If the object
  1254. /// has already authenticated, the old authentication is discarded.
  1255. ///
  1256. /// </summary>
  1257. /// <param name="version"> The version of the Ldap protocol to use
  1258. /// in the bind, use Ldap_V3. Ldap_V2 is not supported.
  1259. ///
  1260. /// </param>
  1261. /// <param name="dn"> If non-null and non-empty, specifies that the
  1262. /// connection and all operations through it should
  1263. /// be authenticated with dn as the distinguished
  1264. /// name.
  1265. ///
  1266. /// </param>
  1267. /// <param name="passwd"> If non-null and non-empty, specifies that the
  1268. /// connection and all operations through it should
  1269. /// be authenticated with dn as the distinguished
  1270. /// name and passwd as password.
  1271. ///
  1272. /// </param>
  1273. /// <exception> LdapException A general exception which includes an error
  1274. /// message and an Ldap error code.
  1275. /// </exception>
  1276. [CLSCompliantAttribute(false)]
  1277. public virtual void Bind(int version, System.String dn, sbyte[] passwd)
  1278. {
  1279. Bind(version, dn, passwd, defSearchCons);
  1280. return ;
  1281. }
  1282. /// <summary>
  1283. /// Synchronously authenticates to the Ldap server (that the object is
  1284. /// currently connected to) using the specified name, password, Ldap version,
  1285. /// and constraints.
  1286. ///
  1287. /// If the object has been disconnected from an Ldap server,
  1288. /// this method attempts to reconnect to the server. If the object
  1289. /// has already authenticated, the old authentication is discarded.
  1290. ///
  1291. /// </summary>
  1292. /// <param name="version"> The Ldap protocol version, use Ldap_V3.
  1293. /// Ldap_V2 is not supported.
  1294. ///
  1295. /// </param>
  1296. /// <param name="dn"> If non-null and non-empty, specifies that the
  1297. /// connection and all operations through it should
  1298. /// be authenticated with dn as the distinguished
  1299. /// name.
  1300. ///
  1301. /// </param>
  1302. /// <param name="passwd"> If non-null and non-empty, specifies that the
  1303. /// connection and all operations through it should
  1304. /// be authenticated with dn as the distinguished
  1305. /// name and passwd as password.
  1306. ///
  1307. /// </param>
  1308. /// <param name="cons"> The constraints specific to the operation.
  1309. ///
  1310. /// </param>
  1311. /// <exception> LdapException A general exception which includes an error
  1312. /// message and an Ldap error code.
  1313. /// </exception>
  1314. [CLSCompliantAttribute(false)]
  1315. public virtual void Bind(int version, System.String dn, sbyte[] passwd, LdapConstraints cons)
  1316. {
  1317. LdapResponseQueue queue = Bind(version, dn, passwd, null, cons, null);
  1318. LdapResponse res = (LdapResponse) queue.getResponse();
  1319. if (res != null)
  1320. {
  1321. // Set local copy of responseControls synchronously if any
  1322. lock (responseCtlSemaphore)
  1323. {
  1324. responseCtls = res.Controls;
  1325. }
  1326. chkResultCode(queue, cons, res);
  1327. }
  1328. return ;
  1329. }
  1330. /// <summary> Asynchronously authenticates to the Ldap server (that the object is
  1331. /// currently connected to) using the specified name, password, Ldap
  1332. /// version, and queue.
  1333. ///
  1334. /// If the object has been disconnected from an Ldap server,
  1335. /// this method attempts to reconnect to the server. If the object
  1336. /// has already authenticated, the old authentication is discarded.
  1337. ///
  1338. ///
  1339. /// </summary>
  1340. /// <param name="version"> The Ldap protocol version, use Ldap_V3.
  1341. /// Ldap_V2 is not supported.
  1342. ///
  1343. /// </param>
  1344. /// <param name="dn"> If non-null and non-empty, specifies that the
  1345. /// connection and all operations through it should
  1346. /// be authenticated with dn as the distinguished
  1347. /// name.
  1348. ///
  1349. /// </param>
  1350. /// <param name="passwd"> If non-null and non-empty, specifies that the
  1351. /// connection and all operations through it should
  1352. /// be authenticated with dn as the distinguished
  1353. /// name and passwd as password.
  1354. ///
  1355. /// </param>
  1356. /// <param name="queue"> Handler for messages returned from a server in
  1357. /// response to this request. If it is null, a
  1358. /// queue object is created internally.
  1359. ///
  1360. /// </param>
  1361. /// <exception> LdapException A general exception which includes an error
  1362. /// message and an Ldap error code.
  1363. /// </exception>
  1364. [CLSCompliantAttribute(false)]
  1365. public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue)
  1366. {
  1367. return Bind(version, dn, passwd, queue, defSearchCons, null);
  1368. }
  1369. /// <summary> Asynchronously authenticates to the Ldap server (that the object is
  1370. /// currently connected to) using the specified name, password, Ldap
  1371. /// version, queue, and constraints.
  1372. ///
  1373. /// If the object has been disconnected from an Ldap server,
  1374. /// this method attempts to reconnect to the server. If the object
  1375. /// had already authenticated, the old authentication is discarded.
  1376. ///
  1377. /// </summary>
  1378. /// <param name="version"> The Ldap protocol version, use Ldap_V3.
  1379. /// Ldap_V2 is not supported.
  1380. ///
  1381. /// </param>
  1382. /// <param name="dn"> If non-null and non-empty, specifies that the
  1383. /// connection and all operations through it should
  1384. /// be authenticated with dn as the distinguished
  1385. /// name.
  1386. ///
  1387. /// </param>
  1388. /// <param name="passwd"> If non-null and non-empty, specifies that the
  1389. /// connection and all operations through it should
  1390. /// be authenticated with dn as the distinguished
  1391. /// name and passwd as password.
  1392. ///
  1393. /// </param>
  1394. /// <param name="queue"> Handler for messages returned from a server in
  1395. /// response to this request. If it is null, a
  1396. /// queue object is created internally.
  1397. ///
  1398. /// </param>
  1399. /// <param name="cons"> Constraints specific to the operation.
  1400. ///
  1401. /// </param>
  1402. /// <exception> LdapException A general exception which includes an error
  1403. /// message and an Ldap error code.
  1404. /// </exception>
  1405. [CLSCompliantAttribute(false)]
  1406. public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue, LdapConstraints cons, string mech)
  1407. {
  1408. int msgId;
  1409. BindProperties bindProps;
  1410. if (cons == null)
  1411. cons = defSearchCons;
  1412. if ((System.Object) dn == null)
  1413. {
  1414. dn = "";
  1415. }
  1416. else
  1417. {
  1418. dn = dn.Trim();
  1419. }
  1420. if (passwd == null)
  1421. passwd = new sbyte[]{};
  1422. bool anonymous = false;
  1423. if (passwd.Length == 0)
  1424. {
  1425. anonymous = true; // anonymous, passwd length zero with simple bind
  1426. dn = ""; // set to null if anonymous
  1427. }
  1428. LdapMessage msg;
  1429. #if TARGET_JVM
  1430. if (mech != null)
  1431. msg = new LdapBindRequest(version, "", mech, passwd, cons.getControls());
  1432. else
  1433. #endif
  1434. msg = new LdapBindRequest(version, dn, passwd, cons.getControls());
  1435. msgId = msg.MessageID;
  1436. bindProps = new BindProperties(version, dn, "simple", anonymous, null, null);
  1437. // For bind requests, if not connected, attempt to reconnect
  1438. if (!conn.Connected)
  1439. {
  1440. if ((System.Object) conn.Host != null)
  1441. {
  1442. conn.connect(conn.Host, conn.Port);
  1443. }
  1444. else
  1445. {
  1446. throw new LdapException(ExceptionMessages.CONNECTION_IMPOSSIBLE, LdapException.CONNECT_ERROR, null);
  1447. }
  1448. }
  1449. #if TARGET_JVM
  1450. // stopping reader to enable stream replace after secure binding is complete, see Connection.ReplaceStreams()
  1451. if (mech != null)
  1452. {
  1453. if (conn.BindSemIdClear) {
  1454. // need to acquire a semaphore only if bindSemId is clear
  1455. // because if we receive SASL_BIND_IN_PROGRESS the semaphore is not
  1456. // released when the response is queued
  1457. conn.acquireWriteSemaphore(msgId);
  1458. conn.BindSemId = msgId;
  1459. }
  1460. conn.stopReaderOnReply(msgId);
  1461. }
  1462. else
  1463. #endif
  1464. // The semaphore is released when the bind response is queued.
  1465. conn.acquireWriteSemaphore(msgId);
  1466. return SendRequestToServer(msg, cons.TimeLimit, queue, bindProps);
  1467. }
  1468. #if TARGET_JVM
  1469. private void BindSecure(System.String username, System.String password, AuthenticationTypes authenticationTypes)
  1470. {
  1471. if ((authenticationTypes & AuthenticationTypes.Secure) != 0) {
  1472. LoginContext loginContext = null;
  1473. try {
  1474. if (username != null && password != null) {
  1475. AuthenticationCallbackHandler callbackHandler = new AuthenticationCallbackHandler (username,password);
  1476. loginContext = new LoginContext (SecurityAppName, callbackHandler);
  1477. }
  1478. else
  1479. loginContext = new LoginContext (SecurityAppName);
  1480. loginContext.login ();
  1481. }
  1482. catch (Exception e) {
  1483. throw new LdapException ("Failed to create login security context", 80, "", e);
  1484. }
  1485. Krb5Helper krb5Helper = null;
  1486. try {
  1487. krb5Helper = new Krb5Helper ("ldap@" + conn.Host, username, loginContext.getSubject (), authenticationTypes, SecurityMech);
  1488. }
  1489. finally {
  1490. loginContext.logout();
  1491. }
  1492. sbyte [] token = krb5Helper.ExchangeTokens (Krb5Helper.EmptyToken);
  1493. for (;;) {
  1494. LdapResponseQueue queue = Bind(LdapConnection.Ldap_V3, username, token, null, null, AuthenticationMech);
  1495. LdapResponse res = (LdapResponse) queue.getResponse ();
  1496. if (res.ResultCode != LdapException.SASL_BIND_IN_PROGRESS &&
  1497. res.ResultCode != LdapException.SUCCESS) {
  1498. krb5Helper.Dispose();
  1499. throw new LdapException(ExceptionMessages.CONNECTION_ERROR, res.ResultCode, res.ErrorMessage);
  1500. }
  1501. Asn1OctetString serverSaslCreds = ((RfcBindResponse)res.Asn1Object.Response).ServerSaslCreds;
  1502. token = serverSaslCreds != null ? serverSaslCreds.byteValue () : null;
  1503. token = krb5Helper.ExchangeTokens(token == null ? Krb5Helper.EmptyToken : token);
  1504. if (res.ResultCode != LdapException.SASL_BIND_IN_PROGRESS)
  1505. break;
  1506. conn.ReplaceStreams (conn.InputStream,conn.OutputStream);
  1507. }
  1508. System.IO.Stream inStream = conn.InputStream;
  1509. System.IO.Stream newIn = new SecureStream (inStream, krb5Helper);
  1510. System.IO.Stream outStream = conn.OutputStream;
  1511. System.IO.Stream newOut = new SecureStream (outStream, krb5Helper);
  1512. conn.ReplaceStreams (newIn,newOut);
  1513. }
  1514. }
  1515. static string SecurityMech
  1516. {
  1517. get {
  1518. string securityMech = null;
  1519. NameValueCollection config = (NameValueCollection) ConfigurationSettings.GetConfig ("mainsoft.directoryservices/settings");
  1520. if (config != null)
  1521. securityMech = config ["securitymech"];
  1522. if (securityMech == null)
  1523. throw new ArgumentException("Security mechanism id not found in application settings");
  1524. return securityMech;
  1525. }
  1526. }
  1527. static string SecurityAppName
  1528. {
  1529. get {
  1530. string securityAppName = null;
  1531. NameValueCollection config = (NameValueCollection) ConfigurationSettings.GetConfig ("mainsoft.directoryservices/settings");
  1532. if (config != null)
  1533. securityAppName = config ["securityappname"];
  1534. if (securityAppName == null)
  1535. throw new ArgumentException("Application section name not found in application settings");
  1536. return securityAppName;
  1537. }
  1538. }
  1539. static string AuthenticationMech
  1540. {
  1541. get {
  1542. string authenticationMech = null;
  1543. NameValueCollection config = (NameValueCollection) ConfigurationSettings.GetConfig ("mainsoft.directoryservices/settings");
  1544. if (config != null)
  1545. authenticationMech = config ["authenticationmech"];
  1546. if (authenticationMech == null)
  1547. throw new ArgumentException("Authentication mechanism not found in application settings");
  1548. return authenticationMech;
  1549. }
  1550. }
  1551. #endif
  1552. //*************************************************************************
  1553. // compare methods
  1554. //*************************************************************************
  1555. /// <summary>
  1556. /// Synchronously checks to see if an entry contains an attribute
  1557. /// with a specified value.
  1558. ///
  1559. /// </summary>
  1560. /// <param name="dn"> The distinguished name of the entry to use in the
  1561. /// comparison.
  1562. ///
  1563. /// </param>
  1564. /// <param name="attr"> The attribute to compare against the entry. The
  1565. /// method checks to see if the entry has an
  1566. /// attribute with the same name and value as this
  1567. /// attribute.
  1568. ///
  1569. /// </param>
  1570. /// <returns> True if the entry has the value,
  1571. /// and false if the entry does not
  1572. /// have the value or the attribute.
  1573. ///
  1574. /// </returns>
  1575. /// <exception> LdapException A general exception which includes an error
  1576. /// message and an Ldap error code.
  1577. /// </exception>
  1578. public virtual bool Compare(System.String dn, LdapAttribute attr)
  1579. {
  1580. return Compare(dn, attr, defSearchCons);
  1581. }
  1582. /// <summary>
  1583. /// Synchronously checks to see if an entry contains an attribute with a
  1584. /// specified value, using the specified constraints.
  1585. ///
  1586. /// </summary>
  1587. /// <param name="dn"> The distinguished name of the entry to use in the
  1588. /// comparison.
  1589. ///
  1590. /// </param>
  1591. /// <param name="attr"> The attribute to compare against the entry. The
  1592. /// method checks to see if the entry has an
  1593. /// attribute with the same name and value as this
  1594. /// attribute.
  1595. ///
  1596. /// </param>
  1597. /// <param name="cons"> Constraints specific to the operation.
  1598. ///
  1599. /// </param>
  1600. /// <returns> True if the entry has the value,
  1601. /// and false if the entry does not
  1602. /// have the value or the attribute.
  1603. ///
  1604. /// </returns>
  1605. /// <exception> LdapException A general exception which includes an error
  1606. /// message and an Ldap error code.
  1607. /// </exception>
  1608. public virtual bool Compare(System.String dn, LdapAttribute attr, LdapConstraints cons)
  1609. {
  1610. bool ret = false;
  1611. LdapResponseQueue queue = Compare(dn, attr, null, cons);
  1612. LdapResponse res = (LdapResponse) queue.getResponse();
  1613. // Set local copy of responseControls synchronously - if there were any
  1614. lock (responseCtlSemaphore)
  1615. {
  1616. responseCtls = res.Controls;
  1617. }
  1618. if (res.ResultCode == LdapException.COMPARE_TRUE)
  1619. {
  1620. ret = true;
  1621. }
  1622. else if (res.ResultCode == LdapException.COMPARE_FALSE)
  1623. {
  1624. ret = false;
  1625. }
  1626. else
  1627. {
  1628. chkResultCode(queue, cons, res);
  1629. }
  1630. return ret;
  1631. }
  1632. /// <summary> Asynchronously compares an attribute value with one in the directory,
  1633. /// using the specified queue.
  1634. ///
  1635. /// Please note that a successful completion of this command results in
  1636. /// one of two status codes: LdapException.COMPARE_TRUE if the entry
  1637. /// has the value, and LdapException.COMPARE_FALSE if the entry
  1638. /// does not have the value or the attribute.
  1639. ///
  1640. /// </summary>
  1641. /// <param name="dn"> The distinguished name of the entry containing an
  1642. /// attribute to compare.
  1643. ///
  1644. /// </param>
  1645. /// <param name="attr"> An attribute to compare.
  1646. ///
  1647. /// </param>
  1648. /// <param name="queue"> The queue for messages returned from a server in
  1649. /// response to this request. If it is null, a
  1650. /// queue object is created internally.
  1651. ///
  1652. /// </param>
  1653. /// <exception> LdapException A general exception which includes an error
  1654. /// message and an Ldap error code.
  1655. ///
  1656. /// </exception>
  1657. /// <seealso cref="LdapException.COMPARE_TRUE">
  1658. /// </seealso>
  1659. /// <seealso cref="LdapException.COMPARE_FALSE">
  1660. /// </seealso>
  1661. public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue)
  1662. {
  1663. return Compare(dn, attr, queue, defSearchCons);
  1664. }
  1665. /// <summary> Asynchronously compares an attribute value with one in the directory,
  1666. /// using the specified queue and contraints.
  1667. ///
  1668. /// Please note that a successful completion of this command results in
  1669. /// one of two status codes: LdapException.COMPARE_TRUE if the entry
  1670. /// has the value, and LdapException.COMPARE_FALSE if the entry
  1671. /// does not have the value or the attribute.
  1672. ///
  1673. /// </summary>
  1674. /// <param name="dn"> The distinguished name of the entry containing an
  1675. /// attribute to compare.
  1676. ///
  1677. /// </param>
  1678. /// <param name="attr"> An attribute to compare.
  1679. ///
  1680. /// </param>
  1681. /// <param name="queue"> Handler for messages returned from a server in
  1682. /// response to this request. If it is null, a
  1683. /// queue object is created internally.
  1684. ///
  1685. /// </param>
  1686. /// <param name="cons"> Constraints specific to the operation.
  1687. ///
  1688. /// </param>
  1689. /// <exception> LdapException A general exception which includes an error
  1690. /// message and an Ldap error code.
  1691. ///
  1692. /// </exception>
  1693. /// <seealso cref="LdapException.COMPARE_TRUE">
  1694. /// </seealso>
  1695. /// <seealso cref="LdapException.COMPARE_FALSE">
  1696. /// </seealso>
  1697. public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue, LdapConstraints cons)
  1698. {
  1699. if (attr.size() != 1)
  1700. {
  1701. throw new System.ArgumentException("compare: Exactly one value " + "must be present in the LdapAttribute");
  1702. }
  1703. if ((System.Object) dn == null)
  1704. {
  1705. // Invalid parameter
  1706. throw new System.ArgumentException("compare: DN cannot be null");
  1707. }
  1708. if (cons == null)
  1709. cons = defSearchCons;
  1710. LdapMessage msg = new LdapCompareRequest(dn, attr.Name, attr.ByteValue, cons.getControls());
  1711. return SendRequestToServer(msg, cons.TimeLimit, queue, null);
  1712. }
  1713. //*************************************************************************
  1714. // connect methods
  1715. //*************************************************************************
  1716. /// <summary>
  1717. /// Connects to the specified host and port.
  1718. ///
  1719. /// If this LdapConnection object represents an open connection, the
  1720. /// connection is closed first before the new connection is opened.
  1721. /// At this point, there is no authentication, and any operations are
  1722. /// conducted as an anonymous client.
  1723. ///
  1724. /// When more than one host name is specified, each host is contacted
  1725. /// in turn until a connection can be established.
  1726. ///
  1727. /// </summary>
  1728. /// <param name="host">A host name or a dotted string representing the IP address
  1729. /// of a host running an Ldap server. It may also
  1730. /// contain a list of host names, space-delimited. Each host
  1731. /// name can include a trailing colon and port number.
  1732. ///
  1733. /// </param>
  1734. /// <param name="port">The TCP or UDP port number to connect to or contact.
  1735. /// The default Ldap port is 389. The port parameter is
  1736. /// ignored for any host hame which includes a colon and
  1737. /// port number.
  1738. ///
  1739. /// </param>
  1740. /// <exception> LdapException A general exception which includes an error
  1741. /// message and an Ldap error code.
  1742. ///
  1743. /// </exception>
  1744. public virtual void Connect(System.String host, int port)
  1745. {
  1746. // connect doesn't affect other clones
  1747. // If not a clone, destroys old connection.
  1748. // Step through the space-delimited list
  1749. SupportClass.Tokenizer hostList = new SupportClass.Tokenizer(host, " ");
  1750. System.String address = null;
  1751. int specifiedPort;
  1752. int colonIndex; //after the colon is the port
  1753. while (hostList.HasMoreTokens())
  1754. {
  1755. try
  1756. {
  1757. specifiedPort = port;
  1758. address = hostList.NextToken();
  1759. colonIndex = address.IndexOf((System.Char) ':');
  1760. if (colonIndex != - 1 && colonIndex + 1 != address.Length)
  1761. {
  1762. //parse Port out of address
  1763. try
  1764. {
  1765. specifiedPort = System.Int32.Parse(address.Substring(colonIndex + 1));
  1766. address = address.Substring(0, (colonIndex) - (0));
  1767. }
  1768. catch (System.Exception e)
  1769. {
  1770. throw new System.ArgumentException(ExceptionMessages.INVALID_ADDRESS);
  1771. }
  1772. }
  1773. // This may return a different conn object
  1774. // Disassociate this clone with the underlying connection.
  1775. conn = conn.destroyClone(true);
  1776. conn.connect(address, specifiedPort);
  1777. break;
  1778. }
  1779. catch (LdapException LE)
  1780. {
  1781. if (!hostList.HasMoreTokens())
  1782. throw LE;
  1783. }
  1784. }
  1785. return ;
  1786. }
  1787. //*************************************************************************
  1788. // delete methods
  1789. //*************************************************************************
  1790. /// <summary>
  1791. /// Synchronously deletes the entry with the specified distinguished name
  1792. /// from the directory.
  1793. ///
  1794. /// Note: A Delete operation will not remove an entry that contains
  1795. /// subordinate entries, nor will it dereference alias entries.
  1796. ///
  1797. /// </summary>
  1798. /// <param name="dn"> The distinguished name of the entry to delete.
  1799. ///
  1800. /// </param>
  1801. /// <exception> LdapException A general exception which includes an error
  1802. /// message and an Ldap error code.
  1803. /// </exception>
  1804. public virtual void Delete(System.String dn)
  1805. {
  1806. Delete(dn, defSearchCons);
  1807. return ;
  1808. }
  1809. /// <summary> Synchronously deletes the entry with the specified distinguished name
  1810. /// from the directory, using the specified constraints.
  1811. ///
  1812. /// Note: A Delete operation will not remove an entry that contains
  1813. /// subordinate entries, nor will it dereference alias entries.
  1814. ///
  1815. /// </summary>
  1816. /// <param name="dn"> The distinguished name of the entry to delete.
  1817. ///
  1818. /// </param>
  1819. /// <param name="cons"> Constraints specific to the operation.
  1820. ///
  1821. /// </param>
  1822. /// <exception> LdapException A general exception which includes an error
  1823. /// message and an Ldap error code.
  1824. /// </exception>
  1825. public virtual void Delete(System.String dn, LdapConstraints cons)
  1826. {
  1827. LdapResponseQueue queue = Delete(dn, null, cons);
  1828. // Get a handle to the delete response
  1829. LdapResponse deleteResponse = (LdapResponse) (queue.getResponse());
  1830. // Set local copy of responseControls synchronously - if there were any
  1831. lock (responseCtlSemaphore)
  1832. {
  1833. responseCtls = deleteResponse.Controls;
  1834. }
  1835. chkResultCode(queue, cons, deleteResponse);
  1836. return ;
  1837. }
  1838. /// <summary> Asynchronously deletes the entry with the specified distinguished name
  1839. /// from the directory and returns the results to the specified queue.
  1840. ///
  1841. /// Note: A Delete operation will not remove an entry that contains
  1842. /// subordinate entries, nor will it dereference alias entries.
  1843. ///
  1844. /// </summary>
  1845. /// <param name="dn"> The distinguished name of the entry to modify.
  1846. ///
  1847. /// </param>
  1848. /// <param name="queue"> The queue for messages returned from a server in
  1849. /// response to this request. If it is null, a
  1850. /// queue object is created internally.
  1851. ///
  1852. /// </param>
  1853. /// <exception> LdapException A general exception which includes an error
  1854. /// message and an Ldap error code.
  1855. ///
  1856. /// </exception>
  1857. public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue)
  1858. {
  1859. return Delete(dn, queue, defSearchCons);
  1860. }
  1861. /// <summary> Asynchronously deletes the entry with the specified distinguished name
  1862. /// from the directory, using the specified contraints and queue.
  1863. ///
  1864. /// Note: A Delete operation will not remove an entry that contains
  1865. /// subordinate entries, nor will it dereference alias entries.
  1866. ///
  1867. /// </summary>
  1868. /// <param name="dn"> The distinguished name of the entry to delete.
  1869. ///
  1870. /// </param>
  1871. /// <param name="queue"> The queue for messages returned from a server in
  1872. /// response to this request. If it is null, a
  1873. /// queue object is created internally.
  1874. ///
  1875. /// </param>
  1876. /// <param name="cons"> The constraints specific to the operation.
  1877. ///
  1878. /// </param>
  1879. /// <exception> LdapException A general exception which includes an error
  1880. /// message and an Ldap error code.
  1881. ///
  1882. /// </exception>
  1883. public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue, LdapConstraints cons)
  1884. {
  1885. if ((System.Object) dn == null)
  1886. {
  1887. // Invalid DN parameter
  1888. throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
  1889. }
  1890. if (cons == null)
  1891. cons = defSearchCons;
  1892. LdapMessage msg = new LdapDeleteRequest(dn, cons.getControls());
  1893. return SendRequestToServer(msg, cons.TimeLimit, queue, null);
  1894. }
  1895. //*************************************************************************
  1896. // disconnect method
  1897. //*************************************************************************
  1898. /// <summary>
  1899. /// Synchronously disconnects from the Ldap server.
  1900. ///
  1901. /// Before the object can perform Ldap operations again, it must
  1902. /// reconnect to the server by calling connect.
  1903. ///
  1904. /// The disconnect method abandons any outstanding requests, issues an
  1905. /// unbind request to the server, and then closes the socket.
  1906. ///
  1907. /// </summary>
  1908. /// <exception> LdapException A general exception which includes an error
  1909. /// message and an Ldap error code.
  1910. ///
  1911. /// </exception>
  1912. public virtual void Disconnect()
  1913. {
  1914. // disconnect from API call
  1915. Disconnect(defSearchCons, true);
  1916. return ;
  1917. }
  1918. /// <summary> Synchronously disconnects from the Ldap server.
  1919. ///
  1920. /// Before the object can perform Ldap operations again, it must
  1921. /// reconnect to the server by calling connect.
  1922. ///
  1923. /// The disconnect method abandons any outstanding requests, issues an
  1924. /// unbind request to the server, and then closes the socket.
  1925. ///
  1926. /// </summary>
  1927. /// <param name="cons">LDPConstraints to be set with the unbind request
  1928. ///
  1929. /// </param>
  1930. /// <exception> LdapException A general exception which includes an error
  1931. /// message and an Ldap error code.
  1932. /// </exception>
  1933. public virtual void Disconnect(LdapConstraints cons)
  1934. {
  1935. // disconnect from API call
  1936. Disconnect(cons, true);
  1937. return ;
  1938. }
  1939. /// <summary> Synchronously disconnect from the server
  1940. ///
  1941. /// </summary>
  1942. /// <param name="how">true if application call disconnect API, false if finalize.
  1943. /// </param>
  1944. private void Disconnect(LdapConstraints cons, bool how)
  1945. {
  1946. // disconnect doesn't affect other clones
  1947. // If not a clone, distroys connection
  1948. conn = conn.destroyClone(how);
  1949. return ;
  1950. }
  1951. //*************************************************************************
  1952. // extendedOperation methods
  1953. //*************************************************************************
  1954. /// <summary> Provides a synchronous means to access extended, non-mandatory
  1955. /// operations offered by a particular Ldapv3 compliant server.
  1956. ///
  1957. /// </summary>
  1958. /// <param name="op"> The object which contains (1) an identifier of an extended
  1959. /// operation which should be recognized by the particular Ldap
  1960. /// server this client is connected to and (2)
  1961. /// an operation-specific sequence of octet strings
  1962. /// or BER-encoded values.
  1963. ///
  1964. /// </param>
  1965. /// <returns> An operation-specific object, containing an ID and either an octet
  1966. /// string or BER-encoded values.
  1967. ///
  1968. /// </returns>
  1969. /// <exception> LdapException A general exception which includes an error
  1970. /// message and an Ldap error code.
  1971. /// </exception>
  1972. public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op)
  1973. {
  1974. return ExtendedOperation(op, defSearchCons);
  1975. }
  1976. /*
  1977. * Synchronous Ldap extended request with SearchConstraints
  1978. */
  1979. /// <summary>
  1980. /// Provides a synchronous means to access extended, non-mandatory
  1981. /// operations offered by a particular Ldapv3 compliant server.
  1982. ///
  1983. /// </summary>
  1984. /// <param name="op"> The object which contains (1) an identifier of an extended
  1985. /// operation which should be recognized by the particular Ldap
  1986. /// server this client is connected to and (2) an
  1987. /// operation-specific sequence of octet strings
  1988. /// or BER-encoded values.
  1989. ///
  1990. /// </param>
  1991. /// <param name="cons">The constraints specific to the operation.
  1992. ///
  1993. /// </param>
  1994. /// <returns> An operation-specific object, containing an ID and either an
  1995. /// octet string or BER-encoded values.
  1996. ///
  1997. /// </returns>
  1998. /// <exception> LdapException A general exception which includes an error
  1999. /// message and an Ldap error code.
  2000. /// </exception>
  2001. public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
  2002. {
  2003. // Call asynchronous API and get back handler to reponse queue
  2004. LdapResponseQueue queue = ExtendedOperation(op, cons, null);
  2005. LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
  2006. // Set local copy of responseControls synchronously - if there were any
  2007. lock (responseCtlSemaphore)
  2008. {
  2009. responseCtls = response.Controls;
  2010. }
  2011. chkResultCode(queue, cons, response);
  2012. return response;
  2013. }
  2014. /*
  2015. * Asynchronous Ldap extended request
  2016. */
  2017. /// <summary> Provides an asynchronous means to access extended, non-mandatory
  2018. /// operations offered by a particular Ldapv3 compliant server.
  2019. ///
  2020. /// </summary>
  2021. /// <param name="op"> The object which contains (1) an identifier of an extended
  2022. /// operation which should be recognized by the particular Ldap
  2023. /// server this client is connected to and (2) an
  2024. /// operation-specific sequence of octet strings
  2025. /// or BER-encoded values.
  2026. ///
  2027. /// </param>
  2028. /// <param name="queue"> The queue for messages returned from a server in
  2029. /// response to this request. If it is null, a queue
  2030. /// object is created internally.
  2031. ///
  2032. /// </param>
  2033. /// <returns> An operation-specific object, containing an ID and either an octet
  2034. /// string or BER-encoded values.
  2035. ///
  2036. /// </returns>
  2037. /// <exception> LdapException A general exception which includes an error
  2038. /// message and an Ldap error code.
  2039. /// </exception>
  2040. public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapResponseQueue queue)
  2041. {
  2042. return ExtendedOperation(op, defSearchCons, queue);
  2043. }
  2044. /*
  2045. * Asynchronous Ldap extended request with SearchConstraints
  2046. */
  2047. /// <summary> Provides an asynchronous means to access extended, non-mandatory
  2048. /// operations offered by a particular Ldapv3 compliant server.
  2049. ///
  2050. /// </summary>
  2051. /// <param name="op"> The object which contains (1) an identifier of an extended
  2052. /// operation which should be recognized by the particular Ldap
  2053. /// server this client is connected to and (2) an operation-
  2054. /// specific sequence of octet strings or BER-encoded values.
  2055. ///
  2056. /// </param>
  2057. /// <param name="queue"> The queue for messages returned from a server in
  2058. /// response to this request. If it is null, a queue
  2059. /// object is created internally.
  2060. ///
  2061. /// </param>
  2062. /// <param name="cons"> The constraints specific to this operation.
  2063. ///
  2064. /// </param>
  2065. /// <returns> An operation-specific object, containing an ID and either an
  2066. /// octet string or BER-encoded values.
  2067. ///
  2068. /// </returns>
  2069. /// <exception> LdapException A general exception which includes an error
  2070. /// message and an Ldap error code.
  2071. /// </exception>
  2072. public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons, LdapResponseQueue queue)
  2073. {
  2074. // Use default constraints if none-specified
  2075. if (cons == null)
  2076. cons = defSearchCons;
  2077. LdapMessage msg = MakeExtendedOperation(op, cons);
  2078. return SendRequestToServer(msg, cons.TimeLimit, queue, null);
  2079. }
  2080. /// <summary> Formulates the extended operation, constraints into an
  2081. /// LdapMessage and returns the LdapMessage. This is used by
  2082. /// extendedOperation and startTLS which needs the LdapMessage to
  2083. /// get the MessageID.
  2084. /// </summary>
  2085. protected internal virtual LdapMessage MakeExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
  2086. {
  2087. // Use default constraints if none-specified
  2088. if (cons == null)
  2089. cons = defSearchCons;
  2090. // error check the parameters
  2091. if ((System.Object) op.getID() == null)
  2092. {
  2093. // Invalid extended operation parameter, no OID specified
  2094. throw new System.ArgumentException(ExceptionMessages.OP_PARAM_ERROR);
  2095. }
  2096. return new LdapExtendedRequest(op, cons.getControls());
  2097. }
  2098. //*************************************************************************
  2099. // getResponseControls method
  2100. //*************************************************************************
  2101. //*************************************************************************
  2102. // modify methods
  2103. //*************************************************************************
  2104. /// <summary> Synchronously makes a single change to an existing entry in the
  2105. /// directory.
  2106. ///
  2107. /// For example, this modify method changes the value of an attribute,
  2108. /// adds a new attribute value, or removes an existing attribute value.
  2109. ///
  2110. /// The LdapModification object specifies both the change to be made and
  2111. /// the LdapAttribute value to be changed.
  2112. ///
  2113. /// If the request fails with {@link LdapException.CONNECT_ERROR},
  2114. /// it is indeterminate whether or not the server made the modification.
  2115. ///
  2116. /// </summary>
  2117. /// <param name="dn"> The distinguished name of the entry to modify.
  2118. ///
  2119. /// </param>
  2120. /// <param name="mod"> A single change to be made to the entry.
  2121. ///
  2122. /// </param>
  2123. /// <exception> LdapException A general exception which includes an error
  2124. /// message and an Ldap error code.
  2125. /// </exception>
  2126. public virtual void Modify(System.String dn, LdapModification mod)
  2127. {
  2128. Modify(dn, mod, defSearchCons);
  2129. return ;
  2130. }
  2131. /// <summary>
  2132. /// Synchronously makes a single change to an existing entry in the
  2133. /// directory, using the specified constraints.
  2134. ///
  2135. /// For example, this modify method changes the value of an attribute,
  2136. /// adds a new attribute value, or removes an existing attribute value.
  2137. ///
  2138. /// The LdapModification object specifies both the change to be
  2139. /// made and the LdapAttribute value to be changed.
  2140. ///
  2141. /// If the request fails with {@link LdapException.CONNECT_ERROR},
  2142. /// it is indeterminate whether or not the server made the modification.
  2143. ///
  2144. /// </summary>
  2145. /// <param name="dn"> The distinguished name of the entry to modify.
  2146. ///
  2147. /// </param>
  2148. /// <param name="mod"> A single change to be made to the entry.
  2149. ///
  2150. /// </param>
  2151. /// <param name="cons"> The constraints specific to the operation.
  2152. ///
  2153. /// </param>
  2154. /// <exception> LdapException A general exception which includes an error
  2155. /// message and an Ldap error code.
  2156. /// </exception>
  2157. public virtual void Modify(System.String dn, LdapModification mod, LdapConstraints cons)
  2158. {
  2159. LdapModification[] mods = new LdapModification[1];
  2160. mods[0] = mod;
  2161. Modify(dn, mods, cons);
  2162. return ;
  2163. }
  2164. /// <summary>
  2165. /// Synchronously makes a set of changes to an existing entry in the
  2166. /// directory.
  2167. ///
  2168. /// For example, this modify method changes attribute values, adds
  2169. /// new attribute values, or removes existing attribute values.
  2170. ///
  2171. /// Because the server applies all changes in an LdapModification array
  2172. /// atomically, the application can expect that no changes
  2173. /// have been performed if an error is returned.
  2174. /// If the request fails with {@link LdapException.CONNECT_ERROR},
  2175. /// it is indeterminate whether or not the server made the modifications.
  2176. ///
  2177. /// </summary>
  2178. /// <param name="dn"> Distinguished name of the entry to modify.
  2179. ///
  2180. /// </param>
  2181. /// <param name="mods"> The changes to be made to the entry.
  2182. ///
  2183. /// </param>
  2184. /// <exception> LdapException A general exception which includes an error
  2185. /// message and an Ldap error code.
  2186. /// </exception>
  2187. public virtual void Modify(System.String dn, LdapModification[] mods)
  2188. {
  2189. Modify(dn, mods, defSearchCons);
  2190. return ;
  2191. }
  2192. /// <summary> Synchronously makes a set of changes to an existing entry in the
  2193. /// directory, using the specified constraints.
  2194. ///
  2195. /// For example, this modify method changes attribute values, adds new
  2196. /// attribute values, or removes existing attribute values.
  2197. ///
  2198. /// Because the server applies all changes in an LdapModification array
  2199. /// atomically, the application can expect that no changes
  2200. /// have been performed if an error is returned.
  2201. /// If the request fails with {@link LdapException.CONNECT_ERROR},
  2202. /// it is indeterminate whether or not the server made the modifications.
  2203. ///
  2204. /// </summary>
  2205. /// <param name="dn"> The distinguished name of the entry to modify.
  2206. ///
  2207. /// </param>
  2208. /// <param name="mods"> The changes to be made to the entry.
  2209. ///
  2210. /// </param>
  2211. /// <param name="cons"> The constraints specific to the operation.
  2212. ///
  2213. /// </param>
  2214. /// <exception> LdapException A general exception which includes an
  2215. /// error message and an Ldap error code.
  2216. /// </exception>
  2217. public virtual void Modify(System.String dn, LdapModification[] mods, LdapConstraints cons)
  2218. {
  2219. LdapResponseQueue queue = Modify(dn, mods, null, cons);
  2220. // Get a handle to the modify response
  2221. LdapResponse modifyResponse = (LdapResponse) (queue.getResponse());
  2222. // Set local copy of responseControls synchronously - if there were any
  2223. lock (responseCtlSemaphore)
  2224. {
  2225. responseCtls = modifyResponse.Controls;
  2226. }
  2227. chkResultCode(queue, cons, modifyResponse);
  2228. return ;
  2229. }
  2230. /// <summary> Asynchronously makes a single change to an existing entry in the
  2231. /// directory.
  2232. ///
  2233. /// For example, this modify method can change the value of an attribute,
  2234. /// add a new attribute value, or remove an existing attribute value.
  2235. ///
  2236. /// The LdapModification object specifies both the change to be made and
  2237. /// the LdapAttribute value to be changed.
  2238. ///
  2239. /// If the request fails with {@link LdapException.CONNECT_ERROR},
  2240. /// it is indeterminate whether or not the server made the modification.
  2241. ///
  2242. /// </summary>
  2243. /// <param name="dn"> Distinguished name of the entry to modify.
  2244. ///
  2245. /// </param>
  2246. /// <param name="mod"> A single change to be made to the entry.
  2247. ///
  2248. /// </param>
  2249. /// <param name="queue"> Handler for messages returned from a server in
  2250. /// response to this request. If it is null, a
  2251. /// queue object is created internally.
  2252. ///
  2253. /// </param>
  2254. /// <exception> LdapException A general exception which includes an error
  2255. /// message and an Ldap error code.
  2256. /// </exception>
  2257. public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue)
  2258. {
  2259. return Modify(dn, mod, queue, defSearchCons);
  2260. }
  2261. /// <summary> Asynchronously makes a single change to an existing entry in the
  2262. /// directory, using the specified constraints and queue.
  2263. ///
  2264. /// For example, this modify method can change the value of an attribute,
  2265. /// add a new attribute value, or remove an existing attribute value.
  2266. ///
  2267. /// The LdapModification object specifies both the change to be made
  2268. /// and the LdapAttribute value to be changed.
  2269. ///
  2270. /// If the request fails with {@link LdapException.CONNECT_ERROR},
  2271. /// it is indeterminate whether or not the server made the modification.
  2272. ///
  2273. /// </summary>
  2274. /// <param name="dn"> Distinguished name of the entry to modify.
  2275. ///
  2276. /// </param>
  2277. /// <param name="mod"> A single change to be made to the entry.
  2278. ///
  2279. /// </param>
  2280. /// <param name="queue"> Handler for messages returned from a server in
  2281. /// response to this request. If it is null, a
  2282. /// queue object is created internally.
  2283. ///
  2284. /// </param>
  2285. /// <param name="cons"> Constraints specific to the operation.
  2286. ///
  2287. /// </param>
  2288. /// <exception> LdapException A general exception which includes an error
  2289. /// message and an Ldap error code.
  2290. /// </exception>
  2291. public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue, LdapConstraints cons)
  2292. {
  2293. LdapModification[] mods = new LdapModification[1];
  2294. mods[0] = mod;
  2295. return Modify(dn, mods, queue, cons);
  2296. }
  2297. /// <summary> Asynchronously makes a set of changes to an existing entry in the
  2298. /// directory.
  2299. ///
  2300. /// For example, this modify method can change attribute values, add new
  2301. /// attribute values, or remove existing attribute values.
  2302. ///
  2303. /// Because the server applies all changes in an LdapModification array
  2304. /// atomically, the application can expect that no changes
  2305. /// have been performed if an error is returned.
  2306. /// If the request fails with {@link LdapException.CONNECT_ERROR},
  2307. /// it is indeterminate whether or not the server made the modifications.
  2308. ///
  2309. /// </summary>
  2310. /// <param name="dn"> The distinguished name of the entry to modify.
  2311. ///
  2312. /// </param>
  2313. /// <param name="mods"> The changes to be made to the entry.
  2314. ///
  2315. /// </param>
  2316. /// <param name="queue"> The queue for messages returned from a server in
  2317. /// response to this request. If it is null, a
  2318. /// queue object is created internally.
  2319. ///
  2320. /// </param>
  2321. /// <exception> LdapException A general exception which includes an error
  2322. /// message and an Ldap error code.
  2323. /// </exception>
  2324. public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue)
  2325. {
  2326. return Modify(dn, mods, queue, defSearchCons);
  2327. }
  2328. /// <summary> Asynchronously makes a set of changes to an existing entry in the
  2329. /// directory, using the specified constraints and queue.
  2330. ///
  2331. /// For example, this modify method can change attribute values, add new
  2332. /// attribute values, or remove existing attribute values.
  2333. ///
  2334. /// Because the server applies all changes in an LdapModification array
  2335. /// atomically, the application can expect that no changes
  2336. /// have been performed if an error is returned.
  2337. /// If the request fails with {@link LdapException.CONNECT_ERROR},
  2338. /// it is indeterminate whether or not the server made the modifications.
  2339. ///
  2340. /// </summary>
  2341. /// <param name="dn"> The distinguished name of the entry to modify.
  2342. ///
  2343. /// </param>
  2344. /// <param name="mods"> The changes to be made to the entry.
  2345. ///
  2346. /// </param>
  2347. /// <param name="queue"> The queue for messages returned from a server in
  2348. /// response to this request. If it is null, a
  2349. /// queue object is created internally.
  2350. ///
  2351. /// </param>
  2352. /// <param name="cons"> Constraints specific to the operation.
  2353. ///
  2354. /// </param>
  2355. /// <exception> LdapException A general exception which includes an error
  2356. /// message and an Ldap error code.
  2357. /// </exception>
  2358. public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue, LdapConstraints cons)
  2359. {
  2360. if ((System.Object) dn == null)
  2361. {
  2362. // Invalid DN parameter
  2363. throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
  2364. }
  2365. if (cons == null)
  2366. cons = defSearchCons;
  2367. LdapMessage msg = new LdapModifyRequest(dn, mods, cons.getControls());
  2368. return SendRequestToServer(msg, cons.TimeLimit, queue, null);
  2369. }
  2370. //*************************************************************************
  2371. // read methods
  2372. //*************************************************************************
  2373. /// <summary> Synchronously reads the entry for the specified distiguished name (DN)
  2374. /// and retrieves all attributes for the entry.
  2375. ///
  2376. /// </summary>
  2377. /// <param name="dn"> The distinguished name of the entry to retrieve.
  2378. ///
  2379. /// </param>
  2380. /// <returns> the LdapEntry read from the server.
  2381. ///
  2382. /// </returns>
  2383. /// <exception> LdapException if the object was not found
  2384. /// </exception>
  2385. public virtual LdapEntry Read(System.String dn)
  2386. {
  2387. return Read(dn, defSearchCons);
  2388. }
  2389. /// <summary>
  2390. /// Synchronously reads the entry for the specified distiguished name (DN),
  2391. /// using the specified constraints, and retrieves all attributes for the
  2392. /// entry.
  2393. ///
  2394. /// </summary>
  2395. /// <param name="dn"> The distinguished name of the entry to retrieve.
  2396. ///
  2397. /// </param>
  2398. /// <param name="cons"> The constraints specific to the operation.
  2399. ///
  2400. /// </param>
  2401. /// <returns> the LdapEntry read from the server
  2402. ///
  2403. /// </returns>
  2404. /// <exception> LdapException if the object was not found
  2405. /// </exception>
  2406. public virtual LdapEntry Read(System.String dn, LdapSearchConstraints cons)
  2407. {
  2408. return Read(dn, null, cons);
  2409. }
  2410. /// <summary>
  2411. /// Synchronously reads the entry for the specified distinguished name (DN)
  2412. /// and retrieves only the specified attributes from the entry.
  2413. ///
  2414. /// </summary>
  2415. /// <param name="dn"> The distinguished name of the entry to retrieve.
  2416. ///
  2417. /// </param>
  2418. /// <param name="attrs"> The names of the attributes to retrieve.
  2419. ///
  2420. /// </param>
  2421. /// <returns> the LdapEntry read from the server
  2422. ///
  2423. /// </returns>
  2424. /// <exception> LdapException if the object was not found
  2425. /// </exception>
  2426. public virtual LdapEntry Read(System.String dn, System.String[] attrs)
  2427. {
  2428. return Read(dn, attrs, defSearchCons);
  2429. }
  2430. /// <summary> Synchronously reads the entry for the specified distinguished name (DN),
  2431. /// using the specified constraints, and retrieves only the specified
  2432. /// attributes from the entry.
  2433. ///
  2434. /// </summary>
  2435. /// <param name="dn"> The distinguished name of the entry to retrieve.
  2436. ///
  2437. /// </param>
  2438. /// <param name="attrs"> The names of the attributes to retrieve.
  2439. ///
  2440. /// </param>
  2441. /// <param name="cons"> The constraints specific to the operation.
  2442. ///
  2443. /// </param>
  2444. /// <returns> the LdapEntry read from the server
  2445. ///
  2446. /// </returns>
  2447. /// <exception> LdapException if the object was not found
  2448. /// </exception>
  2449. public virtual LdapEntry Read(System.String dn, System.String[] attrs, LdapSearchConstraints cons)
  2450. {
  2451. LdapSearchResults sr = Search(dn, SCOPE_BASE, null, attrs, false, cons);
  2452. LdapEntry ret = null;
  2453. if (sr.hasMore())
  2454. {
  2455. ret = sr.next();
  2456. if (sr.hasMore())
  2457. {
  2458. // "Read response is ambiguous, multiple entries returned"
  2459. throw new LdapLocalException(ExceptionMessages.READ_MULTIPLE, LdapException.AMBIGUOUS_RESPONSE);
  2460. }
  2461. }
  2462. return ret;
  2463. }
  2464. /// <summary> Synchronously reads the entry specified by the Ldap URL.
  2465. ///
  2466. /// When this read method is called, a new connection is created
  2467. /// automatically, using the host and port specified in the URL. After
  2468. /// finding the entry, the method closes the connection (in other words,
  2469. /// it disconnects from the Ldap server).
  2470. ///
  2471. /// If the URL specifies a filter and scope, they are not used. Of the
  2472. /// information specified in the URL, this method only uses the Ldap host
  2473. /// name and port number, the base distinguished name (DN), and the list
  2474. /// of attributes to return.
  2475. ///
  2476. /// </summary>
  2477. /// <param name="toGet"> Ldap URL specifying the entry to read.
  2478. ///
  2479. /// </param>
  2480. /// <returns> The entry specified by the base DN.
  2481. ///
  2482. /// </returns>
  2483. /// <exception> LdapException if the object was not found
  2484. /// </exception>
  2485. public static LdapEntry Read(LdapUrl toGet)
  2486. {
  2487. LdapConnection lconn = new LdapConnection();
  2488. lconn.Connect(toGet.Host, toGet.Port);
  2489. LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray);
  2490. lconn.Disconnect();
  2491. return toReturn;
  2492. }
  2493. /// <summary> Synchronously reads the entry specified by the Ldap URL, using the
  2494. /// specified constraints.
  2495. ///
  2496. /// When this method is called, a new connection is created
  2497. /// automatically, using the host and port specified in the URL. After
  2498. /// finding the entry, the method closes the connection (in other words,
  2499. /// it disconnects from the Ldap server).
  2500. ///
  2501. /// If the URL specifies a filter and scope, they are not used. Of the
  2502. /// information specified in the URL, this method only uses the Ldap host
  2503. /// name and port number, the base distinguished name (DN), and the list
  2504. /// of attributes to return.
  2505. ///
  2506. /// </summary>
  2507. /// <returns> The entry specified by the base DN.
  2508. ///
  2509. /// </returns>
  2510. /// <param name="toGet"> Ldap URL specifying the entry to read.
  2511. ///
  2512. /// </param>
  2513. /// <param name="cons"> Constraints specific to the operation.
  2514. ///
  2515. /// </param>
  2516. /// <exception> LdapException if the object was not found
  2517. /// </exception>
  2518. public static LdapEntry Read(LdapUrl toGet, LdapSearchConstraints cons)
  2519. {
  2520. LdapConnection lconn = new LdapConnection();
  2521. lconn.Connect(toGet.Host, toGet.Port);
  2522. LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray, cons);
  2523. lconn.Disconnect();
  2524. return toReturn;
  2525. }
  2526. //*************************************************************************
  2527. // rename methods
  2528. //*************************************************************************
  2529. /// <summary>
  2530. /// Synchronously renames an existing entry in the directory.
  2531. ///
  2532. /// </summary>
  2533. /// <param name="dn"> The current distinguished name of the entry.
  2534. ///
  2535. /// </param>
  2536. /// <param name="newRdn"> The new relative distinguished name for the entry.
  2537. ///
  2538. /// </param>
  2539. /// <param name="deleteOldRdn"> If true, the old name is not retained as an
  2540. /// attribute value. If false, the old name is
  2541. /// retained as an attribute value.
  2542. ///
  2543. /// </param>
  2544. /// <exception> LdapException A general exception which includes an error
  2545. /// message and an Ldap error code.
  2546. /// </exception>
  2547. public virtual void Rename(System.String dn, System.String newRdn, bool deleteOldRdn)
  2548. {
  2549. Rename(dn, newRdn, deleteOldRdn, defSearchCons);
  2550. return ;
  2551. }
  2552. /// <summary>
  2553. /// Synchronously renames an existing entry in the directory, using the
  2554. /// specified constraints.
  2555. ///
  2556. /// </summary>
  2557. /// <param name="dn"> The current distinguished name of the entry.
  2558. ///
  2559. /// </param>
  2560. /// <param name="newRdn"> The new relative distinguished name for the entry.
  2561. ///
  2562. /// </param>
  2563. /// <param name="deleteOldRdn"> If true, the old name is not retained as an
  2564. /// attribute value. If false, the old name is
  2565. /// retained as an attribute value.
  2566. ///
  2567. /// </param>
  2568. /// <param name="cons"> The constraints specific to the operation.
  2569. ///
  2570. /// </param>
  2571. /// <exception> LdapException A general exception which includes an error
  2572. /// message and an Ldap error code.
  2573. /// </exception>
  2574. public virtual void Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapConstraints cons)
  2575. {
  2576. // null for newParentdn means that this is originating as an Ldapv2 call
  2577. Rename(dn, newRdn, null, deleteOldRdn, cons);
  2578. return ;
  2579. }
  2580. /// <summary> Synchronously renames an existing entry in the directory, possibly
  2581. /// repositioning the entry in the directory tree.
  2582. ///
  2583. /// </summary>
  2584. /// <param name="dn"> The current distinguished name of the entry.
  2585. ///
  2586. /// </param>
  2587. /// <param name="newRdn"> The new relative distinguished name for the entry.
  2588. ///
  2589. /// </param>
  2590. /// <param name="newParentdn"> The distinguished name of an existing entry which
  2591. /// is to be the new parent of the entry.
  2592. ///
  2593. /// </param>
  2594. /// <param name="deleteOldRdn"> If true, the old name is not retained as an
  2595. /// attribute value. If false, the old name is
  2596. /// retained as an attribute value.
  2597. ///
  2598. /// </param>
  2599. /// <exception> LdapException A general exception which includes an error
  2600. /// message and an Ldap error code.
  2601. /// </exception>
  2602. public virtual void Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn)
  2603. {
  2604. Rename(dn, newRdn, newParentdn, deleteOldRdn, defSearchCons);
  2605. return ;
  2606. }
  2607. /// <summary>
  2608. /// Synchronously renames an existing entry in the directory, using the
  2609. /// specified constraints and possibly repositioning the entry in the
  2610. /// directory tree.
  2611. ///
  2612. /// </summary>
  2613. /// <param name="dn"> The current distinguished name of the entry.
  2614. ///
  2615. /// </param>
  2616. /// <param name="newRdn"> The new relative distinguished name for the entry.
  2617. ///
  2618. /// </param>
  2619. /// <param name="newParentdn"> The distinguished name of an existing entry which
  2620. /// is to be the new parent of the entry.
  2621. ///
  2622. /// </param>
  2623. /// <param name="deleteOldRdn"> If true, the old name is not retained as an
  2624. /// attribute value. If false, the old name is
  2625. /// retained as an attribute value.
  2626. ///
  2627. /// </param>
  2628. /// <param name="cons"> The constraints specific to the operation.
  2629. ///
  2630. /// </param>
  2631. /// <exception> LdapException A general exception which includes an error
  2632. /// message and an Ldap error code.
  2633. /// </exception>
  2634. public virtual void Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapConstraints cons)
  2635. {
  2636. LdapResponseQueue queue = Rename(dn, newRdn, newParentdn, deleteOldRdn, null, cons);
  2637. // Get a handle to the rename response
  2638. LdapResponse renameResponse = (LdapResponse) (queue.getResponse());
  2639. // Set local copy of responseControls synchronously - if there were any
  2640. lock (responseCtlSemaphore)
  2641. {
  2642. responseCtls = renameResponse.Controls;
  2643. }
  2644. chkResultCode(queue, cons, renameResponse);
  2645. return ;
  2646. }
  2647. /*
  2648. * rename
  2649. */
  2650. /// <summary> Asynchronously renames an existing entry in the directory.
  2651. ///
  2652. /// </summary>
  2653. /// <param name="dn"> The current distinguished name of the entry.
  2654. ///
  2655. /// </param>
  2656. /// <param name="newRdn"> The new relative distinguished name for the entry.
  2657. ///
  2658. /// </param>
  2659. /// <param name="deleteOldRdn"> If true, the old name is not retained as an
  2660. /// attribute value. If false, the old name is
  2661. /// retained as an attribute value.
  2662. ///
  2663. /// </param>
  2664. /// <param name="queue"> The queue for messages returned from a server in
  2665. /// response to this request. If it is null, a
  2666. /// queue object is created internally.
  2667. ///
  2668. /// </param>
  2669. /// <exception> LdapException A general exception which includes an error
  2670. /// message and an Ldap error code.
  2671. /// </exception>
  2672. public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue)
  2673. {
  2674. return Rename(dn, newRdn, deleteOldRdn, queue, defSearchCons);
  2675. }
  2676. /// <summary> Asynchronously renames an existing entry in the directory, using the
  2677. /// specified constraints.
  2678. ///
  2679. /// </summary>
  2680. /// <param name="dn"> The current distinguished name of the entry.
  2681. ///
  2682. /// </param>
  2683. /// <param name="newRdn"> The new relative distinguished name for the entry.
  2684. ///
  2685. /// </param>
  2686. /// <param name="deleteOldRdn"> If true, the old name is not retained as an
  2687. /// attribute value. If false, the old name is
  2688. /// retained as an attribute value.
  2689. ///
  2690. /// </param>
  2691. /// <param name="queue"> The queue for messages returned from a server in
  2692. /// response to this request. If it is null, a
  2693. /// queue object is created internally.
  2694. ///
  2695. /// </param>
  2696. /// <param name="cons"> The constraints specific to the operation.
  2697. ///
  2698. /// </param>
  2699. /// <exception> LdapException A general exception which includes an error
  2700. /// message and an Ldap error code.
  2701. /// </exception>
  2702. public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
  2703. {
  2704. return Rename(dn, newRdn, null, deleteOldRdn, queue, cons);
  2705. }
  2706. /// <summary> Asynchronously renames an existing entry in the directory, possibly
  2707. /// repositioning the entry in the directory.
  2708. ///
  2709. /// </summary>
  2710. /// <param name="dn"> The current distinguished name of the entry.
  2711. ///
  2712. /// </param>
  2713. /// <param name="newRdn"> The new relative distinguished name for the entry.
  2714. ///
  2715. /// </param>
  2716. /// <param name="newParentdn"> The distinguished name of an existing entry which
  2717. /// is to be the new parent of the entry.
  2718. ///
  2719. /// </param>
  2720. /// <param name="deleteOldRdn"> If true, the old name is not retained as an
  2721. /// attribute value. If false, the old name is
  2722. /// retained as an attribute value.
  2723. ///
  2724. /// </param>
  2725. /// <param name="queue"> The queue for messages returned from a server in
  2726. /// response to this request. If it is null, a
  2727. /// queue object is created internally.
  2728. ///
  2729. /// </param>
  2730. /// <exception> LdapException A general exception which includes an error
  2731. /// message and an Ldap error code.
  2732. /// </exception>
  2733. public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue)
  2734. {
  2735. return Rename(dn, newRdn, newParentdn, deleteOldRdn, queue, defSearchCons);
  2736. }
  2737. /// <summary> Asynchronously renames an existing entry in the directory, using the
  2738. /// specified constraints and possibily repositioning the entry in the
  2739. /// directory.
  2740. ///
  2741. /// </summary>
  2742. /// <param name="dn"> The current distinguished name of the entry.
  2743. ///
  2744. /// </param>
  2745. /// <param name="newRdn"> The new relative distinguished name for the entry.
  2746. ///
  2747. /// </param>
  2748. /// <param name="newParentdn"> The distinguished name of an existing entry which
  2749. /// is to be the new parent of the entry.
  2750. ///
  2751. /// </param>
  2752. /// <param name="deleteOldRdn"> If true, the old name is not retained as an
  2753. /// attribute value. If false, the old name is
  2754. /// retained as an attribute value.
  2755. ///
  2756. /// </param>
  2757. /// <param name="queue"> The queue for messages returned from a server in
  2758. /// response to this request. If it is null, a
  2759. /// queue object is created internally.
  2760. ///
  2761. /// </param>
  2762. /// <param name="cons"> The constraints specific to the operation.
  2763. ///
  2764. /// </param>
  2765. /// <exception> LdapException A general exception which includes an error
  2766. /// message and an Ldap error code.
  2767. /// </exception>
  2768. public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
  2769. {
  2770. if ((System.Object) dn == null || (System.Object) newRdn == null)
  2771. {
  2772. // Invalid DN or RDN parameter
  2773. throw new System.ArgumentException(ExceptionMessages.RDN_PARAM_ERROR);
  2774. }
  2775. if (cons == null)
  2776. cons = defSearchCons;
  2777. LdapMessage msg = new LdapModifyDNRequest(dn, newRdn, newParentdn, deleteOldRdn, cons.getControls());
  2778. return SendRequestToServer(msg, cons.TimeLimit, queue, null);
  2779. }
  2780. //*************************************************************************
  2781. // search methods
  2782. //*************************************************************************
  2783. /// <summary>
  2784. /// Synchronously performs the search specified by the parameters.
  2785. ///
  2786. /// </summary>
  2787. /// <param name="base"> The base distinguished name to search from.
  2788. ///
  2789. /// </param>
  2790. /// <param name="scope"> The scope of the entries to search. The following
  2791. /// are the valid options:
  2792. /// <ul>
  2793. /// <li>SCOPE_BASE - searches only the base DN</li>
  2794. ///
  2795. /// <li>SCOPE_ONE - searches only entries under the base DN</li>
  2796. ///
  2797. /// <li>SCOPE_SUB - searches the base DN and all entries
  2798. /// within its subtree</li>
  2799. /// </ul>
  2800. /// </param>
  2801. /// <param name="filter"> Search filter specifying the search criteria.
  2802. ///
  2803. /// </param>
  2804. /// <param name="attrs"> Names of attributes to retrieve.
  2805. ///
  2806. /// </param>
  2807. /// <param name="typesOnly"> If true, returns the names but not the values of
  2808. /// the attributes found. If false, returns the
  2809. /// names and values for attributes found.
  2810. ///
  2811. /// </param>
  2812. /// <exception> LdapException A general exception which includes an error
  2813. /// message and an Ldap error code.
  2814. /// </exception>
  2815. public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly)
  2816. {
  2817. return Search(base_Renamed, scope, filter, attrs, typesOnly, defSearchCons);
  2818. }
  2819. /// <summary>
  2820. /// Synchronously performs the search specified by the parameters,
  2821. /// using the specified search constraints (such as the
  2822. /// maximum number of entries to find or the maximum time to wait for
  2823. /// search results).
  2824. ///
  2825. /// As part of the search constraints, the method allows specifying
  2826. /// whether or not the results are to be delivered all at once or in
  2827. /// smaller batches. If specified that the results are to be delivered in
  2828. /// smaller batches, each iteration blocks only until the next batch of
  2829. /// results is returned.
  2830. ///
  2831. /// </summary>
  2832. /// <param name="base"> The base distinguished name to search from.
  2833. ///
  2834. /// </param>
  2835. /// <param name="scope"> The scope of the entries to search. The following
  2836. /// are the valid options:
  2837. /// <ul>
  2838. /// <li>SCOPE_BASE - searches only the base DN</li>
  2839. ///
  2840. /// <li>SCOPE_ONE - searches only entries under the base DN</li>
  2841. ///
  2842. /// <li>SCOPE_SUB - searches the base DN and all entries
  2843. /// within its subtree</li>
  2844. /// </ul>
  2845. /// </param>
  2846. /// <param name="filter"> The search filter specifying the search criteria.
  2847. ///
  2848. /// </param>
  2849. /// <param name="attrs"> The names of attributes to retrieve.
  2850. ///
  2851. /// </param>
  2852. /// <param name="typesOnly"> If true, returns the names but not the values of
  2853. /// the attributes found. If false, returns the
  2854. /// names and values for attributes found.
  2855. ///
  2856. /// </param>
  2857. /// <param name="cons"> The constraints specific to the search.
  2858. ///
  2859. /// </param>
  2860. /// <exception> LdapException A general exception which includes an error
  2861. /// message and an Ldap error code.
  2862. /// </exception>
  2863. public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchConstraints cons)
  2864. {
  2865. LdapSearchQueue queue = Search(base_Renamed, scope, filter, attrs, typesOnly, null, cons);
  2866. if (cons == null)
  2867. cons = defSearchCons;
  2868. return new LdapSearchResults(this, queue, cons);
  2869. }
  2870. /// <summary> Asynchronously performs the search specified by the parameters.
  2871. ///
  2872. /// </summary>
  2873. /// <param name="base"> The base distinguished name to search from.
  2874. ///
  2875. /// </param>
  2876. /// <param name="scope"> The scope of the entries to search. The following
  2877. /// are the valid options:
  2878. /// <ul>
  2879. /// <li>SCOPE_BASE - searches only the base DN</li>
  2880. ///
  2881. /// <li>SCOPE_ONE - searches only entries under the base DN</li>
  2882. ///
  2883. /// <li>SCOPE_SUB - searches the base DN and all entries
  2884. /// within its subtree</li>
  2885. /// </ul>
  2886. /// </param>
  2887. /// <param name="filter"> Search filter specifying the search criteria.
  2888. ///
  2889. /// </param>
  2890. /// <param name="attrs"> Names of attributes to retrieve.
  2891. ///
  2892. /// </param>
  2893. /// <param name="typesOnly"> If true, returns the names but not the values of
  2894. /// the attributes found. If false, returns the
  2895. /// names and values for attributes found.
  2896. ///
  2897. /// </param>
  2898. /// <param name="queue"> Handler for messages returned from a server in
  2899. /// response to this request. If it is null, a
  2900. /// queue object is created internally.
  2901. ///
  2902. /// </param>
  2903. /// <exception> LdapException A general exception which includes an error
  2904. /// message and an Ldap error code.
  2905. /// </exception>
  2906. public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue)
  2907. {
  2908. return Search(base_Renamed, scope, filter, attrs, typesOnly, queue, defSearchCons);
  2909. }
  2910. /// <summary> Asynchronously performs the search specified by the parameters,
  2911. /// also allowing specification of constraints for the search (such
  2912. /// as the maximum number of entries to find or the maximum time to
  2913. /// wait for search results).
  2914. ///
  2915. /// </summary>
  2916. /// <param name="base"> The base distinguished name to search from.
  2917. ///
  2918. /// </param>
  2919. /// <param name="scope"> The scope of the entries to search. The following
  2920. /// are the valid options:
  2921. /// <ul>
  2922. /// <li>SCOPE_BASE - searches only the base DN</li>
  2923. ///
  2924. /// <li>SCOPE_ONE - searches only entries under the base DN</li>
  2925. ///
  2926. /// <li>SCOPE_SUB - searches the base DN and all entries
  2927. /// within its subtree</li>
  2928. /// </ul>
  2929. /// </param>
  2930. /// <param name="filter"> The search filter specifying the search criteria.
  2931. ///
  2932. /// </param>
  2933. /// <param name="attrs"> The names of attributes to retrieve.
  2934. ///
  2935. /// </param>
  2936. /// <param name="typesOnly"> If true, returns the names but not the values of
  2937. /// the attributes found. If false, returns the
  2938. /// names and values for attributes found.
  2939. ///
  2940. /// </param>
  2941. /// <param name="queue"> The queue for messages returned from a server in
  2942. /// response to this request. If it is null, a
  2943. /// queue object is created internally.
  2944. ///
  2945. /// </param>
  2946. /// <param name="cons"> The constraints specific to the search.
  2947. ///
  2948. /// </param>
  2949. /// <exception> LdapException A general exception which includes an error
  2950. /// message and an Ldap error code.
  2951. /// </exception>
  2952. public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue, LdapSearchConstraints cons)
  2953. {
  2954. if ((System.Object) filter == null)
  2955. {
  2956. filter = "objectclass=*";
  2957. }
  2958. if (cons == null)
  2959. cons = defSearchCons;
  2960. LdapMessage msg = new LdapSearchRequest(base_Renamed, scope, filter, attrs, cons.Dereference, cons.MaxResults, cons.ServerTimeLimit, typesOnly, cons.getControls());
  2961. MessageAgent agent;
  2962. LdapSearchQueue myqueue = queue;
  2963. if (myqueue == null)
  2964. {
  2965. agent = new MessageAgent();
  2966. myqueue = new LdapSearchQueue(agent);
  2967. }
  2968. else
  2969. {
  2970. agent = queue.MessageAgent;
  2971. }
  2972. try
  2973. {
  2974. agent.sendMessage(conn, msg, cons.TimeLimit, myqueue, null);
  2975. }
  2976. catch (LdapException lex)
  2977. {
  2978. throw lex;
  2979. }
  2980. return myqueue;
  2981. }
  2982. /*
  2983. * Ldap URL search
  2984. */
  2985. /// <summary> Synchronously performs the search specified by the Ldap URL, returning
  2986. /// an enumerable LdapSearchResults object.
  2987. ///
  2988. /// </summary>
  2989. /// <param name="toGet">The Ldap URL specifying the entry to read.
  2990. ///
  2991. /// </param>
  2992. /// <exception> LdapException A general exception which includes an error
  2993. /// message and an Ldap error code.
  2994. /// </exception>
  2995. public static LdapSearchResults Search(LdapUrl toGet)
  2996. {
  2997. // Get a clone of default search constraints, method alters batchSize
  2998. return Search(toGet, null);
  2999. }
  3000. /*
  3001. * Ldap URL search
  3002. */
  3003. /// <summary> Synchronously perfoms the search specified by the Ldap URL, using
  3004. /// the specified search constraints (such as the maximum number of
  3005. /// entries to find or the maximum time to wait for search results).
  3006. ///
  3007. /// When this method is called, a new connection is created
  3008. /// automatically, using the host and port specified in the URL. After
  3009. /// all search results have been received from the server, the method
  3010. /// closes the connection (in other words, it disconnects from the Ldap
  3011. /// server).
  3012. ///
  3013. /// As part of the search constraints, a choice can be made as to whether
  3014. /// to have the results delivered all at once or in smaller batches. If
  3015. /// the results are to be delivered in smaller batches, each iteration
  3016. /// blocks only until the next batch of results is returned.
  3017. ///
  3018. ///
  3019. /// </summary>
  3020. /// <param name="toGet"> Ldap URL specifying the entry to read.
  3021. ///
  3022. /// </param>
  3023. /// <param name="cons"> The constraints specific to the search.
  3024. ///
  3025. /// </param>
  3026. /// <exception> LdapException A general exception which includes an error
  3027. /// message and an Ldap error code.
  3028. /// </exception>
  3029. public static LdapSearchResults Search(LdapUrl toGet, LdapSearchConstraints cons)
  3030. {
  3031. LdapConnection lconn = new LdapConnection();
  3032. lconn.Connect(toGet.Host, toGet.Port);
  3033. if (cons == null)
  3034. {
  3035. // This is a clone, so we already have our own copy
  3036. cons = lconn.SearchConstraints;
  3037. }
  3038. else
  3039. {
  3040. // get our own copy of user's constraints because we modify it
  3041. cons = (LdapSearchConstraints) cons.Clone();
  3042. }
  3043. cons.BatchSize = 0; // Must wait until all results arrive
  3044. LdapSearchResults toReturn = lconn.Search(toGet.getDN(), toGet.Scope, toGet.Filter, toGet.AttributeArray, false, cons);
  3045. lconn.Disconnect();
  3046. return toReturn;
  3047. }
  3048. /// <summary> Sends an Ldap request to a directory server.
  3049. ///
  3050. /// The specified the Ldap request is sent to the directory server
  3051. /// associated with this connection using default constraints. An Ldap
  3052. /// request object is a subclass {@link LdapMessage} with the operation
  3053. /// type set to one of the request types. You can build a request by using
  3054. /// the request classes found in this package
  3055. ///
  3056. /// You should note that, since Ldap requests sent to the server
  3057. /// using sendRequest are asynchronous, automatic referral following
  3058. /// does not apply to these requests.
  3059. ///
  3060. /// </summary>
  3061. /// <param name="request">The Ldap request to send to the directory server.
  3062. /// </param>
  3063. /// <param name="queue"> The queue for messages returned from a server in
  3064. /// response to this request. If it is null, a
  3065. /// queue object is created internally.
  3066. /// </param>
  3067. /// <exception> LdapException A general exception which includes an error
  3068. /// message and an Ldap error code.
  3069. ///
  3070. /// </exception>
  3071. /// <seealso cref="LdapMessage.Type">
  3072. /// </seealso>
  3073. /// <seealso cref="RfcLdapMessage.isRequest">
  3074. /// </seealso>
  3075. public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue)
  3076. {
  3077. return SendRequest(request, queue, null);
  3078. }
  3079. /// <summary> Sends an Ldap request to a directory server.
  3080. ///
  3081. /// The specified the Ldap request is sent to the directory server
  3082. /// associated with this connection. An Ldap request object is an
  3083. /// {@link LdapMessage} with the operation type set to one of the request
  3084. /// types. You can build a request by using the request classes found in this
  3085. /// package
  3086. ///
  3087. /// You should note that, since Ldap requests sent to the server
  3088. /// using sendRequest are asynchronous, automatic referral following
  3089. /// does not apply to these requests.
  3090. ///
  3091. /// </summary>
  3092. /// <param name="request">The Ldap request to send to the directory server.
  3093. /// </param>
  3094. /// <param name="queue"> The queue for messages returned from a server in
  3095. /// response to this request. If it is null, a
  3096. /// queue object is created internally.
  3097. /// </param>
  3098. /// <param name="cons"> The constraints that apply to this request
  3099. /// </param>
  3100. /// <exception> LdapException A general exception which includes an error
  3101. /// message and an Ldap error code.
  3102. ///
  3103. /// </exception>
  3104. /// <seealso cref="LdapMessage.Type">
  3105. /// </seealso>
  3106. /// <seealso cref="RfcLdapMessage.isRequest">
  3107. /// </seealso>
  3108. public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue, LdapConstraints cons)
  3109. {
  3110. if (!request.Request)
  3111. {
  3112. throw new System.SystemException("Object is not a request message");
  3113. }
  3114. if (cons == null)
  3115. {
  3116. cons = defSearchCons;
  3117. }
  3118. // Get the correct queue for a search request
  3119. MessageAgent agent;
  3120. LdapMessageQueue myqueue = queue;
  3121. if (myqueue == null)
  3122. {
  3123. agent = new MessageAgent();
  3124. if (request.Type == LdapMessage.SEARCH_REQUEST)
  3125. {
  3126. myqueue = new LdapSearchQueue(agent);
  3127. }
  3128. else
  3129. {
  3130. myqueue = new LdapResponseQueue(agent);
  3131. }
  3132. }
  3133. else
  3134. {
  3135. if (request.Type == LdapMessage.SEARCH_REQUEST)
  3136. {
  3137. agent = queue.MessageAgent;
  3138. }
  3139. else
  3140. {
  3141. agent = queue.MessageAgent;
  3142. }
  3143. }
  3144. try
  3145. {
  3146. agent.sendMessage(conn, request, cons.TimeLimit, myqueue, null);
  3147. }
  3148. catch (LdapException lex)
  3149. {
  3150. throw lex;
  3151. }
  3152. return myqueue;
  3153. }
  3154. //*************************************************************************
  3155. // helper methods
  3156. //*************************************************************************
  3157. /// <summary> Locates the appropriate message agent and sends
  3158. /// the Ldap request to a directory server.
  3159. ///
  3160. /// </summary>
  3161. /// <param name="msg">the message to send
  3162. ///
  3163. /// </param>
  3164. /// <param name="timeout">the timeout value
  3165. ///
  3166. /// </param>
  3167. /// <param name="queue">the response queue or null
  3168. ///
  3169. /// </param>
  3170. /// <returns> the LdapResponseQueue for this request
  3171. ///
  3172. /// </returns>
  3173. /// <exception> LdapException A general exception which includes an error
  3174. /// message and an Ldap error code.
  3175. /// </exception>
  3176. private LdapResponseQueue SendRequestToServer(LdapMessage msg, int timeout, LdapResponseQueue queue, BindProperties bindProps)
  3177. {
  3178. MessageAgent agent;
  3179. if (queue == null)
  3180. {
  3181. agent = new MessageAgent();
  3182. queue = new LdapResponseQueue(agent);
  3183. }
  3184. else
  3185. {
  3186. agent = queue.MessageAgent;
  3187. }
  3188. agent.sendMessage(conn, msg, timeout, queue, bindProps);
  3189. return queue;
  3190. }
  3191. /// <summary> get an LdapConnection object so that we can follow a referral.
  3192. /// This function is never called if cons.getReferralFollowing() returns
  3193. /// false.
  3194. ///
  3195. /// </summary>
  3196. /// <param name="referrals">the array of referral strings
  3197. ///
  3198. ///
  3199. /// </param>
  3200. /// <returns> The referralInfo object
  3201. ///
  3202. /// </returns>
  3203. /// <exception> LdapReferralException A general exception which includes
  3204. /// an error message and an Ldap error code.
  3205. /// </exception>
  3206. private ReferralInfo getReferralConnection(System.String[] referrals)
  3207. {
  3208. ReferralInfo refInfo = null;
  3209. System.Exception ex = null;
  3210. LdapConnection rconn = null;
  3211. LdapReferralHandler rh = defSearchCons.getReferralHandler();
  3212. int i = 0;
  3213. // Check if we use LdapRebind to get authentication credentials
  3214. if ((rh == null) || (rh is LdapAuthHandler))
  3215. {
  3216. for (i = 0; i < referrals.Length; i++)
  3217. {
  3218. // dn, pw are null in the default case (anonymous bind)
  3219. System.String dn = null;
  3220. sbyte[] pw = null;
  3221. try
  3222. {
  3223. rconn = new LdapConnection();
  3224. rconn.Constraints = defSearchCons;
  3225. LdapUrl url = new LdapUrl(referrals[i]);
  3226. rconn.Connect(url.Host, url.Port);
  3227. if (rh != null)
  3228. {
  3229. if (rh is LdapAuthHandler)
  3230. {
  3231. // Get application supplied dn and pw
  3232. LdapAuthProvider ap = ((LdapAuthHandler) rh).getAuthProvider(url.Host, url.Port);
  3233. dn = ap.DN;
  3234. pw = ap.Password;
  3235. }
  3236. }
  3237. rconn.Bind(Ldap_V3, dn, pw);
  3238. ex = null;
  3239. refInfo = new ReferralInfo(rconn, referrals, url);
  3240. // Indicate this connection created to follow referral
  3241. rconn.Connection.ActiveReferral = refInfo;
  3242. break;
  3243. }
  3244. catch (System.Exception lex)
  3245. {
  3246. if (rconn != null)
  3247. {
  3248. try
  3249. {
  3250. rconn.Disconnect();
  3251. rconn = null;
  3252. ex = lex;
  3253. }
  3254. catch (LdapException e)
  3255. {
  3256. ; // ignore
  3257. }
  3258. }
  3259. }
  3260. }
  3261. }
  3262. // Check if application gets connection and does bind
  3263. else
  3264. {
  3265. // rh instanceof LdapBind
  3266. try
  3267. {
  3268. rconn = ((LdapBindHandler) rh).Bind(referrals, this);
  3269. if (rconn == null)
  3270. {
  3271. LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR);
  3272. rex.setReferrals(referrals);
  3273. throw rex;
  3274. }
  3275. // Figure out which Url belongs to the connection
  3276. for (int idx = 0; idx < referrals.Length; idx++)
  3277. {
  3278. try
  3279. {
  3280. LdapUrl url = new LdapUrl(referrals[idx]);
  3281. if (url.Host.ToUpper().Equals(rconn.Host.ToUpper()) && (url.Port == rconn.Port))
  3282. {
  3283. refInfo = new ReferralInfo(rconn, referrals, url);
  3284. break;
  3285. }
  3286. }
  3287. catch (System.Exception e)
  3288. {
  3289. ; // ignore
  3290. }
  3291. }
  3292. if (refInfo == null)
  3293. {
  3294. // Could not match LdapBind.bind() connecction with URL list
  3295. ex = new LdapLocalException(ExceptionMessages.REFERRAL_BIND_MATCH, LdapException.CONNECT_ERROR);
  3296. }
  3297. }
  3298. catch (System.Exception lex)
  3299. {
  3300. rconn = null;
  3301. ex = lex;
  3302. }
  3303. }
  3304. if (ex != null)
  3305. {
  3306. // Could not connect to any server, throw an exception
  3307. LdapException ldapex;
  3308. if (ex is LdapReferralException)
  3309. {
  3310. throw (LdapReferralException) ex;
  3311. }
  3312. else if (ex is LdapException)
  3313. {
  3314. ldapex = (LdapException) ex;
  3315. }
  3316. else
  3317. {
  3318. ldapex = new LdapLocalException(ExceptionMessages.SERVER_CONNECT_ERROR, new System.Object[]{conn.Host}, LdapException.CONNECT_ERROR, ex);
  3319. }
  3320. // Error attempting to follow a referral
  3321. LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ldapex);
  3322. rex.setReferrals(referrals);
  3323. // Use last URL string for the failed referral
  3324. rex.FailedReferral = referrals[referrals.Length - 1];
  3325. throw rex;
  3326. }
  3327. // We now have an authenticated connection
  3328. // to be used to follow the referral.
  3329. return refInfo;
  3330. }
  3331. /// <summary> Check the result code and throw an exception if needed.
  3332. ///
  3333. /// If referral following is enabled, checks if we need to
  3334. /// follow a referral
  3335. ///
  3336. /// </summary>
  3337. /// <param name="queue">- the message queue of the current response
  3338. ///
  3339. /// </param>
  3340. /// <param name="cons">- the constraints that apply to the request
  3341. ///
  3342. /// </param>
  3343. /// <param name="response">- the LdapResponse to check
  3344. /// </param>
  3345. private void chkResultCode(LdapMessageQueue queue, LdapConstraints cons, LdapResponse response)
  3346. {
  3347. if ((response.ResultCode == LdapException.REFERRAL) && cons.ReferralFollowing)
  3348. {
  3349. // Perform referral following and return
  3350. System.Collections.ArrayList refConn = null;
  3351. try
  3352. {
  3353. chaseReferral(queue, cons, response, response.Referrals, 0, false, null);
  3354. }
  3355. finally
  3356. {
  3357. releaseReferralConnections(refConn);
  3358. }
  3359. }
  3360. else
  3361. {
  3362. // Throws exception for non success result
  3363. response.chkResultCode();
  3364. }
  3365. return ;
  3366. }
  3367. /// <summary> Follow referrals if necessary referral following enabled.
  3368. /// This function is called only by synchronous requests.
  3369. /// Search responses come here only if referral following is
  3370. /// enabled and if we are processing a SearchResultReference
  3371. /// or a Response with a status of REFERRAL, i.e. we are
  3372. /// going to follow a referral.
  3373. ///
  3374. /// This functions recursively follows a referral until a result
  3375. /// is returned or until the hop limit is reached.
  3376. ///
  3377. /// </summary>
  3378. /// <param name="queue">The LdapResponseQueue for this request
  3379. ///
  3380. /// </param>
  3381. /// <param name="cons">The constraints that apply to the request
  3382. ///
  3383. /// </param>
  3384. /// <param name="msg">The referral or search reference response message
  3385. ///
  3386. /// </param>
  3387. /// <param name="initialReferrals">The referral array returned from the
  3388. /// initial request.
  3389. ///
  3390. /// </param>
  3391. /// <param name="hopCount">the number of hops already used while
  3392. /// following this referral
  3393. ///
  3394. /// </param>
  3395. /// <param name="searchReference">true if the message is a search reference
  3396. ///
  3397. /// </param>
  3398. /// <param name="connectionList">An optional array list used to store
  3399. /// the LdapConnection objects used in following the referral.
  3400. ///
  3401. /// </param>
  3402. /// <returns> The array list used to store the all LdapConnection objects
  3403. /// used in following the referral. The list will be empty
  3404. /// if there were none.
  3405. ///
  3406. /// </returns>
  3407. /// <exception> LdapException A general exception which includes an error
  3408. /// message and an Ldap error code.
  3409. /// </exception>
  3410. /* package */
  3411. internal virtual System.Collections.ArrayList chaseReferral(LdapMessageQueue queue, LdapConstraints cons, LdapMessage msg, System.String[] initialReferrals, int hopCount, bool searchReference, System.Collections.ArrayList connectionList)
  3412. {
  3413. System.Collections.ArrayList connList = connectionList;
  3414. LdapConnection rconn = null; // new conn for following referral
  3415. ReferralInfo rinfo = null; // referral info
  3416. LdapMessage origMsg;
  3417. // Get a place to store new connections
  3418. if (connList == null)
  3419. {
  3420. connList = new System.Collections.ArrayList(cons.HopLimit);
  3421. }
  3422. // Following referrals or search reference
  3423. System.String[] refs; // referral list
  3424. if (initialReferrals != null)
  3425. {
  3426. // Search continuation reference from a search request
  3427. refs = initialReferrals;
  3428. origMsg = msg.RequestingMessage;
  3429. }
  3430. else
  3431. {
  3432. // Not a search request
  3433. LdapResponse resp = (LdapResponse) queue.getResponse();
  3434. if (resp.ResultCode != LdapException.REFERRAL)
  3435. {
  3436. // Not referral result,throw Exception if nonzero result
  3437. resp.chkResultCode();
  3438. return connList;
  3439. }
  3440. // We have a referral response
  3441. refs = resp.Referrals;
  3442. origMsg = resp.RequestingMessage;
  3443. }
  3444. LdapUrl refUrl; // referral represented as URL
  3445. try
  3446. {
  3447. // increment hop count, check max hops
  3448. if (hopCount++ > cons.HopLimit)
  3449. {
  3450. throw new LdapLocalException("Max hops exceeded", LdapException.REFERRAL_LIMIT_EXCEEDED);
  3451. }
  3452. // Get a connection to follow the referral
  3453. rinfo = getReferralConnection(refs);
  3454. rconn = rinfo.ReferralConnection;
  3455. refUrl = rinfo.ReferralUrl;
  3456. connList.Add(rconn);
  3457. // rebuild msg into new msg changing msgID,dn,scope,filter
  3458. LdapMessage newMsg = rebuildRequest(origMsg, refUrl, searchReference);
  3459. // Send new message on new connection
  3460. try
  3461. {
  3462. MessageAgent agent;
  3463. if (queue is LdapResponseQueue)
  3464. {
  3465. agent = queue.MessageAgent;
  3466. }
  3467. else
  3468. {
  3469. agent = queue.MessageAgent;
  3470. }
  3471. agent.sendMessage(rconn.Connection, newMsg, defSearchCons.TimeLimit, queue, null);
  3472. }
  3473. catch (InterThreadException ex)
  3474. {
  3475. // Error ending request to referred server
  3476. LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_SEND, LdapException.CONNECT_ERROR, null, ex);
  3477. rex.setReferrals(initialReferrals);
  3478. ReferralInfo ref_Renamed = rconn.Connection.ActiveReferral;
  3479. rex.FailedReferral = ref_Renamed.ReferralUrl.ToString();
  3480. throw rex;
  3481. }
  3482. if (initialReferrals == null)
  3483. {
  3484. // For operation results, when all responses are complete,
  3485. // the stack unwinds back to the original and returns
  3486. // to the application.
  3487. // An exception is thrown for an error
  3488. connList = chaseReferral(queue, cons, null, null, hopCount, false, connList);
  3489. }
  3490. else
  3491. {
  3492. // For search, just return to LdapSearchResults object
  3493. return connList;
  3494. }
  3495. }
  3496. catch (System.Exception ex)
  3497. {
  3498. if (ex is LdapReferralException)
  3499. {
  3500. throw (LdapReferralException) ex;
  3501. }
  3502. else
  3503. {
  3504. // Set referral list and failed referral
  3505. LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ex);
  3506. rex.setReferrals(refs);
  3507. if (rinfo != null)
  3508. {
  3509. rex.FailedReferral = rinfo.ReferralUrl.ToString();
  3510. }
  3511. else
  3512. {
  3513. rex.FailedReferral = refs[refs.Length - 1];
  3514. }
  3515. throw rex;
  3516. }
  3517. }
  3518. return connList;
  3519. }
  3520. /// <summary> Builds a new request replacing dn, scope, and filter where approprate
  3521. ///
  3522. /// </summary>
  3523. /// <param name="msg">the original LdapMessage to build the new request from
  3524. ///
  3525. /// </param>
  3526. /// <param name="url">the referral url
  3527. ///
  3528. /// </param>
  3529. /// <returns> a new LdapMessage with appropriate information replaced
  3530. ///
  3531. /// </returns>
  3532. /// <exception> LdapException A general exception which includes an error
  3533. /// message and an Ldap error code.
  3534. /// </exception>
  3535. private LdapMessage rebuildRequest(LdapMessage msg, LdapUrl url, bool reference)
  3536. {
  3537. System.String dn = url.getDN(); // new base
  3538. System.String filter = null;
  3539. switch (msg.Type)
  3540. {
  3541. case LdapMessage.SEARCH_REQUEST:
  3542. if (reference)
  3543. {
  3544. filter = url.Filter;
  3545. }
  3546. break;
  3547. // We are allowed to get a referral for the following
  3548. case LdapMessage.ADD_REQUEST:
  3549. case LdapMessage.BIND_REQUEST:
  3550. case LdapMessage.COMPARE_REQUEST:
  3551. case LdapMessage.DEL_REQUEST:
  3552. case LdapMessage.EXTENDED_REQUEST:
  3553. case LdapMessage.MODIFY_RDN_REQUEST:
  3554. case LdapMessage.MODIFY_REQUEST:
  3555. break;
  3556. // The following return no response
  3557. case LdapMessage.ABANDON_REQUEST:
  3558. case LdapMessage.UNBIND_REQUEST:
  3559. default:
  3560. throw new LdapLocalException(ExceptionMessages.IMPROPER_REFERRAL, new System.Object[]{msg.Type}, LdapException.LOCAL_ERROR);
  3561. }
  3562. return msg.Clone(dn, filter, reference);
  3563. }
  3564. /*
  3565. * Release connections acquired by following referrals
  3566. *
  3567. * @param list the list of the connections
  3568. */
  3569. /* package */
  3570. internal virtual void releaseReferralConnections(System.Collections.ArrayList list)
  3571. {
  3572. if (list == null)
  3573. {
  3574. return ;
  3575. }
  3576. // Release referral connections
  3577. for (int i = list.Count - 1; i >= 0; i--)
  3578. {
  3579. LdapConnection rconn = null;
  3580. try
  3581. {
  3582. rconn=(LdapConnection)list[i];
  3583. list.RemoveAt(i);
  3584. // rconn = (LdapConnection) list.RemoveAt(i);
  3585. rconn.Disconnect();
  3586. }
  3587. catch (System.IndexOutOfRangeException ex)
  3588. {
  3589. continue;
  3590. }
  3591. catch (LdapException lex)
  3592. {
  3593. continue;
  3594. }
  3595. }
  3596. return ;
  3597. }
  3598. //*************************************************************************
  3599. // Schema Related methods
  3600. //*************************************************************************
  3601. /// <summary> Retrieves the schema associated with a particular schema DN in the
  3602. /// directory server.
  3603. /// The schema DN for a particular entry is obtained by calling the
  3604. /// getSchemaDN method of LDAPConnection
  3605. ///
  3606. /// </summary>
  3607. /// <param name="schemaDN">The schema DN used to fetch the schema.
  3608. ///
  3609. /// </param>
  3610. /// <returns> An LDAPSchema entry containing schema attributes. If the
  3611. /// entry contains no schema attributes then the returned LDAPSchema object
  3612. /// will be empty.
  3613. ///
  3614. /// </returns>
  3615. /// <exception> LDAPException This exception occurs if the schema entry
  3616. /// cannot be retrieved with this connection.
  3617. /// </exception>
  3618. /// <seealso cref="GetSchemaDN()">
  3619. /// </seealso>
  3620. /// <seealso cref="GetSchemaDN(String)">
  3621. /// </seealso>
  3622. public virtual LdapSchema FetchSchema(System.String schemaDN)
  3623. {
  3624. LdapEntry ent = Read(schemaDN, LdapSchema.schemaTypeNames);
  3625. return new LdapSchema(ent);
  3626. }
  3627. /// <summary> Retrieves the Distiguished Name (DN) for the schema advertised in the
  3628. /// root DSE of the Directory Server.
  3629. ///
  3630. /// The DN can be used with the methods fetchSchema and modify to retreive
  3631. /// and extend schema definitions. The schema entry is located by reading
  3632. /// subschemaSubentry attribute of the root DSE. This is equivalent to
  3633. /// calling {@link #getSchemaDN(String) } with the DN parameter as an empty
  3634. /// string: <code>getSchemaDN("")</code>.
  3635. ///
  3636. ///
  3637. /// </summary>
  3638. /// <returns> Distinguished Name of a schema entry in effect for the
  3639. /// Directory.
  3640. /// </returns>
  3641. /// <exception> LDAPException This exception occurs if the schema DN
  3642. /// cannot be retrieved, or if the subschemaSubentry attribute associated
  3643. /// with the root DSE contains multiple values.
  3644. ///
  3645. /// </exception>
  3646. /// <seealso cref="FetchSchema">
  3647. /// </seealso>
  3648. /// <seealso cref="Modify">
  3649. /// </seealso>
  3650. public virtual System.String GetSchemaDN()
  3651. {
  3652. return GetSchemaDN("");
  3653. }
  3654. /// <summary> Retrieves the Distiguished Name (DN) of the schema associated with a
  3655. /// entry in the Directory.
  3656. ///
  3657. /// The DN can be used with the methods fetchSchema and modify to retreive
  3658. /// and extend schema definitions. Reads the subschemaSubentry of the entry
  3659. /// specified.
  3660. ///
  3661. /// </summary>
  3662. /// <param name="dn"> Distinguished Name of any entry. The subschemaSubentry
  3663. /// attribute is queried from this entry.
  3664. ///
  3665. /// </param>
  3666. /// <returns> Distinguished Name of a schema entry in effect for the entry
  3667. /// identified by <code>dn</code>.
  3668. ///
  3669. /// </returns>
  3670. /// <exception> LDAPException This exception occurs if a null or empty
  3671. /// value is passed as dn, if the subschemasubentry attribute cannot
  3672. /// be retrieved, or the subschemasubentry contains multiple values.
  3673. ///
  3674. /// </exception>
  3675. /// <seealso cref="FetchSchema">
  3676. /// </seealso>
  3677. /// <seealso cref="Modify">
  3678. /// </seealso>
  3679. public virtual System.String GetSchemaDN(System.String dn)
  3680. {
  3681. System.String[] attrSubSchema = new System.String[]{"subschemaSubentry"};
  3682. /* Read the entries subschemaSubentry attribute. Throws an exception if
  3683. * no entries are returned. */
  3684. LdapEntry ent = this.Read(dn, attrSubSchema);
  3685. LdapAttribute attr = ent.getAttribute(attrSubSchema[0]);
  3686. System.String[] values = attr.StringValueArray;
  3687. if (values == null || values.Length < 1)
  3688. {
  3689. throw new LdapLocalException(ExceptionMessages.NO_SCHEMA, new System.Object[]{dn}, LdapException.NO_RESULTS_RETURNED);
  3690. }
  3691. else if (values.Length > 1)
  3692. {
  3693. throw new LdapLocalException(ExceptionMessages.MULTIPLE_SCHEMA, new System.Object[]{dn}, LdapException.CONSTRAINT_VIOLATION);
  3694. }
  3695. return values[0];
  3696. }
  3697. }
  3698. }