2009-06-24 5 views
38

Возникли вопросы о converting from a SID to an account name; нет другого для другого.Преобразование имени пользователя в строку SID в C# /. NET

Как вы можете преобразовать имя пользователя в строку SID, например, чтобы узнать, какой подраздел HKEY_USERS относится к пользователю с заданным именем?

ответ

76

Подкаст говорит мне, что я должен спросить и ответить на вопросы, когда они уже не отвечают на СО. Вот оно.

Самый простой способ, с .NET 2.0 и выше, заключается в следующем:

NTAccount f = new NTAccount("username"); 
SecurityIdentifier s = (SecurityIdentifier) f.Translate(typeof(SecurityIdentifier)); 
String sidString = s.ToString(); 

Трудный путь, который работает, когда это не будет, и работает на .NET 1.1 также:

[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; 
      } 
     } 
    } 
} 
+1

Я заинтригован, почему я выбрал 'f' как переменную для NTAccount! – crb

+1

", который работает, когда это не будет" ... любые указатели на то, когда простой подход не будет работать, если у меня есть .NET 2.0? – Rory

+0

Не то, чтобы я вспоминаю извинения. Я, вероятно, имел в виду только до 2.0; Я ожидаю, что это сводится к тем же вызовам Win32 API. – crb

1

Нативный метод LookupAccountName() имеет то преимущество, что его можно выполнять на удаленной машине, тогда как методы .NET не могут выполняться удаленно.

Хотя пример не показывает его LookupAccountName(null) < - это удаленная система для выполнения.

0
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); 
     } 
     } 
    } 
}