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):
- Using Windows Management Instrumentation (WMI). It's the slowest way to get info.
- 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];
oReturn.InvokeMethod("GetOwner", (object[])o);
processname = (string)oReturn["Name"];
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,
int DesiredAccess,
ref IntPtr TokenHandle
);
[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
);
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)
{
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