New submission from Eryk Sun <eryk...@gmail.com>:

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

----------
components: Library (Lib), Windows
messages: 412495
nosy: eryksun, paul.moore, steve.dower, tim.golden, zach.ware
priority: normal
severity: normal
stage: needs patch
status: open
title: Implement a "strict" mode for getpass.getuser()
type: enhancement
versions: Python 3.11

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue46631>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to