How to change Windows 8.1 Group Policy programmatically in c#? - c#

I am developing a Windows 8.1 kiosk-type application,and I need to set the group policy custom user interface setting to the .exe of the application. This, of course, can be accomplished by hand, but I would like to be able to change it via c#, or alternatively, an installer (I'm using Visual Studio Setup right now).
Thanks for the help!

The way to go is:
Create a Custom Action and add it to the Install section of your installer.
Use the unmanaged LsaAddAccountRights method to set any policy to any user account or group (e.g. Administrators, Users, Everyone). All you need to know is the right Policy Handle and the User Right that you want to assign.
Now, down to the implementation :-)
Please check the code below. This is the implementation I ended up with by analyzing and borrowing different code snippets from different resources:
public class LSAManager
{
[DllImport("advapi32.dll", PreserveSig = true)]
private static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, Int32 DesiredAccess, out IntPtr PolicyHandle);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
private static extern uint LsaAddAccountRights(IntPtr PolicyHandle, IntPtr pSID, LSA_UNICODE_STRING[] UserRights, int CountOfRights);
[DllImport("advapi32.dll")]
public static extern void FreeSid(IntPtr pSid);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
private static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName, ref int cbdomainLength, ref int use);
[DllImport("advapi32.dll")]
private static extern bool IsValidSid(IntPtr pSid);
[DllImport("advapi32.dll")]
private static extern int LsaClose(IntPtr ObjectHandle);
[DllImport("advapi32.dll")]
private static extern int LsaNtStatusToWinError(int status);
[DllImport("kernel32.dll")]
private static extern int GetLastError();
[StructLayout(LayoutKind.Sequential)]
private struct LSA_UNICODE_STRING
{
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential)]
private struct LSA_OBJECT_ATTRIBUTES
{
public int Length;
public IntPtr RootDirectory;
public LSA_UNICODE_STRING ObjectName;
public UInt32 Attributes;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;
}
private enum LSA_AccessPolicy : long
{
POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L,
POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
POLICY_TRUST_ADMIN = 0x00000008L,
POLICY_CREATE_ACCOUNT = 0x00000010L,
POLICY_CREATE_SECRET = 0x00000020L,
POLICY_CREATE_PRIVILEGE = 0x00000040L,
POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
POLICY_SERVER_ADMIN = 0x00000400L,
POLICY_LOOKUP_NAMES = 0x00000800L,
POLICY_NOTIFICATION = 0x00001000L
}
/// <summary>Adds a privilege to an account</summary>
/// <param name="accountName">Name of an account - "domain\account" or only "account"</param>
/// <param name="privilegeName">Name of the privilege</param>
/// <returns>The windows error code returned by LsaAddAccountRights (0 = success)</returns>
public static long SetRight(String accountName, String privilegeName)
{
long winErrorCode = 0; //contains the last error
//pointer an size for the SID
IntPtr sid = IntPtr.Zero;
int sidSize = 0;
//StringBuilder and size for the domain name
StringBuilder domainName = new StringBuilder();
int nameSize = 0;
//account-type variable for lookup
int accountType = 0;
//get required buffer size
LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
//allocate buffers
domainName = new StringBuilder(nameSize);
sid = Marshal.AllocHGlobal(sidSize);
//lookup the SID for the account
bool result = LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
// check SID if required: IsValidSid(sid));
if (!result)
{
winErrorCode = GetLastError();
}
else
{
//initialize an empty unicode-string
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
//combine all policies
int access = (int)(
LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
LSA_AccessPolicy.POLICY_CREATE_PRIVILEGE |
LSA_AccessPolicy.POLICY_CREATE_SECRET |
LSA_AccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
LSA_AccessPolicy.POLICY_LOOKUP_NAMES |
LSA_AccessPolicy.POLICY_NOTIFICATION |
LSA_AccessPolicy.POLICY_SERVER_ADMIN |
LSA_AccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
LSA_AccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
LSA_AccessPolicy.POLICY_TRUST_ADMIN |
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION
);
//initialize a pointer for the policy handle
IntPtr policyHandle = IntPtr.Zero;
//these attributes are not used, but LsaOpenPolicy wants them to exists
LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();
ObjectAttributes.Length = 0;
ObjectAttributes.RootDirectory = IntPtr.Zero;
ObjectAttributes.Attributes = 0;
ObjectAttributes.SecurityDescriptor = IntPtr.Zero;
ObjectAttributes.SecurityQualityOfService = IntPtr.Zero;
//get a policy handle
uint resultPolicy = LsaOpenPolicy(ref systemName, ref ObjectAttributes, access, out policyHandle);
winErrorCode = LsaNtStatusToWinError((int)resultPolicy);
if (winErrorCode == 0)
{
//Now that we have the SID and the policy,
//we can add rights to the account.
//initialize an unicode-string for the privilege name
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
userRights[0] = new LSA_UNICODE_STRING();
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
userRights[0].Length = (UInt16)(privilegeName.Length * UnicodeEncoding.CharSize);
userRights[0].MaximumLength = (UInt16)((privilegeName.Length + 1) * UnicodeEncoding.CharSize);
//add the right to the account
uint res = LsaAddAccountRights(policyHandle, sid, userRights, 1);
winErrorCode = LsaNtStatusToWinError((int)res);
LsaClose(policyHandle);
}
FreeSid(sid);
}
return winErrorCode;
}
}
I've put this code in a separate class called LSAManager for convenience. In order to use this code, simply call:
string userName = "alex";
// Set "Logon As a Service" privilege (for example):
if (LSAManager.SetRight(userName, "SeServiceLogonRight") != 0)
{
// handle error here
}

Related

How do I get Current Windows Username in C# Console Application?

My Problem:
I am developing a Standalone Console Application that has to find the currently logged-on active Windows Username.
Test Cases:
Multiple Users logged on and only one user active.
One user currently active, accessing other remote user also
Others users in remote user same user that is currently active.
The order of signing in may vary, but in all cases only the current active user is required.
I've found these codes for the above mentioned task:
string UserName1 = System.Security.Principal.WindowsIdentity.GetCurrent().Name; // Gives NT AUTHORITY\SYSTEM
string UserName2 = Request.LogonUserIdentity.Name; // Gives NT AUTHORITY\SYSTEM
string UserName3 = Environment.UserName; // Gives SYSTEM
string UserName4 = HttpContext.Current.User.Identity.Name; // Gives actual user logged on (as seen in <ASP:Login />)
string UserName5 = System.Windows.Forms.SystemInformation.UserName; // Gives SYSTEM
string DisplayName = System.DirectoryServices.AccountManagement.UserPrincipal.Current.DisplayName
I know HttpContext is not purely console based, but if it satisfies the condition and comparable I will use it.
I don't know all the possible test cases and not able to test them.
I'm not sure which one will suit all my test cases.
I will accept any solution that will suit the needs.
Help me find the possible way.
Sorry for any mistakes and thanks for the help.
I've converted a C code to C# and implemented it.
public static class UserInfo
{
#region PInvoke
[DllImport("wtsapi32.dll", SetLastError = true)]
static extern Int32 WTSEnumerateSessions(
IntPtr hServer,
[MarshalAs(UnmanagedType.U4)] Int32 Reserved,
[MarshalAs(UnmanagedType.U4)] Int32 Version,
ref IntPtr ppSessionInfo,
[MarshalAs(UnmanagedType.U4)] ref Int32 pCount);
[DllImport("wtsapi32.dll")]
static extern void WTSFreeMemory(IntPtr pMemory);
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO
{
public Int32 SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public String pWinStationName;
public WTS_CONNECTSTATE_CLASS State;
}
public enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
[DllImport("Wtsapi32.dll")]
public static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTSInfoClass wtsInfoClass, out IntPtr ppBuffer, out uint pBytesReturned);
public enum WTSInfoClass
{
WTSInitialProgram,
WTSApplicationName,
WTSWorkingDirectory,
WTSOEMId,
WTSSessionId,
WTSUserName,
WTSWinStationName,
WTSDomainName,
WTSConnectState,
WTSClientBuildNumber,
WTSClientName,
WTSClientDirectory,
WTSClientProductId,
WTSClientHardwareId,
WTSClientAddress,
WTSClientDisplay,
WTSClientProtocolType,
WTSIdleTime,
WTSLogonTime,
WTSIncomingBytes,
WTSOutgoingBytes,
WTSIncomingFrames,
WTSOutgoingFrames,
WTSClientInfo,
WTSSessionInfo
}
[Flags]
public enum LocalMemoryFlags
{
LMEM_FIXED = 0x0000,
LMEM_MOVEABLE = 0x0002,
LMEM_NOCOMPACT = 0x0010,
LMEM_NODISCARD = 0x0020,
LMEM_ZEROINIT = 0x0040,
LMEM_MODIFY = 0x0080,
LMEM_DISCARDABLE = 0x0F00,
LMEM_VALID_FLAGS = 0x0F72,
LMEM_INVALID_HANDLE = 0x8000,
LHND = (LMEM_MOVEABLE | LMEM_ZEROINIT),
LPTR = (LMEM_FIXED | LMEM_ZEROINIT),
NONZEROLHND = (LMEM_MOVEABLE),
NONZEROLPTR = (LMEM_FIXED)
}
[DllImport("kernel32.dll")]
static extern IntPtr LocalAlloc(uint uFlags, UIntPtr uBytes);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LocalFree(IntPtr hMem);
[DllImport("kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
#endregion PInvoke
#region Helper Methods
public static bool GetPhysicallyLoggedOnUserName(out string PhysicallyLoggedOnUserName, out string DomainName)
{
PhysicallyLoggedOnUserName = string.Empty;
DomainName = string.Empty;
IntPtr WTS_CURRENT_SERVER_HANDLE = (IntPtr)null;
try
{
IntPtr ppSessionInfo = IntPtr.Zero;
Int32 pCount = 0;
Int32 retval = WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref ppSessionInfo, ref pCount);
Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
if (retval != 0)
{
Int64 current = (int)ppSessionInfo;
int totalactiveuser = 0;
for (int i = 0; i < pCount; i++)
{
WTS_SESSION_INFO wts = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
current += dataSize;
if (wts.State == WTS_CONNECTSTATE_CLASS.WTSActive)
{
totalactiveuser++;
}
}
if (totalactiveuser < 1)
{
return false;
}
current = (int)ppSessionInfo;
for (int i = 0; i < pCount; i++)
{
WTS_SESSION_INFO wts = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
current += dataSize;
if (wts.State != WTS_CONNECTSTATE_CLASS.WTSActive)
{
continue;
}
IntPtr szUserName = IntPtr.Zero;
uint dwLen = 0;
bool bStatus = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, wts.SessionID, WTSInfoClass.WTSUserName, out szUserName, out dwLen);
if (bStatus)
{
IntPtr szUpn = LocalAlloc((uint)LocalMemoryFlags.LMEM_FIXED, new UIntPtr(unchecked((uint)szUserName.ToInt32())));
CopyMemory(szUpn, szUserName, (uint)IntPtr.Size);
LocalFree(szUpn);
}
IntPtr ProtoType = IntPtr.Zero;
bStatus = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, wts.SessionID, WTSInfoClass.WTSClientProtocolType, out ProtoType, out dwLen);
int cpt = Marshal.ReadInt32(ProtoType);
WTSFreeMemory(ProtoType);
if (cpt == 0) // WTS_PROTOCOL_TYPE_CONSOLE
{
PhysicallyLoggedOnUserName = Marshal.PtrToStringAnsi(szUserName);
WTSFreeMemory(szUserName);
dwLen = 0;
IntPtr szDomainName = IntPtr.Zero;
bStatus = WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, wts.SessionID, WTSInfoClass.WTSDomainName, out szDomainName, out dwLen);
DomainName = Marshal.PtrToStringAnsi(szDomainName);
WTSFreeMemory(szDomainName);
return true;
}
WTSFreeMemory(szUserName);
}
}
}
catch
{
return false;
}
return false;
}
#endregion Helper Methods
}

WTSQueryUserToken returning FALSE

I'm making a interactive service on Windows 7, on visual studio 2015, that is able to initialize an application UI but the WTSQueryUserToken method is retuning false.
IntPtr hToken = IntPtr.Zero;
if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken)) //FALSE returned
I really don't have much experience with C# so I've searched online to get an answer and I found that "To call this function (WTSQueryUserToken) successfully, the calling application must be running within the context of the LocalSystem account and have the SE_TCB_NAME privilege", but I don't know how can I give the application SE_TCB_NAME privilege privilege on the code. Does anyone know how can I code this?
Thank you.
You have to do impersonation to launch the application under the user account.
Here is a sample of that, showing also how to get the SE_TCB_NAME privilege.
In this sample we first get the security token for the Current Process and then escalate the privileges to include the SE_TCB_NAME privilege.
Once we are done with that then we take the SessionId of the explorer process, and duplicate the security token associated with it, which we then pass to CreateProcessAsUser.
public class Impersonation
{
#region DLL Imports
internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
internal const int TOKEN_ASSIGN_PRIMARY = 0x0001;
internal const int TOKEN_DUPLICATE = 0x0002;
internal const int TOKEN_IMPERSONATE = 0X00000004;
internal const int TOKEN_ADJUST_DEFAULT = 0x0080;
internal const int TOKEN_ADJUST_SESSIONID = 0x0100;
internal const int MAXIMUM_ALLOWED = 0x2000000;
internal const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
internal const int NORMAL_PRIORITY_CLASS = 0x20;
internal const int CREATE_NEW_CONSOLE = 0x00000010;
internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
internal const string SE_TCB_NAME = "SeTcbPrivilege";
internal const string SE_RESTORE_NAME = "SeRestorePrivilege";
private static WindowsImpersonationContext impersonatedUser;
public static IntPtr hToken = IntPtr.Zero;
public static IntPtr dupeTokenHandle = IntPtr.Zero;
const string SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege";
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
struct SECURITY_ATTRIBUTES
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
public enum ShowCommands : int
{
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_FORCEMINIMIZE = 11,
SW_MAX = 11
}
[DllImport("shell32.dll")]
static extern IntPtr ShellExecute(
IntPtr hwnd,
string lpOperation,
string lpFile,
string lpParameters,
string lpDirectory,
ShowCommands nShowCmd);
[DllImport("advapi32.dll", SetLastError = true)]
static extern int ImpersonateLoggedOnUser(IntPtr hToken);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
[DllImport("kernel32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
static extern bool CloseHandle(IntPtr handle);
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
static extern bool DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel, Int32 dwTokenType,
ref IntPtr phNewToken);
[DllImport("userenv.dll", SetLastError = true)]
static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool CreateProcessAsUser(
IntPtr hToken,
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
#endregion
private static readonly ILog log = LogManager.GetLogger(typeof(Impersonation));
private static void WriteToLog(string message)
{
log.Debug(message);
}
/// <summary>
/// Duplicates the token information derived
/// from the logged in user's credentials. This
/// is required to run the application on the
/// logged in users desktop.
/// </summary>
/// <returns>Returns true if the application was successfully started in the user's desktop.</returns>
public static bool ExecuteAppAsLoggedOnUser(string AppName, string CmdLineArgs)
{
WriteToLog("In ExecuteAppAsLoggedOnUser for all users.");
IntPtr LoggedInUserToken = IntPtr.Zero;
IntPtr DuplicateToken = IntPtr.Zero;
IntPtr ShellProcessToken = IntPtr.Zero;
if (!OpenProcessToken(Process.GetCurrentProcess().Handle, TOKEN_ADJUST_PRIVILEGES, ref LoggedInUserToken))
{
WriteToLog("OpenProcessToken failed: " + Marshal.GetLastWin32Error());
return false;
}
else
{
//Below part for increasing the UAC previleges to the token.
TokPriv1Luid tp = new TokPriv1Luid();
tp.Count = 1;
tp.Luid = 0;
if (!LookupPrivilegeValue(null, SE_INCREASE_QUOTA_NAME, ref tp.Luid))
{
WriteToLog("LookupPrivilegeValue failed: " + Marshal.GetLastWin32Error());
return false;
}
tp.Attr = SE_PRIVILEGE_ENABLED;
if (!AdjustTokenPrivileges(LoggedInUserToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero))
{
WriteToLog("OpenProcessToken failed: " + Marshal.GetLastWin32Error());
return false;
}
CloseHandle(LoggedInUserToken);
}
List<Process> explorerProcessList = new List<Process>();
string trayProcessName = AppName.Substring(AppName.LastIndexOf(#"\") + 1, AppName.Length - AppName.LastIndexOf(#"\") - 5);
foreach (Process explorerProcess in Process.GetProcessesByName("explorer"))
{
bool IsProcessRunningForUser = false;
foreach (Process PHTrayProcess in Process.GetProcessesByName(trayProcessName))
{
if (explorerProcess.SessionId == PHTrayProcess.SessionId)
{
if (log.IsDebugEnabled) log.Debug(trayProcessName + " is already running for user SessionId " + explorerProcess.SessionId);
IsProcessRunningForUser = true;
break;
}
}
if (((Environment.OSVersion.Version.Major > 5 && explorerProcess.SessionId > 0)
|| Environment.OSVersion.Version.Major == 5)
&& !IsProcessRunningForUser)
{
if (log.IsDebugEnabled) log.Debug(trayProcessName + " is not running for user SessionId " + explorerProcess.SessionId);
explorerProcessList.Add(explorerProcess);
}
}
if (null != explorerProcessList && explorerProcessList.Count > 0)
{
foreach (Process explorerProcess in explorerProcessList)
{
Process ShellProcess = explorerProcess;
ShellProcess.StartInfo.LoadUserProfile = true;
try
{
int tokenRights = MAXIMUM_ALLOWED; //TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID;
if (!OpenProcessToken(ShellProcess.Handle, tokenRights, ref ShellProcessToken))
{
WriteToLog("Unable to OpenProcessToken " + Marshal.GetLastWin32Error());
return false;
}
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.nLength = Marshal.SizeOf(sa);
if (!DuplicateTokenEx(ShellProcessToken, tokenRights, ref sa, 2, 1, ref DuplicateToken))
{
WriteToLog("Unable to duplicate token " + Marshal.GetLastWin32Error());
return false;
}
WriteToLog("Duplicated the token " + WindowsIdentity.GetCurrent().Name);
SECURITY_ATTRIBUTES processAttributes = new SECURITY_ATTRIBUTES();
SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
PROCESS_INFORMATION pi;
STARTUPINFO si = new STARTUPINFO();
si.cb = (uint)Marshal.SizeOf(si);
IntPtr UserEnvironment = IntPtr.Zero;
uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
if (!CreateEnvironmentBlock(out UserEnvironment, ShellProcessToken, true))
{
WriteToLog("Unable to create user's enviroment block " + Marshal.GetLastWin32Error());
}
else
{
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
//string userName = getUserName(UserEnvironment);
//WriteToLog("UserName:::" + userName);
if (!CreateProcessAsUser(DuplicateToken, AppName, (CmdLineArgs == null) ? string.Empty : CmdLineArgs, ref processAttributes, ref threadAttributes, true, dwCreationFlags, UserEnvironment, AppName.Substring(0, AppName.LastIndexOf('\\')), ref si, out pi))
{
WriteToLog("Unable to create process " + Marshal.GetLastWin32Error());
if (Marshal.GetLastWin32Error() == 740)
{
WriteToLog("Please check the installation as some elevated permissions is required to execute the binaries");
}
return false;
}
Process trayApp = Process.GetProcessById(Convert.ToInt32(pi.dwProcessId));
trayApp.StartInfo.LoadUserProfile = true;
}
finally
{
if (ShellProcessToken != null) CloseHandle(ShellProcessToken);
if (DuplicateToken != null) CloseHandle(DuplicateToken);
}
}
}
else
{
WriteToLog("No user has been identified to have logged into the system.");
return false;
}
WriteToLog("Finished ExecuteAppAsLoggedOnUser for all users.");
return true;
}
/// <summary>
/// Impersonate the user credentials. This would be required by
/// the service applications to impersonate the logged in user
/// credentials to launch certain applications or applying the
/// power scheme.
/// </summary>
/// <returns>Returns true if the impersonation is successful.</returns>
public static bool ImpersonateUser()
{
// For simplicity I'm using the PID of System here
//if (log.IsDebugEnabled) log.Debug("GetaProcess for Explorer");
Process Pname = GetaProcess("explorer");
//This can be null if no user has not logged into the system.
if (Pname == null) return false;
int pid = Pname.Id;
Process proc = Process.GetProcessById(pid);
if (OpenProcessToken(proc.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, ref hToken)) // != 0)
{
WindowsIdentity newId = new WindowsIdentity(hToken);
//log.Debug(newId.Owner);
try
{
const int SecurityImpersonation = 2;
dupeTokenHandle = DupeToken(hToken,
SecurityImpersonation);
if (IntPtr.Zero == dupeTokenHandle)
{
string s = String.Format("Dup failed {0}, privilege not held",
Marshal.GetLastWin32Error());
throw new Exception(s);
}
impersonatedUser = newId.Impersonate();
return true;
}
finally
{
CloseHandle(hToken);
}
}
else
{
string s = String.Format("OpenProcess Failed {0}, privilege not held", Marshal.GetLastWin32Error());
throw new Exception(s);
}
}
/// <summary>
/// Duplicate the token for user impersonation.
/// </summary>
/// <param name="token">Token to duplicate for impersonation</param>
/// <param name="Level">Impersonation security level, currently hardcored to 2</param>
/// <returns>Returns duplicated token</returns>
public static IntPtr DupeToken(IntPtr token, int Level)
{
IntPtr dupeTokenHandle = IntPtr.Zero;
bool retVal = DuplicateToken(token, Level, ref dupeTokenHandle);
return dupeTokenHandle;
}
/// <summary>
/// Get the process running locally on the machine.
/// If the specified process does not exists, it
/// returns back the current process.
/// </summary>
/// <param name="processname">Process name to get</param>
/// <returns>Returns back the process</returns>
public static Process GetaProcess(string processname)
{
Process[] aProc = Process.GetProcessesByName(processname);
if (aProc.Length > 0) return aProc[0];
else
{
//if (log.IsDebugEnabled) log.Debug("Explorer is not running");
Process currentProcess = Process.GetCurrentProcess();
return currentProcess;
}
}
/// <summary>
/// Roleback the impersonation if applied previously.
/// </summary>
public static void UndoImpersonate()
{
impersonatedUser.Undo();
if (hToken != IntPtr.Zero) CloseHandle(hToken);
if (dupeTokenHandle != IntPtr.Zero) CloseHandle(dupeTokenHandle);
return;
}
}
And then you can just do
Impersonation.ExecuteAppAsLoggedOnUser("applicationName", null);
You can either set Act as part of the operating system in Local security policy, or you can also set the privileges programmatically using LsaAddAccountRights.

Starting a new user session from a service

I have the following problem:
From a service I need to start an application in a user session. No human user log on that machine, since it is a server. Launched application must have a session != 0.
Current "solution"
I used a scheduled task at machine startup, that task launch ( in session 0, of course ) an application launching a Remote Desktop logon on the same machine: this creates a user session > 0 and in the user startup the is the final application to launch. It works, but too tricky.
Is there some smartest way? It is critical that I can reuse a user session already on since there is potentially no user logged on.
MAJOR UPDATE
Well after a lot of research and partial successes, and also thanks to some SysAdmin inflexibility about creating an user for a specific pourpose, I decided to use OpenGL instead of WPF for render the 3d portion broken in Session 0.
Surprisingly it took less than expected. I think having this question as a reference could be useful to other who want try to render a Viewport3D from a service.
I'm not sure if this will work, but maybe this answer helps in your case.
Use the class from the answer I link i provided and the following method (with the appropriate values):
public static void EnableVideoDrivers(bool enable)
{
// every type of device has a hard-coded GUID, put here the one for
// video drivers
Guid videoGuid = new Guid("{device GUID}");
// get this from the properties dialog box of this device in Device Manager
string instancePath = #"Device Instance Path";
DeviceHelper.SetDeviceEnabled(videoGuid, instancePath, enable);
}
Here's a list of Popular Device Class GUIDs.
I'm not sure I understand correctly your needs, but maybe just starting process with given credentials and redirect input and output is what you need. Starting process with given credentials:
Process p = new Process();
p.StartInfo = new ProcessStartInfo(fileName, args);
p.StartInfo.UserName = userName;
p.StartInfo.Password = pass;
p.Start();
You may also need to redirect input and output of the application. That problem is well described on CodeProjecgt in this artice.
This is how I start a process for a particular usersession from a Local windows service.
It uses C#, with some DLL imports from kernel32.dll, wtsaspi.dll, userev.dll, and advapi32.dll.
For context, my code will search all user sessions. In my scenario, my service is running on a Windows Terminal server and wants to keep a particular app "alive" in each user's session. Meaning, if we check and its not running anymore, we restart it.
Here is the program logic (abbreviated), this is how you call the method that starts the user process:
foreach(var sesh in ProcessExtensions.GetSessions().Where(r => r.State == "Active").ToList())
{
var running = procs.Any(r => r.ProcessName == filename && r.SessionId == sesh.SessionId);
if (!running)
{
try
{
ProcessExtensions.StartProcessForSession(sesh.SessionId, (string)item, "/restart", System.IO.Path.GetDirectoryName((string)item), true);
}
catch (Exception ex)
{
Trace.TraceWarning("Error: {0}", ex);
}
}
}
Here is the implementation of ProcessExtensions where all of the good stuff is.
Disclaimer - I did not write this code, This is an example I found online and adjusted it to my needs. If you authored the original post. Apologies for the lack of footnote.
ProcessExtensions.cs
public static class ProcessExtensions
{
#region Win32 Constants
private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
private const int CREATE_NO_WINDOW = 0x08000000;
private const int CREATE_NEW_CONSOLE = 0x00000010;
private const uint INVALID_SESSION_ID = 0xFFFFFFFF;
private static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
#endregion
#region DllImports
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
private static extern bool CreateProcessAsUser(
IntPtr hToken,
String lpApplicationName,
String lpCommandLine,
IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes,
bool bInheritHandle,
uint dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
private static extern bool DuplicateTokenEx(
IntPtr ExistingTokenHandle,
uint dwDesiredAccess,
IntPtr lpThreadAttributes,
int TokenType,
int ImpersonationLevel,
ref IntPtr DuplicateTokenHandle);
[DllImport("userenv.dll", SetLastError = true)]
private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
[DllImport("userenv.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("kernel32.dll")]
private static extern uint WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll")]
private static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
[DllImport("wtsapi32.dll", SetLastError = true)]
private static extern int WTSEnumerateSessions(
IntPtr hServer,
int Reserved,
int Version,
ref IntPtr ppSessionInfo,
ref int pCount);
#endregion
#region Win32 Structs
private enum SW
{
SW_HIDE = 0,
SW_SHOWNORMAL = 1,
SW_NORMAL = 1,
SW_SHOWMINIMIZED = 2,
SW_SHOWMAXIMIZED = 3,
SW_MAXIMIZE = 3,
SW_SHOWNOACTIVATE = 4,
SW_SHOW = 5,
SW_MINIMIZE = 6,
SW_SHOWMINNOACTIVE = 7,
SW_SHOWNA = 8,
SW_RESTORE = 9,
SW_SHOWDEFAULT = 10,
SW_MAX = 10
}
private enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
private enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
private enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation = 2
}
[StructLayout(LayoutKind.Sequential)]
private struct WTS_SESSION_INFO
{
public readonly UInt32 SessionID;
[MarshalAs(UnmanagedType.LPStr)]
public readonly String pWinStationName;
public readonly WTS_CONNECTSTATE_CLASS State;
}
#endregion
public static IEnumerable<UserSessionData> GetSessions()
{
//var bResult = false;
var hImpersonationToken = IntPtr.Zero;
//var activeSessionId = INVALID_SESSION_ID;
var pSessionInfo = IntPtr.Zero;
var sessionCount = 0;
if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref sessionCount) != 0)
{
var arrayElementSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
var current = pSessionInfo;
for (var i = 0; i < sessionCount; i++)
{
var si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
current += arrayElementSize;
var data = new UserSessionData
{
SessionId = (int)si.SessionID,
State = si.State.ToString().Substring(3),
Name = si.pWinStationName
};
yield return data;
}
}
}
private static bool GetUserTokenForSession(int sessionId, ref IntPtr phUserToken)
{
var bResult = false;
var hImpersonationToken = IntPtr.Zero;
var pSessionInfo = IntPtr.Zero;
if (WTSQueryUserToken((uint)sessionId, ref hImpersonationToken) != 0)
{
// Convert the impersonation token to a primary token
bResult = DuplicateTokenEx(hImpersonationToken, 0, IntPtr.Zero,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,
ref phUserToken);
CloseHandle(hImpersonationToken);
}
return bResult;
}
private static bool GetCurrentUserSessionToken(ref IntPtr phUserToken)
{
var bResult = false;
var hImpersonationToken = IntPtr.Zero;
var activeSessionId = INVALID_SESSION_ID;
var pSessionInfo = IntPtr.Zero;
var sessionCount = 0;
// Get a handle to the user access token for the current active session.
if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref sessionCount) != 0)
{
var arrayElementSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
var current = pSessionInfo;
for (var i = 0; i < sessionCount; i++)
{
var si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
current += arrayElementSize;
if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive)
{
activeSessionId = si.SessionID;
}
}
}
// If enumerating did not work, fall back to the old method
if (activeSessionId == INVALID_SESSION_ID)
{
activeSessionId = WTSGetActiveConsoleSessionId();
}
if (WTSQueryUserToken(activeSessionId, ref hImpersonationToken) != 0)
{
// Convert the impersonation token to a primary token
bResult = DuplicateTokenEx(hImpersonationToken, 0, IntPtr.Zero,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,
ref phUserToken);
CloseHandle(hImpersonationToken);
}
return bResult;
}
public static bool StartProcessForSession(int sessionId, string appPath, string cmdLine = null, string workDir = null, bool visible = true)
{
var hUserToken = IntPtr.Zero;
var startInfo = new STARTUPINFO();
var procInfo = new PROCESS_INFORMATION();
var pEnv = IntPtr.Zero;
int iResultOfCreateProcessAsUser;
startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
try
{
if (!GetUserTokenForSession(sessionId, ref hUserToken))
{
throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");
}
uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
startInfo.lpDesktop = "winsta0\\default";
if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
{
throw new Exception("StartProcessInSession: CreateEnvironmentBlock failed.");
}
if (!CreateProcessAsUser(hUserToken,
appPath, // Application Name
cmdLine, // Command Line
IntPtr.Zero,
IntPtr.Zero,
false,
dwCreationFlags,
pEnv,
workDir, // Working directory
ref startInfo,
out procInfo))
{
iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed. Error Code -" + iResultOfCreateProcessAsUser);
}
iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
}
finally
{
CloseHandle(hUserToken);
if (pEnv != IntPtr.Zero)
{
DestroyEnvironmentBlock(pEnv);
}
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
}
return true;
}
public static bool StartProcessAsCurrentUser(string appPath, string cmdLine = null, string workDir = null, bool visible = true)
{
var hUserToken = IntPtr.Zero;
var startInfo = new STARTUPINFO();
var procInfo = new PROCESS_INFORMATION();
var pEnv = IntPtr.Zero;
int iResultOfCreateProcessAsUser;
startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));
try
{
if (!GetCurrentUserSessionToken(ref hUserToken))
{
throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");
}
uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
startInfo.lpDesktop = "winsta0\\default";
if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
{
throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");
}
if (!CreateProcessAsUser(hUserToken,
appPath, // Application Name
cmdLine, // Command Line
IntPtr.Zero,
IntPtr.Zero,
false,
dwCreationFlags,
pEnv,
workDir, // Working directory
ref startInfo,
out procInfo))
{
iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed. Error Code -" + iResultOfCreateProcessAsUser);
}
iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
}
finally
{
CloseHandle(hUserToken);
if (pEnv != IntPtr.Zero)
{
DestroyEnvironmentBlock(pEnv);
}
CloseHandle(procInfo.hThread);
CloseHandle(procInfo.hProcess);
}
return true;
}
}

Network folder browser service

there are some similar questions to this on the net - even a few here, but even though the askers seem happy I can't find one that actually does what I need.
I'm trying to add a remote directory browsing feature to a web-based administration control panel (intranet based).
I don't need to worry about security at this point as this is handled elsewhere.
To do this I'm using a webservice which accepts a server name and a share/folder path as parameters. I just need it to return the subdirectories of this path, if any.
Doesn't sound so hard, does it? Well, it is (at least to me!)
The only bit I need help with is actually producing a list of directories for the server and path supplied.
All help is appreciated, but please don't just link to a site as I've probably seen it already but failed to get a working solution; most of these don't even seem to attempt to do what the title implies.
Some explaination would be helpful as well!
Cheers
To enumerate subfolders of specified folder in .NET you can use for example DirectoryInfo.EnumerateDirectories method.
To enumerate shares of some computer you can use WNetEnumResource native function if hidden administrative shares like C$, ADMIN$, print$ and so on are not important for you or use NetShareEnum to enumerate all shares.
The corresponding code could be
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Runtime.InteropServices;
namespace Subfolders {
static internal class Native {
[DllImport ("Netapi32.dll", SetLastError = true)]
internal static extern uint NetApiBufferFree (IntPtr buffer);
[DllImport ("Netapi32.dll", CharSet = CharSet.Unicode)]
internal static extern uint NetShareEnum (
string serverName,
int level,
ref IntPtr bufPtr,
uint prefmaxlen,
ref int entriesread,
ref int totalentries,
ref int resumeHandle
);
[DllImport ("MPR.dll", CharSet = CharSet.Auto)]
internal static extern uint WNetEnumResource(IntPtr hEnum, ref int lpcCount, IntPtr lpBuffer, ref int lpBufferSize);
[DllImport ("MPR.dll", CharSet = CharSet.Auto)]
internal static extern uint WNetOpenEnum(ResourceScope dwScope, ResourceType dwType, ResourceUsage dwUsage,
IntPtr lpNetResource, out IntPtr lphEnum);
[DllImport ("MPR.dll", CharSet = CharSet.Auto)]
internal static extern uint WNetCloseEnum(IntPtr hEnum);
internal const uint MaxPreferredLength = 0xFFFFFFFF;
internal const int NerrSuccess = 0;
internal enum NetError : uint {
NerrSuccess = 0,
NerrBase = 2100,
NerrUnknownDevDir = (NerrBase + 16),
NerrDuplicateShare = (NerrBase + 18),
NerrBufTooSmall = (NerrBase + 23),
}
internal enum ShareType : uint {
StypeDisktree = 0,
StypePrintq = 1,
StypeDevice = 2,
StypeIpc = 3,
StypeSpecial = 0x80000000,
}
[StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ShareInfo1 {
public string shi1_netname;
public uint shi1_type;
public string shi1_remark;
public ShareInfo1 (string sharename, uint sharetype, string remark) {
shi1_netname = sharename;
shi1_type = sharetype;
shi1_remark = remark;
}
public override string ToString () {
return shi1_netname;
}
}
public enum ResourceScope: uint {
ResourceConnected = 0x00000001,
ResourceGlobalnet = 0x00000002,
ResourceRemembered = 0x00000003,
ResourceRecent = 0x00000004,
ResourceContext = 0x00000005
}
public enum ResourceType: uint {
ResourcetypeAny = 0x00000000,
ResourcetypeDisk = 0x00000001,
ResourcetypePrint = 0x00000002,
ResourcetypeReserved = 0x00000008,
ResourcetypeUnknown = 0xFFFFFFFF
}
public enum ResourceUsage: uint {
ResourceusageConnectable = 0x00000001,
ResourceusageContainer = 0x00000002,
ResourceusageNolocaldevice = 0x00000004,
ResourceusageSibling = 0x00000008,
ResourceusageAttached = 0x00000010,
ResourceusageAll = (ResourceusageConnectable | ResourceusageContainer | ResourceusageAttached),
ResourceusageReserved = 0x80000000
}
public enum ResourceDisplaytype: uint {
ResourcedisplaytypeGeneric = 0x00000000,
ResourcedisplaytypeDomain = 0x00000001,
ResourcedisplaytypeServer = 0x00000002,
ResourcedisplaytypeShare = 0x00000003,
ResourcedisplaytypeFile = 0x00000004,
ResourcedisplaytypeGroup = 0x00000005,
ResourcedisplaytypeNetwork = 0x00000006,
ResourcedisplaytypeRoot = 0x00000007,
ResourcedisplaytypeShareadmin = 0x00000008,
ResourcedisplaytypeDirectory = 0x00000009,
ResourcedisplaytypeTree = 0x0000000A,
ResourcedisplaytypeNdscontainer = 0x0000000B
}
[StructLayout (LayoutKind.Sequential)]
public struct NetResource {
public ResourceScope dwScope;
public ResourceType dwType;
public ResourceDisplaytype dwDisplayType;
public ResourceUsage dwUsage;
[MarshalAs (UnmanagedType.LPTStr)]
public string lpLocalName;
[MarshalAs (UnmanagedType.LPTStr)]
public string lpRemoteName;
[MarshalAs (UnmanagedType.LPTStr)]
public string lpComment;
[MarshalAs (UnmanagedType.LPTStr)]
public string lpProvider;
}
}
class Program {
static IEnumerable<string> GetShares(string computerName) {
var resources = new List<string>();
IntPtr hEnum = IntPtr.Zero, pResource = IntPtr.Zero;
try {
var resource = new Native.NetResource();
int bufferSize = 163840;
resource.dwType = Native.ResourceType.ResourcetypeAny;
resource.dwScope = Native.ResourceScope.ResourceGlobalnet;
resource.dwUsage = Native.ResourceUsage.ResourceusageContainer;
resource.lpRemoteName = computerName;
pResource = Marshal.AllocHGlobal(Marshal.SizeOf(resource));
Marshal.StructureToPtr (resource, pResource, false);
uint status = Native.WNetOpenEnum (Native.ResourceScope.ResourceGlobalnet,
Native.ResourceType.ResourcetypeDisk,
0,
pResource,
out hEnum);
if (status != 0)
return resources;
int numberOfEntries = -1;
IntPtr pBuffer = Marshal.AllocHGlobal(bufferSize);
status = Native.WNetEnumResource (hEnum, ref numberOfEntries, pBuffer, ref bufferSize);
if (status == Native.NerrSuccess && numberOfEntries > 0) {
var ptr = pBuffer;
for (int i = 0; i < numberOfEntries; i++, ptr += Marshal.SizeOf(resource)) {
resource = (Native.NetResource)Marshal.PtrToStructure (ptr, typeof (Native.NetResource));
resources.Add (resource.lpRemoteName.StartsWith (computerName + '\\',
StringComparison.OrdinalIgnoreCase)
? resource.lpRemoteName.Substring (computerName.Length + 1)
: resource.lpRemoteName);
}
}
} finally {
if (hEnum != IntPtr.Zero) {
Native.WNetCloseEnum (hEnum);
}
if (pResource != IntPtr.Zero) {
Marshal.FreeHGlobal(pResource);
}
}
return resources;
}
static IEnumerable<string> GetAllShares (string computerName) {
var shares = new List<string> ();
IntPtr bufPtr = IntPtr.Zero;
int entriesread = 0;
int totalentries = 0;
int resumeHandle = 0;
int nStructSize = Marshal.SizeOf (typeof (Native.ShareInfo1));
try {
uint ret = Native.NetShareEnum (computerName, 1, ref bufPtr,
Native.MaxPreferredLength,
ref entriesread,
ref totalentries,
ref resumeHandle);
if (ret == (uint)Native.NetError.NerrSuccess) {
var currentPtr = bufPtr;
for (int i = 0; i < entriesread; i++) {
var shi1 = (Native.ShareInfo1)Marshal.PtrToStructure (currentPtr, typeof (Native.ShareInfo1));
if ((shi1.shi1_type & ~(uint)Native.ShareType.StypeSpecial) == (uint)Native.ShareType.StypeDisktree) {
shares.Add (shi1.shi1_netname);
}
currentPtr = new IntPtr (currentPtr.ToInt32 () + nStructSize);
}
}
} finally {
if (bufPtr != IntPtr.Zero)
Native.NetApiBufferFree (bufPtr);
}
return shares;
}
static IEnumerable<string> GetSubdirectories (string root) {
var dirInfo = new DirectoryInfo (root);
return (from info in dirInfo.EnumerateDirectories () select info.Name).ToList();
}
static void Main () {
var root = #"\\OK01\Users";
Console.WriteLine ("Subdirectories of {0}:", root);
foreach (var dir in GetSubdirectories (root)) {
Console.WriteLine (dir);
}
Console.WriteLine ();
root = #"\\OK01\Users\Public";
Console.WriteLine ("Subdirectories of {0}:", root);
foreach (var dir in GetSubdirectories (root)) {
Console.WriteLine (dir);
}
Console.WriteLine ();
root = #"\\OK01";
Console.WriteLine ("All Shares of {0} (inclusive hidden):", root);
foreach (var shareName in GetAllShares (root)) {
Console.WriteLine (shareName);
}
Console.WriteLine ();
root = #"\\OK01";
Console.WriteLine ("Shares of {0}:", root);
foreach (var shareName in GetShares (root)) {
Console.WriteLine (shareName);
}
}
}
}
which produce output like
Subdirectories of \\OK01\Users:
All Users
ASP.NET v4.0
Default
Default User
MSSQL$SQL2012
Oleg
Public
Subdirectories of \\OK01\Users\Public:
Desktop
Documents
Downloads
Favorites
Libraries
Music
Pictures
Recorded TV
Roaming
Videos
All Shares of \\OK01 (inclusive hidden):
ADMIN$
C$
print$
Q$
Users
Virtual Machines
VMware
Shares of \\OK01:
Users
Virtual Machines
VMware
The above code is simplified to demonstrate only how to use the corresponding API. It contains no real error reporting.
You can use method described here using Interop.
I made a few modifications to the code to come up with this. I have not extensively tested this, so it may have errors but it should get you started.
private List<string> GetSubDirectories(string serverName, string folderPath)
{
List<string> subDirectories = new List<string>();
string folder_path = Path.Combine(serverName, folderPath);
IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
WIN32_FIND_DATA findData;
IntPtr findHandle;
findHandle = FindFirstFile(folder_path, out findData);
if (findHandle == INVALID_HANDLE_VALUE)
{
int error = Marshal.GetLastWin32Error();
Console.WriteLine(error.ToString());
return null;
}
do
{
try
{
if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
subDirectories.Add(findData.cFileName);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
while (FindNextFile(findHandle, out findData));
FindClose(findHandle);
return subDirectories;
}
public const int FILE_ATTRIBUTE_DIRECTORY = 0x10;
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool FindClose(IntPtr hFindFile);
[StructLayout(LayoutKind.Sequential)]
public struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct WIN32_FIND_DATA
{
public uint dwFileAttributes;
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
public uint nFileSizeHigh;
public uint nFileSizeLow;
public uint dwReserved0;
public uint dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
}
You can call it like:
var subdirectories = GetSubDirectories(#"\\[serverName]", #"[folderPath]\*");
You have to add "\*" as per MSDN
On network shares, you can use an lpFileName in the form of the
following: "\Server\Share*". However, you cannot use an lpFileName
that points to the share itself; for example, "\Server\Share" is not
valid.
Not sure if we can achieve this. We had similar problem but finally resolved it by providing the shared path (\SERVERNAME\FOLDER).
Most important webservice should use a account that has full permission to access the directory else exception related to permission will be thrown out to calling client.
Well, actually it can be done using NetShareEnum Win32API function.
But here is .NET wrapper classes to enumerate network shares on local and remote machines, and convert local file paths to UNC paths. Please see the article Network Shares and UNC paths.

Trying to perform a Diffie Hellman Key exchange, using Win32 API in C#

I'm trying to build some code that will switch between the old CAPI or the new CNG-based Diffie-Hellman algorithms.
(Despite documentation, the new ECC-based DH algorithm, as part of CNG, is not supported on Windows XP).
Anyway, I've begun exposing the Win32 CAPI, as follows:
public static class CAPI
{
private static int ALG_CLASS_KEY_EXCHANGE = 5 << 13;
private static int ALG_TYPE_DH = 5 << 9;
private static int ALG_SID_DH_EPHEM = 2;
public static int CALG_DH_EPHEM = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_EPHEM);
public static uint CRYPT_VERIFYCONTEXT = 0xF0000000;
public static uint CRYPT_SILENT = 0x00000040;
public static uint PROV_DSS_DH = 13;
public static uint CRYPT_EXPORTABLE = 0x00000001;
public static uint CRYPT_PREGEN = 0x00000040;
public static uint KEY_SIZE = 0x00000400;
public static string MS_ENH_DSS_DH_PROV = "Microsoft Enhanced DSS and Diffie-Hellman Cryptographic Provider";
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptAcquireContext(ref IntPtr hProv, string pszContainer, string pszProvider, uint dwProvType, uint dwFlags);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptReleaseContext(IntPtr hProv, uint dwFlags);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptGenKey(IntPtr hProv, int Algid, uint dwFlags, ref IntPtr phKey);
[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptDestroyKey(IntPtr key);
}
and I have begun building a .NET DH class ontop of this:
public sealed class CAPIDiffieHellman : IDisposable
{
private IntPtr _publicKeyPointer = new IntPtr();
private IntPtr _hProv = new IntPtr();
private uint _contextFlags = CAPI.CRYPT_VERIFYCONTEXT | CAPI.CRYPT_SILENT;
private uint _keyGenerationFlags = CAPI.CRYPT_EXPORTABLE | CAPI.CRYPT_PREGEN;
public CAPIDiffieHellman()
{
if (!CAPI.CryptAcquireContext(
ref this._hProv,
null,
CAPI.MS_ENH_DSS_DH_PROV,
CAPI.PROV_DSS_DH,
this._contextFlags))
{
throw new ApplicationException(string.Format("Unable to acquire cryptographic context. Error Code: {0}", Marshal.GetLastWin32Error()));
}
}
public byte[] GeneratePublicKey()
{
if (!CAPI.CryptGenKey(this._hProv, CAPI.CALG_DH_EPHEM, this._keyGenerationFlags, ref this._publicKeyPointer))
{
throw new ApplicationException(string.Format("Unable to generate cryptographic key. Error Code: {0}", Marshal.GetLastWin32Error()));
}
var publicKey = new byte[128];
Marshal.Copy(this._publicKeyPointer, publicKey, 0, publicKey.Length);
return publicKey;
}
public byte[] DerivePrivateKey(byte[] publicKey)
{
return null;
}
public void Dispose()
{
CAPI.CryptReleaseContext(this._hProv, 0);
CAPI.CryptDestroyKey(this._publicKeyPointer);
}
}
I am working from this documentation
However, I'm realising that I'm not sure what the process I need to follow is; what I'm calling the 'public key' probably isn't!
So, a step-by-step guide for how to use the CAPI to perform a DH key exchange would be greatly appreciated!
thanks.
Use this method to acquire either public or private keys by passing correspondent isPublicKey value:
public static bool ExportCryptKey(IntPtr cryptKey, out byte[] outData, ref uint outDataSize, bool isPublicKey)
{
uint keyType = isPublicKey ? 0x6u : 0x7u;
outData = null;
if (!CryptExportKey(cryptKey, IntPtr.Zero, keyType, 0, null, ref outDataSize))
{
var err = Marshal.GetLastWin32Error();
Debug.Print(new Win32Exception(err).Message);
return false;
}
outData = new byte[outDataSize];
if (!CryptExportKey(cryptKey, IntPtr.Zero, keyType, 0, outData, ref outDataSize))
return false;
return true;
}

Categories