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.
 
 

393 lines
22 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 EnumerateOpenConnections
  34. /// <summary>Enumerates open connections from the local host.</summary>
  35. /// <returns><see cref="OpenConnectionInfo"/> connection information from the local host.</returns>
  36. /// <exception cref="ArgumentNullException"/>
  37. /// <exception cref="NetworkInformationException"/>
  38. [SecurityCritical]
  39. public static IEnumerable<OpenConnectionInfo> EnumerateOpenConnections()
  40. {
  41. return EnumerateOpenConnectionsCore(null, null, false);
  42. }
  43. /// <summary>Enumerates open connections from the specified host.</summary>
  44. /// <returns><see cref="OpenConnectionInfo"/> connection information from the specified <paramref name="host"/>.</returns>
  45. /// <exception cref="ArgumentNullException"/>
  46. /// <exception cref="NetworkInformationException"/>
  47. /// <param name="host">The DNS or NetBIOS name of the remote server. <see langword="null"/> refers to the local host.</param>
  48. /// <param name="share">The name of the Server Message Block (SMB) share.</param>
  49. /// <param name="continueOnException">
  50. /// <para><see langword="true"/> suppress any Exception that might be thrown as a result from a failure,</para>
  51. /// <para>such as unavailable resources.</para>
  52. /// </param>
  53. [SecurityCritical]
  54. public static IEnumerable<OpenConnectionInfo> EnumerateOpenConnections(string host, string share, bool continueOnException)
  55. {
  56. return EnumerateOpenConnectionsCore(host, share, continueOnException);
  57. }
  58. #endregion // EnumerateOpenConnections
  59. #region EnumerateShares
  60. /// <summary>Enumerates Server Message Block (SMB) shares from the local host.</summary>
  61. /// <returns><see cref="IEnumerable{ShareInfo}"/> shares from the specified host.</returns>
  62. /// <remarks>This method also enumerates hidden shares.</remarks>
  63. [SecurityCritical]
  64. public static IEnumerable<ShareInfo> EnumerateShares()
  65. {
  66. return EnumerateSharesCore(null, ShareType.All, false);
  67. }
  68. /// <summary>Enumerates Server Message Block (SMB) shares from the local host.</summary>
  69. /// <returns><see cref="IEnumerable{ShareInfo}"/> shares from the specified host.</returns>
  70. /// <remarks>This method also enumerates hidden shares.</remarks>
  71. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  72. [SecurityCritical]
  73. public static IEnumerable<ShareInfo> EnumerateShares(bool continueOnException)
  74. {
  75. return EnumerateSharesCore(null, ShareType.All, continueOnException);
  76. }
  77. /// <summary>Enumerates Server Message Block (SMB) shares from the local host.</summary>
  78. /// <returns><see cref="IEnumerable{ShareInfo}"/> shares from the specified host.</returns>
  79. /// <remarks>This method also enumerates hidden shares.</remarks>
  80. /// <param name="shareType">The type of the shared resource to retrieve.</param>
  81. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  82. [SecurityCritical]
  83. public static IEnumerable<ShareInfo> EnumerateShares(ShareType shareType, bool continueOnException)
  84. {
  85. return EnumerateSharesCore(null, shareType, continueOnException);
  86. }
  87. /// <summary>Enumerates Server Message Block (SMB) shares from the specified <paramref name="host"/>.</summary>
  88. /// <returns><see cref="IEnumerable{ShareInfo}"/> shares from the specified host.</returns>
  89. /// <remarks>This method also enumerates hidden shares.</remarks>
  90. /// <param name="host">The DNS or NetBIOS name of the specified host.</param>
  91. [SecurityCritical]
  92. public static IEnumerable<ShareInfo> EnumerateShares(string host)
  93. {
  94. return EnumerateSharesCore(host, ShareType.All, false);
  95. }
  96. /// <summary>Enumerates Server Message Block (SMB) shares from the specified <paramref name="host"/>.</summary>
  97. /// <returns><see cref="IEnumerable{ShareInfo}"/> shares from the specified host.</returns>
  98. /// <remarks>This method also enumerates hidden shares.</remarks>
  99. /// <param name="host">The DNS or NetBIOS name of the specified host.</param>
  100. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  101. [SecurityCritical]
  102. public static IEnumerable<ShareInfo> EnumerateShares(string host, bool continueOnException)
  103. {
  104. return EnumerateSharesCore(host, ShareType.All, continueOnException);
  105. }
  106. /// <summary>Enumerates Server Message Block (SMB) shares from the specified <paramref name="host"/>.</summary>
  107. /// <returns><see cref="IEnumerable{ShareInfo}"/> shares from the specified host.</returns>
  108. /// <remarks>This method also enumerates hidden shares.</remarks>
  109. /// <param name="host">The DNS or NetBIOS name of the specified host.</param>
  110. /// <param name="shareType">The type of the shared resource to retrieve.</param>
  111. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  112. [SecurityCritical]
  113. public static IEnumerable<ShareInfo> EnumerateShares(string host, ShareType shareType, bool continueOnException)
  114. {
  115. return EnumerateSharesCore(host, shareType, continueOnException);
  116. }
  117. #endregion // EnumerateShares
  118. #region GetHostShareFromPath
  119. /// <summary>Gets the host and share path name for the given <paramref name="uncPath"/>.</summary>
  120. /// <param name="uncPath">The share in the format: \\host\share.</param>
  121. /// <returns>The host and share path. For example, if <paramref name="uncPath"/> is: "\\SERVER001\C$\WINDOWS\System32",
  122. /// its is returned as string[0] = "SERVER001" and string[1] = "\C$\WINDOWS\System32".
  123. /// <para>If the conversion from local path to UNC path fails, <see langword="null"/> is returned.</para>
  124. /// </returns>
  125. [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Utils.IsNullOrWhiteSpace validates arguments.")]
  126. [SecurityCritical]
  127. public static string[] GetHostShareFromPath(string uncPath)
  128. {
  129. if (Utils.IsNullOrWhiteSpace(uncPath))
  130. return null;
  131. Uri uri;
  132. if (Uri.TryCreate(Path.GetRegularPathCore(uncPath, GetFullPathOptions.None, false), UriKind.Absolute, out uri) && uri.IsUnc)
  133. {
  134. return new[]
  135. {
  136. uri.Host,
  137. uri.AbsolutePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)
  138. };
  139. }
  140. return null;
  141. }
  142. #endregion // GetHostShareFromPath
  143. #region GetShareInfo
  144. /// <summary>Retrieves information about the Server Message Block (SMB) share as defined on the specified host.</summary>
  145. /// <returns>A <see cref="ShareInfo"/> class, or <see langword="null"/> on failure or when not available, and <paramref name="continueOnException"/> is <see langword="true"/>.</returns>
  146. /// <param name="uncPath">The share in the format: \\host\share.</param>
  147. /// <param name="continueOnException"><see langword="true"/> to suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  148. [SecurityCritical]
  149. public static ShareInfo GetShareInfo(string uncPath, bool continueOnException)
  150. {
  151. var unc = GetHostShareFromPath(uncPath);
  152. return GetShareInfoCore(ShareInfoLevel.Info503, unc[0], unc[1], continueOnException);
  153. }
  154. /// <summary>Retrieves information about the Server Message Block (SMB) share as defined on the specified host.</summary>
  155. /// <returns>A <see cref="ShareInfo"/> class, or <see langword="null"/> on failure or when not available, and <paramref name="continueOnException"/> is <see langword="true"/>.</returns>
  156. /// <param name="shareLevel">One of the <see cref="ShareInfoLevel"/> options.</param>
  157. /// <param name="uncPath">The share in the format: \\host\share.</param>
  158. /// <param name="continueOnException"><see langword="true"/> to suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  159. [SecurityCritical]
  160. public static ShareInfo GetShareInfo(ShareInfoLevel shareLevel, string uncPath, bool continueOnException)
  161. {
  162. var unc = GetHostShareFromPath(uncPath);
  163. return GetShareInfoCore(shareLevel, unc[0], unc[1], continueOnException);
  164. }
  165. /// <summary>Retrieves information about the Server Message Block (SMB) share as defined on the specified host.</summary>
  166. /// <returns>A <see cref="ShareInfo"/> class, or <see langword="null"/> on failure or when not available, and <paramref name="continueOnException"/> is <see langword="true"/>.</returns>
  167. /// <param name="host">The DNS or NetBIOS name of the specified host.</param>
  168. /// <param name="share">The name of the Server Message Block (SMB) share.</param>
  169. /// <param name="continueOnException"><see langword="true"/> to suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  170. [SecurityCritical]
  171. public static ShareInfo GetShareInfo(string host, string share, bool continueOnException)
  172. {
  173. return GetShareInfoCore(ShareInfoLevel.Info503, host, share, continueOnException);
  174. }
  175. /// <summary>Retrieves information about the Server Message Block (SMB) share as defined on the specified host.</summary>
  176. /// <returns>A <see cref="ShareInfo"/> class, or <see langword="null"/> on failure or when not available, and <paramref name="continueOnException"/> is <see langword="true"/>.</returns>
  177. /// <param name="shareLevel">One of the <see cref="ShareInfoLevel"/> options.</param>
  178. /// <param name="host">A string that specifies the DNS or NetBIOS name of the specified <paramref name="host"/>.</param>
  179. /// <param name="share">A string that specifies the name of the Server Message Block (SMB) share.</param>
  180. /// <param name="continueOnException"><see langword="true"/> to suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  181. [SecurityCritical]
  182. public static ShareInfo GetShareInfo(ShareInfoLevel shareLevel, string host, string share, bool continueOnException)
  183. {
  184. return GetShareInfoCore(shareLevel, host, share, continueOnException);
  185. }
  186. #endregion // GetShareInfo
  187. #region Internal Methods
  188. #region EnumerateOpenConnectionsCore
  189. /// <summary>Enumerates open connections from the specified host and <paramref name="share"/>.</summary>
  190. /// <returns><see cref="OpenConnectionInfo"/> connection information from the specified <paramref name="host"/>.</returns>
  191. /// <exception cref="ArgumentNullException"/>
  192. /// <exception cref="NetworkInformationException"/>
  193. /// <param name="host">The DNS or NetBIOS name of the remote server. <see langword="null"/> refers to the local host.</param>
  194. /// <param name="share">The name of the Server Message Block (SMB) share.</param>
  195. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  196. [SecurityCritical]
  197. private static IEnumerable<OpenConnectionInfo> EnumerateOpenConnectionsCore(string host, string share, bool continueOnException)
  198. {
  199. if (Utils.IsNullOrWhiteSpace(share))
  200. throw new ArgumentNullException("share");
  201. return EnumerateNetworkObjectCore(new FunctionData { ExtraData1 = share }, (NativeMethods.CONNECTION_INFO_1 structure, SafeGlobalMemoryBufferHandle buffer) =>
  202. new OpenConnectionInfo(host, structure),
  203. (FunctionData functionData, out SafeGlobalMemoryBufferHandle buffer, int prefMaxLen, out uint entriesRead, out uint totalEntries, out uint resumeHandle) =>
  204. {
  205. // When host == null, the local computer is used.
  206. // However, the resulting OpenResourceInfo.Host property will be empty.
  207. // So, explicitly state Environment.MachineName to prevent this.
  208. // Furthermore, the UNC prefix: \\ is not required and always removed.
  209. string stripUnc = Utils.IsNullOrWhiteSpace(host) ? Environment.MachineName : Path.GetRegularPathCore(host, GetFullPathOptions.CheckInvalidPathChars, false).Replace(Path.UncPrefix, string.Empty);
  210. return NativeMethods.NetConnectionEnum(stripUnc, functionData.ExtraData1, 1, out buffer, NativeMethods.MaxPreferredLength, out entriesRead, out totalEntries, out resumeHandle);
  211. },
  212. continueOnException);
  213. }
  214. #endregion // EnumerateOpenConnectionsCore
  215. #region EnumerateSharesCore
  216. /// <summary>Enumerates Server Message Block (SMB) shares from a local or remote host.</summary>
  217. /// <returns><see cref="IEnumerable{ShareInfo}"/> shares from the specified host.</returns>
  218. /// <remarks>This method also enumerates hidden shares.</remarks>
  219. /// <exception cref="ArgumentNullException"/>
  220. /// <exception cref="NetworkInformationException"/>
  221. /// <param name="host">The DNS or NetBIOS name of the specified host.</param>
  222. /// <param name="shareType">The type of the shared resource to retrieve.</param>
  223. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  224. [SecurityCritical]
  225. internal static IEnumerable<ShareInfo> EnumerateSharesCore(string host, ShareType shareType, bool continueOnException)
  226. {
  227. // When host == null, the local computer is used.
  228. // However, the resulting Host property will be empty.
  229. // So, explicitly state Environment.MachineName to prevent this.
  230. // Furthermore, the UNC prefix: \\ is not required and always removed.
  231. var stripUnc = Utils.IsNullOrWhiteSpace(host) ? Environment.MachineName : Path.GetRegularPathCore(host, GetFullPathOptions.CheckInvalidPathChars, false).Replace(Path.UncPrefix, string.Empty);
  232. var fd = new FunctionData();
  233. var hasItems = false;
  234. var yieldAll = shareType == ShareType.All;
  235. // Try SHARE_INFO_503 structure.
  236. foreach (var si in EnumerateNetworkObjectCore(fd, (NativeMethods.SHARE_INFO_503 structure, SafeGlobalMemoryBufferHandle buffer) =>
  237. new ShareInfo(stripUnc, ShareInfoLevel.Info503, structure),
  238. (FunctionData functionData, out SafeGlobalMemoryBufferHandle buffer, int prefMaxLen, out uint entriesRead, out uint totalEntries, out uint resumeHandle) =>
  239. NativeMethods.NetShareEnum(stripUnc, 503, out buffer, NativeMethods.MaxPreferredLength, out entriesRead, out totalEntries, out resumeHandle), continueOnException).Where(si => yieldAll || si.ShareType == shareType))
  240. {
  241. yield return si;
  242. hasItems = true;
  243. }
  244. // SHARE_INFO_503 is requested, but not supported/possible.
  245. // Try again with SHARE_INFO_2 structure.
  246. if (!hasItems)
  247. foreach (var si in EnumerateNetworkObjectCore(fd, (NativeMethods.SHARE_INFO_2 structure, SafeGlobalMemoryBufferHandle buffer) =>
  248. new ShareInfo(stripUnc, ShareInfoLevel.Info2, structure),
  249. (FunctionData functionData, out SafeGlobalMemoryBufferHandle buffer, int prefMaxLen, out uint entriesRead, out uint totalEntries, out uint resumeHandle) =>
  250. NativeMethods.NetShareEnum(stripUnc, 2, out buffer, NativeMethods.MaxPreferredLength, out entriesRead, out totalEntries, out resumeHandle), continueOnException).Where(si => yieldAll || si.ShareType == shareType))
  251. {
  252. yield return si;
  253. hasItems = true;
  254. }
  255. // SHARE_INFO_2 is requested, but not supported/possible.
  256. // Try again with SHARE_INFO_1 structure.
  257. if (!hasItems)
  258. foreach (var si in EnumerateNetworkObjectCore(fd, (NativeMethods.SHARE_INFO_1 structure, SafeGlobalMemoryBufferHandle buffer) =>
  259. new ShareInfo(stripUnc, ShareInfoLevel.Info1, structure),
  260. (FunctionData functionData, out SafeGlobalMemoryBufferHandle buffer, int prefMaxLen, out uint entriesRead, out uint totalEntries, out uint resumeHandle) =>
  261. NativeMethods.NetShareEnum(stripUnc, 1, out buffer, NativeMethods.MaxPreferredLength, out entriesRead, out totalEntries, out resumeHandle), continueOnException).Where(si => yieldAll || si.ShareType == shareType))
  262. {
  263. yield return si;
  264. }
  265. }
  266. #endregion // EnumerateSharesCore
  267. #region GetShareInfoCore
  268. /// <summary>Gets the <see cref="ShareInfo"/> structure of a Server Message Block (SMB) share.</summary>
  269. /// <returns>A <see cref="ShareInfo"/> class, or <see langword="null"/> on failure or when not available, and <paramref name="continueOnException"/> is <see langword="true"/>.</returns>
  270. /// <exception cref="NetworkInformationException"/>
  271. /// <param name="shareLevel">One of the <see cref="ShareInfoLevel"/> options.</param>
  272. /// <param name="host">A string that specifies the DNS or NetBIOS name of the specified <paramref name="host"/>.</param>
  273. /// <param name="share">A string that specifies the name of the Server Message Block (SMB) share.</param>
  274. /// <param name="continueOnException"><see langword="true"/> to suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  275. [SecurityCritical]
  276. internal static ShareInfo GetShareInfoCore(ShareInfoLevel shareLevel, string host, string share, bool continueOnException)
  277. {
  278. if (Utils.IsNullOrWhiteSpace(share))
  279. return null;
  280. // When host == null, the local computer is used.
  281. // However, the resulting Host property will be empty.
  282. // So, explicitly state Environment.MachineName to prevent this.
  283. // Furthermore, the UNC prefix: \\ is not required and always removed.
  284. var stripUnc = Utils.IsNullOrWhiteSpace(host) ? Environment.MachineName : Path.GetRegularPathCore(host, GetFullPathOptions.CheckInvalidPathChars, false).Replace(Path.UncPrefix, string.Empty);
  285. var fallback = false;
  286. startNetShareGetInfo:
  287. SafeGlobalMemoryBufferHandle safeBuffer;
  288. uint structureLevel = Convert.ToUInt16(shareLevel, CultureInfo.InvariantCulture);
  289. var lastError = NativeMethods.NetShareGetInfo(stripUnc, share, structureLevel, out safeBuffer);
  290. using (safeBuffer)
  291. {
  292. switch (lastError)
  293. {
  294. case Win32Errors.NERR_Success:
  295. switch (shareLevel)
  296. {
  297. case ShareInfoLevel.Info1005:
  298. return new ShareInfo(stripUnc, shareLevel, safeBuffer.PtrToStructure<NativeMethods.SHARE_INFO_1005>(0))
  299. {
  300. NetFullPath = Path.CombineCore(false, Path.UncPrefix + stripUnc, share)
  301. };
  302. case ShareInfoLevel.Info503:
  303. return new ShareInfo(stripUnc, shareLevel, safeBuffer.PtrToStructure<NativeMethods.SHARE_INFO_503>(0));
  304. case ShareInfoLevel.Info2:
  305. return new ShareInfo(stripUnc, shareLevel, safeBuffer.PtrToStructure<NativeMethods.SHARE_INFO_2>(0));
  306. case ShareInfoLevel.Info1:
  307. return new ShareInfo(stripUnc, shareLevel, safeBuffer.PtrToStructure<NativeMethods.SHARE_INFO_1>(0));
  308. }
  309. break;
  310. // Observed when SHARE_INFO_503 is requested, but not supported/possible.
  311. // Fall back on SHARE_INFO_2 structure and try again.
  312. case Win32Errors.RPC_X_BAD_STUB_DATA:
  313. case Win32Errors.ERROR_ACCESS_DENIED:
  314. if (!fallback && shareLevel != ShareInfoLevel.Info2)
  315. {
  316. shareLevel = ShareInfoLevel.Info2;
  317. fallback = true;
  318. goto startNetShareGetInfo;
  319. }
  320. break;
  321. default:
  322. if (!continueOnException)
  323. throw new NetworkInformationException((int) lastError);
  324. break;
  325. }
  326. return null;
  327. }
  328. }
  329. #endregion // GetShareInfoCore
  330. #endregion // Internal Methods
  331. }
  332. }