Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How To Get Process Owner ID and Current User SID

0.00/5 (No votes)
15 Jul 2006 1  
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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here