Re: HELP! CreateProcessWithLogonW issue
charlie_at_nunya.com
Date: 09/10/04
- Next message: [MSFT]: "Re: Web Services on Win 2003 to SQL Server on Win 2000"
- Previous message: suresh g: "Re: WebException while calling Web Service over HTTPS..."
- In reply to: Matthew Wieder: "Re: HELP! CreateProcessWithLogonW issue"
- Messages sorted by: [ date ] [ thread ]
Date: Fri, 10 Sep 2004 00:15:26 GMT
OK - here is how I impersonate - the impersonation class is at the end of
this message. I'll just do some code snippets to show the calling of the
impersonation and the executing of the process in WMI. Since we are doing
WMI on the same machine that we are executing on, there is no validation at
that point. However, we need to impersonate first to create the correct
security context in which to execute the external process.
... some code...
Impersonation i = new Impersonation();
// userid and password are stored in an encrypted registry entry
string userID = i.GetUserNameFromRegistry();
string password = i.GetPasswordFromRegistry();
//domain is stored in a config file
string domain = settings.DefaultDomain;
string app = @pAppPath + @"bin\MergeEngine.exe";
string args = @"whatever arguments you need to pass";
WindowsImpersonationContext mWIC =
i.ImpersonateUser(userID,password,domain);
rc = RunWMI(domain,userID,password,app,args);
if (mWIC != null)
{
impersonation.UndoImpersonate(mWIC);
}
... some more code...
public string RunWMI(string domain, string userID, string pwd, string
appString, string argString)
{
string rc = "";
ConnectionOptions options = new ConnectionOptions();
string serverName = Dns.GetHostName();
// because we are impersonating and running against the local machine
// we do not validate
//options.Username = domain + @"\" + userID;
//options.Password = pwd;
//Create a scope to work in
ManagementScope WmiScope = new ManagementScope(@"\\" + serverName, options);
WmiScope.Connect();
ManagementClass processClass = new ManagementClass("Win32_Process");
processClass.Scope = WmiScope;
//Get an input parameters object for this method
ManagementBaseObject inParams = processClass.GetMethodParameters("Create");
//Fill in input parameter values
inParams["CommandLine"] = appString + " " + argString; //' Or whatever
application you want
//Note: The return code of the method is provided in the "returnValue"
property of the outParams object
ManagementBaseObject outParams = processClass.InvokeMethod("Create",
inParams, null);
return rc;
}
Impesonation Class follows:
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
using System.Text;
using Microsoft.Win32;
[assembly:SecurityPermissionAttribute(SecurityAction.RequestMinimum,
UnmanagedCode=true)]
namespace Security.WebModules
{
/// <summary>
/// This class has all the necessary methods to allow the application to
impersonate another user
/// when the standard user does not have the required permissions.
/// </summary>
public class Impersonation
{
public Impersonation()
{ }
/// <summary>
/// This method returns the user name that has been stored in encrypted
form in the registry.
/// The user name should have been previously created and have the
appropriate permissions.
/// </summary>
public string GetUserNameFromRegistry()
{
string userName = "";
Lookup l = new Lookup();
userName = l.GetUserNameFromRegistry();
return userName;
}
/// <summary>
/// This method returns the user name that has been stored in encrypted
form in the registry.
/// The user name should have been previously created and have the
appropriate permissions.
/// </summary>
public string GetPasswordFromRegistry()
{
string password = "";
Lookup l = new Lookup();
password = l.GetPasswordFromRegistry();
return password;
}
public WindowsImpersonationContext ImpersonateUser(string user, string
password, string domain)
{
WindowsImpersonationContext mWIC = null;
ChangeUser cu = new ChangeUser();
mWIC = cu.Impersonate(user,password,domain);
return mWIC;
}
public bool UndoImpersonate(WindowsImpersonationContext mWIC)
{
bool rc = true;
ChangeUser cu = new ChangeUser();
if (mWIC != null)
{
rc = cu.UndoImpersonate(mWIC);
}
return rc;
}
}
public class ChangeUser
{
public ChangeUser()
{ }
[DllImport("advapi32.dll")]
private static extern bool LogonUser(String
lpszUsername, String lpszDomain, String lpszPassword,
int dwLogonType, int dwLogonProvider, out int
phToken);
[DllImport("Kernel32.dll")]
private static extern int GetLastError();
public WindowsImpersonationContext Impersonate(string user, string
password, string domain)
{
// The Windows user token.
int token1;
int ret = 0;
WindowsImpersonationContext mWIC = null;
bool loggedOn = LogonUser(user,domain,password,8,0, out token1);
// Call GetLastError to try to determine why logon failed if it did not
succeed.
if (!loggedOn)
{
ret = GetLastError();
}
if (ret != 0)
{
return mWIC;
}
//Starting impersonation here:
WindowsIdentity mWI1 = WindowsIdentity.GetCurrent();
IntPtr token2 = new IntPtr(token1);
WindowsIdentity mWI2 = new WindowsIdentity(token2);
// Impersonate the user.
mWIC = mWI2.Impersonate();
return mWIC;
}
public bool UndoImpersonate(WindowsImpersonationContext mWIC)
{
bool rc = true;
// Revert to previous identity.
mWIC.Undo();
return rc;
}
}
public class Lookup
{
private RegistryKey pRootKey;
private RegistryKey pIdentityKey;
private byte[] entropyBytes = null;
private string description;
public RegistryKey rootKey
{
get
{
return pRootKey;
}
set
{
pRootKey = value;
}
}
public RegistryKey identityKey
{
get
{
return pIdentityKey;
}
set
{
pIdentityKey = value;
}
}
public Lookup()
{
pRootKey = Registry.LocalMachine.OpenSubKey("SOFTWARE",false);
pIdentityKey = pRootKey.OpenSubKey(@"RQTitleCo\identity\ASPNET_SETREG");
}
// Wrapper for DPAPI CryptUnprotectData function.
[DllImport(
"crypt32.dll",SetLastError=true,CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern
bool CryptUnprotectData(ref DATA_BLOB pCipherText,
ref string pszDescription,
ref DATA_BLOB pEntropy,
IntPtr pReserved,
ref CRYPTPROTECT_PROMPTSTRUCT pPrompt,
int dwFlags,
ref DATA_BLOB pPlainText);
// BLOB structure used to pass data to DPAPI functions.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
// Prompt structure to be used for required parameters.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct CRYPTPROTECT_PROMPTSTRUCT
{
public int cbSize;
public int dwPromptFlags;
public IntPtr hwndApp;
public string szPrompt;
}
// Wrapper for the NULL handle or pointer.
static private IntPtr NullPtr = ((IntPtr)((int)(0)));
// DPAPI key initialization flags.
private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1;
private const int CRYPTPROTECT_LOCAL_MACHINE = 0x4;
public string GetUserNameFromRegistry()
{
string userName = "";
byte[] userNameBytes;
userNameBytes = (byte[]) pIdentityKey.GetValue("userName");
userNameBytes = Decrypt(userNameBytes,entropyBytes,out description);
userName = (new UnicodeEncoding()).GetString(userNameBytes);
return userName;
}
public string GetPasswordFromRegistry()
{
string password = "";
byte[] passwordBytes;
passwordBytes = (byte[]) pIdentityKey.GetValue("password");
passwordBytes = Decrypt(passwordBytes,entropyBytes,out description);
password = (new UnicodeEncoding()).GetString(passwordBytes);
return password;
}
/// <SUMMARY>
/// Initializes empty prompt structure.
/// </SUMMARY>
/// <PARAM name="ps">
/// Prompt parameter (which we do not actually need).
/// </PARAM>
private static void InitPrompt(ref CRYPTPROTECT_PROMPTSTRUCT ps)
{
ps.cbSize = Marshal.SizeOf(
typeof(CRYPTPROTECT_PROMPTSTRUCT));
ps.dwPromptFlags= 0;
ps.hwndApp = NullPtr;
ps.szPrompt = null;
}
/// <SUMMARY>
/// Initializes a BLOB structure from a byte array.
/// </SUMMARY>
/// <PARAM name="data">
/// Original data in a byte array format.
/// </PARAM>
/// <PARAM name="blob">
/// Returned blob structure.
/// </PARAM>
private static void InitBLOB(byte[] data, ref DATA_BLOB blob)
{
// Allocate memory for the BLOB data.
blob.pbData = Marshal.AllocHGlobal(data.Length);
// Make sure that memory allocation was successful.
if (blob.pbData == IntPtr.Zero)
throw new Exception(
"Unable to allocate data buffer for BLOB structure.");
// Specify number of bytes in the BLOB.
blob.cbData = data.Length;
// Copy data from original source to the BLOB structure.
Marshal.Copy(data, 0, blob.pbData, data.Length);
}
// Wrapper for Win32 message formatter.
[DllImport("kernel32.dll",
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern
int FormatMessage( int dwFlags,
ref IntPtr pMessageSource,
int dwMessageID,
int dwLanguageID,
ref string lpBuffer,
int nSize,
IntPtr* pArguments);
public static byte[] Decrypt( byte[] cipherTextBytes,
byte[] entropyBytes,
out string description)
{
// Create BLOBs to hold data.
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherTextBlob = new DATA_BLOB();
DATA_BLOB entropyBlob = new DATA_BLOB();
// We only need prompt structure because it is a required
// parameter.
CRYPTPROTECT_PROMPTSTRUCT prompt =
new CRYPTPROTECT_PROMPTSTRUCT();
InitPrompt(ref prompt);
// Initialize description string.
description = String.Empty;
try
{
// Convert ciphertext bytes into a BLOB structure.
try
{
InitBLOB(cipherTextBytes, ref cipherTextBlob);
}
catch (Exception ex)
{
throw new Exception(
"Cannot initialize ciphertext BLOB. " +
ex.Message);
}
// we don't use entropy bytes so this code is commented out...
// // Convert entropy bytes into a BLOB structure.
// try
// {
// InitBLOB(entropyBytes, ref entropyBlob);
// }
// catch (Exception ex)
// {
// throw new Exception(
// "Cannot initialize entropy BLOB. " +
// ex.Message);
// }
// Disable any types of UI. CryptUnprotectData does not
// mention CRYPTPROTECT_LOCAL_MACHINE flag in the list of
// supported flags so we will not set it up.
int flags = CRYPTPROTECT_UI_FORBIDDEN;
// Call DPAPI to decrypt data.
bool success = CryptUnprotectData(ref cipherTextBlob,
ref description,
ref entropyBlob,
IntPtr.Zero,
ref prompt,
flags,
ref plainTextBlob);
// Check the result.
if (!success)
{
// If operation failed, retrieve the last Win32 error.
throw new Exception(
"CryptUnprotectData failed. " +
GetErrorMessage(Marshal.GetLastWin32Error()));
}
// Allocate memory to hold plaintext.
byte[] plainTextBytes = new byte[plainTextBlob.cbData];
// Copy ciphertext from the BLOB to a byte array.
Marshal.Copy(plainTextBlob.pbData,
plainTextBytes,
0,
plainTextBlob.cbData);
// Return the result.
return plainTextBytes;
}
catch (Exception ex)
{
throw new Exception("DPAPI was unable to decrypt data. " +
ex.Message);
}
// Free all memory allocated for BLOBs.
finally
{
if (plainTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(plainTextBlob.pbData);
if (cipherTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(cipherTextBlob.pbData);
if (entropyBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(entropyBlob.pbData);
}
}
/// <SUMMARY>
/// Formats error message from a Win32 error code.
/// </SUMMARY>
/// <PARAM name="errorCode">
/// Error code.
/// </PARAM>
/// <RETURNS>
/// Formatted error message.
/// </RETURNS>
private unsafe static string GetErrorMessage(int errorCode)
{
// Define flags used to build message.
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
// Initialize data variables.
int messageSize = 0;
int minBufferSize = 0;
string messageBuffer = String.Empty;
string message = String.Empty;
// We need build a system message as opposed to a message from
// a resource DLL. The operation will require auto memory
// allocation. We will not use formatted arguments.
int dwFlags = FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS;
// Set null pointers.
IntPtr pMessageSource = new IntPtr();
IntPtr pArguments = new IntPtr();
// Use default language.
int langID = 0;
// Get message.
messageSize = FormatMessage( dwFlags,
ref pMessageSource,
errorCode,
langID,
ref messageBuffer,
minBufferSize,
&pArguments);
// Include error code in the message.
if (messageSize == 0)
message = String.Format("Error {0} occurred.",
errorCode);
else
message = String.Format("Error {0}: {1}",
errorCode, messageBuffer);
// Return formatted message.
return message;
}
}
}
- Next message: [MSFT]: "Re: Web Services on Win 2003 to SQL Server on Win 2000"
- Previous message: suresh g: "Re: WebException while calling Web Service over HTTPS..."
- In reply to: Matthew Wieder: "Re: HELP! CreateProcessWithLogonW issue"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|