Как получить SID для входа в систему в C#
Как получить SID входа в Windows в C# .net? (не SID пользователя, а уникальный новый для каждого сеанса)
3 ответа
Боюсь, вам придется прибегнуть к использованию P/Invoke. Вот пример, как это сделать на pinvoke.net (см. Внизу страницы):
Result = GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenSessionId , TokenInformation , TokenInfLength , out TokenInfLength );
Обратите внимание, что я изменил пример, изменив только одну строку, я заменил TOKEN_INFORMATION_CLASS.TokenUser
с TOKEN_INFORMATION_CLASS.TokenSessionId
что именно то, что вам нужно.
Надеюсь это поможет.
Обновление: вот рабочий (по крайней мере, на моей машине) код:
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
namespace LinqTest
{
public class ClsLookupAccountName
{
public const uint SE_GROUP_LOGON_ID = 0xC0000000; // from winnt.h
public const int TokenGroups = 2; // from TOKEN_INFORMATION_CLASS
enum TOKEN_INFORMATION_CLASS
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin
}
[StructLayout(LayoutKind.Sequential)]
public struct SID_AND_ATTRIBUTES
{
public IntPtr Sid;
public uint Attributes;
}
[StructLayout(LayoutKind.Sequential)]
public struct TOKEN_GROUPS
{
public int GroupCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
public SID_AND_ATTRIBUTES[] Groups;
};
// Using IntPtr for pSID instead of Byte[]
[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool ConvertSidToStringSid(IntPtr pSID, out IntPtr ptrSid);
[DllImport("kernel32.dll")]
static extern IntPtr LocalFree(IntPtr hMem);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool GetTokenInformation(
IntPtr TokenHandle,
TOKEN_INFORMATION_CLASS TokenInformationClass,
IntPtr TokenInformation,
int TokenInformationLength,
out int ReturnLength);
public static string GetLogonId()
{
int TokenInfLength = 0;
// first call gets lenght of TokenInformation
bool Result = GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenGroups, IntPtr.Zero, TokenInfLength, out TokenInfLength);
IntPtr TokenInformation = Marshal.AllocHGlobal(TokenInfLength);
Result = GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenGroups, TokenInformation, TokenInfLength, out TokenInfLength);
if (!Result)
{
Marshal.FreeHGlobal(TokenInformation);
return string.Empty;
}
string retVal = string.Empty;
TOKEN_GROUPS groups = (TOKEN_GROUPS)Marshal.PtrToStructure(TokenInformation, typeof(TOKEN_GROUPS));
int sidAndAttrSize = Marshal.SizeOf(new SID_AND_ATTRIBUTES());
for (int i = 0; i < groups.GroupCount; i++)
{
SID_AND_ATTRIBUTES sidAndAttributes = (SID_AND_ATTRIBUTES)Marshal.PtrToStructure(
new IntPtr(TokenInformation.ToInt64() + i * sidAndAttrSize + IntPtr.Size), typeof(SID_AND_ATTRIBUTES));
if ((sidAndAttributes.Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID)
{
IntPtr pstr = IntPtr.Zero;
ConvertSidToStringSid(sidAndAttributes.Sid, out pstr);
retVal = Marshal.PtrToStringAuto(pstr);
LocalFree(pstr);
break;
}
}
Marshal.FreeHGlobal(TokenInformation);
return retVal;
}
}
}
Примечание: я проверил это на своей машине x64, поэтому, пожалуйста, обратите пристальное внимание на TokenInformation.ToInt64()
кусок кода, может быть, вы должны заменить его TokenInformation.ToInt32()
System.Security.Principal.WindowsIdentity.GetCurrent().User.AccountDomainSid - может сработать?
Я просто потратил много времени на получение SID с помощью TOKEN_USER и так далее, а затем обнаружил ярлык в C#. Вам все еще нужно получить дескриптор процесса (например, https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.process.handle?view=netcore-3.1), а затем токен с P / invoke:
OpenProcessToken(hProcess, TOKEN_READ, out IntPtr hToken))
Но как только у вас есть токен, вам не нужно делать ничего неприятного. GetTokenInformation(hToken, TOKEN_INFORMATION_CLASS.TokenUser...
вещи, которые вы просто используете:
var winId = System.Security.Principal.WindowsIdentity(hToken);
... и BOOM вы можете получить всю необходимую информацию (включая SID) для пользователя из winId.
Не забывай CloseHandle(hToken)
и потом на hProcess!
Я знаю, что это старый пост. Просто столкнулся с этой проблемой, так как мне нужно было получить идентификатор сеанса ICA и идентификатор сеанса RDP, чтобы программа собирала правильные переменные для каждого типа удаленного соединения. Текущий идентификатор сеанса находится в Regedit HKEY_CURRENT_USER\Remote*. Поскольку я не смог найти никаких альтернатив WTS, я публикую здесь свое решение.
// Prints out ICA or RDP session ID of current user
using System;
using Microsoft.Win32;
namespace ViaRegedit
{
class Program03
{
static void Main(string[] args)
{
// Obtain an instance of RegistryKey for the CurrentUser registry
RegistryKey rkCurrentUser = Registry.CurrentUser;
// Obtain the test key (read-only) and display it.
RegistryKey rkTest = rkCurrentUser.OpenSubKey("Remote");
foreach (string valueName in rkTest.GetSubKeyNames())
{
//Getting path to RDP/Citrix session ID
string RDPICApath = "";
if (rkTest.OpenSubKey(valueName) != null && rkTest.OpenSubKey(valueName) != null) { RDPICApath = rkTest.OpenSubKey(valueName).ToString(); }
Console.WriteLine("Getting CurrentUser ICA-RDP path from string = " + RDPICApath);
//Seperating RDPICApath to get session number
string RDPICAnumber = RDPICApath.Substring(RDPICApath.LastIndexOf('\\') + 1);
Console.WriteLine("Current User RDPICAnumber = " + RDPICAnumber);
}
rkTest.Close();
rkCurrentUser.Close();
Console.ReadLine();
}
}
}