Validating A User/Password Pair + Getting Groups On Unix

Discussion in 'Python' started by Tim Daneliuk, Mar 1, 2005.

  1. Tim Daneliuk

    Tim Daneliuk Guest

    OK, I've Googled for this and cannot seem to quite find what I need.
    So, I turn to the Gentle Geniuses here for help. Here is what I
    need to do from within a script:

    Given a username and a password (plain text):

    1) Validate that the password is correct for that user *without actually logging in*.

    2) If the password is valid, return a list of all the groups the user belongs to.
    Otherwise, return some error string.

    I seem to not be able to crack how to do 1.

    I can do 2) by brute force - just parse through /etc/group - but this
    misses the primary group a given user may belong to - and that requires
    also scanning /etc/passwd and then looking up the corresponding primary
    group in /etc/group. Is there a better way?

    TIA,
    --
    ----------------------------------------------------------------------------
    Tim Daneliuk
    PGP Key: http://www.tundraware.com/PGP/
    Tim Daneliuk, Mar 1, 2005
    #1
    1. Advertising

  2. Tim Daneliuk

    Kanenas Guest

    On 28 Feb 2005 20:17:58 EST, Tim Daneliuk <>
    wrote:

    [...]
    >Given a username and a password (plain text):
    >
    > 1) Validate that the password is correct for that user *without actually logging in*.
    >

    The 'pwd' module probably won't be able (and won't try) to read the
    shadow password file, so 'pwd' won't be of use. There may not be a
    Python module which handles your local authentication scheme (there's
    a 'krb5' module for Kerberos authentication), so you may need to write
    one. The best approach may be to write an extension module in C or
    C++ which wraps around whatever local authentication functions are
    appropriate (e.g. a 'pam' module for PAM, an 'auth' module for BSD).
    You'd only need to wrap the functions needed for simple pass/fail
    authentication (e.g. auth_userokay), but the other functions could
    easily be added to the extension later if needed.

    The process that calls the authentication functions will probably need
    special access privileges so that the functions can succesfully accept
    or reject the password. The man pages for the authentication
    functions should have details. For example, auth_userokay calls
    getpwnam, which requires the effective uid to be 0 (or, on some
    systems, the user to be in the "_shadow" group) for it to include the
    encrypted password in the passwd entry.

    If you're not sure what authentication scheme your system uses, try
    `man -s 3 authenticate` or examine "/usr/src/usr.bin/login/login.c".

    extending Python:
    http://www.python.org/doc/2.4/ext/ext.html

    Python/C API:
    http://www.python.org/doc/2.4/api/api.html

    Information on Linux-PAM
    http://www.kernel.org/pub/linux/libs/pam/

    You could even add support for the full authentication API to your
    module and contribute the extension to the Python community.
    http://www.python.org/download/Contributed.html.


    > 2) If the password is valid, return a list of all the groups the user belongs to.
    > Otherwise, return some error string.
    >

    [...]
    >I can do 2) by brute force - just parse through /etc/group - but this
    >misses the primary group a given user may belong to - and that requires
    >also scanning /etc/passwd and then looking up the corresponding primary
    >group in /etc/group. Is there a better way?
    >

    Slightly better would be to use the grp and pwd modules:
    http://www.python.org/doc/2.4/lib/module-grp.html
    http://www.python.org/doc/2.4/lib/module-pwd.html

    Even better would be to write an extension or add to the grp module to
    wrap around local group database access functions (e.g. getgrouplist).
    See the 'getgrouplist' man page for more information and examine the
    source of the `groups` command (probably
    "/usr/src/usr.bin/groups/groups.c") or `id` command (should be
    "/usr/src/usr.bin/id/id.c") for other group DB access functions.

    You could also call the `groups` command via 'os.popen(...)'.
    Kanenas, Mar 1, 2005
    #2
    1. Advertising

  3. Tim Daneliuk

    Kanenas Guest

    On 28 Feb 2005 20:17:58 EST, Tim Daneliuk <>
    wrote:

    [...]
    >Given a username and a password (plain text):
    >
    > 1) Validate that the password is correct for that user *without actually logging in*.
    >

    The naive solution is to use the 'crypt' module to encrypt the alleged
    password, use 'pwd.getpwuid' or 'pwd.getpwnam' to get the user's
    encrypted password (assuming the python process has appropriate access
    privileges) and compare the two. This is naive in that:
    * 'pwd.getpw*' may not retrieve the encrypted password even though the
    current process has appropriate access privileges
    * the password may be for an encryption or authentication scheme other
    than that provided by 'crypt'.
    Using the local authentication scheme shouldn't have these
    shortcomings.

    There may not be a Python module which handles your local
    authentication scheme (there's a 'krb5' module for Kerberos
    authentication), so you may need to write one. This could be done by
    an extension module in C or C++ which wraps around whatever local
    authentication functions are appropriate (e.g. a 'pam' module for PAM,
    an 'auth' module for BSD). You'd only need to wrap the functions
    needed for simple pass/fail authentication (e.g. 'auth_userokay'), but
    the other functions could easily be added to the extension later if
    needed.

    If you're not sure what authentication scheme your system uses, try
    `man -s 3 authenticate` or examine "/usr/src/usr.bin/login/login.c".

    Whichever approach you use, the process that calls the authentication
    functions needs special access privileges so that the functions can
    succesfully accept or reject the password. The man pages for the
    authentication functions should have details. For example, 'getpwnam'
    (used by 'auth_userokay' and the 'pwd' module) requires the effective
    uid to be 0 (or, on some systems, the user to be in the "_shadow"
    group) for it to include the encrypted password in the returned passwd
    entry.

    'crypt' and 'pwd' modules:
    http://www.python.org/doc/2.4/lib/module-crypt.html
    http://www.python.org/doc/2.4/lib/module-pwd.html

    extending Python:
    http://www.python.org/doc/2.4/ext/ext.html

    Python/C API:
    http://www.python.org/doc/2.4/api/api.html

    Information on Linux-PAM
    http://www.kernel.org/pub/linux/libs/pam/

    You could even add support for the full authentication API to your
    module and contribute the extension to the Python community.
    http://www.python.org/download/Contributed.html.


    > 2) If the password is valid, return a list of all the groups the user belongs to.
    > Otherwise, return some error string.
    >

    [...]
    >I can do 2) by brute force - just parse through /etc/group - but this
    >misses the primary group a given user may belong to - and that requires
    >also scanning /etc/passwd and then looking up the corresponding primary
    >group in /etc/group. Is there a better way?
    >

    Slightly better would be to use the 'grp' and 'pwd' modules. One
    advantage of this is it should support networked user databases (such
    as YP).
    http://www.python.org/doc/2.4/lib/module-grp.html
    http://www.python.org/doc/2.4/lib/module-pwd.html

    If you've grabbed the password entry for a user during authentication,
    you've already got the login group but you'll still need to check for
    additional groups. You could create a dictionary which maps user
    names or IDs to groups. This would still require processing all
    groups (via 'grp.getpwall()'), but is more efficient if you need to
    fetch the groups of more than one user in the life of the process
    (from the outline, I'm guessing this will only be the case if the
    program is a server of some sort). Just make sure you have a method
    to re-process the group database into the group dictionary in case the
    group file changes.

    Even better would be to write an extension or add to the grp module to
    wrap around local group database access functions (e.g. getgrouplist).
    See the 'getgrouplist' man page for more information and examine the
    source of the `groups` command (probably
    "/usr/src/usr.bin/groups/groups.c") or `id` command (should be
    "/usr/src/usr.bin/id/id.c") for other group DB access functions.

    You could also call the `groups` command via 'os.popen(...)'.
    Kanenas, Mar 1, 2005
    #3
  4. >> 1) Validate that the password is correct for that user *without
    >> actually logging in*.
    >>

    Kanenas> The 'pwd' module probably won't be able (and won't try) to read
    Kanenas> the shadow password file, so 'pwd' won't be of use.

    Note that an spwd module was recently added to Python's CVS repository. I
    imagine it will be in 2.5.

    Skip
    Skip Montanaro, Mar 1, 2005
    #4
  5. Tim Daneliuk

    Kanenas Guest

    On Tue, 1 Mar 2005 09:45:26 -0600, Skip Montanaro <>
    wrote:

    > >> 1) Validate that the password is correct for that user *without
    > >> actually logging in*.
    > >>

    > Kanenas> The 'pwd' module probably won't be able (and won't try) to read
    > Kanenas> the shadow password file, so 'pwd' won't be of use.
    >
    >Note that an spwd module was recently added to Python's CVS repository. I
    >imagine it will be in 2.5.
    >
    >Skip


    It turns out 'pwd' uses the system 'getpwuid' and 'getpwnam' rather
    than parsing /etc/passwd, so it can get the encrypted password if the
    getpw* functions read the shadow passwd and the Python process has
    EUID 0 (or whatever access rights getpw* use to determine when to
    return the encrypted passwd). I misread (was misled by?) the 'pwd'
    documentation:

    "However most modern unices use a so-called shadow password
    system. On those unices the field pw_passwd only contains a asterisk
    ('*') or the letter "x" where the encrypted password is stored in a
    file /etc/shadow which is not world readable."

    This is true if the getpw* don't read from the shadow passwd, which is
    the case for Solaris and Linux. Linux and Solaris use getsp*, which
    'spwd' is based on, to manage the shadow passwd. On OpenBSD and
    FreeBSD, getpw* read from the shadow passwd and the getsp* don't
    exist.

    In summation, use 'pwd' to retrieve encrypted password on OpenBSD and
    FreeBSD (and others?), 'spwd' on Linux and Solaris (and others?).
    Assuming one goes this route.
    --
    Kanenas
    Kanenas, Mar 1, 2005
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. nicholas

    validating groups of user controls

    nicholas, Apr 7, 2005, in forum: ASP .Net
    Replies:
    5
    Views:
    392
    nicholas
    Apr 8, 2005
  2. anonymous
    Replies:
    1
    Views:
    4,581
    Francisco Padron
    May 8, 2005
  3. AAaron123
    Replies:
    2
    Views:
    2,148
    AAaron123
    Jan 16, 2009
  4. AAaron123
    Replies:
    1
    Views:
    1,333
    Oriane
    Jan 16, 2009
  5. Brandon Hoppe
    Replies:
    10
    Views:
    184
    Tad McClellan
    Feb 9, 2006
Loading...

Share This Page