/* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using Alphaleonis.Win32.Filesystem;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Net;
using System.Net.NetworkInformation;
using System.Security;
using System.Text;
namespace Alphaleonis.Win32.Network
{
partial class Host
{
#region ConnectDrive
/// Creates a connection to a network resource. The function can redirect a local device to a network resource.
/// If is or string.Empty, returns the last available drive letter, otherwise.
///
/// The name of a local device to be redirected, such as "F:". When is or
/// string.Empty, the last available drive letter will be used. Letters are assigned beginning with Z:, then Y: and so on.
///
/// The network resource to connect to. The string can be up to MAX_PATH characters in length.
[SecurityCritical]
public static string ConnectDrive(string localName, string remoteName)
{
return ConnectDisconnectCore(new ConnectDisconnectArguments
{
LocalName = localName,
RemoteName = remoteName,
IsDeviceMap = true
});
}
/// Creates a connection to a network resource. The function can redirect a local device to a network resource.
/// If is or string.Empty, returns the last available drive letter, null otherwise.
///
/// The name of a local device to be redirected, such as "F:". When is or
/// string.Empty, the last available drive letter will be used. Letters are assigned beginning with Z:, then Y: and so on.
///
/// The network resource to connect to. The string can be up to MAX_PATH characters in length.
///
/// The user name for making the connection. If is , the function uses the default
/// user name. (The user context for the process provides the default user name)
///
///
/// The password to be used for making the network connection. If is , the function
/// uses the current default password associated with the user specified by .
///
/// always pops-up an authentication dialog box.
/// successful network resource connections will be saved.
///
/// When the operating system prompts for a credential, the credential should be saved by the credential manager when true.
///
[SecurityCritical]
public static string ConnectDrive(string localName, string remoteName, string userName, string password, bool prompt, bool updateProfile, bool saveCredentials)
{
return ConnectDisconnectCore(new ConnectDisconnectArguments
{
LocalName = localName,
RemoteName = remoteName,
UserName = userName,
Password = password,
Prompt = prompt,
UpdateProfile = updateProfile,
SaveCredentials = saveCredentials,
IsDeviceMap = true
});
}
/// Creates a connection to a network resource. The function can redirect a local device to a network resource.
/// If is or string.Empty, returns the last available drive letter, null otherwise.
///
/// The name of a local device to be redirected, such as "F:". When is or
/// string.Empty, the last available drive letter will be used. Letters are assigned beginning with Z:, then Y: and so on.
///
/// The network resource to connect to. The string can be up to MAX_PATH characters in length.
///
/// An instance of which provides credentials for password-based authentication schemes such as basic,
/// digest, NTLM, and Kerberos authentication.
///
/// always pops-up an authentication dialog box.
/// successful network resource connections will be saved.
///
/// When the operating system prompts for a credential, the credential should be saved by the credential manager when true.
///
[SecurityCritical]
public static string ConnectDrive(string localName, string remoteName, NetworkCredential credentials, bool prompt, bool updateProfile, bool saveCredentials)
{
return ConnectDisconnectCore(new ConnectDisconnectArguments
{
LocalName = localName,
RemoteName = remoteName,
Credential = credentials,
Prompt = prompt,
UpdateProfile = updateProfile,
SaveCredentials = saveCredentials,
IsDeviceMap = true
});
}
/// Creates a connection to a network resource. The function can redirect a local device to a network resource.
/// If is or string.Empty, returns the last available drive letter, null otherwise.
/// Handle to a window that the provider of network resources can use as an owner window for dialog boxes.
///
/// The name of a local device to be redirected, such as "F:". When is or
/// string.Empty, the last available drive letter will be used. Letters are assigned beginning with Z:, then Y: and so on.
///
/// The network resource to connect to. The string can be up to MAX_PATH characters in length.
///
/// The user name for making the connection. If is , the function uses the default
/// user name. (The user context for the process provides the default user name)
///
///
/// The password to be used for making the network connection. If is , the function
/// uses the current default password associated with the user specified by .
///
/// always pops-up an authentication dialog box.
/// successful network resource connections will be saved.
///
/// When the operating system prompts for a credential, the credential should be saved by the credential manager when true.
///
[SecurityCritical]
public static string ConnectDrive(IntPtr winOwner, string localName, string remoteName, string userName, string password, bool prompt, bool updateProfile, bool saveCredentials)
{
return ConnectDisconnectCore(new ConnectDisconnectArguments
{
WinOwner = winOwner,
LocalName = localName,
RemoteName = remoteName,
UserName = userName,
Password = password,
Prompt = prompt,
UpdateProfile = updateProfile,
SaveCredentials = saveCredentials,
IsDeviceMap = true
});
}
/// Creates a connection to a network resource. The function can redirect a local device to a network resource.
/// If is or string.Empty, returns the last available drive letter, null otherwise.
/// Handle to a window that the provider of network resources can use as an owner window for dialog boxes.
///
/// The name of a local device to be redirected, such as "F:". When is or
/// string.Empty, the last available drive letter will be used. Letters are assigned beginning with Z:, then Y: and so on.
///
/// The network resource to connect to. The string can be up to MAX_PATH characters in length.
///
/// An instance of which provides credentials for password-based authentication schemes such as basic,
/// digest, NTLM, and Kerberos authentication.
///
/// always pops-up an authentication dialog box.
/// successful network resource connections will be saved.
///
/// When the operating system prompts for a credential, the credential should be saved by the credential manager when true.
///
[SecurityCritical]
public static string ConnectDrive(IntPtr winOwner, string localName, string remoteName, NetworkCredential credentials, bool prompt, bool updateProfile, bool saveCredentials)
{
return ConnectDisconnectCore(new ConnectDisconnectArguments
{
WinOwner = winOwner,
LocalName = localName,
RemoteName = remoteName,
Credential = credentials,
Prompt = prompt,
UpdateProfile = updateProfile,
SaveCredentials = saveCredentials,
IsDeviceMap = true
});
}
#endregion // ConnectDrive
#region ConnectTo
/// Creates a connection to a network resource.
///
/// A network resource to connect to, for example: \\server or \\server\share.
[SecurityCritical]
public static void ConnectTo(string remoteName)
{
ConnectDisconnectCore(new ConnectDisconnectArguments { RemoteName = remoteName });
}
/// Creates a connection to a network resource.
///
/// A network resource to connect to, for example: \\server or \\server\share.
///
/// The user name for making the connection. If is , the function uses the default
/// user name. (The user context for the process provides the default user name)
///
///
/// The password to be used for making the network connection. If is , the function
/// uses the current default password associated with the user specified by .
///
/// always pops-up an authentication dialog box.
/// successful network resource connections will be saved.
///
/// When the operating system prompts for a credential, the credential should be saved by the credential manager when true.
///
[SecurityCritical]
public static void ConnectTo(string remoteName, string userName, string password, bool prompt, bool updateProfile, bool saveCredentials)
{
ConnectDisconnectCore(new ConnectDisconnectArguments
{
RemoteName = remoteName,
UserName = userName,
Password = password,
Prompt = prompt,
UpdateProfile = updateProfile,
SaveCredentials = saveCredentials
});
}
/// Creates a connection to a network resource.
/// A network resource to connect to, for example: \\server or \\server\share.
/// An instance of which provides credentials for password-based authentication schemes such as basic, digest, NTLM, and Kerberos authentication.
/// always pops-up an authentication dialog box.
/// successful network resource connections will be saved.
/// When the operating system prompts for a credential, the credential should be saved by the credential manager when true.
///
///
[SecurityCritical]
public static void ConnectTo(string remoteName, NetworkCredential credentials, bool prompt, bool updateProfile, bool saveCredentials)
{
ConnectDisconnectCore(new ConnectDisconnectArguments
{
RemoteName = remoteName,
Credential = credentials,
Prompt = prompt,
UpdateProfile = updateProfile,
SaveCredentials = saveCredentials
});
}
/// Creates a connection to a network resource.
///
/// Handle to a window that the provider of network resources can use as an owner window for dialog boxes.
/// A network resource to connect to, for example: \\server or \\server\share.
///
/// The user name for making the connection. If is , the function uses the default
/// user name. (The user context for the process provides the default user name)
///
///
/// The password to be used for making the network connection. If is , the function
/// uses the current default password associated with the user specified by .
///
/// always pops-up an authentication dialog box.
/// successful network resource connections will be saved.
/// When the operating system prompts for a credential, the credential should be saved by the credential manager when true.
[SecurityCritical]
public static void ConnectTo(IntPtr winOwner, string remoteName, string userName, string password, bool prompt, bool updateProfile, bool saveCredentials)
{
ConnectDisconnectCore(new ConnectDisconnectArguments
{
WinOwner = winOwner,
RemoteName = remoteName,
UserName = userName,
Password = password,
Prompt = prompt,
UpdateProfile = updateProfile,
SaveCredentials = saveCredentials
});
}
/// Creates a connection to a network resource.
///
/// Handle to a window that the provider of network resources can use as an owner window for dialog boxes.
/// A network resource to connect to, for example: \\server or \\server\share.
/// An instance of which provides credentials for password-based authentication schemes such as basic, digest, NTLM, and Kerberos authentication.
/// always pops-up an authentication dialog box.
/// successful network resource connections will be saved.
/// When the operating system prompts for a credential, the credential should be saved by the credential manager when true.
[SecurityCritical]
public static void ConnectTo(IntPtr winOwner, string remoteName, NetworkCredential credentials, bool prompt, bool updateProfile, bool saveCredentials)
{
ConnectDisconnectCore(new ConnectDisconnectArguments
{
WinOwner = winOwner,
RemoteName = remoteName,
Credential = credentials,
Prompt = prompt,
UpdateProfile = updateProfile,
SaveCredentials = saveCredentials
});
}
#endregion // ConnectTo
#region DisconnectDrive
/// Cancels an existing network connection. You can also call the function to remove remembered network connections that are not currently connected.
/// The name of a local device to be disconnected, such as "F:".
[SecurityCritical]
public static void DisconnectDrive(string localName)
{
ConnectDisconnectCore(new ConnectDisconnectArguments
{
LocalName = localName,
IsDeviceMap = true,
IsDisconnect = true
});
}
/// Cancels an existing network connection. You can also call the function to remove remembered network connections that are not currently connected.
/// The name of a local device to be disconnected, such as "F:".
///
/// Specifies whether the disconnection should occur if there are open files or jobs on the connection.
/// If this parameter is , the function fails if there are open files or jobs.
///
/// successful removal of network resource connections will be saved.
[SecurityCritical]
public static void DisconnectDrive(string localName, bool force, bool updateProfile)
{
ConnectDisconnectCore(new ConnectDisconnectArguments
{
LocalName = localName,
Prompt = force,
UpdateProfile = updateProfile,
IsDeviceMap = true,
IsDisconnect = true
});
}
#endregion // DisconnectDrive
#region DisconnectFrom
/// Cancels an existing network connection. You can also call the function to remove remembered network connections that are not currently connected.
/// A network resource to disconnect from, for example: \\server or \\server\share.
[SecurityCritical]
public static void DisconnectFrom(string remoteName)
{
ConnectDisconnectCore(new ConnectDisconnectArguments
{
RemoteName = remoteName,
IsDisconnect = true
});
}
/// Cancels an existing network connection. You can also call the function to remove remembered network connections that are not currently connected.
/// A network resource to disconnect from, for example: \\server or \\server\share.
///
/// Specifies whether the disconnection should occur if there are open files or jobs on the connection.
/// If this parameter is , the function fails if there are open files or jobs.
///
/// successful removal of network resource connections will be saved.
[SecurityCritical]
public static void DisconnectFrom(string remoteName, bool force, bool updateProfile)
{
ConnectDisconnectCore(new ConnectDisconnectArguments
{
RemoteName = remoteName,
Prompt = force,
UpdateProfile = updateProfile,
IsDisconnect = true
});
}
#endregion // DisconnectFrom
#region Internal Methods
/// Connects to/disconnects from a network resource. The function can redirect a local device to a network resource.
/// If is or string.Empty, returns the last available drive letter, null otherwise.
///
///
/// The .
[SuppressMessage("Microsoft.Usage", "CA2208:InstantiateArgumentExceptionsCorrectly")]
[SecurityCritical]
internal static string ConnectDisconnectCore(ConnectDisconnectArguments arguments)
{
uint lastError;
// Always remove backslash for local device.
if (!Utils.IsNullOrWhiteSpace(arguments.LocalName))
arguments.LocalName = Path.RemoveTrailingDirectorySeparator(arguments.LocalName, false).ToUpperInvariant();
#region Disconnect
if (arguments.IsDisconnect)
{
bool force = arguments.Prompt; // Use value of prompt variable for force value.
string target = arguments.IsDeviceMap ? arguments.LocalName : arguments.RemoteName;
if (Utils.IsNullOrWhiteSpace(target))
throw new ArgumentNullException(arguments.IsDeviceMap ? "localName" : "remoteName");
lastError = NativeMethods.WNetCancelConnection(target, arguments.UpdateProfile ? NativeMethods.Connect.UpdateProfile : NativeMethods.Connect.None, force);
if (lastError != Win32Errors.NO_ERROR)
throw new NetworkInformationException((int)lastError);
return null;
}
#endregion // Disconnect
#region Connect
// arguments.LocalName is allowed to be null or empty.
//if (Utils.IsNullOrWhiteSpace(arguments.LocalName) && !arguments.IsDeviceMap)
// throw new ArgumentNullException("localName");
if (Utils.IsNullOrWhiteSpace(arguments.RemoteName) && !arguments.IsDeviceMap)
throw new ArgumentNullException("remoteName");
// When supplied, use data from NetworkCredential instance.
if (arguments.Credential != null)
{
arguments.UserName = Utils.IsNullOrWhiteSpace(arguments.Credential.Domain)
? arguments.Credential.UserName
: string.Format(CultureInfo.InvariantCulture, @"{0}\{1}", arguments.Credential.Domain, arguments.Credential.UserName);
arguments.Password = arguments.Credential.Password;
}
// Assemble Connect arguments.
var connect = NativeMethods.Connect.None;
if (arguments.IsDeviceMap)
connect = connect | NativeMethods.Connect.Redirect;
if (arguments.Prompt)
connect = connect | NativeMethods.Connect.Prompt | NativeMethods.Connect.Interactive;
if (arguments.UpdateProfile)
connect = connect | NativeMethods.Connect.UpdateProfile;
if (arguments.SaveCredentials)
connect = connect | NativeMethods.Connect.SaveCredentialManager;
// Initialize structure.
var resource = new NativeMethods.NETRESOURCE
{
lpLocalName = arguments.LocalName,
lpRemoteName = arguments.RemoteName,
dwType = NativeMethods.ResourceType.Disk
};
// Three characters for: "X:\0" (Drive X: with null terminator)
uint bufferSize = 3;
StringBuilder buffer;
do
{
buffer = new StringBuilder((int)bufferSize);
uint result;
lastError = NativeMethods.WNetUseConnection(arguments.WinOwner, ref resource, arguments.Password, arguments.UserName, connect, buffer, out bufferSize, out result);
switch (lastError)
{
case Win32Errors.NO_ERROR:
break;
case Win32Errors.ERROR_MORE_DATA:
// MSDN, lpBufferSize: If the call fails because the buffer is not large enough,
// the function returns the required buffer size in this location.
//
// Windows 8 x64: bufferSize remains unchanged.
bufferSize = bufferSize * 2;
break;
}
} while (lastError == Win32Errors.ERROR_MORE_DATA);
if (lastError != Win32Errors.NO_ERROR)
throw new NetworkInformationException((int)lastError);
return arguments.IsDeviceMap ? buffer.ToString() : null;
#endregion // Connect
}
#endregion // Internal Methods
}
}