Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a Unique ID for the current user's logon session in windows - c#

Tags:

c#

.net

windows

I need to get a value that uniquely identifies the current windows user's logon session. This is for a winforms app, not ASP.NET. I'll be retrieving this from within multiple processes so it needs to return the same value when retrieved within the same logon session. It only needs to be unique on the current machine for the duration of all user sessions - e.g. until the machine is next restarted.

I think the Windows Logon Id is the right thing, but seems a bit of a pain to retrieve. Is there anything else or any easier way to get this?

I'll be using the ID to include in an address of a named pipes service to communicate between two processes running on the machine. I want to include the Logon Id to avoid conflicts when there are multiple users logged in, including perhaps multiple sessions of the same user.

like image 668
Rory Avatar asked May 19 '11 15:05

Rory


People also ask

Can session ID be reused?

By default, ASP.NET allows you to reuse a session identifier. For example, if you make a request and your query string contains an expired session, ASP.NET creates a new session and uses that session ID.

What is Session ID 0x3e7?

The Windows logon ID (not user ID) 0x3e7 (not 0xe37) is a hardcoded LUID that represents the local system itself, i.e. all services running as "SYSTEM". For AD-joined machines, this logon ID has access to the machine's AD computer account.

Is ASP.NET session ID unique?

The SessionID property is used to uniquely identify a browser with session data on the server. The SessionID value is randomly generated by ASP.NET and stored in a non-expiring session cookie in the browser. The SessionID value is then sent in a cookie with each request to the ASP.NET application.

How do I get the current username in .NET using C#?

GetCurrent(). Name; Returns: NetworkName\Username. Gets the user's Windows logon name.


2 Answers

The easiest way to get Session Id is to look at Process.SessionId property:

System.Diagnostics.Process.GetCurrentProcess().SessionId

The value is the same as returned by GetTokenInformation(...,TokenSessionId,...).

Note: One thing you should keep in mind is that Session Id is not a Logon Id. For example, on Win7 elevated process launched under the same user in the same session will have different LogonId (copmaring to non-elevated one), but will have the same SessionId. Even runniung non-elevated process with RunAs explicitly specifying credentials of the same user will create new Logon Sesison Id. Such behavior has meaning, for example, when you map network drives. Since Vista, a process with one token LogonId will not see network dirves mapped with another LogonId, even if processes are running in the same session and under same user.

Below is the sample app that you can launch on different sessions/creds to see the difference:

using System;
using System.Runtime.InteropServices;

namespace GetCurrentSessionId
{
    class Program
    {

        enum TokenInformationClass
        {
            TokenUser = 1,
            TokenGroups,
            TokenPrivileges,
            TokenOwner,
            TokenPrimaryGroup,
            TokenDefaultDacl,
            TokenSource,
            TokenType,
            TokenImpersonationLevel,
            TokenStatistics,
            TokenRestrictedSids,
            TokenSessionId,
            TokenGroupsAndPrivileges,
            TokenSessionReference,
            TokenSandBoxInert,
            TokenAuditPolicy,
            TokenOrigin
        }

        enum TokenType
        {
            TokenPrimary = 1, 
            TokenImpersonation
        }

        enum SecurityImpersonationLevel 
        { 
            SecurityAnonymous,
            SecurityIdentification,
            SecurityImpersonation,
            SecurityDelegation
        }

        [StructLayout(LayoutKind.Sequential)]
        struct TokenStatistics
        {
            public Int64 TokenId;
            public Int64 AuthenticationId;
            public Int64 ExpirationTime;
            public TokenType TokenType;
            public SecurityImpersonationLevel ImpersonationLevel;
            public Int32 DynamicCharged;
            public Int32 DynamicAvailable;
            public Int32 GroupCount;
            public Int32 PrivilegeCount;
            public Int64 ModifiedId;
        }

        struct TokenOrigin
        {
            public Int64 OriginatingLogonSession;
        }

        [DllImport("advapi32.dll", EntryPoint = "GetTokenInformation", SetLastError = true)]
        static extern bool GetTokenInformation(
            IntPtr tokenHandle,
            TokenInformationClass tokenInformationClass,
            IntPtr tokenInformation,
            int tokenInformationLength,
            out int ReturnLength);

        public const int ERROR_INSUFFICIENT_BUFFER = 0x7a;

        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Session Id: {0}", System.Diagnostics.Process.GetCurrentProcess().SessionId);

                IntPtr tokenInfo;
                bool result;
                int infoSize;

                IntPtr hToken = System.Security.Principal.WindowsIdentity.GetCurrent().Token;

                result = GetTokenInformation(hToken, TokenInformationClass.TokenStatistics, IntPtr.Zero, 0, out infoSize);
                if (!result && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
                {
                    tokenInfo = Marshal.AllocHGlobal(infoSize);
                    result = GetTokenInformation(hToken, TokenInformationClass.TokenStatistics, tokenInfo, infoSize, out infoSize);
                    if (result)
                    {
                        TokenStatistics tokenStats = (TokenStatistics)Marshal.PtrToStructure(tokenInfo, typeof(TokenStatistics));
                        Console.WriteLine("LogonId: 0x{0:X16}", tokenStats.AuthenticationId);
                    }
                    else
                    {
                        Console.Error.WriteLine("LogonId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
                    }
                    Marshal.FreeHGlobal(tokenInfo);
                }
                else
                {
                    Console.Error.WriteLine("LogonId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
                }


                tokenInfo = Marshal.AllocHGlobal(sizeof (Int32));
                result = GetTokenInformation(hToken, TokenInformationClass.TokenSessionId, tokenInfo, sizeof (Int32), out infoSize);
                if (result)
                {
                    int tokenSessionId = Marshal.ReadInt32(tokenInfo);
                    Console.WriteLine("TokenSessionId: {0}", tokenSessionId);
                }
                else
                {
                    Console.Error.WriteLine("TokenSessionId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
                }

                Marshal.FreeHGlobal(tokenInfo);


                result = GetTokenInformation(hToken, TokenInformationClass.TokenOrigin, IntPtr.Zero, 0, out infoSize);
                if (!result && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER)
                {
                    tokenInfo = Marshal.AllocHGlobal(infoSize);
                    result = GetTokenInformation(hToken, TokenInformationClass.TokenOrigin, tokenInfo, infoSize, out infoSize);
                    if (result)
                    {
                        TokenOrigin tokenOrigin = (TokenOrigin) Marshal.PtrToStructure(tokenInfo, typeof (TokenOrigin));
                        Console.WriteLine("OriginatingSessionId: 0x{0:X16}", tokenOrigin.OriginatingLogonSession);
                    }
                    else
                    {
                        Console.WriteLine("OriginatingSessionId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
                    }
                    Marshal.FreeHGlobal(tokenInfo);
                }
                else
                {
                    Console.WriteLine("OriginatingSessionId: FAILED with 0x{0:X08}", Marshal.GetLastWin32Error());
                }

                Console.WriteLine("Press any key...");
                Console.ReadKey();

            }
            catch (Exception ex)
            {
                Console.Error.WriteLine("Unexpected error: {0}", ex);
                Console.ReadKey();
            }
        }
    }
}
like image 180
mistika Avatar answered Sep 28 '22 20:09

mistika


As I understand, what you need is this:

SID: S-1-5-5-X-Y Name: Logon Session Description: A logon session. The X and Y values for these SIDs are different for each session.

Well-known security identifiers in Windows operating systems http://support.microsoft.com/kb/243330

Somebody asked for something similar here:

How to get the logon SID in C#

They have a good answer there, but I want to add my own

This is my solution:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace TestLogonSid
{
    public partial class Form1 : Form
    {

        private delegate bool EnumDesktopProc(string lpszDesktop, IntPtr lParam);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click_1(object sender, EventArgs e)
        {

            this.textBox1.Text = GetLogonSid.getLogonSid();
        }


    }

    public class GetLogonSid
    {
        //The SID structure that identifies the user that is currently associated with the specified object. 
        //If no user is associated with the object, the value returned in the buffer pointed to by lpnLengthNeeded is zero. 
        //Note that SID is a variable length structure. 
        //You will usually make a call to GetUserObjectInformation to determine the length of the SID before retrieving its value.
        private const int UOI_USER_SID = 4;

        //GetUserObjectInformation function
        //Retrieves information about the specified window station or desktop object.
        [DllImport("user32.dll")]
        static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, [MarshalAs(UnmanagedType.LPArray)] byte[] pvInfo, int nLength, out uint lpnLengthNeeded);


        //GetThreadDesktop function
        //Retrieves a handle to the desktop assigned to the specified thread.
        [DllImport("user32.dll")]
        private static extern IntPtr GetThreadDesktop(int dwThreadId);


        //GetCurrentThreadId function
        //Retrieves the thread identifier of the calling thread.
        [DllImport("kernel32.dll")]
        public static extern int GetCurrentThreadId();

        //ConvertSidToStringSid function
        //The ConvertSidToStringSid function converts a security identifier (SID) to a string format suitable for display, storage, or transmission.
        //To convert the string-format SID back to a valid, functional SID, call the ConvertStringSidToSid function.

        [DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
        static extern bool ConvertSidToStringSid(
            [MarshalAs(UnmanagedType.LPArray)] byte[] pSID,
            out IntPtr ptrSid);


        /// <summary>
        /// The getLogonSid function returns the Logon Session string
        /// </summary>
        /// <returns></returns>
        public static string getLogonSid()
        {
            string sidString = "";
            IntPtr hdesk = GetThreadDesktop(GetCurrentThreadId());
            byte[] buf = new byte[100];
            uint lengthNeeded;
            GetUserObjectInformation(hdesk, UOI_USER_SID, buf, 100, out lengthNeeded);
            IntPtr ptrSid;
            if (!ConvertSidToStringSid(buf, out ptrSid))
                throw new System.ComponentModel.Win32Exception();
            try
            {
                sidString = Marshal.PtrToStringAuto(ptrSid);
            }
            catch
            {
            }
            return sidString;
        }

    }
}
like image 31
ccarmona1981 Avatar answered Sep 28 '22 20:09

ccarmona1981