Section 10.2. Programming with Directory Services

10.2. Programming with Directory Services

As a programmer, you frequently need to deal with directory information, whether you realize it or not. Your application uses Directory Services each time it looks up a host entry or authenticates a password. The Open Directory architecture unifies what used to be a random collection of flat files in /etc . The good news is that the flat files still work. The other good news is that there is a brave new world just beyond those flat files. So, while all your old Unix code should work with the Open Directory architecture, you should look for new ways to accomplish old tasks , especially if you can continue writing portable code.

To get at directory information, Unix applications typically go through the C library using such functions as gethostent( ) . The C library connects to lookupd , a thin shim that is the doorway to the DirectoryService daemon. The DirectoryService daemon consults the available plug-ins until it finds the one that can answer the directory query.

10.2.1. Working with Passwords

One traditional route to user and password information was through the getpw* family of functions. However, those functions are not ideal for working with systems that support multiple directories (flat files, NetInfo, LDAP, etc.). Also, in the interest of thwarting dictionary attacks against password files , many operating systems have stopped returning encrypted passwords through those APIs. Many Unix and Linux systems simply return an " x " when you invoke a function like getpwnam( ) . However, those systems can return an encrypted password through functions like getspnam( ) , which consult shadow password entries and can generally be invoked by the root user only. Example 10-1 shows the typical usage of such an API, where the user enters her plaintext password, and the program encrypts it and then compares it against the encrypted password stored in the system.

Example 10-1. Using getpwnam( ) to retrieve an encrypted password
 /*  * getpw* no longer returns a crypted password.  *  * Compile with gcc checkpass.c -o checkpass  * Run with: ./checkpass  */ #include <pwd.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) {   const char *user = NULL;   struct passwd *pwd;   /* Set the user name if it was supplied on the command    * line.  Bail out if we don't end up with a user name.    */   if (argc == 2)     user = argv[1];   if(!user)   {     fprintf(stderr, "Usage: checkpass <username>\n");     exit(1);   }   /* Fetch the password entry. */   if (pwd = getpwnam(user))   {     char *password = (char *) getpass("Enter your password: ");     /* Encrypt the password using the encrypted password as salt.      * See crypt(3) for complete details.      */     char *crypted  = (char *) crypt(password, pwd->pw_passwd);     /* Are the two encrypted passwords identical? */     if (strcmp(pwd->pw_passwd, crypted) == 0)       printf("Success.\n");     else     {       printf("Bad password: %s != %s\n", pwd->pw_passwd, crypted);       return 1;     }   }   else   {     fprintf(stderr, "Could not find password for %s.\n", user);     return 1;   }   return 0; } 

As of Mac OS X Panther (v 10.3), your code no longer has a chance to look at an encrypted password . There are no functions such as getspnam( ) , and if you invoke a function like getpwnam( ) , you'll get one or more asterisks as the result. For example:

 $  gcc checkpass.c -o checkpass  $  ./checkpass   bjepson    Enter your password:     Bad password: ******** != **yRnqib5QSRI 

There are some circumstances where you can obtain an encrypted password, but this is not the default behavior of Mac OS X. See the getpwent(3) manpage for complete details.


Instead of retrieving and comparing encrypted passwords, you should go through the Linux-PAM APIs. Since Linux-PAM is included with (or available for) many flavors of Unix, you can use it to write portable code. Example 10-2 shows a simple program that uses Linux-PAM to prompt a user for his password.

Example 10-2. Using Linux-PAM to authenticate a user
 /*  * Use Linux-PAM to check passwords.  *  * Compile with gcc pam_example.c -o pam_example -lpam  * Run with: ./pam_example <username>  */ #include <stdio.h> #include <pam/pam_appl.h> #include <pam/pam_misc.h> int main(int argc, char *argv[]) {   int retval;   static struct pam_conv pam_conv;   pam_conv.conv = misc_conv;   pam_handle_t *pamh = NULL;   const char *user = NULL;   /* Set the username if it was supplied on the command    * line. Bail out if we don't end up with a username.    */   if (argc == 2)     user = argv[1];   if(!user)   {     fprintf(stderr, "Usage: pam_example <username>\n");     exit(1);   }   /* Initialize Linux-PAM. */  retval = pam_start("pam_example", user, &pam_conv, &pamh);  if (retval != PAM_SUCCESS)   {     fprintf(stderr, "Could not start pam: %s\n",         pam_strerror(pamh, retval));     exit(1);   }   /* Try to authenticate the user. This could cause Linux-PAM    * to prompt the user for a password.    */   retval = pam_authenticate(pamh, 0);   if (retval == PAM_SUCCESS)     printf("Success.\n");   else     fprintf(stderr, "Failure: %s\n", pam_strerror(pamh, retval));   /* Shutdown Linux-PAM. Return with an error if    * something goes wrong.    */   return pam_end(pamh, retval) == PAM_SUCCESS ? 0 : 1; } 

In order for this to work, you must create a file called pam_example in /etc/pam.d with the following contents (the filename must match the first argument to pam_start( ) , which is shown in bold in Example 10-2):

 auth       required  pam_securityserver.so     account    required  pam_permit.so     password   required  pam_deny.so 

Be careful when making any changes in the /etc/pam.d directory. If you change one of the files that is consulted for system login, you may lock yourself out of the system. For more information on Linux-PAM, see the pam(8) manpage.

Once you've compiled this program and created the pam_example file in /etc/pam.d , you can test it out:

 $  gcc pam_example.c -o pam_example -lpam  $  ./pam_example   bjepson    Password:  ********  Success. 



MAC OS X Tiger in a Nutshell
Mac OS X Tiger in a Nutshell: A Desktop Quick Reference (In a Nutshell (OReilly))
ISBN: 0596009437
EAN: 2147483647
Year: 2003
Pages: 130

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net