Issue46631
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2022-02-04 05:55 by eryksun, last changed 2022-04-11 14:59 by admin.
Messages (2) | |||
---|---|---|---|
msg412495 - (view) | Author: Eryk Sun (eryksun) * | Date: 2022-02-04 05:55 | |
getpass.getuser() checks the environment variables LOGNAME (login name), USER, LNAME, and USERNAME, in that order. In Windows, LOGNAME, USER, and LNAME have no conventional usage. I think there should be a strict mode that restricts getuser() to check only USERNAME in Windows and only LOGNAME in POSIX [1]. If the login variable isn't defined, it should fall back on using the system API, based on the user ID in POSIX and the logon ID in Windows. For the fallback in Windows, the _winapi module could implement GetCurrentProcessToken(), GetTokenInformation(), and LsaGetLogonSessionData(). For TokenStatistics, return a dict with just "AuthenticationId". For LsaGetLogonSessionData(), return a dict with just "UserName". GetCurrentProcessToken() returns a pseudohandle (-4), which should not be closed. For example, assuming _winapi wraps the required functions: def getuser(strict=False): """Get the username from the environment or password database. First try various environment variables. If strict, check only LOGNAME in POSIX and only USERNAME in Windows. As a fallback, in POSIX get the user name from the password database, and in Windows get the user name from the logon-session data of the current process. """ posix = sys.platform != 'win32' if strict: names = ('LOGNAME',) if posix else ('USERNAME',) else: names = ('LOGNAME', 'USER', 'LNAME', 'USERNAME') for name in names: if user := os.environ.get(name): return user if posix: import pwd return pwd.getpwuid(os.getuid())[0] import _winapi logon_id = _winapi.GetTokenInformation( _winapi.GetCurrentProcessToken(), _winapi.TokenStatistics)['AuthenticationId'] return _winapi.LsaGetLogonSessionData(logon_id)['UserName'] Like WinAPI GetUserNameW(), the above fallback returns the logon user name instead of the account name of the token user. As far as I know, the user name and the account name only differ for the builtin service account logons "SYSTEM" (999) and "NETWORK SERVICE" (996), for which the user name is the machine security principal (i.e. the machine's NETBIOS name plus "$"). The user name of the builtin "LOCAL SERVICE" logon (997), on the other hand, is just the "LOCAL SERVICE" account name, since this account lacks network access. Unlike GetUserNameW(), the above code uses the process token instead of the effective token. This is like POSIX getuid(), whereas what GetUserNameW() does is like geteuid(). getuser() could implement an `effective` option to return the effective user name. In Windows this would switch to calling GetCurrentThreadEffectiveToken() instead of GetCurrentProcessToken(). --- [1] https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html |
|||
msg412556 - (view) | Author: Eryk Sun (eryksun) * | Date: 2022-02-05 03:39 | |
Here's an example for the suggested changes to _winapi. Include these headers: #include <ntsecapi.h> // LsaGetLogonSessionData #include <subauth.h> // STATUS_SUCCESS Add these argument-clinic macros to _winapi_functions: _WINAPI_GETCURRENTPROCESSTOKEN_METHODDEF _WINAPI_GETTOKENINFORMATION_METHODDEF _WINAPI_LSAGETLOGONSESSIONDATA_METHODDEF Add TokenStatistics in winapi_exec(): WINAPI_CONSTANT(F_DWORD, TokenStatistics); Add minimal implementations that wrap the WinAPI functions: /*[clinic input] _winapi.GetCurrentProcessToken -> HANDLE Return a handle for the access token of the current process. [clinic start generated code]*/ static HANDLE _winapi_GetCurrentProcessToken_impl(PyObject *module) /*[clinic end generated code: output=cf8e8e20dd41dd6e input=73a282cf3718af9e]*/ { return GetCurrentProcessToken(); } /*[clinic input] _winapi.GetTokenInformation handle: HANDLE information_class: unsigned_long / Get information from an access token. [clinic start generated code]*/ static PyObject * _winapi_GetTokenInformation_impl(PyObject *module, HANDLE handle, unsigned long information_class) /*[clinic end generated code: output=caecec0a25658348 input=b277ad2414f1b03e]*/ { if (information_class != TokenStatistics) { return PyErr_Format( PyExc_NotImplementedError, "Unsupported information class: %d", information_class); } DWORD returned_size; TOKEN_STATISTICS info; if (!GetTokenInformation(handle, information_class, &info, sizeof(info), &returned_size)) { return PyErr_SetFromWindowsErr(0); } PyObject *result = PyDict_New(); if (!result) { return NULL; } PyObject *value = PyLong_FromUnsignedLongLong( (((uint64_t)info.AuthenticationId.HighPart) << 32) + info.AuthenticationId.LowPart); if (!value) { goto error; } if (PyDict_SetItemString(result, "AuthenticationId", value) < 0) { Py_DECREF(value); goto error; } Py_DECREF(value); return result; error: Py_CLEAR(result); return NULL; } /*[clinic input] _winapi.LsaGetLogonSessionData logon_id: unsigned_long_long / Get data for the logon session identified by logon_id. [clinic start generated code]*/ static PyObject * _winapi_LsaGetLogonSessionData_impl(PyObject *module, unsigned long long logon_id) /*[clinic end generated code: output=680ac7725ef34527 input=01ff4216b89d01ef]*/ { SECURITY_LOGON_SESSION_DATA *pdata; LUID logon_luid; logon_luid.HighPart = logon_id >> 32; logon_luid.LowPart = logon_id & 0xFFFFFFFF; NTSTATUS status = LsaGetLogonSessionData(&logon_luid, &pdata); if (status != STATUS_SUCCESS) { return PyErr_SetFromWindowsErr(LsaNtStatusToWinError(status)); } PyObject *result = PyDict_New(); if (!result) { goto error; } PyObject *value = PyUnicode_FromWideChar(pdata->UserName.Buffer, pdata->UserName.Length / sizeof(WCHAR)); if (!value) { goto error; } if (PyDict_SetItemString(result, "UserName", value) < 0) { Py_DECREF(value); goto error; } Py_DECREF(value); LsaFreeReturnBuffer(pdata); return result; error: LsaFreeReturnBuffer(pdata); Py_CLEAR(result); return NULL; } |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:59:55 | admin | set | github: 90789 |
2022-02-05 03:39:16 | eryksun | set | messages: + msg412556 |
2022-02-04 05:55:34 | eryksun | create |