471,601 Members | 1,185 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 471,601 software developers and data experts.

Validating A User/Password Pair + Getting Groups On Unix

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 tu****@tundraware.com
PGP Key: http://www.tundraware.com/PGP/

Jul 18 '05 #1
4 3036
On 28 Feb 2005 20:17:58 EST, Tim Daneliuk <tu****@tundraware.com>
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(...)'.

Jul 18 '05 #2
On 28 Feb 2005 20:17:58 EST, Tim Daneliuk <tu****@tundraware.com>
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(...)'.

Jul 18 '05 #3
>> 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
Jul 18 '05 #4
On Tue, 1 Mar 2005 09:45:26 -0600, Skip Montanaro <sk**@pobox.com>
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
Jul 18 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Michael Glaesemann | last post: by
reply views Thread by krisk | last post: by
8 posts views Thread by db2admin | last post: by
232 posts views Thread by robert maas, see http://tinyurl.com/uh3t | last post: by
3 posts views Thread by Jennifer.Berube | last post: by
1 post views Thread by XIAOLAOHU | last post: by
reply views Thread by leo001 | last post: by

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.