Message390535
> 3. Worth fixing in `ntpath.expanduser()`
To expand on the suggestion in msg390507, here's a demo that implements getting the profile path of a local user account, with support for the special profile directories "Default", "Public", and "ProgramData" (i.e. ALLUSERSPROFILE).
ERROR_NONE_MAPPED = 1332
def get_profile_path(name):
if not isinstance(name, str):
raise TypeError(f'name must be str, not {type(name).__name__}')
profile_list = r'Software\Microsoft\Windows NT\CurrentVersion\ProfileList'
if name.lower() in ('default', 'public', 'programdata'):
subkey = profile_list
value = name
else:
try:
sid = lookup_account_name(name)[0]
except OSError as e:
if e.winerror != ERROR_NONE_MAPPED:
raise
raise KeyError(f'name not found: {name}')
subkey = f'{profile_list}\\{sid}'
value = 'ProfileImagePath'
try:
with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, subkey) as hkey:
path, dtype = winreg.QueryValueEx(hkey, value)
except FileNotFoundError:
raise KeyError(f'name not found: {name}')
if dtype == winreg.REG_SZ:
return path
if dtype == winreg.REG_EXPAND_SZ:
return winreg.ExpandEnvironmentStrings(path)
raise TypeError('profile path value must be a string type (1 or 2), '
f'not {dtype}')
For example:
>>> print(get_profile_path('administrator'))
C:\Users\Administrator
>>> print(get_profile_path('default'))
C:\Users\Default
>>> print(get_profile_path('public'))
C:\Users\Public
>>> print(get_profile_path('programdata'))
C:\ProgramData
>>> print(get_profile_path('system'))
C:\Windows\system32\config\systemprofile
>>> print(get_profile_path('localservice'))
C:\Windows\ServiceProfiles\LocalService
>>> print(get_profile_path('networkservice'))
C:\Windows\ServiceProfiles\NetworkService
For lookup_account_name(), _winapi.LookupAccountName(system_name, account_name) has to be implemented. It should convert the SID result to string form via ConvertSidToStringSidW() and return the tuple (sid_string, domain_name, account_type). Here's a ctypes prototype implementation of lookup_account_name():
import ctypes
lsalookup = ctypes.WinDLL(
'api-ms-win-security-lsalookup-l2-1-0', use_last_error=True)
sddl = ctypes.WinDLL('api-ms-win-security-sddl-l1-1-0', use_last_error=True)
heap = ctypes.WinDLL('api-ms-win-core-heap-l2-1-0', use_last_error=True)
ERROR_INSUFFICIENT_BUFFER = 122
def lookup_account_name(name):
sid = (ctypes.c_char * 1)()
cb = ctypes.c_ulong()
cch = ctypes.c_ulong()
name_use = ctypes.c_ulong()
lsalookup.LookupAccountNameW(None, name, sid, ctypes.byref(cb),
None, ctypes.byref(cch), ctypes.byref(name_use))
error = ctypes.get_last_error()
if error != ERROR_INSUFFICIENT_BUFFER:
raise ctypes.WinError(error)
sid = (ctypes.c_char * cb.value)()
domain_name = (ctypes.c_wchar * cch.value)()
success = lsalookup.LookupAccountNameW(None, name, sid,
ctypes.byref(cb), domain_name, ctypes.byref(cch),
ctypes.byref(name_use))
if not success:
raise ctypes.WinError(ctypes.get_last_error())
ssid = ctypes.c_wchar_p()
if not sddl.ConvertSidToStringSidW(sid, ctypes.byref(ssid)):
raise ctypes.WinError(ctypes.get_last_error())
string_sid = ssid.value
heap.LocalFree(ssid)
return string_sid, domain_name.value, name_use.value |
|
Date |
User |
Action |
Args |
2021-04-08 15:50:33 | eryksun | set | recipients:
+ eryksun, serhiy.storchaka, barneygale |
2021-04-08 15:50:33 | eryksun | set | messageid: <1617897033.63.0.0234053907199.issue42998@roundup.psfhosted.org> |
2021-04-08 15:50:33 | eryksun | link | issue42998 messages |
2021-04-08 15:50:33 | eryksun | create | |
|