tags:

views:

560

answers:

2

Hi,

How does one retrieve the Windows Logon SID in c# .net? (not the user sid, but the unique new one for each session).

Thanks in advance,

+1  A: 

System.Security.Principal.WindowsIdentity.GetCurrent().User.AccountDomainSid - might do the trick?

SilverSkin
It is *not* the Logon Session ID SilverSkin asked about
Igor Korkhov
I think the user SID remains unchanged between sessions, but for each login a token is created, it should be possible to access this via ...GetCurrent().User.Token ?
SilverSkin
The token is indeed what I need, but I have to convert to a usable SID.
Jos
What do you need it for? Impersonation and other things should be available through the token.
SilverSkin
I have an external application that creates a named pipe with the Logon UID in it. Without it, I can't determine the name of the pipe.
Jos
A: 

I'm afraid you have to resort to using P/Invoke. There's an example how to do it at pinvoke.net (please see the bottom of the page):

Result = GetTokenInformation(WindowsIdentity.GetCurrent().Token, TOKEN_INFORMATION_CLASS.TokenSessionId , TokenInformation , TokenInfLength , out TokenInfLength );

Please note that I changed the example by altering just one line, I replaced TOKEN_INFORMATION_CLASS.TokenUser with TOKEN_INFORMATION_CLASS.TokenSessionId which is exactly what you need.

Hope this helps.

Update: Here's the working (at least on my machine) code:

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

N.B. I tested it on my x64 machine, so please pay close attention on TokenInformation.ToInt64() piece of code, maybe you should replace it with TokenInformation.ToInt32()

Igor Korkhov
Doesn't work unfortunately. It returns nothing. According to this (http://msdn.microsoft.com/en-us/library/aa379626%28VS.85%29.aspx), it only works on terminal server, so it might not be the session id I need.
Jos
I added another version of the code, it works on my machine. Please feel free to ask me if something is not clear.
Igor Korkhov
Thanks! This one works perfectly. I used TokenLogonSid instead of TokenGroups, but that only works for Windows Vista and 7.
Jos