You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

295 lines
15 KiB

  1. /* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. using Alphaleonis.Win32.Filesystem;
  22. using System;
  23. using System.Collections.Generic;
  24. using System.Diagnostics.CodeAnalysis;
  25. using System.Globalization;
  26. using System.Linq;
  27. using System.Net.NetworkInformation;
  28. using System.Security;
  29. namespace Alphaleonis.Win32.Network
  30. {
  31. partial class Host
  32. {
  33. #region EnumerateDfsLinks
  34. /// <summary>Enumerates the DFS Links from a DFS namespace.</summary>
  35. /// <returns><see cref="IEnumerable{DfsInfo}"/> of DFS namespaces.</returns>
  36. /// <exception cref="ArgumentNullException"/>
  37. /// <exception cref="NetworkInformationException"/>
  38. /// <exception cref="PlatformNotSupportedException"/>
  39. /// <param name="dfsName">The Universal Naming Convention (UNC) path of a DFS root or link.</param>
  40. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  41. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dfs")]
  42. [SecurityCritical]
  43. public static IEnumerable<DfsInfo> EnumerateDfsLinks(string dfsName)
  44. {
  45. if (!Filesystem.NativeMethods.IsAtLeastWindowsVista)
  46. throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
  47. if (Utils.IsNullOrWhiteSpace(dfsName))
  48. throw new ArgumentNullException("dfsName");
  49. var fd = new FunctionData();
  50. return EnumerateNetworkObjectCore(fd, (NativeMethods.DFS_INFO_9 structure, SafeGlobalMemoryBufferHandle buffer) =>
  51. new DfsInfo(structure),
  52. (FunctionData functionData, out SafeGlobalMemoryBufferHandle buffer, int prefMaxLen, out uint entriesRead, out uint totalEntries, out uint resumeHandle1) =>
  53. {
  54. totalEntries = 0;
  55. return NativeMethods.NetDfsEnum(dfsName, 9, prefMaxLen, out buffer, out entriesRead, out resumeHandle1);
  56. }, false);
  57. }
  58. #endregion // EnumerateDfsLinks
  59. #region EnumerateDfsRoot
  60. /// <summary>Enumerates the DFS namespaces from the local host.</summary>
  61. /// <returns><see cref="IEnumerable{String}"/> of DFS Root namespaces from the local host.</returns>
  62. /// <exception cref="NetworkInformationException"/>
  63. /// <exception cref="PlatformNotSupportedException"/>
  64. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  65. [SecurityCritical]
  66. public static IEnumerable<string> EnumerateDfsRoot()
  67. {
  68. return EnumerateDfsRootCore(null, false);
  69. }
  70. /// <summary>Enumerates the DFS namespaces from a host.</summary>
  71. /// <returns><see cref="IEnumerable{String}"/> of DFS Root namespaces from a host.</returns>
  72. /// <exception cref="NetworkInformationException"/>
  73. /// <exception cref="PlatformNotSupportedException"/>
  74. /// <param name="host">The DNS or NetBIOS name of a host.</param>
  75. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  76. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  77. [SecurityCritical]
  78. public static IEnumerable<string> EnumerateDfsRoot(string host, bool continueOnException)
  79. {
  80. return EnumerateDfsRootCore(host, continueOnException);
  81. }
  82. #endregion // EnumerateDfsRoot
  83. #region EnumerateDomainDfsRoot
  84. /// <summary>Enumerates the DFS namespaces from the domain.</summary>
  85. /// <returns><see cref="IEnumerable{String}"/> of DFS Root namespaces from the domain.</returns>
  86. /// <exception cref="NetworkInformationException"/>
  87. /// <exception cref="PlatformNotSupportedException"/>
  88. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  89. [SecurityCritical]
  90. public static IEnumerable<string> EnumerateDomainDfsRoot()
  91. {
  92. return EnumerateDomainDfsRootCore(null, false);
  93. }
  94. /// <summary>Enumerates the DFS namespaces from a domain.</summary>
  95. /// <returns><see cref="IEnumerable{String}"/> of DFS Root namespaces from a domain.</returns>
  96. /// <exception cref="NetworkInformationException"/>
  97. /// <exception cref="PlatformNotSupportedException"/>
  98. /// <param name="domain">A domain name.</param>
  99. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  100. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  101. [SecurityCritical]
  102. public static IEnumerable<string> EnumerateDomainDfsRoot(string domain, bool continueOnException)
  103. {
  104. return EnumerateDomainDfsRootCore(domain, continueOnException);
  105. }
  106. #endregion // EnumerateDomainDfsRoot
  107. #region GetDfsClientInfo
  108. /// <summary>Gets information about a DFS root or link from the cache maintained by the DFS client.</summary>
  109. /// <returns>A <see cref="DfsInfo"/> instance.</returns>
  110. /// <exception cref="NetworkInformationException"/>
  111. /// <exception cref="PlatformNotSupportedException"/>
  112. /// <param name="dfsName">The Universal Naming Convention (UNC) path of a DFS root or link.</param>
  113. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  114. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dfs")]
  115. [SecurityCritical]
  116. public static DfsInfo GetDfsClientInfo(string dfsName)
  117. {
  118. return GetDfsInfoCore(true, dfsName, null, null);
  119. }
  120. /// <summary>Gets information about a DFS root or link from the cache maintained by the DFS client.</summary>
  121. /// <returns>A <see cref="DfsInfo"/> instance.</returns>
  122. /// <exception cref="NetworkInformationException"/>
  123. /// <exception cref="PlatformNotSupportedException"/>
  124. /// <param name="dfsName">The Universal Naming Convention (UNC) path of a DFS root or link.</param>
  125. /// <param name="serverName">The name of the DFS root target or link target server.</param>
  126. /// <param name="shareName">The name of the share corresponding to the DFS root target or link target.</param>
  127. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  128. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dfs")]
  129. [SecurityCritical]
  130. public static DfsInfo GetDfsClientInfo(string dfsName, string serverName, string shareName)
  131. {
  132. return GetDfsInfoCore(true, dfsName, serverName, shareName);
  133. }
  134. #endregion // GetDfsClientInfo
  135. #region GetDfsInfo
  136. /// <summary>Gets information about a specified DFS root or link in a DFS namespace.</summary>
  137. /// <returns>A <see cref="DfsInfo"/> instance.</returns>
  138. /// <exception cref="NetworkInformationException"/>
  139. /// <exception cref="PlatformNotSupportedException"/>
  140. /// <param name="dfsName">The Universal Naming Convention (UNC) path of a DFS root or link.</param>
  141. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  142. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dfs")]
  143. [SecurityCritical]
  144. public static DfsInfo GetDfsInfo(string dfsName)
  145. {
  146. return GetDfsInfoCore(false, dfsName, null, null);
  147. }
  148. #endregion // GetDfsInfo
  149. #region Internal Methods
  150. /// <summary>Enumerates the DFS namespaces from a host.</summary>
  151. /// <returns><see cref="IEnumerable{String}"/> of DFS Root namespaces from a host.</returns>
  152. /// <exception cref="ArgumentNullException"/>
  153. /// <exception cref="NetworkInformationException"/>
  154. /// <exception cref="PlatformNotSupportedException"/>
  155. /// <param name="host">The DNS or NetBIOS name of a host.</param>
  156. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  157. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  158. [SecurityCritical]
  159. private static IEnumerable<string> EnumerateDfsRootCore(string host, bool continueOnException)
  160. {
  161. if (!Filesystem.NativeMethods.IsAtLeastWindowsVista)
  162. throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
  163. return EnumerateNetworkObjectCore(new FunctionData(), (NativeMethods.DFS_INFO_300 structure, SafeGlobalMemoryBufferHandle buffer) =>
  164. new DfsInfo { EntryPath = structure.DfsName },
  165. (FunctionData functionData, out SafeGlobalMemoryBufferHandle buffer, int prefMaxLen, out uint entriesRead, out uint totalEntries, out uint resumeHandle) =>
  166. {
  167. totalEntries = 0;
  168. // When host == null, the local computer is used.
  169. // However, the resulting Host property will be empty.
  170. // So, explicitly state Environment.MachineName to prevent this.
  171. // Furthermore, the UNC prefix: \\ is not required and always removed.
  172. string stripUnc = Utils.IsNullOrWhiteSpace(host) ? Environment.MachineName : Path.GetRegularPathCore(host, GetFullPathOptions.CheckInvalidPathChars, false).Replace(Path.UncPrefix, string.Empty);
  173. return NativeMethods.NetDfsEnum(stripUnc, 300, prefMaxLen, out buffer, out entriesRead, out resumeHandle);
  174. }, continueOnException).Select(dfs => dfs.EntryPath);
  175. }
  176. /// <summary>Enumerates the DFS namespaces from a domain.</summary>
  177. /// <returns><see cref="IEnumerable{String}"/> of DFS Root namespaces from a domain.</returns>
  178. /// <exception cref="ArgumentNullException"/>
  179. /// <exception cref="NetworkInformationException"/>
  180. /// <exception cref="PlatformNotSupportedException"/>
  181. /// <param name="domain">A domain name.</param>
  182. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  183. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dfs")]
  184. [SecurityCritical]
  185. private static IEnumerable<string> EnumerateDomainDfsRootCore(string domain, bool continueOnException)
  186. {
  187. if (!Filesystem.NativeMethods.IsAtLeastWindowsVista)
  188. throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
  189. return EnumerateNetworkObjectCore(new FunctionData(), (NativeMethods.DFS_INFO_200 structure, SafeGlobalMemoryBufferHandle buffer) =>
  190. new DfsInfo { EntryPath = string.Format(CultureInfo.CurrentCulture, "{0}{1}{2}{3}", Path.UncPrefix, NativeMethods.ComputerDomain, Path.DirectorySeparatorChar, structure.FtDfsName) },
  191. (FunctionData functionData, out SafeGlobalMemoryBufferHandle buffer, int prefMaxLen, out uint entriesRead, out uint totalEntries, out uint resumeHandle) =>
  192. {
  193. totalEntries = 0;
  194. // When host == null, the local computer is used.
  195. // However, the resulting Host property will be empty.
  196. // So, explicitly state Environment.MachineName to prevent this.
  197. // Furthermore, the UNC prefix: \\ is not required and always removed.
  198. string stripUnc = Utils.IsNullOrWhiteSpace(domain) ? NativeMethods.ComputerDomain : Path.GetRegularPathCore(domain, GetFullPathOptions.CheckInvalidPathChars, false).Replace(Path.UncPrefix, string.Empty);
  199. return NativeMethods.NetDfsEnum(stripUnc, 200, prefMaxLen, out buffer, out entriesRead, out resumeHandle);
  200. }, continueOnException).Select(dfs => dfs.EntryPath);
  201. }
  202. /// <summary>Retrieves information about a specified DFS root or link in a DFS namespace.</summary>
  203. /// <returns>A <see cref="DfsInfo"/> instance.</returns>
  204. /// <exception cref="ArgumentNullException"/>
  205. /// <exception cref="NetworkInformationException"/>
  206. /// <exception cref="PlatformNotSupportedException"/>
  207. /// <param name="getFromClient">
  208. /// <see langword="true"/> retrieves information about a Distributed File System (DFS) root or link from the cache maintained by the
  209. /// DFS client. When <see langword="false"/> retrieves information about a specified Distributed File System (DFS) root or link in a
  210. /// DFS namespace.
  211. /// </param>
  212. /// <param name="dfsName">The Universal Naming Convention (UNC) path of a DFS root or link.</param>
  213. /// <param name="serverName">
  214. /// The name of the DFS root target or link target server. If <paramref name="getFromClient"/> is <see langword="false"/>, this
  215. /// parameter is always <see langword="null"/>.
  216. /// </param>
  217. /// <param name="shareName">
  218. /// The name of the share corresponding to the DFS root target or link target. If <paramref name="getFromClient"/> is
  219. /// <see langword="false"/>, this parameter is always <see langword="null"/>.
  220. /// </param>
  221. [SecurityCritical]
  222. private static DfsInfo GetDfsInfoCore(bool getFromClient, string dfsName, string serverName, string shareName)
  223. {
  224. if (!Filesystem.NativeMethods.IsAtLeastWindowsVista)
  225. throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
  226. if (Utils.IsNullOrWhiteSpace(dfsName))
  227. throw new ArgumentNullException("dfsName");
  228. serverName = Utils.IsNullOrWhiteSpace(serverName) ? null : serverName;
  229. shareName = Utils.IsNullOrWhiteSpace(shareName) ? null : shareName;
  230. SafeGlobalMemoryBufferHandle safeBuffer;
  231. // Level 9 = DFS_INFO_9
  232. uint lastError = getFromClient
  233. ? NativeMethods.NetDfsGetClientInfo(dfsName, serverName, shareName, 9, out safeBuffer)
  234. : NativeMethods.NetDfsGetInfo(dfsName, null, null, 9, out safeBuffer);
  235. if (lastError == Win32Errors.NERR_Success)
  236. return new DfsInfo(safeBuffer.PtrToStructure<NativeMethods.DFS_INFO_9>(0));
  237. throw new NetworkInformationException((int) lastError);
  238. }
  239. #endregion // Internal Methods
  240. }
  241. }