Click here to Skip to main content
Click here to Skip to main content

How To Get Process Owner ID and Current User SID

By , 15 Jul 2006
 

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.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalwhen i run the InvokeMethod("GetOwner", object[])o);membercholo12349 Mar '10 - 6:36 
i get the following error:
 
Operation is not valid due to the current state of the object.
 
please help i been tryign to get this to work for a long time. this is my code:
 
ManagementScope scope = new ManagementScope(@"\\" + remMachine +
@"\root\cimv2", connection);
scope.Connect();
 
ObjectQuery sq = new ObjectQuery
("Select Name, ProcessID from Win32_Process Where ProcessID =32588");
 
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope,sq))
{
int number = searcher.Get().Count;
foreach (ManagementObject oReturn in searcher.Get())
{
string name = oReturn["Name"].ToString();
string pid = oReturn["ProcessID"].ToString();
string[] names = new String[2];

oReturn.InvokeMethod("GetOwner", (object[])names);

if (names[0] != null)
{
string Username = names[0];
string domain = names[1];
}
else
{
Console.WriteLine("null");
}
GeneralRe: when i run the InvokeMethod("GetOwner", object[])o); Pinmemberlaxmanchip22 Jul '10 - 8:13 
I am receiving the same error. Did you ever resolve this and, if so, could you post the solution?
 
Thanks!
 
Tom
GeneralRe: when i run the InvokeMethod("GetOwner", object[])o); Pinmemberlaxmanchip22 Jul '10 - 8:37 
I found the solution! I changed my query from "Select Name FROM ...." to "Select * FROM ...."

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

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