Convertir un nombre de usuario a una cadena SID en C#/.NET
windows identity (3)
Hay una pregunta sobre la conversión de un SID a un nombre de cuenta ; No hay uno para el otro lado.
¿Cómo convertir un nombre de usuario a una cadena SID, por ejemplo, para averiguar qué subclave HKEY_USERS se relaciona con un usuario de un nombre dado?
El método nativo LookupAccountName()
tiene la ventaja de poder ejecutarse en una máquina remota, mientras que los métodos .NET no pueden ejecutarse de forma remota.
Aunque el ejemplo no lo muestra LookupAccountName(null)
<- este es el sistema remoto para ejecutar.
El podcast me dice que debo hacer y contestar preguntas cuando aún no están respondidas en SO. Aquí va.
La forma fácil, con .NET 2.0 y superior, es la siguiente:
NTAccount f = new NTAccount("username");
SecurityIdentifier s = (SecurityIdentifier) f.Translate(typeof(SecurityIdentifier));
String sidString = s.ToString();
La forma más difícil, que funciona cuando eso no funciona, y funciona en .NET 1.1 también:
[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);
/// <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;
}
}
}
}
using System;
using System.Management;
using System.Windows.Forms;
namespace WMISample
{
public class MyWMIQuery
{
public static void Main()
{
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root//CIMV2",
"SELECT * FROM Win32_UserAccount where name=''Galia''");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("-----------------------------------");
Console.WriteLine("Win32_UserAccount instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("Name: {0}", queryObj["Name"]);
Console.WriteLine("SID: {0}", queryObj["SID"]);
}
}
catch (ManagementException e)
{
MessageBox.Show("An error occurred while querying for WMI
data: " + e.Message);
}
}
}
}