Click here to Skip to main content
Licence CPOL
First Posted 15 Jul 2006
Views 126,613
Downloads 1,245
Bookmarked 42 times

How To Get Process Owner ID and Current User SID

By | 15 Jul 2006 | Article
The article explains how to get the process owner ID and current user SID

Introduction

The article explains how to get process owner ID and current user SID. It's useful when you develop Terminal Server applications. There are two main ways to get process owner SID by process ID (PID):

  1. Using Windows Management Instrumentation (WMI). It's the slowest way to get info.
  2. Using the Win32 API.

How To Get Process Owner SID using WMI

The shortest and slowest way to get process owner SID is to use WMI. The code is very simple and there are no comments needed.

public static string GetProcessInfoByPID(int PID, out string User, out string Domain)
{
    User = String.Empty;
    Domain = String.Empty;
    OwnerSID = String.Empty;
    string processname = String.Empty;
    try
    {
        ObjectQuery sq = new ObjectQuery
            ("Select * from Win32_Process Where ProcessID = '" + PID + "'");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(sq);
        if (searcher.Get().Count == 0)
            return OwnerSID;
        foreach (ManagementObject oReturn in searcher.Get())
        {
            string[] o = new String[2];
            //Invoke the method and populate the o var with the user name and domain
            oReturn.InvokeMethod("GetOwner", (object[])o);

            //int pid = (int)oReturn["ProcessID"];
            processname = (string)oReturn["Name"];
            //dr[2] = oReturn["Description"];
            User = o[0];
            if (User == null)
                User = String.Empty;
            Domain = o[1];
            if (Domain == null)
                Domain = String.Empty;
            string[] sid = new String[1];
            oReturn.InvokeMethod("GetOwnerSid", (object[])sid);
            OwnerSID = sid[0];
     return OwnerSID;
        }
    }
    catch
    {
        return OwnerSID;
    }
    return OwnerSID;
}

How To Get Process Owner SID using Win32 API

The Win32 API way is a little bit complicated, but works far better (faster).

public const int TOKEN_QUERY = 0X00000008;

const int ERROR_NO_MORE_ITEMS = 259;

enum TOKEN_INFORMATION_CLASS                           
{
    TokenUser = 1,
    TokenGroups,
    TokenPrivileges,
    TokenOwner,
    TokenPrimaryGroup,
    TokenDefaultDacl,
    TokenSource,
    TokenType,
    TokenImpersonationLevel,
    TokenStatistics,
    TokenRestrictedSids,
    TokenSessionId
}

[DllImport("advapi32")]
static extern bool OpenProcessToken(
    HANDLE ProcessHandle, // handle to process
    int DesiredAccess, // desired access to process
    ref IntPtr TokenHandle // handle to open access token
);

[DllImport("kernel32")]
static extern HANDLE GetCurrentProcess();

[DllImport("advapi32", CharSet = CharSet.Auto)]
static extern bool GetTokenInformation(
    HANDLE hToken,
    TOKEN_INFORMATION_CLASS tokenInfoClass,
    IntPtr TokenInformation,
    int tokeInfoLength,
    ref int reqLength
);

[DllImport("kernel32")]
static extern bool CloseHandle(HANDLE handle);

[DllImport("advapi32", CharSet = CharSet.Auto)]
static extern bool ConvertSidToStringSid(
    IntPtr pSID,
    [In, Out, MarshalAs(UnmanagedType.LPTStr)] ref string pStringSid
);

[DllImport("advapi32", CharSet = CharSet.Auto)]
static extern bool ConvertStringSidToSid(
    [In, MarshalAs(UnmanagedType.LPTStr)] string pStringSid,
    ref IntPtr pSID
);

/// <summary>
/// Collect User Info
/// </summary>
/// <param name="pToken">Process Handle</param>
public static bool DumpUserInfo(HANDLE pToken, out IntPtr SID)
{
    int Access = TOKEN_QUERY;
    HANDLE procToken = IntPtr.Zero;
    bool ret = false;
    SID = IntPtr.Zero;
    try
    {
        if (OpenProcessToken(pToken, Access, ref procToken))
        {
            ret = ProcessTokenToSid(procToken, out SID);
            CloseHandle(procToken);
        }
        return ret;
    }
    catch (Exception err)
    {
        return false;
    }
}

private static bool ProcessTokenToSid(HANDLE token, out IntPtr SID)
{
    TOKEN_USER tokUser;
    const int bufLength = 256;            
    IntPtr tu = Marshal.AllocHGlobal(bufLength);
    bool ret = false;
    SID = IntPtr.Zero;
    try
    {
        int cb = bufLength;
        ret = GetTokenInformation(token, 
                TOKEN_INFORMATION_CLASS.TokenUser, tu, cb, ref cb)
        if (ret)
        {
            tokUser = (TOKEN_USER)Marshal.PtrToStructure(tu, typeof(TOKEN_USER));
            SID = tokUser.User.Sid;
        }
        return ret;
    }
    catch (Exception err)
    {
        return false;
    }
    finally
    {
        Marshal.FreeHGlobal(tu);
    }
}

public static string ExGetProcessInfoByPID
    (int PID, out string SID)//, out string OwnerSID)
{                                                                  
    IntPtr _SID = IntPtr.Zero;                                       
    SID = String.Empty;                                             
    try                                                             
    {                                                                
        Process process = Process.GetProcessById(PID);
        if (DumpUserInfo(process.Handle, out _SID))
        {                                                                    
            ConvertSidToStringSid(_SID, ref SID);
        }
        return process.ProcessName;                                          
    }                                                                           
    catch
    {                                                                           
        return "Unknown";
    }
}

How To Get Current User SID

How to use information about owner SID? Imagine a simple situation when you should show a list of current user processes. This is a typical thing when you develop some application to use on the Terminal Server, where a lot of users work with applications with the same name.

private WindowsIdentity _user = WindowsIdentity.GetCurrent();

...

public bool IsCurrentUserProcess(int ProcessID)
{
    string stringSID = String.Empty;
    string process = Utils.ExGetProcessInfoByPID(ProcessID, out stringSID);
    return String.Compare(stringSID, this._user.User.Value, true) == 0);
}

Conclusion

This is just a small sample of what WMI could do. Unfortunately WMI works quite slowly, so for now, there isn't a faster way to get the needed info than using the Win32 API.

References

History

  • 16th July, 2006: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Warlib

Web Developer

Russian Federation Russian Federation

Member

I am a CIO in Nizhny Novgorod, Russia.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
SuggestionC++ sample PinmemberJeest3:38 29 Sep '11  
GeneralRe: C++ sample ( other similar code) Pinmemberdmihailescu7:52 24 Jan '12  
GeneralMy vote of 3 PinmemberAndromeda Shun2:45 16 Sep '11  
QuestionGet Process Name (process info) of Active Window PinmemberAli Taghvajou8:53 31 Mar '11  
General[My vote of 1] Copied code HANDLE SID [modified] PinmemberChuck141111:14 7 Sep '10  
Generalwhen i run the InvokeMethod("GetOwner", object[])o); Pinmembercholo12346:36 9 Mar '10  
GeneralRe: when i run the InvokeMethod("GetOwner", object[])o); Pinmemberlaxmanchip8:13 22 Jul '10  
GeneralRe: when i run the InvokeMethod("GetOwner", object[])o); Pinmemberlaxmanchip8:37 22 Jul '10  
GeneralAn alternate method Pinmemberefwb0018:37 6 Nov '09  
GeneralNone of them works PinmemberMember 33345067:13 8 Mar '09  
GeneralRe: None of them works Pinmembersubsrisk3:11 6 Sep '09  
QuestionHANDLE?? Pinmembertfwarlord13:10 18 Dec '08  
AnswerRe: HANDLE?? Pinmemberbergdoktor4:04 25 Mar '09  
GeneralVB.net 2005 Translation Pinmemberrerb3:57 11 Jun '07  
I am a VB.net coder and need help translating the API version. Any help would be greatly appreciated.
GeneralRe: VB.net 2005 Translation Pinmemberrerb7:00 11 Jun '07  
GeneralClever PinmemberJared Hill16:21 26 Mar '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120529.1 | Last Updated 16 Jul 2006
Article Copyright 2006 by Warlib
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid