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.
 
 

245 line
11 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.IO;
  27. using System.Net;
  28. using System.Net.NetworkInformation;
  29. using System.Runtime.InteropServices;
  30. using System.Security;
  31. using System.Text;
  32. using Path = Alphaleonis.Win32.Filesystem.Path;
  33. namespace Alphaleonis.Win32.Network
  34. {
  35. /// <summary>Provides static methods to retrieve network resource information from a local- or remote host.</summary>
  36. public static partial class Host
  37. {
  38. #region GetUncName
  39. /// <summary>Return the host name in UNC format, for example: \\hostname.</summary>
  40. /// <returns>The unc name.</returns>
  41. [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  42. [SecurityCritical]
  43. public static string GetUncName()
  44. {
  45. return string.Format(CultureInfo.InvariantCulture, "{0}{1}", Path.UncPrefix, Environment.MachineName);
  46. }
  47. /// <summary>Return the host name in UNC format, for example: \\hostname.</summary>
  48. /// <param name="computerName">Name of the computer.</param>
  49. /// <returns>The unc name.</returns>
  50. [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Utils.IsNullOrWhiteSpace validates arguments.")]
  51. [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
  52. [SecurityCritical]
  53. public static string GetUncName(string computerName)
  54. {
  55. return Utils.IsNullOrWhiteSpace(computerName)
  56. ? GetUncName()
  57. : (computerName.StartsWith(Path.UncPrefix, StringComparison.OrdinalIgnoreCase)
  58. ? computerName.Trim()
  59. : Path.UncPrefix + computerName.Trim());
  60. }
  61. #endregion // GetUncName
  62. #region Internal Methods
  63. private delegate uint EnumerateNetworkObjectDelegate(
  64. FunctionData functionData, out SafeGlobalMemoryBufferHandle netApiBuffer, [MarshalAs(UnmanagedType.I4)] int prefMaxLen,
  65. [MarshalAs(UnmanagedType.U4)] out uint entriesRead, [MarshalAs(UnmanagedType.U4)] out uint totalEntries,
  66. [MarshalAs(UnmanagedType.U4)] out uint resumeHandle);
  67. /// <summary>Structure is used to pass additional data to the Win32 function.</summary>
  68. private struct FunctionData
  69. {
  70. public int EnumType;
  71. public string ExtraData1;
  72. public string ExtraData2;
  73. }
  74. [SecurityCritical]
  75. private static IEnumerable<TStruct> EnumerateNetworkObjectCore<TStruct, TNative>(FunctionData functionData, Func<TNative, SafeGlobalMemoryBufferHandle, TStruct> createTStruct, EnumerateNetworkObjectDelegate enumerateNetworkObject, bool continueOnException)
  76. {
  77. Type objectType;
  78. int objectSize;
  79. bool isString;
  80. switch (functionData.EnumType)
  81. {
  82. // Logical Drives
  83. case 1:
  84. objectType = typeof(IntPtr);
  85. isString = true;
  86. objectSize = Marshal.SizeOf(objectType) + UnicodeEncoding.CharSize;
  87. break;
  88. default:
  89. objectType = typeof(TNative);
  90. isString = objectType == typeof(string);
  91. objectSize = isString ? 0 : Marshal.SizeOf(objectType);
  92. break;
  93. }
  94. uint lastError;
  95. do
  96. {
  97. uint entriesRead;
  98. uint totalEntries;
  99. uint resumeHandle;
  100. SafeGlobalMemoryBufferHandle buffer;
  101. lastError = enumerateNetworkObject(functionData, out buffer, NativeMethods.MaxPreferredLength, out entriesRead, out totalEntries, out resumeHandle);
  102. using (buffer)
  103. switch (lastError)
  104. {
  105. case Win32Errors.NERR_Success:
  106. case Win32Errors.ERROR_MORE_DATA:
  107. if (entriesRead > 0)
  108. {
  109. for (int i = 0, itemOffset = 0; i < entriesRead; i++, itemOffset += objectSize)
  110. yield return (TStruct) (isString
  111. ? buffer.PtrToStringUni(itemOffset, 2)
  112. : (object) createTStruct(buffer.PtrToStructure<TNative>(itemOffset), buffer));
  113. }
  114. break;
  115. case Win32Errors.ERROR_BAD_NETPATH:
  116. break;
  117. // Observed when SHARE_INFO_503 is requested but not supported/possible.
  118. case Win32Errors.RPC_X_BAD_STUB_DATA:
  119. yield break;
  120. }
  121. } while (lastError == Win32Errors.ERROR_MORE_DATA);
  122. if (lastError != Win32Errors.NO_ERROR && !continueOnException)
  123. throw new NetworkInformationException((int) lastError);
  124. }
  125. /// <summary>This method uses <see cref="NativeMethods.REMOTE_NAME_INFO"/> level to retieve full REMOTE_NAME_INFO structure.</summary>
  126. /// <returns>A <see cref="NativeMethods.REMOTE_NAME_INFO"/> structure.</returns>
  127. /// <remarks>AlphaFS regards network drives created using SUBST.EXE as invalid.</remarks>
  128. /// <exception cref="ArgumentException"/>
  129. /// <exception cref="ArgumentNullException"/>
  130. /// <exception cref="PathTooLongException"/>
  131. /// <exception cref="NetworkInformationException"/>
  132. /// <param name="path">The local path with drive name.</param>
  133. /// <param name="continueOnException"><see langword="true"/> suppress any Exception that might be thrown as a result from a failure, such as unavailable resources.</param>
  134. [SecurityCritical]
  135. internal static NativeMethods.REMOTE_NAME_INFO GetRemoteNameInfoCore(string path, bool continueOnException)
  136. {
  137. if (Utils.IsNullOrWhiteSpace(path))
  138. throw new ArgumentNullException("path");
  139. path = Path.GetRegularPathCore(path, GetFullPathOptions.CheckInvalidPathChars, false);
  140. // If path already is a network share path, we fill the REMOTE_NAME_INFO structure ourselves.
  141. if (Path.IsUncPathCore(path, true, false))
  142. return new NativeMethods.REMOTE_NAME_INFO
  143. {
  144. lpUniversalName = Path.AddTrailingDirectorySeparator(path, false),
  145. lpConnectionName = Path.RemoveTrailingDirectorySeparator(path, false),
  146. lpRemainingPath = Path.DirectorySeparator
  147. };
  148. uint lastError;
  149. // Use large enough buffer to prevent a 2nd call.
  150. uint bufferSize = 1024;
  151. do
  152. {
  153. using (var buffer = new SafeGlobalMemoryBufferHandle((int) bufferSize))
  154. {
  155. // Structure: UNIVERSAL_NAME_INFO_LEVEL = 1 (not used in AlphaFS).
  156. // Structure: REMOTE_NAME_INFO_LEVEL = 2
  157. lastError = NativeMethods.WNetGetUniversalName(path, 2, buffer, out bufferSize);
  158. switch (lastError)
  159. {
  160. case Win32Errors.NO_ERROR:
  161. return buffer.PtrToStructure<NativeMethods.REMOTE_NAME_INFO>(0);
  162. case Win32Errors.ERROR_MORE_DATA:
  163. //bufferSize = Received the required buffer size, retry.
  164. break;
  165. }
  166. }
  167. } while (lastError == Win32Errors.ERROR_MORE_DATA);
  168. if (!continueOnException && lastError != Win32Errors.NO_ERROR)
  169. throw new NetworkInformationException((int) lastError);
  170. // Return an empty structure (all fields set to null).
  171. return new NativeMethods.REMOTE_NAME_INFO();
  172. }
  173. internal struct ConnectDisconnectArguments
  174. {
  175. /// <summary>Handle to a window that the provider of network resources can use as an owner window for dialog boxes.</summary>
  176. public IntPtr WinOwner;
  177. /// <summary>The name of a local device to be redirected, such as "F:". When <see cref="LocalName"/> is <see langword="null"/> or <c>string.Empty</c>, the last available drive letter will be used. Letters are assigned beginning with Z:, then Y: and so on.</summary>
  178. public string LocalName;
  179. /// <summary>A network resource to connect to/disconnect from, for example: \\server or \\server\share</summary>
  180. public string RemoteName;
  181. /// <summary>A <see cref="NetworkCredential"/> instance. Use either this or the combination of <see cref="UserName"/> and <see cref="Password"/>.</summary>
  182. public NetworkCredential Credential;
  183. /// <summary>The user name for making the connection. If <see cref="UserName"/> is <see langword="null"/>, the function uses the default user name. (The user context for the process provides the default user name)</summary>
  184. public string UserName;
  185. /// <summary>The password to be used for making the network connection. If <see cref="Password"/> is <see langword="null"/>, the function uses the current default password associated with the user specified by <see cref="UserName"/>.</summary>
  186. public string Password;
  187. /// <summary><see langword="true"/> always pops-up an authentication dialog box.</summary>
  188. public bool Prompt;
  189. /// <summary><see langword="true"/> successful network resource connections will be saved.</summary>
  190. public bool UpdateProfile;
  191. /// <summary>When the operating system prompts for a credential, the credential should be saved by the credential manager when true.</summary>
  192. public bool SaveCredentials;
  193. /// <summary><see langword="true"/> indicates that the operation concerns a drive mapping.</summary>
  194. public bool IsDeviceMap;
  195. /// <summary><see langword="true"/> indicates that the operation needs to disconnect from the network resource, otherwise connect.</summary>
  196. public bool IsDisconnect;
  197. }
  198. #endregion // Internal Methods
  199. }
  200. }