[Introduction]

Unix Incompatibility Notes:
Password Checking

Jan Wolter

Suppose we have a login name and a plain-text password, and we want to know if they are valid on our system. How do we check this?

There are always three steps:

  1. Use the user's login to look up the user's encrypted password in the appropriate database.
  2. Encrypt the plain-text password.
  3. Compare the two with strcmp(). If they match, the login is valid.
Both of the first two steps are done differently on different Unixes. We will outline those variations here.

We will not discuss authenticating through PAM here. See elsewhere.

1. Traditional

In traditional Unix systems, the user's encrypted password was stored in the /etc/passwd file. Because /etc/passwd is publicly readable, you don't need to be root to check authentication on such systems. Passwords are fetched with getpwnam() and encrypted with crypt(), as follows:
   #include <pwd.h>
   :
   struct passwd *user;
   :
   if ((user= getpwnam(login)) == NULL)
   	printf("No such user\n");
   else if (!strcmp(user->pw_passwd, crypt(password, user->pw_passwd))
        printf("Password correct\n");
   else
        printf("Password incorrect\n");
On some systems, you will need to link with -lcrypt to get the crypt() function.

2. BSD Shadow System

These days it is considered a really bad idea to have encrypted passwords in a publicly readable file so they are no longer stored in /etc/passwd on most modern Unix systems. Instead they are stored in a ``shadow'' database (often the file /etc/shadow) which is only readable by root.

Most BSD systems, including FreeBSD, NetBSD, OpenBSD, and BSDI implement this very transparently. You still call getpwnam(), but if you aren't root, it doesn't return the encrypted password. Thus the password checking code looks exactly like the traditional code, except you have to be root for it to work.

3. Sun Shadow System

Sun's Solaris operating system and all recent Linux versions use a separate call, getspnam() to get information from the shadow database. It works like this:
   #include <shadow.h>
   :
   struct spwd *user;
   :
   if ((user= getspnam(login)) == NULL)
   	printf("No such user\n");
   else if (!strcmp(user->sp_pwdp, crypt(password, user->sp_pwdp))
        printf("Password correct\n");
   else
        printf("Password incorrect\n");
On some systems, you will need to link with -lcrypt to get the crypt() function.

The open source Linux version of this was developed by Julianne F. Haugh. Some installations that use that may need to link with -lshadow to get the getspnam() function (and faster versions of getpwnam()).

Ancient versions of the Julianne F. Haugh shadow package replaced the crypt() function with one named pw_encrypt() which was supposed to do a better job encrypting long passwords. It didn't really, and has fallen into disfavor, and is rarely seen now. It's arguments were the same as those to crypt().

4. AIX Shadow System

I believe that if you are root on AIX, getpwnam() will return the encrypted password, just like the BSD systems. However their manual pages suggest that it is prefered to use the getuserpw() routine to fetch the password. If you use this, I think the code is something like this:
   #include <userpw.h>
   :
   struct userpw *user;
   :
   if ((user= getuserpw(login)) == NULL)
   	printf("No such user\n");
   else if (!strcmp(user->upw_passwd, crypt(password, user->upw_passwd))
        printf("Password correct\n");
   else
        printf("Password incorrect\n");
I haven't actually tried this.

5. HP-UX Shadow System

It appears that HP-UX's shadow system uses getprpwnam() to access the shadow database. The code is apparantly like this:
   #include <sys/type.h>
   #include <hpsecurity.h>
   #include <prot.h>
   :
   struct pr_passwd *user;
   :
   if ((user= getspwnam(login)) == NULL)
   	printf("No such user\n");
   else if (!strcmp(user->ufld.fd_encrypt,
                    crypt(password, user->ufld.fd_encrypt))
        printf("Password correct\n");
   else
        printf("Password incorrect\n");
I haven't actually tried this. It's possible that you have to call bigcrypt() instead of crypt().

HP-UX also has a function called getspwnam() which returns the encrypted password with less other baggage than getprpwnam() does, but their documentation suggests it is depreciated.


Jan Wolter (E-Mail)
Mon Apr 3 01:58:51 EDT 2000 - Original Release.