Many IS shops either demand or would like to implement some means of password aging. The idea is to improve security by decreasing the window of vulnerability for a password that has been guessed or given away. Various methods exist for enforcing password aging, for instance Sun Solaris-5.x uses special fields in the shadow password file /etc/shadow, while HP uses a suffix added to the encrypted password field in the /etc/passwd file. Each of these techniques works well in a standalone system, however a problem arises in larger shops where NIS is needed to scale administration.
I generally recommend using NIS to my clients with four or more UNIX hosts, because of the time savings in administering their environment. Thus, it doesn't take much to be large enough to profit from using NIS. Sun supports password aging in a distributed environment via the NIS+ product. NIS+ is the so-called next generation of NIS. It adds a hierarchical structure similar to DNS and the ability to securely distribute information, including encrypted passwords, across the Net. The problem is that none of the other UNIX vendors support NIS+ (except HP, discussed later).
Although most UNIX vendors support NIS, Sun does not support password aging under NIS. HP does support password aging under NIS, however the "suffix" method of password aging is incompatible with Sun's NIS implementation. Thus, a shop requiring password aging would either have to be homogeneous Sun/Solaris or able to separate the Suns into an NIS/NIS+ domain apart from their other platforms. None of the companies I've come across are Sun-only shops. Most have at least a few HPs, SGIs, or one or more of various other flavors. Because of this, system segregation is not a good idea, either.
HP supports NIS+ in HP-UX 11, and I have heard that they intend to add NIS+ support to HP-UX 10.2. However, I suspect they will not provide NIS+ support for releases prior to 10.2. Companies often need to keep legacy systems to run applications that either aren't available on later releases, or they may not want to invest in the upgrade due to the legacy status of the application. In these cases, NIS+ remains out of reach. So, some means of providing password aging in a heterogeneous NIS environment is necessary.
One of my clients was recently in such a situation. They had HPs running HP-UX 9.x and Suns running Solaris 2.5 and 2.6. The HPs were all running shop floor equipment and were unsuitable for use as an NIS master, so one of the Sun servers was chosen for that task. I was asked to produce a way of handling the password aging. I accomplished this via a relatively short (about 350 lines of code) awk script called pwupd (see Listing 1, available from ftp.mfi.com in /pub/sysadmin).
Before writing the script, I familiarized myself with the respective password implementations on Solaris and HP-UX and made some interesting discoveries. First, Solaris 2.5 and later has the suffix method of aging implemented in the login facility and local /bin/passwd command. But, rpc.yppasswdd, the NIS password change facility that updates the NIS master's files, doesn't handle this method. A user with an expired suffix password will be challenged for a new password, but the NIS update fails, so the user cannot successfully change the password.
I have seen reference to a Sun patch that allows password aging if the NIS update utility is designed to handle the suffix password, as on an HP. This discovery, while promising, wasn't very useful since the NIS master in this case had to be a Sun. Solaris uses the same utility, /bin/passwd, to handle password changes on a client regardless of whether the password is stored in local files, NIS, or NIS+. The utility has several hard links to the same file, so the behavior is affected by the name by which it is called - passwd for local files, yppasswd for NIS, and nispasswd for NIS+. The behavior is also affected by the passwd setting in the /etc/nsswitch.conf file.
HP-UX 9.x has two different password change utilities - /bin/passwd for local files and /usr/bin/yppasswd for NIS. The normal NIS master implementation on Solaris 2.5 or later copies the encrypted password from the shadow file into the password field of the NIS passwd map. Thus, entries in the passwd map look similar to other, non-shadow file, passwd implementations. When a user's password is changed, that change is passed to rpc.yppasswdd on the NIS master, which updates the NIS shadow file (including aging), and runs the NIS make. The make copies the new encrypted password into the passwd map.
The second discovery I made relates to a Solaris 2.5 or later NIS client. If a given user exists both in NIS and in the local file, and the /etc/nsswitch.conf file lists "files nis", in that order, as the search order for the passwd database, both the local and the NIS shadow files will be updated. This undocumented feature made the Solaris NIS password aging task much easier.
So, we have the tools to accomplish password aging on local clients, but how do we handle this in an NIS domain? The first step is to propagate the aging information through a new NIS map. Since the shadow file already exists in the standard Solaris NIS master's files, it seems a logical choice. We're not really giving up any security by distributing the shadow file, because we're already distributing the encrypted password via the passwd map. By propagating the entire shadow file, we are distributing the aging information as well.
The Solaris clients already expect the aging information to be in shadow file form, but don't have any provision for looking to NIS for the shadow file. They use the password aging information in the local /etc/shadow file, so the challenge is to merge the NIS passwd and shadow maps into the local /etc/passwd and /etc/shadow files.
The HP clients don't have a shadow file, and the aging is through the suffix method. To complicate things further, the HP suffix aging is based on weeks since the beginning of the so-called epoch (1/1/1970), while the Solaris aging is based on days since that same beginning. Thus, HP clients require that the aging be translated from days to weeks, and the resulting aging string must be appended to the password field in the /etc/passwd file.
Both Solaris and HP clients need to have their local files updated regularly to add new users to NIS, as well as remove users who are no longer in NIS. I chose to run the pwupd awk script as a cron job on an hourly basis. Updating the local files from the NIS maps, as described, causes the client to challenge an expired-password user for a new password on login.
The next task is to propagate the changed password back to NIS and the other clients in the domain. I mentioned previously that the /bin/passwd utility on Solaris 2.5 and later updates both the local file and NIS. So, when a user changes his or her expired password, the local client and NIS passwords are changed as well. Unfortunately, this doesn't instantly propagate to other clients in the domain. We depend on the pwupd cron job to handle that.
Propagating back to NIS on the HPs is a more difficult task. If an expired-password user tries to log in, the HP-UX login facility (vuelogin for the sake of this article) will update the /etc/passwd file, but ignore NIS. Now the password is changed, and the user can log in, but only on the local machine. Unless the change is propagated, the next time cron runs pwupd, the user's password will revert back to their old, expired password. So, we need a way to update NIS as well as the local file.
The best way to do this would be to write a compiled binary wrapper for the password change utility, which would accept the user's password, check against local/NIS passwords, and then update both the local and NIS passwords when appropriate. We didn't want to expend that much effort in the project, so we opted for a quicker, albeit less elegant, solution. For this project, we renamed /bin/passwd to /bin/passwd.local, and linked usr/bin/yppasswd to /bin/passwd. Thus, the login facility will change the NIS password instead of the local password when an expired-password user tries to log in.
This setup introduces yet another problem. The NIS password has been updated, but the local password is still expired, so the user still can't log in until cron runs pwupd again. Fortunately, HP-VUE has a mechanism for handling that, which is the Xreset script. Xreset is run as root whenever a VUE session ends (including an expired-password login session), and can be used to force pwupd to run immediately, thereby propagating the password change back to the local client so that the user can immediately log in.
As with almost everything in life, there are caveats. The simultaneous local/NIS update for Solaris is an undocumented feature, and could change if Sun decides it was a mistake. Since the pwupd script is run as root, care should be taken that the script is writable only by root. Also, because changes have been made to the base OS (via renaming /bin/passwd on the HP), care must be taken when installing patches or upgrades that would overwrite the /bin/passwd or /usr/bin/yppasswd utilities. Also, keep in mind that the technique described in this article calls for setting cron to run a script that manipulates the passwd and shadow files. Buyer beware, your mileage may vary, and so on.
The script itself was designed to run as-is on both Solaris and HP-UX. The awk script is wrapped in a Bourne shell script that does nothing more than detect which OS is running, and sets the path to awk appropriately. One of the requirements for the script was that it use built-in facilities - Perl need not apply, alas. Also, I wanted the convenience of associative arrays found in awk (nawk more specifically), so that pretty much defined the language.
The first part of the script loads the information from local and NIS passwd/shadow maps into arrays, including auxiliary arrays used for sorting. It then compares the local files to the NIS maps, basically building new local files in memory. The new users from NIS are added in numeric seqence by UID, and users absent from NIS are deleted. User IDs of 100 or lower are left alone, to preserve special users such as root and bin. The password fields are also considered. If the password has been changed for a preexisting user, it is updated in the local files, with special consideration for HP clients to account for the aging information contained in the encrypted password. Finally, the new files are written in order by UID, and switched with the original files. The old version of each file is preserved until the next time pwupd is run.
Note that my client has the luxury of a small user namespace - less than 100 users above UID 100. As such, pwupd neither uses much memory, nor takes a significant time to run. Shops with a larger namespace would be different, and it may be necessary to tune the script to be less memory- and CPU-intensive. For example, you may want to use a sort utility that is more efficient than my lowly bubble sort.
Sun Bug report 4024446: RFE to have login and yppasswdd deal with NIS passwd aging as implemented by other vendors. Includes a description of HP password aging.
Sun Infodoc 16699: Description of passwd aging under Solaris
Sun Bug 1160152, basically acknowledges rpc.yppasswdd not handling aging suffix.
About the Author
Paul McKinley received his Bachelor's degree in Mechanical Engineering in 1979, then switched to UNIX Systems Administration in 1992. He currently works for Stonebridge Technologies, a systems integrator. In his "spare" time he is developing a residential airpark for pilots. He can be reached at: firstname.lastname@example.org.