Cover V13, i05

Article

may2004.tar

Using LDAP to Manage Unix Accounts

Jeff Machols

User management is one of the most tedious tasks in a systems administrator's job. There have been some attempts to centralize user management with NIS and NIS+. NIS fizzled out because of its security holes, and NIS+ is not very straightforward to configure. So, what's the best way to centralize user management in an environment? The answer is looking more and more like LDAP.

LDAP (Lightweight Directory Access Protocol) is quickly emerging as the standard in hierarchical data, such as user and group data. LDAP servers are designed for an "update seldom, access often" scenario. One of the roadblocks LDAP has faced in gaining popularity as a centralized user management system is the effort to get client machines to securely authenticate users. In the past, this required writing custom PAM modules or trying to configure existing ones. However, as major Unix vendors are realizing the potential of LDAP, they are including clients in the operating system.

These built-in clients also contain the PAM libraries for authentication with an LDAP server. These client-side applications are included in the Solaris 8 and 9 distributions, as well as AIX 5L. HP-UX has a free software depot called ldapux that can be found at software.hp.com, and Linux has an RPM called nss_ldap. These clients include built-in libraries, so fears about writing C programs to authenticate or having holes in your security can be put to rest.

Server Considerations

Several LDAP servers are available on the market. Currently, the two predominant servers are OpenLDAP and Sun One Directory Server (formerly iPlanet). If Solaris is your OS for the LDAP server, Sun One Directory Server is the way to go. It is currently bundled with Solaris 9, and version 5.1 is free up to 200,000 entries (each distinguished name in the server is considered an entry). Sun One Directory Server is also available on HP-UX, AIX, and Linux. OpenLDAP is free and can be compiled on most flavors of Unix, but configuration and compilation take a little more effort.

The LDAP community has created an RFC (RFC 2307) to define a schema for Unix to use LDAP as an NIS provider. The schema defines all the previous maps that were available for NIS, so it is aptly named the nis.schema. This schema comes loaded in the standard installation of Sun One Directory Server. If you are using OpenLDAP or another server, be sure the schema is loaded into your server. As part of the nis.schema, the following services can be centralized with LDAP: password, shadow password, groups, and netgroups. Other services, such as DNS, are also available with LDAP, but that is beyond the scope of this article.

The default communications for the LDAP server and clients are clear ASN1 strings. All information is sent in clear text. This is the major problem with NIS, so be sure you don't make this mistake with your LDAP implementation. I recommend using the default communication method during the installation and initial test. Once you have tested the server and the clients, and are comfortable with the configuration, switch to SSL.

When configuring your clients, you will need to specify a search base. This is the point in the directory at which the client starts looking for NIS entries. This functionality allows you to separate Unix user and group accounts from other parts of the directory. For example, you may want to set up a group with a distinguished name (DN) of "ou=unix nis, dc=mydomain, dc=com". You can segregate this more if desired, but all Unix accounts would be under this organizational unit; this DN would be your clients' search base.

Segregating your NIS environment inside the LDAP server will give you two advantages. The first advantage is speed. When you specify the start DN, your clients will not have to search through the entire directory to find the accounts, which will help performance. The second benefit is administrative flexibility. You can give account administrators access to a specific area of the server, instead of to your entire directory. You can have different search bases for different Unix clients. If you do this, note that user accounts will need to be replicated in both search bases to have access to the different clients.

Adding NIS Entries in the LDAP Server

To add a Unix group into LDAP, you will need to create an entry of object class posixGroup. The attribute gidNumber corresponds to the Unix GID number for the group. Since the local and LDAP groups are treated the same, it is important to keep all the gidNumbers in LDAP as well as the local GIDs unique. The Full Name, or cn attribute, is the name of the group. The memberUid attribute correlates to the users who are part if that group. Each user will be an additional attribute in the group's entry. In the example below, users jdoe and scarter are part the admins group:

dn: cn=admins, ou=unix nis, dc=mydomain, dc=com
gidNumber: 900
memberUid: jdoe
memberUid: scarter
objectClass: top
objectClass: posixgroup
cn: admins
Here are the instructions for adding entries. If you are unsure how to add an entry into an LDAP server, copy the above entry information into a file on the LDAP host and run the following command:

$ ldapadd -D "directory_manager_dn" -w "directory_manager_password" -f filename
You can assign users to groups in two ways; the first way is described above. Each posixGroup entry will have a list of users. The second method is to assign gidNumbers for each group in the posixAccount entry (described below). These methods can be intermixed but, for consistency, I recommend choosing one method. When you create a new user, you will use the object class posixAccount and shadowAccount along with the standard person object classes. The uid attribute is the user login name, and the uidNumber is the user's Unix uid. The gidNumber attribute lists the groups to which the user belongs. When you specify the password, there are multiple ways to store the ciphered password. For authentication on Unix, you must use the crypt method. This is accomplished by using the {CRYPT} tag in front of the cipher password:

dn: uid=jdoe, ou=unix nis, dc=mydomain, dc=com
givenName: John
sn: Doe
userPassword: {CRYPT}QGxOG7iX3lbLU
loginShell: /usr/bin/ksh
uidNumber: 343
gidNumber: 900
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetorgperson
objectClass: posixAccount
objectClass: shadowaccount
uid: jdoe
cn: John Doe
homeDirectory: /export/home/jdoe
Along with specifying the password, you can also set password options such as length, minimum characters, expiration, etc. All of the attributes in the NIS schema can be found in RFC2307. With replication and the correct setup, your LDAP environment will be reliable, but there are still some users you should keep out of LDAP. The most obvious is root; this user should always be kept local. I suggest keeping application users local, so even if the network goes down, your applications will still be able to run (assuming they don't need the network).

LDAP supports the use of netgroups, so you can control user access to individual servers. The object class is called NisNetGroup and uses the same "triple" notation as NIS. Each entry has three fields: host, user, and domain. If you leave a field blank, it allows complete access. In the entry below, jdoe is in the appuser netgroup for all servers, all domains. The user scarter is in the appuser netgroup only on the server mars, and all users are in the appuser netgroup on the server pluto:

dn: cn=appuser, ou=unix nis, dc=mydomain, dc=com
        nisNetgroupTriple: ( , jdoe , )
        nisNetgroupTriple: ( mars , scarter , )
        nisNetgroupTriple: ( pluto , , )
        cn: appuser
        objectClass: top
        objectClass: nisnetgroup
The passwd command can be used to change the password in the LDAP server. The only change is an extra switch -- the -r option. To change the password for user jdoe:

$ passwd -r ldap jdoe
Configuring the Unix Client

Unfortunately, the client setup is different for each version of Unix. There is an effort on the Apache Directory project to document the steps for configuring each client. As each configuration is tested, the documentation will be posted on the Directory Project site. I will use Solaris 9 as an example for the rest of the article.

The Solaris 9 clients will run a daemon called /usr/lib/ldap/ldap_cachemgr, which will handle all communication between the client and the LDAP servers. The clients use a configuration profile stored on the servers and periodically update themselves against the profile. This allows you to make a configuration change once that will be populated out to clients automatically. To do this, you need to create an organizational unit for the profile to reside in. Add the following OU:

dn: ou=profile, dc=mydomain, dc=com
ObjectClass: top
ObjectClass: OrganizationalUnit
ou: profile
Next, create the profile. This is accomplished by using the ldapclient command built into the OS. This command will create LDIF output that will be added as an entry into the server. The following example will create a profile that will configure the clients to use multiple servers (for replication and failover) and map where in the directory the NIS information will be stored. This command can be run on any Solaris 9 machine regardless of whether it is a server or a client:

$ /usr/sbin/ldapclient genprofile \
-a defaultSearchBase="ou=unix nis,dc=mydomain,dc=com" \
-a serviceSearchDescriptor="passwd: ou=unix nis,dc=mydomain,dc=com" \
-a serviceSearchDescriptor="group: ou=unix nis,dc=mydomain,dc=com" \
-a serviceSearchDescriptor="shadow: ou=unix nis,dc=mydomain,dc=com" \
-a serviceSearchDescriptor="netgroup: ou=unix nis,dc=mydomain,dc=com" \
-a authenticationMethod=simple \
-a credentialLevel=proxy \
-a "defaultServerList=192.168.0.155 192.168.0.156 192.168.10.100" > profile.ldif
The profile.ldif file will contain the entry information. Normally, you should not have to do anything to this file, but you can make changes before adding the entry, if necessary. When you are happy with the profile, add it to the server:

$ ldapadd -D "directory_manager_dn" -w "directory_manager_password" \
  -f profile.ldif
Once the profile entry has been added, set up each of the clients to use it. On the client machine, run the ldapclient command with the init option. This command will configure the ldap_cachemgr; it will also copy the /etc/nsswitch.ldap to /etc/nsswitch.conf and start the client in the background:

$ ldapclient -v init -a proxyDN=" directory_manager_dn" \
  -w "directory_manager_password" ldapserver_IP_address
If the client does not start or you encounter other problems, you can add debug flags to get more information. Just add option -d 6 to the command for verbose output:

$ /usr/lib/ldap/ldap_cachemgr -d 6
After ldap_cachemgr is up and running, you can test the connection to the server. It will be easier to test if you have at least one entry for each NIS component you are using. To get a list of entries the client finds, run the ldaplist command. You should see all the entries in your search base:

$ ldaplist

dn: cn=admins, ou=unix nis, dc=mydomain,dc=com
dn: uid=jdoe,ou=unix nis,dc=mydomain,dc=com
dn: cn=appuser, ou=unix nis, dc=mydomain,dc=com
Once you get the client talking to the LDAP server, you can begin configuring the OS for user authentication. The first step is to add LDAP as a service in the /etc/nsswitch.conf file. The following nsswitch.conf file will support user authentication, groups, and netgroups in LDAP. If you are not using netgroups, replace the passwd: compat entry with passwd: files ldap and delete the passwd_compat entry:

#
# /etc/nsswitch.conf
#
passwd: compat
passwd_compat:  ldap
group:      files ldap
#
#  All other services are unchanged
#
netgroup:   ldap
If you are not using netgroups, you don't need to change the /etc/passwd file. If you are using netgroups, you will need to add the name of the netgroups with access. You will also need to deny other net users. The following snippet can be inserted at the end of the /etc/passwd file to allow users in the netgroup appusers to log onto the server:

+@appusers:x:::::
-:x:::::
After the entry is added, run the pwconv command to update the /etc/shadow file.

You will need to add the LDAP PAM library to the /etc/pam.conf in order to authenticate. The library should already exist in /usr/lib/security; it will be called pam_ldap.so.1:

#
# Authentication management
#
# login service (explicit because of pam_dial_auth)
#
login   auth required           pam_authtok_get.so.1
login   auth required           pam_dhkeys.so.1
login   auth required           pam_dial_auth.so.1
login   auth sufficient         pam_unix_auth.so.1
login   auth required           pam_ldap.so.1
#
other   auth required           pam_authtok_get.so.1
other   auth required           pam_dhkeys.so.1
other   auth sufficient         pam_unix_auth.so.1
other   auth required           pam_ldap.so.1
#
passwd  auth sufficient         pam_passwd_auth.so.1
passwd  auth required           pam_ldap.so.1
other   account requisite       pam_roles.so.1
other   account required        pam_projects.so.1
other   account required        pam_unix_account.so.1
#
# Default definition for Session management
# Used when service name is not explicitly mentioned for session
#
other   session required        pam_unix_session.so.1
#
other   password required       pam_dhkeys.so.1
other   password required       pam_authtok_get.so.1
other   password required       pam_authtok_check.so.1
other   password sufficient     pam_authtok_store.so.1
other   password required       pam_ldap.so.1
Conclusion

Besides GUIs supplied by the LDAP server, command-line clients also exist. These LDAP clients allow you to add, delete, and modify LDAP entries via the command line and LDIF files. This is useful for scripting or creating custom application to access LDAP.

With the built-in clients, secure connections, and the ability to build GUIs around the server, LDAP has become a viable solution for user management and authentication. Not only does it make it easier to administer users, but LDAP also allows much of the work to be moved to a help desk or level 2 systems administrator support.

Jeff Machols is the Manager of the Unix Administration team for a financial institution and the co-founder of the Apache Directory Project. He can be contacted at: jmachols@apache.org.