I want to check if the LocalGroup Remote Desktop Users exist by its SID which is S-1-5-32-555 and then run some codes to get the name of it. I want to user SID because the name of the group is different in different languages.
I'm currently using this code but I get Unexpected handle on SidTranslator when the system doesn't have Remote Desktop Users LocalGroup.
P.S: extractName is a Regex to convert BUILTIN\GROUPNAME to GROUPNAME.
SecurityIdentifier rduSID = new
SecurityIdentifier(WellKnownSidType.BuiltinRemoteDesktopUsersSid, null);
string rduName = extractName(MBC.Security.SidTranslator.GetName(rduSID.ToString()));
SidTranslator.cs (MBC.Security):
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
namespace MBC.Security
{
/// <summary>
/// This class provides two metods to convert object name (user, group) to SID and vice-versa.
/// </summary>
public class SidTranslator
{
[DllImport( "advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool LookupAccountSid([In,MarshalAs(UnmanagedType.LPTStr)] string systemName, IntPtr sid, [Out,MarshalAs(UnmanagedType.LPTStr)] StringBuilder name, ref int cbName, StringBuilder referencedDomainName, ref int cbReferencedDomainName, out int use );
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool LookupAccountName([In,MarshalAs(UnmanagedType.LPTStr)] string systemName, [In,MarshalAs(UnmanagedType.LPTStr)] string accountName, IntPtr sid, ref int cbSid, StringBuilder referencedDomainName, ref int cbReferencedDomainName, out int use);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool ConvertSidToStringSid(IntPtr sid, [In,Out,MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool ConvertStringSidToSid([In, MarshalAs(UnmanagedType.LPTStr)] string pStringSid, ref IntPtr sid);
/// <summary>
/// The method converts object name (user, group) into SID string.
/// </summary>
/// <param name="name">Object name in form domain\object_name.</param>
/// <returns>SID string.</returns>
public static string GetSid(string name)
{
IntPtr _sid = IntPtr.Zero; //pointer to binary form of SID string.
int _sidLength = 0; //size of SID buffer.
int _domainLength = 0; //size of domain name buffer.
int _use; //type of object.
StringBuilder _domain = new StringBuilder(); //stringBuilder for domain name.
int _error = 0;
string _sidString = "";
//first call of the function only returns the sizes of buffers (SDI, domain name)
LookupAccountName(null, name, _sid, ref _sidLength, _domain, ref _domainLength, out _use);
_error = Marshal.GetLastWin32Error();
if (_error != 122) //error 122 (The data area passed to a system call is too small) - normal behaviour.
{
throw(new Exception(new Win32Exception(_error).Message));
}
else
{
_domain = new StringBuilder(_domainLength); //allocates memory for domain name
_sid = Marshal.AllocHGlobal(_sidLength); //allocates memory for SID
bool _rc = LookupAccountName(null, name, _sid, ref _sidLength, _domain, ref _domainLength, out _use);
if (_rc == false)
{
_error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(_sid);
throw(new Exception(new Win32Exception(_error).Message));
}
else
{
// converts binary SID into string
_rc = ConvertSidToStringSid(_sid, ref _sidString);
if (_rc == false)
{
_error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(_sid);
throw(new Exception(new Win32Exception(_error).Message));
}
else
{
Marshal.FreeHGlobal(_sid);
return _sidString;
}
}
}
}
/// <summary>
/// The method converts SID string (user, group) into object name.
/// </summary>
/// <param name="name">SID string.</param>
/// <returns>Object name in form domain\object_name.</returns>
public static string GetName(string sid)
{
IntPtr _sid = IntPtr.Zero; //pointer to binary form of SID string.
int _nameLength = 0; //size of object name buffer
int _domainLength = 0; //size of domain name buffer
int _use; //type of object
StringBuilder _domain = new StringBuilder(); //domain name variable
int _error = 0;
StringBuilder _name = new StringBuilder(); //object name variable
bool _rc0 = ConvertStringSidToSid(sid, ref _sid); //converts SID string into the binary form
if (_rc0 == false)
{
_error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(_sid);
throw(new Exception(new Win32Exception(_error).Message));
}
//first call of method returns the size of domain name and object name buffers
bool _rc = LookupAccountSid(null, _sid, _name, ref _nameLength, _domain, ref _domainLength, out _use);
_domain = new StringBuilder(_domainLength); //allocates memory for domain name
_name = new StringBuilder(_nameLength); //allocates memory for object name
_rc = LookupAccountSid(null, _sid, _name, ref _nameLength, _domain, ref _domainLength, out _use);
if (_rc == false)
{
_error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(_sid);
throw(new Exception(new Win32Exception(_error).Message));
}
else
{
Marshal.FreeHGlobal(_sid);
return _domain.ToString() + "\\" + _name.ToString();
}
}
}
}`
Related
I am creating a Shared folder on a remote computer/server and have this working but am unable to find if it is possible to change the share settings. I would like to be able to turn off Allow caching of share and turn on Access-based Enumeration but am unable to find anything on this on here and through searching google. Does anybody know if this is possible with C#?
The code i am using to create the share is:
public static void CreateRemoteShare(string servername, string FolderPath, string ShareName, string Description)
{
try
{
string scope = string.Format("\\\\{0}\\root\\cimv2", servername);
ManagementScope ms = new ManagementScope(scope);
ManagementClass managementClass = new ManagementClass("Win32_Share");
managementClass.Scope = ms;
ManagementBaseObject inParams = managementClass.GetMethodParameters("Create");
ManagementBaseObject outParams;
inParams["Description"] = Description;
inParams["Name"] = ShareName;
inParams["Path"] = FolderPath;
inParams["Type"] = 0x0;
NTAccount everyoneAccount = new NTAccount(null, "EVERYONE");
SecurityIdentifier sid = (SecurityIdentifier)everyoneAccount.Translate(typeof(SecurityIdentifier));
byte[] sidArray = new byte[sid.BinaryLength];
sid.GetBinaryForm(sidArray, 0);
ManagementObject everyone = new ManagementClass("Win32_Trustee");
everyone["Domain"] = null;
everyone["Name"] = "EVERYONE";
everyone["SID"] = sidArray;
ManagementObject dacl = new ManagementClass("Win32_Ace");
dacl["AccessMask"] = 2032127;
dacl["AceFlags"] = 3;
dacl["AceType"] = 0;
dacl["Trustee"] = everyone;
ManagementObject securityDescriptor = new ManagementClass("Win32_SecurityDescriptor");
securityDescriptor["ControlFlags"] = 4; //SE_DACL_PRESENT
securityDescriptor["DACL"] = new object[] { dacl };
inParams["Access"] = securityDescriptor;
outParams = managementClass.InvokeMethod("Create", inParams, null);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
If anybody knows of any way to do this i would be eternaly greatfull.
After looking in to this a bit more i found a site that contained a way to do it in PowerShell and from the site i added this to my C# code. The site is: ABE Powershell
The resulting code extracted is as follows:
public enum Share_Type : uint
{
STYPE_DISKTREE = 0x00000000, // Disk Drive
STYPE_PRINTQ = 0x00000001, // Print Queue
STYPE_DEVICE = 0x00000002, // Communications Device
STYPE_IPC = 0x00000003, // InterProcess Communications
STYPE_SPECIAL = 0x80000000, // Special share types (C$, ADMIN$, IPC$, etc)
STYPE_TEMPORARY = 0x40000000 // Temporary share
}
public enum Share_ReturnValue : int
{
NERR_Success = 0,
ERROR_ACCESS_DENIED = 5,
ERROR_NOT_ENOUGH_MEMORY = 8,
ERROR_INVALID_PARAMETER = 87,
ERROR_INVALID_LEVEL = 124, // unimplemented level for info
ERROR_MORE_DATA = 234,
NERR_BufTooSmall = 2123, // The API return buffer is too small.
NERR_NetNameNotFound = 2310 // This shared resource does not exist.
}
[System.Flags]
public enum Shi1005_flags
{
SHI1005_FLAGS_DFS = 0x0001, // Part of a DFS tree (Cannot be set)
SHI1005_FLAGS_DFS_ROOT = 0x0002, // Root of a DFS tree (Cannot be set)
SHI1005_FLAGS_RESTRICT_EXCLUSIVE_OPENS = 0x0100, // Disallow Exclusive file open
SHI1005_FLAGS_FORCE_SHARED_DELETE = 0x0200, // Open files can be force deleted
SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING = 0x0400, // Clients can cache the namespace
SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM = 0x0800, // Only directories for which a user has FILE_LIST_DIRECTORY will be listed
SHI1005_FLAGS_FORCE_LEVELII_OPLOCK = 0x1000, // Prevents exclusive caching
SHI1005_FLAGS_ENABLE_HASH = 0x2000, // Used for server side support for peer caching
SHI1005_FLAGS_ENABLE_CA = 0X4000 // Used for Clustered shares
}
public static class NetApi32
{
// ********** Structures **********
// SHARE_INFO_502
[StructLayout(LayoutKind.Sequential)]
public struct SHARE_INFO_502
{
[MarshalAs(UnmanagedType.LPWStr)]
public string shi502_netname;
public uint shi502_type;
[MarshalAs(UnmanagedType.LPWStr)]
public string shi502_remark;
public Int32 shi502_permissions;
public Int32 shi502_max_uses;
public Int32 shi502_current_uses;
[MarshalAs(UnmanagedType.LPWStr)]
public string shi502_path;
public IntPtr shi502_passwd;
public Int32 shi502_reserved;
public IntPtr shi502_security_descriptor;
}
// SHARE_INFO_1005
[StructLayout(LayoutKind.Sequential)]
public struct SHARE_INFO_1005
{
public Int32 Shi1005_flags;
}
private class unmanaged
{
//NetShareGetInfo
[DllImport("Netapi32.dll", SetLastError = true)]
internal static extern int NetShareGetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string serverName,
[MarshalAs(UnmanagedType.LPWStr)] string netName,
Int32 level,
ref IntPtr bufPtr
);
[DllImport("Netapi32.dll", SetLastError = true)]
public extern static Int32 NetShareSetInfo(
[MarshalAs(UnmanagedType.LPWStr)] string servername,
[MarshalAs(UnmanagedType.LPWStr)] string netname, Int32 level, IntPtr bufptr, out Int32 parm_err);
}
// ***** Functions *****
public static SHARE_INFO_502 NetShareGetInfo_502(string ServerName, string ShareName)
{
Int32 level = 502;
IntPtr lShareInfo = IntPtr.Zero;
SHARE_INFO_502 shi502_Info = new SHARE_INFO_502();
Int32 result = unmanaged.NetShareGetInfo(ServerName, ShareName, level, ref lShareInfo);
if ((Share_ReturnValue)result == Share_ReturnValue.NERR_Success)
{
shi502_Info = (SHARE_INFO_502)Marshal.PtrToStructure(lShareInfo, typeof(SHARE_INFO_502));
}
else
{
throw new Exception("Unable to get 502 structure. Function returned: " + (Share_ReturnValue)result);
}
return shi502_Info;
}
public static SHARE_INFO_1005 NetShareGetInfo_1005(string ServerName, string ShareName)
{
Int32 level = 1005;
IntPtr lShareInfo = IntPtr.Zero;
SHARE_INFO_1005 shi1005_Info = new SHARE_INFO_1005();
Int32 result = unmanaged.NetShareGetInfo(ServerName, ShareName, level, ref lShareInfo);
if ((Share_ReturnValue)result == Share_ReturnValue.NERR_Success)
{
shi1005_Info = (SHARE_INFO_1005)Marshal.PtrToStructure(lShareInfo, typeof(SHARE_INFO_1005));
}
else
{
throw new Exception("Unable to get 1005 structure. Function returned: " + (Share_ReturnValue)result);
}
return shi1005_Info;
}
public static int NetShareSetInfo_1005(string ServerName, string ShareName, SHARE_INFO_1005 shi1005_Info) // Int32 Shi1005_flags
{
Int32 level = 1005;
Int32 err;
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(shi1005_Info));
Marshal.StructureToPtr(shi1005_Info, ptr, false);
var result = unmanaged.NetShareSetInfo(ServerName, ShareName, level, ptr, out err);
return result;
}
}
static void Main(string[] args)
{
abeTest();
}
public static void abeTest()
{
NetApi32.SHARE_INFO_1005 test = new NetApi32.SHARE_INFO_1005();
test.Shi1005_flags = 2048;
NetApi32.NetShareSetInfo_1005("FileStore2", "TestShare2$", test);
}
By combining both this and the above code you are able to create a share and set the access based enumeration.
In a WPF application, I would like to provide the typical "Remember Me" option to remember credentials and use them automatically next time the application is launched.
Using a one-way hash is clearly not an option, and while I can store credentials in isolated storage or in the registry, there is one issue to deal with when encrypting the credentials.
If I use a symmetric key encryption algorithm, I will need to store the key somewhere. And if the key is, for example, hardcoded in memory, then I imagine it would be easy to disassemble the .NET assemblies and find it.
What is the best way to encrypt credentials in .NET and keep them secure, keeping the encryption key completely out of reach?
Here's a summary of my blog post: How to store a password on Windows?
You can use the Data Protection API and its .NET implementation (ProtectedData) to encrypt the password. Here's an example:
public static string Protect(string str)
{
byte[] entropy = Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().FullName);
byte[] data = Encoding.ASCII.GetBytes(str);
string protectedData = Convert.ToBase64String(ProtectedData.Protect(data, entropy, DataProtectionScope.CurrentUser));
return protectedData;
}
public static string Unprotect(string str)
{
byte[] protectedData = Convert.FromBase64String(str);
byte[] entropy = Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().FullName);
string data = Encoding.ASCII.GetString(ProtectedData.Unprotect(protectedData, entropy, DataProtectionScope.CurrentUser));
return data;
}
Or you can use the Windows Credential Manager (This is the way I prefer because it allows users to backup/restore/edit their credentials even if your application has no such functionality). I've created a NuGet package Meziantou.Framework.Win32.CredentialManager. How to use it:
CredentialManager.WriteCredential("ApplicationName", "username", "Pa$$w0rd", CredentialPersistence.Session);
var cred = CredentialManager.ReadCredential("ApplicationName");
Assert.AreEqual("username", cred.UserName);
Assert.AreEqual("Pa$$w0rd", cred.Password);
CredentialManager.DeleteCredential("ApplicationName");
Original answer with the native API wrapper (A more recent version of this is available on GitHub):
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Text;
using System.ComponentModel;
public static class CredentialManager
{
public static Credential ReadCredential(string applicationName)
{
IntPtr nCredPtr;
bool read = CredRead(applicationName, CredentialType.Generic, 0, out nCredPtr);
if (read)
{
using (CriticalCredentialHandle critCred = new CriticalCredentialHandle(nCredPtr))
{
CREDENTIAL cred = critCred.GetCredential();
return ReadCredential(cred);
}
}
return null;
}
private static Credential ReadCredential(CREDENTIAL credential)
{
string applicationName = Marshal.PtrToStringUni(credential.TargetName);
string userName = Marshal.PtrToStringUni(credential.UserName);
string secret = null;
if (credential.CredentialBlob != IntPtr.Zero)
{
secret = Marshal.PtrToStringUni(credential.CredentialBlob, (int)credential.CredentialBlobSize / 2);
}
return new Credential(credential.Type, applicationName, userName, secret);
}
public static int WriteCredential(string applicationName, string userName, string secret)
{
byte[] byteArray = Encoding.Unicode.GetBytes(secret);
if (byteArray.Length > 512)
throw new ArgumentOutOfRangeException("secret", "The secret message has exceeded 512 bytes.");
CREDENTIAL credential = new CREDENTIAL();
credential.AttributeCount = 0;
credential.Attributes = IntPtr.Zero;
credential.Comment = IntPtr.Zero;
credential.TargetAlias = IntPtr.Zero;
credential.Type = CredentialType.Generic;
credential.Persist = (UInt32)CredentialPersistence.Session;
credential.CredentialBlobSize = (UInt32)Encoding.Unicode.GetBytes(secret).Length;
credential.TargetName = Marshal.StringToCoTaskMemUni(applicationName);
credential.CredentialBlob = Marshal.StringToCoTaskMemUni(secret);
credential.UserName = Marshal.StringToCoTaskMemUni(userName ?? Environment.UserName);
bool written = CredWrite(ref credential, 0);
int lastError = Marshal.GetLastWin32Error();
Marshal.FreeCoTaskMem(credential.TargetName);
Marshal.FreeCoTaskMem(credential.CredentialBlob);
Marshal.FreeCoTaskMem(credential.UserName);
if (written)
return 0;
throw new Exception(string.Format("CredWrite failed with the error code {0}.", lastError));
}
public static IReadOnlyList<Credential> EnumerateCrendentials()
{
List<Credential> result = new List<Credential>();
int count;
IntPtr pCredentials;
bool ret = CredEnumerate(null, 0, out count, out pCredentials);
if (ret)
{
for (int n = 0; n < count; n++)
{
IntPtr credential = Marshal.ReadIntPtr(pCredentials, n * Marshal.SizeOf(typeof(IntPtr)));
result.Add(ReadCredential((CREDENTIAL)Marshal.PtrToStructure(credential, typeof(CREDENTIAL))));
}
}
else
{
int lastError = Marshal.GetLastWin32Error();
throw new Win32Exception(lastError);
}
return result;
}
[DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CredRead(string target, CredentialType type, int reservedFlag, out IntPtr credentialPtr);
[DllImport("Advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CredWrite([In] ref CREDENTIAL userCredential, [In] UInt32 flags);
[DllImport("advapi32", SetLastError = true, CharSet = CharSet.Unicode)]
static extern bool CredEnumerate(string filter, int flag, out int count, out IntPtr pCredentials);
[DllImport("Advapi32.dll", EntryPoint = "CredFree", SetLastError = true)]
static extern bool CredFree([In] IntPtr cred);
private enum CredentialPersistence : uint
{
Session = 1,
LocalMachine,
Enterprise
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct CREDENTIAL
{
public UInt32 Flags;
public CredentialType Type;
public IntPtr TargetName;
public IntPtr Comment;
public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
public UInt32 CredentialBlobSize;
public IntPtr CredentialBlob;
public UInt32 Persist;
public UInt32 AttributeCount;
public IntPtr Attributes;
public IntPtr TargetAlias;
public IntPtr UserName;
}
sealed class CriticalCredentialHandle : CriticalHandleZeroOrMinusOneIsInvalid
{
public CriticalCredentialHandle(IntPtr preexistingHandle)
{
SetHandle(preexistingHandle);
}
public CREDENTIAL GetCredential()
{
if (!IsInvalid)
{
CREDENTIAL credential = (CREDENTIAL)Marshal.PtrToStructure(handle, typeof(CREDENTIAL));
return credential;
}
throw new InvalidOperationException("Invalid CriticalHandle!");
}
protected override bool ReleaseHandle()
{
if (!IsInvalid)
{
CredFree(handle);
SetHandleAsInvalid();
return true;
}
return false;
}
}
}
public enum CredentialType
{
Generic = 1,
DomainPassword,
DomainCertificate,
DomainVisiblePassword,
GenericCertificate,
DomainExtended,
Maximum,
MaximumEx = Maximum + 1000,
}
public class Credential
{
private readonly string _applicationName;
private readonly string _userName;
private readonly string _password;
private readonly CredentialType _credentialType;
public CredentialType CredentialType
{
get { return _credentialType; }
}
public string ApplicationName
{
get { return _applicationName; }
}
public string UserName
{
get { return _userName; }
}
public string Password
{
get { return _password; }
}
public Credential(CredentialType credentialType, string applicationName, string userName, string password)
{
_applicationName = applicationName;
_userName = userName;
_password = password;
_credentialType = credentialType;
}
public override string ToString()
{
return string.Format("CredentialType: {0}, ApplicationName: {1}, UserName: {2}, Password: {3}", CredentialType, ApplicationName, UserName, Password);
}
}
Usage:
WriteCredential("ApplicationName", "Meziantou", "Passw0rd");
Console.WriteLine(ReadCredential("Demo"));
I'm looking for a programmatic solution that has the same effect as setting the "Configure Windows NTP Client" state in GPOE Administrative Templates > System > Windows Time Service > Time Providers > Configure Windows NTP Client to Not Configured or Disabled, but I'll take any help I can get at this point.
Is there a registry key I can modify using the .NET Registry class or a property I can modify using the RSoP WMI classes? I've been looking in both places for days, but haven't found anything that will effectively disable the GPO or have the same effect as disabling or setting it to Not Configured in the GUI.
Firstly you have to find the registry value to edit. They are all listed in the XLS document downloadable at http://www.microsoft.com/en-us/download/details.aspx?id=25250. This document does not indicate the type of the value (REGSZ, DWORD, etc), so you have to set the setting by using the editor and then look the type of the value with regedit.
Now you have the registry key, the value name and its type, let's add some C# and use the COM interface IGroupPolicyObject
[ComImport, Guid("EA502722-A23D-11d1-A7D3-0000F87571E3")]
internal class GPClass
{
}
[ComImport, Guid("EA502723-A23D-11d1-A7D3-0000F87571E3"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IGroupPolicyObject
{
uint New([MarshalAs(UnmanagedType.LPWStr)] string domainName, [MarshalAs(UnmanagedType.LPWStr)] string displayName, uint flags);
uint OpenDSGPO([MarshalAs(UnmanagedType.LPWStr)] string path, uint flags);
uint OpenLocalMachineGPO(uint flags);
uint OpenRemoteMachineGPO([MarshalAs(UnmanagedType.LPWStr)] string computerName, uint flags);
uint Save([MarshalAs(UnmanagedType.Bool)] bool machine, [MarshalAs(UnmanagedType.Bool)] bool add, [MarshalAs(UnmanagedType.LPStruct)] Guid extension, [MarshalAs(UnmanagedType.LPStruct)] Guid app);
uint Delete();
uint GetName([MarshalAs(UnmanagedType.LPWStr)] StringBuilder name, int maxLength);
uint GetDisplayName([MarshalAs(UnmanagedType.LPWStr)] StringBuilder name, int maxLength);
uint SetDisplayName([MarshalAs(UnmanagedType.LPWStr)] string name);
uint GetPath([MarshalAs(UnmanagedType.LPWStr)] StringBuilder path, int maxPath);
uint GetDSPath(uint section, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder path, int maxPath);
uint GetFileSysPath(uint section, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder path, int maxPath);
uint GetRegistryKey(uint section, out IntPtr key);
uint GetOptions(out uint options);
uint SetOptions(uint options, uint mask);
uint GetType(out IntPtr gpoType);
uint GetMachineName([MarshalAs(UnmanagedType.LPWStr)] StringBuilder name, int maxLength);
uint GetPropertySheetPages(out IntPtr pages);
}
public enum GroupPolicySection
{
Root = 0,
User = 1,
Machine = 2,
}
public abstract class GroupPolicyObject
{
protected const int MaxLength = 1024;
/// <summary>
/// The snap-in that processes .pol files
/// </summary>
private static readonly Guid RegistryExtension = new Guid(0x35378EAC, 0x683F, 0x11D2, 0xA8, 0x9A, 0x00, 0xC0, 0x4F, 0xBB, 0xCF, 0xA2);
/// <summary>
/// This application
/// </summary>
private static readonly Guid LocalGuid = new Guid(GetAssemblyAttribute<GuidAttribute>(Assembly.GetExecutingAssembly()).Value);
protected IGroupPolicyObject Instance = null;
static T GetAssemblyAttribute<T>(ICustomAttributeProvider assembly) where T : Attribute
{
object[] attributes = assembly.GetCustomAttributes(typeof(T), true);
if (attributes.Length == 0)
return null;
return (T)attributes[0];
}
internal GroupPolicyObject()
{
Instance = GetInstance();
}
public void Save()
{
var result = Instance.Save(true, true, RegistryExtension, LocalGuid);
if (result != 0)
{
throw new Exception("Error saving machine settings");
}
result = Instance.Save(false, true, RegistryExtension, LocalGuid);
if (result != 0)
{
throw new Exception("Error saving user settings");
}
}
public void Delete()
{
var result = Instance.Delete();
if (result != 0)
{
throw new Exception("Error deleting the GPO");
}
Instance = null;
}
public RegistryKey GetRootRegistryKey(GroupPolicySection section)
{
IntPtr key;
var result = Instance.GetRegistryKey((uint)section, out key);
if (result != 0)
{
throw new Exception(string.Format("Unable to get section '{0}'", Enum.GetName(typeof(GroupPolicySection), section)));
}
var handle = new SafeRegistryHandle(key, true);
return RegistryKey.FromHandle(handle, RegistryView.Default);
}
public abstract string GetPathTo(GroupPolicySection section);
protected static IGroupPolicyObject GetInstance()
{
var concrete = new GPClass();
return (IGroupPolicyObject)concrete;
}
}
public class GroupPolicyObjectSettings
{
public readonly bool LoadRegistryInformation;
public readonly bool Readonly;
public GroupPolicyObjectSettings(bool loadRegistryInfo = true, bool readOnly = false)
{
LoadRegistryInformation = loadRegistryInfo;
Readonly = readOnly;
}
private const uint RegistryFlag = 0x00000001;
private const uint ReadonlyFlag = 0x00000002;
internal uint Flag
{
get
{
uint flag = 0x00000000;
if (LoadRegistryInformation)
{
flag |= RegistryFlag;
}
if (Readonly)
{
flag |= ReadonlyFlag;
}
return flag;
}
}
}
public class ComputerGroupPolicyObject : GroupPolicyObject
{
public readonly bool IsLocal;
public ComputerGroupPolicyObject(GroupPolicyObjectSettings options = null)
{
options = options ?? new GroupPolicyObjectSettings();
var result = Instance.OpenLocalMachineGPO(options.Flag);
if (result != 0)
{
throw new Exception("Unable to open local machine GPO");
}
IsLocal = true;
}
public ComputerGroupPolicyObject(string computerName, GroupPolicyObjectSettings options = null)
{
options = options ?? new GroupPolicyObjectSettings();
var result = Instance.OpenRemoteMachineGPO(computerName, options.Flag);
if (result != 0)
{
throw new Exception(string.Format("Unable to open GPO on remote machine '{0}'", computerName));
}
IsLocal = false;
}
public static void SetPolicySetting(string registryInformation, string settingValue, RegistryValueKind registryValueKind)
{
string valueName;
GroupPolicySection section;
string key = Key(registryInformation, out valueName, out section);
// Thread must be STA
Exception exception = null;
var t = new Thread(() =>
{
try
{
var gpo = new ComputerGroupPolicyObject();
using (RegistryKey rootRegistryKey = gpo.GetRootRegistryKey(section))
{
// Data can't be null so we can use this value to indicate key must be delete
if (settingValue == null)
{
using (RegistryKey subKey = rootRegistryKey.OpenSubKey(key, true))
{
if (subKey != null)
{
subKey.DeleteValue(valueName);
}
}
}
else
{
using (RegistryKey subKey = rootRegistryKey.CreateSubKey(key))
{
subKey.SetValue(valueName, settingValue, registryValueKind);
}
}
}
gpo.Save();
}
catch (Exception ex)
{
exception = ex;
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
if (exception != null)
throw exception;
}
public static object GetPolicySetting(string registryInformation)
{
string valueName;
GroupPolicySection section;
string key = Key(registryInformation, out valueName, out section);
// Thread must be STA
object result = null;
var t = new Thread(() =>
{
var gpo = new ComputerGroupPolicyObject();
using (RegistryKey rootRegistryKey = gpo.GetRootRegistryKey(section))
{
// Data can't be null so we can use this value to indicate key must be delete
using (RegistryKey subKey = rootRegistryKey.OpenSubKey(key, true))
{
if (subKey == null)
{
result = null;
}
else
{
result = subKey.GetValue(valueName);
}
}
}
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
return result;
}
private static string Key(string registryInformation, out string value, out GroupPolicySection section)
{
// Parse parameter of format HKCU\Software\Policies\Microsoft\Windows\Personalization!NoChangingSoundScheme
string[] split = registryInformation.Split('!');
string key = split[0];
string hive = key.Substring(0, key.IndexOf('\\'));
key = key.Substring(key.IndexOf('\\') + 1);
value = split[1];
if (hive.Equals(#"HKLM", StringComparison.OrdinalIgnoreCase)
|| hive.Equals(#"HKEY_LOCAL_MACHINE", StringComparison.OrdinalIgnoreCase))
{
section = GroupPolicySection.Machine;
}
else
{
section = GroupPolicySection.User;
}
return key;
}
/// <summary>
/// Retrieves the file system path to the root of the specified GPO section.
/// The path is in UNC format.
/// </summary>
public override string GetPathTo(GroupPolicySection section)
{
var sb = new StringBuilder(MaxLength);
var result = Instance.GetFileSysPath((uint)section, sb, MaxLength);
if (result != 0)
{
throw new Exception(string.Format("Unable to retrieve path to section '{0}'", Enum.GetName(typeof(GroupPolicySection), section)));
}
return sb.ToString();
}
}
And how to use it:
static void Main(string[] args)
{
ComputerGroupPolicyObject.SetPolicySetting(#"HKLM\Software\Policies\Microsoft\Windows\HomeGroup!DisableHomeGroup", "0", RegistryValueKind.DWord);
ComputerGroupPolicyObject.SetPolicySetting(#"HKLM\Software\Policies\Microsoft\Windows\HomeGroup!DisableHomeGroup", "1", RegistryValueKind.DWord);
ComputerGroupPolicyObject.SetPolicySetting(#"HKLM\Software\Policies\Microsoft\Windows\HomeGroup!DisableHomeGroup", null, RegistryValueKind.Unknown);
}
Code inspired from https://bitbucket.org/MartinEden/local-policy
What I’m trying to do is to connect to SharePoint list by other credentials (impersonation) and print its items.
I’m using this code for the impersonation, and it works almost perfectly, until clientContext.ExecuteQuery() is performed. I found that during this command, the impersonation is expired (actually this is the critical command I need to impersonate for).
How can I get over it?
CredentialsController.Impersonator imp = null;
imp = new CredentialsController.Impersonator("myUsername", "myDomain", "myPassword");
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml = query;
listItemCollection = selectedList.GetItems(camlQuery);
clientContext.Load(listItemCollection);
clientContext.ExecuteQuery(); // ****This line cancels the impersonation****
imp.UndoImpersonation();
Notes:
To run the code below, you need to:
Add reference to two dlls (Can be downloaded from here):
Microsoft.SharePoint.Client.dll
Microsoft.SharePoint.Client.Runtime.dll
Make sure that you use .NET 3.5 (currently not higher)
Insert real values in the following lines
string siteUrl = "https://SP_Server.com/sites/some_site/";
string listID = "3c84e774-86c4-4b45-8a0a-437526e8728f";
imp = new CredentialsController.Impersonator("myUsername", "myDomain", "myPassword");
Console.WriteLine(oListItem["Title"].ToString());
(I'm using VS2010 ultimate on Win 7 64 bit)
Here is the complete code:
using System;
using System.Collections.Generic;
using System.Security.Principal;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Microsoft.SharePoint.Client;
namespace WhereAmILoggedIn
{
class SharePointGetter
{
static void Main()
{
string siteUrl = "https://SP_Server/sites/some_site/";
string query = "<View></View>";
string listID = "3c84e774-86c4-4b45-8a0a-437526e8728f";
CredentialsController.Impersonator imp = null;
imp = new CredentialsController.Impersonator("myUsername", "myDomain", "myPassword");
ListItemCollection listItemCollection;
try
{
Microsoft.SharePoint.Client.ClientContext clientContext = new ClientContext(siteUrl);
Microsoft.SharePoint.Client.List selectedList = clientContext.Web.Lists.GetById(new Guid(listID));
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml = query;
listItemCollection = selectedList.GetItems(camlQuery);
clientContext.Load(listItemCollection);
Console.WriteLine(Convert.ToString(WindowsIdentity.GetCurrent().Name)); //************ Before
clientContext.ExecuteQuery();
Console.WriteLine(Convert.ToString(WindowsIdentity.GetCurrent().Name)); //************ After
}
catch (Exception)
{
throw new Exception("Access denied", new Exception("Are you missing permissions?"));
}
foreach (ListItem oListItem in listItemCollection)
{
Console.WriteLine(oListItem["Title"].ToString());
}
if (imp != null)
imp.UndoImpersonation();
}
}
class CredentialsController
{
public enum LogonType
{
LOGON32_LOGON_INTERACTIVE = 2,
LOGON32_LOGON_NETWORK = 3,
LOGON32_LOGON_BATCH = 4,
LOGON32_LOGON_SERVICE = 5,
LOGON32_LOGON_UNLOCK = 7,
LOGON32_LOGON_NETWORK_CLEARTEXT = 8, // Win2K or higher
LOGON32_LOGON_NEW_CREDENTIALS = 9 // Win2K or higher
};
public enum LogonProvider
{
LOGON32_PROVIDER_DEFAULT = 0,
LOGON32_PROVIDER_WINNT35 = 1,
LOGON32_PROVIDER_WINNT40 = 2,
LOGON32_PROVIDER_WINNT50 = 3
};
public enum ImpersonationLevel
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3
}
class Win32NativeMethods
{
[DllImport("advapi32.dll", SetLastError = true)]
public static extern int LogonUser(string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken(IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern bool CloseHandle(IntPtr handle);
}
public class Impersonator : IDisposable
{
private WindowsImpersonationContext _wic;
public Impersonator(string userName, string domainName, string password, LogonType logonType, LogonProvider logonProvider)
{
Impersonate(userName, domainName, password, logonType, logonProvider);
}
public Impersonator(string userName, string domainName, string password)
{
Impersonate(userName, domainName, password, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT);
}
public Impersonator()
{ }
public void Dispose()
{
UndoImpersonation();
}
public void Impersonate(string userName, string domainName, string password)
{
Impersonate(userName, domainName, password, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT);
}
public void Impersonate(string userName, string domainName, string password, LogonType logonType, LogonProvider logonProvider)
{
UndoImpersonation();
IntPtr logonToken = IntPtr.Zero;
IntPtr logonTokenDuplicate = IntPtr.Zero;
try
{
// revert to the application pool identity, saving the identity of the current requestor
_wic = WindowsIdentity.Impersonate(IntPtr.Zero);
// do logon & impersonate
if (Win32NativeMethods.LogonUser(userName,
domainName,
password,
(int)logonType,
(int)logonProvider,
ref logonToken) != 0)
{
if (Win32NativeMethods.DuplicateToken(logonToken, (int)ImpersonationLevel.SecurityImpersonation, ref logonTokenDuplicate) != 0)
{
var wi = new WindowsIdentity(logonTokenDuplicate);
wi.Impersonate(); // discard the returned identity context (which is the context of the application pool)
}
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}
else
throw new Win32Exception(Marshal.GetLastWin32Error());
}
finally
{
if (logonToken != IntPtr.Zero)
Win32NativeMethods.CloseHandle(logonToken);
if (logonTokenDuplicate != IntPtr.Zero)
Win32NativeMethods.CloseHandle(logonTokenDuplicate);
}
}
/// Stops impersonation.
public void UndoImpersonation()
{
// restore saved requestor identity
if (_wic != null)
_wic.Undo();
_wic = null;
}
}
}
}
I am using MSScriptControl in C#. I would like to pass a class from the script to the host. Simplified example:
Javascript:
function Fx(n) {
this.name = n;
}
var fx = new Fx("test");
rfx.DoEffect(fx);
C#:
[ComVisible(true)]
public class Rfx {
public void DoEffect(object fx) {
// Try to read fx.name
}
}
My question is: How do I get the data out of the object (which C# reports as System.__ComObject). I tried the technique offered here, but it doesn't work:
public void DoEffect(object fx)
{
System.Reflection.FieldInfo[] myFields = fx.GetType().GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
Console.WriteLine("FieldInfo length = " + myFields.Length);
for (int i = 0; i < myFields.Length; i++)
{
Console.WriteLine("The value of {0} is: {1}", myFields[i].Name, myFields[i].GetValue(fx));
}
}
myFields.Length is 0.
Building off Mangist's code, this works:
using System;
using System.Runtime.InteropServices;
using ComTypes = System.Runtime.InteropServices.ComTypes;
public class ComHelper
{
public static string GetValue(object comObj, string name)
{
if (comObj == null)
return String.Empty;
if (!Marshal.IsComObject(comObj))
//The specified object is not a COM object
return String.Empty;
IDispatch dispatch = comObj as IDispatch;
if (dispatch == null)
//The specified COM object doesn't support getting type information
return String.Empty;
try
{
int language_id = 0;
int DISPATCH_METHOD = 0x1;
int DISPATCH_PROPERTYGET = 0x2;
int[] displayIDs = new int[1];
Guid empty = Guid.Empty;
string[] names = new string[] { name };
dispatch.GetIDsOfNames(ref empty, names, names.Length, language_id, displayIDs);
System.Runtime.InteropServices.ComTypes.DISPPARAMS dspp = new System.Runtime.InteropServices.ComTypes.DISPPARAMS();
System.Runtime.InteropServices.ComTypes.EXCEPINFO ei = new System.Runtime.InteropServices.ComTypes.EXCEPINFO();
IntPtr[] arg_err = new IntPtr[10];
object result;
if (1 == displayIDs.Length)
{
dispatch.Invoke(displayIDs[0], ref empty, language_id, (ushort)(DISPATCH_METHOD | DISPATCH_PROPERTYGET), ref dspp, out result, ref ei, arg_err);
return result.ToString();
}
return String.Empty;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return String.Empty;
}
}
}
I had done this previously in C++ so I could copy the code over, but am still getting my feet wet in C#.
Since the introduction of dynamic, one can treat COM Objects as dynamics, in your example you could simply do:
dynamic fx = scriptControl.Run("youFunction");
string name = fx.name;
using System;
using System.Runtime.InteropServices;
using ComTypes = System.Runtime.InteropServices.ComTypes;
namespace ComUtils
{
public class ComHelper
{
/// <summary>
/// Returns a string value representing the type name of the specified COM object.
/// </summary>
/// <param name="comObj">A COM object the type name of which to return.</param>
/// <returns>A string containing the type name.</returns>
public static string GetTypeName(object comObj)
{
if (comObj == null)
return String.Empty;
if (!Marshal.IsComObject(comObj))
//The specified object is not a COM object
return String.Empty;
IDispatch dispatch = comObj as IDispatch;
if (dispatch == null)
//The specified COM object doesn't support getting type information
return String.Empty;
ComTypes.ITypeInfo typeInfo = null;
try
{
try
{
// obtain the ITypeInfo interface from the object
dispatch.GetTypeInfo(0, 0, out typeInfo);
}
catch (Exception ex)
{
//Cannot get the ITypeInfo interface for the specified COM object
return String.Empty;
}
string typeName = "";
string documentation, helpFile;
int helpContext = -1;
try
{
//retrieves the documentation string for the specified type description
typeInfo.GetDocumentation(-1, out typeName, out documentation,
out helpContext, out helpFile);
}
catch (Exception ex)
{
// Cannot extract ITypeInfo information
return String.Empty;
}
return typeName;
}
catch (Exception ex)
{
// Unexpected error
return String.Empty;
}
finally
{
if (typeInfo != null) Marshal.ReleaseComObject(typeInfo);
}
}
}
/// <summary>
/// Exposes objects, methods and properties to programming tools and other
/// applications that support Automation.
/// </summary>
[ComImport()]
[Guid("00020400-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IDispatch
{
[PreserveSig]
int GetTypeInfoCount(out int Count);
[PreserveSig]
int GetTypeInfo(
[MarshalAs(UnmanagedType.U4)] int iTInfo,
[MarshalAs(UnmanagedType.U4)] int lcid,
out ComTypes.ITypeInfo typeInfo);
[PreserveSig]
int GetIDsOfNames(
ref Guid riid,
[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.LPWStr)]
string[] rgsNames,
int cNames,
int lcid,
[MarshalAs(UnmanagedType.LPArray)] int[] rgDispId);
[PreserveSig]
int Invoke(
int dispIdMember,
ref Guid riid,
uint lcid,
ushort wFlags,
ref ComTypes.DISPPARAMS pDispParams,
out object pVarResult,
ref ComTypes.EXCEPINFO pExcepInfo,
IntPtr[] pArgErr);
}
}