PWX - Password Expiration

  1. What it is
  2. Access and Security
  3. The Transaction Engine
  4. The Command Set
  5. Pwx, the Client Utility
  6. Pwxpire, the Expiration Processor Client Utility
  7. The PWX API

What it is

Pwxd is a simple transaction server that keeps track of when each users' password is going to expire. Whenever a password is changed, a message is sent to the pwxd server specifying the user and the time stamp for the password change. Pwxd then updates its database for later query.

Each day, the pwxpire utility is run to determine who has an expiring password. It sends a warning message to anyone within 15 days of their expiration and expires those beyond their expiration date.

The underlying mechanism is a general purpose, fault tolerant transaction engine. This is the same basic engine that is used to support our passwd file synchronization and email server aliasing.

Pwxd maintains a simple database of key-value pairs. The key is the normally the UW NetID, the value is usually a string of colon separated single letter codes and values defined as follows:

C: Last change time as seconds since the beginning of the epoch.
D: Delay in seconds until expiration (default 0 days = disabled).
E: Expiration time stamp.
F: Flags in hexidecimal (see /tulsa/include/pwx.h for flag values).
G: Medical Centers AMC/ORCA/MINDscape last password change time.
H: Medical Centers AMC/ORCA/MINDscape password expiration time.
W: Warning message template ordinal (default zero).

For example: C:918856795:E:936136795:F:1:D:17280000:W:4 would be someone who changed their password on February 12th 1999. It's scheduled to expire on Tue Aug 31, 1999. He has already been warned with warning message number four and will expire again 200 days after it gets been reset.

In addition to the last password change time and expiration schedules for UW NetIDs, the pwx database also keeps track of a few other key values as follows:

netid
An entry starting with a lowercase letter indicates a standard UW NetID password status record as described above.

uid:clusters
An entry starting with a digit indicates a pwsync entry. The "E" value indicates when /etc/passwd entries should be deleted from the pwsync database. If, when the time arrives, the indicated pwsync entry shows up with an expired shell it is removed.

/uid:clusters
A leading slash followed by a UID indicates the home directory for a pwsync entry. The "E" value indicates when files for pwsync entries should be deleted. If, when the time arrives, the indicated pwsync entry has an expired shell and no other entries share the home directory of that the files associated with that home directory are removed.

#subscription_code:netid
A leading octothorpe followed by a subscription code, a colon and a NetID indicates a non-pwsync subscription event. The "E" value indicates when a deactivate action should be performed on the indicated subscription. This will occur iff the subscription is either not permitted or is already in an expired state. Eg: A second deactivate is scheduled to delete expired UW Google Apps accounts four weeks after the first deactivate puts them into a suspended state.

$symbol
A leading dollar sign indicates a special symbol or semaphore. The value string associated with the symbol is interpretted by whatever tool set the value.

other
Other combinations of characters are subject to future definition.

Access and Security

Pwx uses Jim Fox's Lightweight Secure Connection Library to control access to the database. Each client connecting to the pwx dæmon must specify a valid LSC key. LSC keys have a public portion and a private portion. The key names are in the form: which encodes the following information:

X: Security level
The security level is a hexidecimal digit from 0 to F. The higher the level, the more privileged the client.

0: Level zero is unprivileged and can only access unprivileged commands.
2: Level 2 is required to retrieve values.
3: Level 3 is required to change values.
4: Level 4 is required to delete existing names.
A: Level 10 is required to checkpoint the database.
C: Level 12 is required to checksum the database.
F: The master servers all run at level 15.

group
The group is an arbitrary character string (eg: UCS, NDC, etc).

member
The member is an arbitrary character string, but for practical purposes should be the host name of the computer owning the key.
The public keys for the servers need to be distributed to each of the servers. There's a script, newkey.sh in the installation materials that will create a new private and public key and update the global file that gets installed everywhere. This script can be used when adding a new host to the list of server hosts.

The Transaction Engine

The PWX servers use the same transaction engine as the pwsync and deskmail servers. The Pwx server on each of the server hosts act as peers. Any one of them could be the master and the rest act as chiefs. If the master server goes down for whatever reason one of the chiefs will take over as master.

The Command Set

The set of commands supported by the server are:

Advance name [timestamp [delay]]
The Advance command sets the password expiration date to the specified timestamp plus the delay. If not specified or specified as zero, the current time is used as the timestamp. The delay defaults to the PWX_MIN_ADVANCE value in the /tulsa/include/pwx.h file.

Create name value
The Create command checks for the specified principal name in the Pwx database. If it does not exist, the command processing proceeds as in the Set command below. If the principal is already in the database, an "Already exists" error is returned.

Delete name
The Delete command deletes a name-value pair from the Pwx database. Deleting a nonexistant name is not an error and simply does nothing.

Get name
The Get command retrieves a value from the pwx database for the given name. If the name is not in the database an error is returned.

Modify name fields
The modify command is implemented in the stand-alone pwx client utility and is not a pwx server command per se. The pwx client fetches the current value from a local database and then generates a SetIf command to apply the updates iff one or more of the indicated fields is different than the current value. To use the modify command, the local system must run a pwx dæmon that maintains a local copy of the database.

Set name value
Stores the specified value in the Pwx database. The value field consists of several colon-delimited single character keywords and values. The keywords are described above.

Setflag name +/-bits
The Setflag command sets or clears the appropriate flags for the specified name. A leading plus on the bits field will set those bits, a leading minus will clear the specified bits and a leading asterisk will set the entire flag word to the specified bit pattern. The bit pattern is specified as a hexidecimal value.

SetIf name oldvalue"newvalue
Sets the specified new value iff the current value matches the specified old value. This allows the atomic function of applying changes without stepping on the toes of someone else who's trying to change some other field in the value.

Setpw name [timestamp] [delay]
The Setpw command sets the last changed time for the indicated user's password. The WARNED and EXPIRED flags are cleared. If not specified or zero, the timestamp defaults to now. If not specified, the delay is left as is. If specified as zero, the delay reverts to the default delay (default currently zero == no expiration). The expiration date for the password is advanced by the delay or is cleared if the delay (and default delay) is zero.

PWX command [parameters]
The above commands are all database specific. The generic commands prefixed by the PWX keyword are passed to the transaction engine for processing. These commands are described elsewhere.

Pwx, the Client Utility

The pwx utility is used to perform maintenance activities such as checkpoints and checksums and general debugging. In its standard mode:

The specified command is sent to the master server. If no -c option is specified or a single dash is specified for the command, all lines on stdin are processed as separate commands until there is an error, end of file or an end/exit/quit command is encountered.

If the optional symbol is specified with the -s (minus-sierra) option, that symbol (prefixed by a dollar sign) must be expired (or non-existant) in the pwx database before the commands will be processed. This implements a simple locking mechanism that can be used to allow multiple cron jobs, say, to all attempt a particular task and the first one in will get control.

The default delay on the symbol expiration is 12 hours. The minus-lima parameter can be used to change that expiration schedule. The default unit is hours, but you can indicate seconds, minutes, days or weeks by appending its first letter. Eg, -l 15m. Once established, the delay will persist, so it only needs to be specified if it needs to be changed.

The pwx utility also supports a mode wherein it spews out the status for a particular user:

The status of the specified user is issued to stdout in a format suitable for a user to read. The minus-two option causes the output to come out in second person. Default is third person. The minus-whiskey option will include html tags suitable for including in a web page to tell the user when his password will expire.

Pwxpire, the Expiration Processor Client Utility

The pwxpire command is used to process entries in the pwx database that are past their pull dates. Pwxpire does its job in several passes. First it will generate a list of things to do and then it will process that list, performing the desired actions.

-f file
Normally the directives list file is stored in /usr/local/lib/pwx/todo. This location can be changed with the minus-foxtrot option.

-u pattern
Normally all users are processed. The scope can be reduced to a subset by specifying a pattern to match individual users with the minus-uniform option. It's not clear why you'd want to work with a subset other than all or one, but hey, why not.

-s symbol
The minus-sierra option can be used as a semaphore to lock out changes by other processes. Normally the pwxpire utility is run to do its daily chores by a cron job on a number of servers. These servers all try to advance the same symbol. If the pwxpire utility detects that the symbol is less than 12 hours old it will do nothing. If it's older than 12 hours it will attempt to set it to the current time with the atomic SetIf command. If that succeeds, it assumes that it won the race and goes ahead and performs the daily chores. The symbol is stored in the pwx database with a leading dollar sign.

-l
The minus-lima option tells pwxpire to generate a new list of directives in its todo file. If not specified, the existing list will be used. This is mostly used with debugging since a current list is necessary when doing the daily chores.

-w
The minus-whiskey option tells pwxpire to send out warnings to people who are approaching their password expiration time. The warning comes out PWX_DEFAULT_WARN prior to expiration. This is defined in the /tulsa/include/pwx.h file (15 days). The actual warning sent to people is defined by the "W" key in their value. The message with ordinal zero is the default one. Message text appears in the /tulsa/src/pwx/msgs file. Once warned, the PWX_F_WARNED flag is set to prevent multiple warnings.

-p
The minus-papa option tells pwxpire to delete password entries from the pwsync database. Entries whose key starts with a digit are considered UIDs of account entries that may need to be removed when their expiration date arrives.

-r
The minus-romeo option tells pwxpire to remove home directories. Entries with keys starting with a slash indicate home directories that may need to be deleted. If the shell for the account is expired and there are no other accounts for the user that refer to the same directory, it is removed.

The normal pwsync password expiration is accomplished by setting the PS_CHANGE shell modifier in the pwsync database. This sets the user's shell on the pwsync computers to /usr/local/etc/pwchange# followed by their original shell. The pwchange utility repeatedly throws the user into the passwd utility until this shell modifier flag is cleared. The modifier flag will get cleared by two separate events. When the passwd utility receives an "ok" response from kadmind it will issue a pwsync command to clear the modifier immediately. If the user happens to use kpasswd on a desktop or other non-UA platform, kadmind will write the password to its squirrel log. The squirreld dæmon running on the KDC host will feed this password back to Kiwi. The master Kiwi server will send the password to the rest of the Kiwi servers which includes a slave running on the uwnetid.washington.edu cluster of computers. This Kiwi dæmon will clear the PS_CHANGE modifier as well as update the master pwxd dæmon with the new password change timestamp.

The pwxpire utility generates a report of what it did that looks something like:

The ineligible NetIDs are the ones that have a pwx presence, presumably because they have a Kerberos principal and have shown up in Kiwi, but don't have a presence in the pwsync system. If the indicated NetID subsequently shows up in the pwsync system after the password expires, the password will be advanced and counted here.

If the actual count of /etc/passwd entries and home directories deleted is lower than the number scheduled, it is likely because the /etc/passwd entry was no longer in an expired state or the home directory is now being referenced by another cluster's entry.

The non-pwsync subscriptions scheduled for expiration will receive a deactivate action if they are unpermitted or are already in an expired state when the event's expiration date has passed.

The 15 day counts include all the ones happening between five and fifteen days from today. These counts will include the accounts that have been reactivated whose original deletion time has not yet come up.

The PWX API

Communication with the Pwx servers is accomplished through the Pwx Application Programming Interface. This library is based on the standard transaction engine API. The Pwx specific routines are:
extern char *pwx_errmsg;
extern int  pwx_errno;

int   pwx_init(char *dir);

int   pwx_cmd(char *command);
int   pwx_stat_dec(char *value, pwx_stat_t *ps);
char *pwx_stat_enc(pwx_stat_t *ps, char *value, int len);

General Basics

The normal sequence is to call pwx_init with a null parameter to things set up. This initializes the various global variables and reads the configuration file, /usr/local/lib/pwx/conf, which defines the host and tcp/udp port and ordinal for the pwx servers.

Once initialized, the pwx_cmd routine can be called to issue individual commands to the server. The pwx_stat_dec routine will decode a character string returned by a get or list request into a pwx_stat_t structure. See the include file /tulsa/include/pwx.h for a description of this structure. The pwx_stat_enc routine can be used to encode a structure into a value string if necessary. A typical calling sequence might be:

    int  rc;
    char *s, line[128], user[12];

    while (fgets(user, sizeof(user), stdin)) {
      if (s = strchr(user, "\n")) *s = '\0';
      sprintf(line, "get %d", user);
      rc = pwx_cmd(line);
      if (rc != PWX_OKAY) {
        fprintf(stderr, "pwx get(%s): %s\n", user, pwx_errmsg);
      } else {
        pwx_stat_t ps;
        rc = pwx_stat_dec(pwx_errmsg, &ps);
        if (rc != PWX_OKAY) {
          fprintf(stderr, "pwx decode(%s): %s\n", user, pwx_errmsg);
        } else {
          fprintf(stderr, "User %s expires on %s", user, ctime(&ps.ps_etime));
        }
     }
   }

Ken Lowe
Email -- ken@u.washington.edu
Web -- http://staff.washington.edu/krl/