PWX - Password Expiration
- What it is
- Access and Security
- The Transaction Engine
- The Command Set
- Pwx, the Client Utility
- Pwxpire, the Expiration Processor Client Utility
- The PWX API
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.
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 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 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.
The pwx utility is used to perform maintenance activities such
as checkpoints and checksums and general debugging. In its standard
mode:
pwx -c 'command' [-s symbol [-l delay]]
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.
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.
pwxpire [-f file] [-lprwx] [-u pattern] [-s symbol]
- -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:
Created new shedule file: /usr/local/lib/pwx/todo
10 password expiration warnings.
182 password expirations.
156 ineligible netids.
45 password advances.
21 /etc/passwd deletions.
17 home directory deletions.
22 non-pwsync subscription expirations.
25 /etc/passwd deletions in 1 day
14 non-pwsync subscription expirations in 1 day
326 /etc/passwd deletions in 5 days
377 home directory deletions in 5 days
7 non-pwsync subscription expirations in 5 days
1297 /etc/passwd deletions in 15 days
1209 home directory deletions in 15 days
22 non-pwsync subscription expirations in 15 days
140 non-pwsync subscription expirations in 30 days
Sent 10 warnings, expired 182 shells, advanced 45 users.
Deleted 19 of 21 /etc/passwd entries.
Deleted 17 of 17 directories.
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.
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/