tigerneil / psutil

Automatically exported from code.google.com/p/psutil
Other
0 stars 0 forks source link

Process username / groupname #14

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Per conversation with Jay this should be scheduled for 0.1.1 release.
The real effort is the Windows implementation since on OS X and Linux pwd
module already does the work for us.

Original issue reported on code.google.com by billiej...@gmail.com on 18 Feb 2009 at 2:38

GoogleCodeExporter commented 9 years ago

Original comment by billiej...@gmail.com on 18 Feb 2009 at 2:43

GoogleCodeExporter commented 9 years ago

Original comment by billiej...@gmail.com on 23 Feb 2009 at 5:49

GoogleCodeExporter commented 9 years ago
Any progress on this front? Yan was working on a patch I think, so if that's 
the case
I don't want to implement it on Windows myself. 

We should implement this on the UNIX side at least. My suggestion is we use pwd
module to create username and groupname properties. The properties should check 
if
the platform module has a get_username() / get_groupname() attribute, and if so 
use
that. Otherwise, look for pwd module and use that to translate the UID/GID to 
names.
If neither, raise NotImplemented exceptions.

Original comment by jlo...@gmail.com on 1 Mar 2009 at 6:56

GoogleCodeExporter commented 9 years ago
I know that Yan wrote some code but that's all.
I'll try to contact him tomorrow and let you know something more.
I could take care of the UNIX part.

Original comment by billiej...@gmail.com on 2 Mar 2009 at 12:45

GoogleCodeExporter commented 9 years ago
Implemented on Linux as r199.

Original comment by billiej...@gmail.com on 2 Mar 2009 at 11:43

GoogleCodeExporter commented 9 years ago
Implemented on FreeBSD and OS X as r200 and r201.

Original comment by billiej...@gmail.com on 2 Mar 2009 at 12:50

GoogleCodeExporter commented 9 years ago
Postponed.

Original comment by billiej...@gmail.com on 7 Mar 2009 at 3:23

GoogleCodeExporter commented 9 years ago
Determining the owner of a process is not trivial on Microsoft Windows. Search 
the 
Internet and you will see how many headaches to programmers are caused by this. 
I 
have identified several ways to accomplish the task, each of them has pros and 
cons.

--------------

The first solution I have investigated involves OpenProcessToken and 
GetTokenInformation to retrieve user's and group's SIDs.
This would be the best and most reliable way to get the information we need.
The main  issue is that, even using an administrative account, it is not 
possible to 
open the token of a process not belonging to the calling user.
The only way to succeed would be to call OpenProcessToken from the SYSTEM 
account 
(tested with Sysinternal's utility psexec).
Unluckily no API calls are provided to promote execution to local system.
Two methods are possible to solve the problem:

1) Use a service. Services usually run within the SYSTEM account.
We have to create and install the service, make it collect the data, create a 
pipe 
to pass information to the main program, stop the service, uninstall it... It 
is not 
a minor programming effort and I am not sure it is worth trying... just to get 
a 
username...

2) Use a driver. This solution, quite effective, goes far beyond my knowledge...

--------------

The second way to get the process owner takes advantage of 
WTSEnumerateProcesses.
The solution is the simplest I have found, but requires TermService service to 
be up 
and running.
On Microsoft Windows 2000 professional, Terminal Services isn't even installed 
by 
default.
I don't think we should rely on the presence of a component that can be easily 
stopped or disabled.

-------------

The third solution is the one I chose. In my opinion it is a good mix of 
simplicity 
and reliability.

The code uses GetKernelObjectSecurity to obtain the process security descriptor 
and 
GetSecurityDescriptorOwner to extract the user's SID.
The program works from any administrative account.
During my tests I only run into a couple of minor problems:

- SYSTEM's processes are mysteriously reported as owned by 
BULTIN\Administrators 
(it's a group!). The adopted workaround was filtering the response and 
replacing it 
with the correct NT AUTHORITY\SYSTEM owner.

- The owner of avp.exe process (belonging to my Kaspersky antivirus) could not 
be 
resolved. This AV has kernel self protection that prevents other processes to 
get 
inner details. I think we can safely skip this problem, the program will report 
no 
owner.

BTW, the first solution proposed is not affected by any of these limitations if 
launched within the SYSTEM account.

MS Windows gives no way to get the local group list bound to the security 
descriptor 
of a process. I solved the problem searching directly for the group membership 
of 
the process owner user. I identified four well known local groups we could be 
interested in (Administrators, Power users, Users and Guests).
Using NetUserGetLocalGroups it is possible to enumerate all the groups a user 
belongs to. The most powerful well known group is returned. Most system users 
(system, local service, network service...) are reported with no group 
membership.

Visual studio express 2008 project for the third solution is provided as an 
attachment.

If you compile the code from a new project, don't forget to add Netapi32.lib to 
your 
linker option.

Original comment by yanra...@gmail.com on 11 Mar 2009 at 5:43

Attachments:

GoogleCodeExporter commented 9 years ago
Yan this sounds great, I would definitely agree this is the best solution to go 
with
based on my research so far. I'm surprised OpenProcessToken() fails for all 
processes
not owned by the calling user, but at least the GetKernelObjectSecurity() method
allows us to read more data. I'll take a look at this in the next couple of 
days and
we'll decide whether we want to go ahead and include username / groupname in the
0.1.2 release or wait for another release.

Thanks!

Original comment by jlo...@gmail.com on 12 Mar 2009 at 5:43

GoogleCodeExporter commented 9 years ago

Original comment by billiej...@gmail.com on 17 Mar 2009 at 4:19

GoogleCodeExporter commented 9 years ago
Now that we implemented cpu and memory information on all platforms I think we 
should
focus on cleaning up the current code, stabilize what we've done so far (tests,
etc...), release 0.1.2 and postpone this one for 0.1.3 or 0.2.0.

Original comment by billiej...@gmail.com on 21 Mar 2009 at 9:07

GoogleCodeExporter commented 9 years ago

Original comment by billiej...@gmail.com on 7 May 2009 at 3:12

GoogleCodeExporter commented 9 years ago
Implemented Windows username functionality as r383.

Original comment by billiej...@gmail.com on 9 May 2009 at 12:02

GoogleCodeExporter commented 9 years ago
Are we done with this issue, or are we still waiting on groupname functionality 
for
Windows? Is that even possible really since Windows doesn't have group 
ownership for
processes?

Original comment by jlo...@gmail.com on 14 Jul 2009 at 1:21

GoogleCodeExporter commented 9 years ago
Implemented Process groupname on Windows [Rev 418]
Needs testing on Windows 2000 and Windows Vista

Original comment by yanra...@gmail.com on 22 Jul 2009 at 10:51

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Could you please update the current groupname docstring (__init__.py) 
describing its
behavior on Windows (e.g. in case of multiple groups for the same process the 
most
powerful one is returned, etc.)?

Original comment by billiej...@gmail.com on 25 Jul 2009 at 12:14

GoogleCodeExporter commented 9 years ago

Original comment by billiej...@gmail.com on 17 Sep 2009 at 8:55

GoogleCodeExporter commented 9 years ago

Original comment by billiej...@gmail.com on 17 Sep 2009 at 8:57

GoogleCodeExporter commented 9 years ago
Now that username code is fixed and groupname raises an exception as it was 
supposed
to do since day one I have a clearer point about the groupname functionnality 
on Windows.

groupname on Windows in summary:

- it works only for processes owned by the current user.

- for all other processes a WindowsError exception is raised (before the error
checking an ampty string was returned).

- if the user belongs to a group incuded in (administrators, power users, users,
guests) the most powerful one is returned. 

- the other groups the user belongs to are omitted (on Windows a single user 
belongs
to different groups - this can be easily observed with procexp utility).

Here is a script which shows how the functionnality "looks" right now:

<snippet>
for proc in psutil.process_iter():
    try:
        print proc.groupname
    except:
        print "Error: pid=%s, username=%s" %(proc.pid, proc.username)
</snippet>

The output:

<snippet>
Error: pid=0, username=NT AUTHORITY\SYSTEM
Error: pid=4, username=NT AUTHORITY\SYSTEM
Error: pid=256, username=NT AUTHORITY\SYSTEM
Error: pid=348, username=NT AUTHORITY\SYSTEM
Error: pid=408, username=NT AUTHORITY\SYSTEM
Error: pid=432, username=NT AUTHORITY\SYSTEM
Error: pid=456, username=NT AUTHORITY\SYSTEM
Error: pid=480, username=NT AUTHORITY\SYSTEM
Error: pid=488, username=NT AUTHORITY\SYSTEM
Error: pid=548, username=NT AUTHORITY\SYSTEM
Error: pid=628, username=NT AUTHORITY\SYSTEM
Error: pid=688, username=NT AUTHORITY\SYSTEM
Error: pid=728, username=NT AUTHORITY\NETWORK SERVICE
Error: pid=800, username=NT AUTHORITY\LOCAL SERVICE
Error: pid=860, username=NT AUTHORITY\SYSTEM
Error: pid=888, username=NT AUTHORITY\SYSTEM
Error: pid=268, username=NT AUTHORITY\LOCAL SERVICE
Error: pid=644, username=NT AUTHORITY\NETWORK SERVICE
Error: pid=1096, username=NT AUTHORITY\LOCAL SERVICE
Error: pid=1216, username=NT AUTHORITY\SYSTEM
Error: pid=1476, username=NT AUTHORITY\SYSTEM
Error: pid=1520, username=NT AUTHORITY\SYSTEM
Error: pid=1556, username=NT AUTHORITY\SYSTEM
Error: pid=1588, username=NT AUTHORITY\LOCAL SERVICE
Error: pid=1620, username=NT AUTHORITY\SYSTEM
Error: pid=1648, username=NT AUTHORITY\SYSTEM
Error: pid=1392, username=NT AUTHORITY\SYSTEM
Error: pid=1800, username=NT AUTHORITY\SYSTEM
Error: pid=464, username=NT AUTHORITY\NETWORK SERVICE
Error: pid=516, username=NT AUTHORITY\SYSTEM
Administrators
Administrators
Administrators
Administrators
Administrators
Administrators
Administrators
Error: pid=3064, username=NT AUTHORITY\LOCAL SERVICE
Administrators
Administrators
Error: pid=952, username=NT AUTHORITY\LOCAL SERVICE
Administrators
Administrators
Administrators
Administrators
</snippet>

For all these reasons I think that we should just remove groupname support for 
Windows.
As for the UNIX platform support I think it doesn't make sense to preserve it 
as well
for 3 reasons:

- I don't like to support only 3 platforms out of 4.

- despite on Unix a user belongs only to a single group the groupname is 
something
which is not strictly related to processes, in fact utilities like ps, top, etc
dont't include the groupname in their results.

- If for some reason the user wants to know the user groupname he can use the 
grp
module resulting in a single line of python code:
>>> grp.getgrgid(gid).gr_name

I'd like some comments to decide what to do.

Original comment by billiej...@gmail.com on 17 Feb 2010 at 7:41

GoogleCodeExporter commented 9 years ago
I have no problem with removing it for now, we can always add the code back in 
at a
later date if someone requests it. I can't really imagine a need for groupname 
but
you never know, maybe someday someone will come up with a reason!

Original comment by jlo...@gmail.com on 17 Feb 2010 at 7:43

GoogleCodeExporter commented 9 years ago
Remove groupname code as r496.

Original comment by billiej...@gmail.com on 17 Feb 2010 at 9:00

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Updated csets after the SVN -> Mercurial migration:
r199 == revision 01f6ebfc172f
r200 == revision 5f247ca6869b
r383 == revision e2629514408f
r496 == revision d31f827d679d

Original comment by g.rodola on 2 Mar 2013 at 11:39