Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the Windows equivalent of pwd.getpwnam(username).pw_dir?

The Python pwd module provides access to getpwnam(3) POSIX API, which can be used to get the home directory for a particular user by username, as well determining if the username is valid at all. pwd.getpwnam will raise an exception if called with a non-existent username.

At first it seems like the same result can be achieved in a cross-platform manner via os.path.expanduser('~username'). However, it appears that with Python 2.6 on Windows XP this won't actually produce a failure for a non-existent username. Furthermore, on Python 2.5 on Windows XP, it seems to fail even for valid users.

Can this information be obtained reliably on Windows? How?

like image 246
Jean-Paul Calderone Avatar asked Jul 22 '10 04:07

Jean-Paul Calderone


2 Answers

Reading the 2.6 documentation shows that os.path.expanduser() is broken on Windows:

On Windows, HOME and USERPROFILE will be used if set, otherwise a combination of HOMEPATH and HOMEDRIVE will be used. An initial ~user is handled by stripping the last directory component from the created user path derived above.

Say whaat? This assumes all user homes have to be under the same parent directory. Nuh-ugh!

It was a bit hard to dig but here is a solution that will look up a local user by given name:

from win32security import LookupAccountName, ConvertSidToStringSid
from _winreg import OpenKey, QueryValueEx, HKEY_LOCAL_MACHINE

def getUserDir(userName):
    ssid = ConvertSidToStringSid(LookupAccountName(None, userName)[0])
    key = OpenKey(HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\\' + ssid)
    return QueryValueEx(key, 'ProfileImagePath')[0]
like image 124
Nas Banov Avatar answered Oct 14 '22 09:10

Nas Banov


I am new to Windows security... but reading MSDN and some blogs it seems to me that the way MS want us to handle other users specific data is by getting a user token.

There used to be a nice wiki of Keith Brown .Net Developers Guide to Windows Security... you can still find it in Google cache for "pluralsight keith.guidebook"

Case 1: If you don't have the user password:

For local accounts you can try reading the Windows registry as Nas Banov already suggested and there are some other recipes on SO or the Internet.

I am not sure how various Windows versions behaves for freshly create users ... those which have never performed an interactive session login ... does it automatically creates their registry, home folder and profile data? I have done some tests on Windows XP and those registry keys were not present after creating an local account ... but in this case you can try to guess it based in All Users registry values ... or just fail :)

For desktop applications, when the application is running as a logged in user, I am using something like this to get the home folder.... and to get the equivalent of ~/.local I am using CSIDL_APPDATA, for roaming profiles, or just CSIDL_LOCAL_APPDATA.

from win32com.shell import shell, shellcon
# See microsoft references for further CSIDL constants
# http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx
folder_name = shell.SHGetFolderPath(0, shellcon.CSIDL_PROFILE, 0, 0)

Reading Keith Brown article "How To Get A Token For A User" .. you can look for some other ways of getting an user token without a password...

Case 2: If you have the user password:

Reading the MSDN I got the impressing that if I have an user token, I can get its folders by calling something like the code below... but it did not worked for me. (not sure why)

token = win32security.LogonUser(
            username,
            None, # we uses UPN format for username
            password,
            win32security.LOGON32_LOGON_NETWORK,
            win32security.LOGON32_PROVIDER_DEFAULT,
            )
folder_name = shell.SHGetFolderPath(0, shellcon.CSIDL_PROFILE, token, 0)

This is why I ended up with this code...which is far from being perfect due to the fact that it requires username and password.

token = win32security.LogonUser(
            username,
            None, # Here should be the domain ... or just go with default values
            password,
            win32security.LOGON32_LOGON_NETWORK,
            win32security.LOGON32_PROVIDER_DEFAULT,
            )
win32security.ImpersonateLoggedOnUser(token)
folder_name = shell.SHGetFolderPath(0, shellcon.CSIDL_PROFILE, 0, 0)
win32security.RevertToSelf()

This question is somehow related: How to find the real user home directory using python?

like image 39
Adi Roiban Avatar answered Oct 14 '22 07:10

Adi Roiban