[sf-lug] one-shot force password change and lock if not changed by ...

Michael Paoli Michael.Paoli at cal.berkeley.edu
Tue Apr 14 01:09:53 PDT 2020


So, not uncommonly, as a linux sysadmin, one ends up resetting a user's
password ... it happens.  Or one sets up their account initially.

In any case, easy enough - they're given a secure (as in non-trivial,
difficult to guess or brute force) password.  However, it may go
over less than wonderfully secure communications channel, or regardless,
often per various security policy(/ies) and/or best practices, not only
should user then change their password "immediately" (or as soon as
feasible), and they should be forced to change their password
upon first authenticating with that initial or reset temporary
password (easy enough with Linux:
chage -d 0 user
), but additionally, account should be locked if they don't
change their password after some set period of time (depending
upon policy and such, between 3 and 10 days is pretty typical).
Well, that last bit, there isn't quite a simple standard
Linux way to do that with one mere simple command.  But regardless,
it's still pretty easy to do.  Let's say, for illustration,
our user's login name is user.  We can then do something like this:
# (cd / && at now + 10 days << \__EOT__
grep '^user:[^:]*:0:' /etc/shadow >>/dev/null 2>&1 &&
usermod -p '!' user
:
__EOT__
)
warning: commands will be executed using /bin/sh
job 51 at Thu Apr 23 23:30:00 2020
#
Something like that, with slight changes, would be easy enough
to script ... and could be added to some standard program used
to create users, or reset their passwords - to ensure their
accounts would lock if they didn't change from the temporary
password they were (re)set to and should change, within some
specified (/policy) period of time.

And, in the above example, if one entered it interactively, shell
would prompt with PS2 (defaults to "> ") while it was waiting
additional lines of input to complete the command (I didn't show
that bit).

How does it work?
shadow(5)
chage(1)
usermod(8)
at(1)
The 3rd field of /etc/shadow, indicates (nominally) when the
password was last changed, in days since the (Unix/Linux) epoch.
That is used in /etc/shadow to enforce various bits of password
aging/lifetime.  If that field is empty, it's unknown/unspecified.
If the field is set to 0, however, it has a special meaning.
It means the password is expired, force the user to change the
password.  So,
# chage -d 0 user
forces user to change password once they login.
Though there are other aging mechanisms available in standard shadow(5),
including things like minimum and maximum days between password changes,
and an absolute expiration date (account "expires" and is locked at that
date), there's nothing in there that will force user to change their
password by a certain date(/time), and if not changed, lock or expire
it, but don't otherwise use or set any particular aging or expiration
criteria.

Well, we can use at(1), to do something in the future., not all that
unlike cron(1) and crontab(8), but those latter ones are suited for
recurring tasks.  However, at(1) is quite ideal for a one-shot scheduled
task.  Anyway, for such a deadline to change a password, we can use
at(1), check if the password has still not been changed (3rd field
of /etc/shadow is still 0), and in such case, lock the account.
The usermod command works for locking.  Generally don't want to use
the -p option of usermod, as it "leaks" (available via ps(1), etc.)
password (hash) information, and that's not good from a security
standpoint.  But in special case such as '!', it leaks no password
data (only leaks that the account is being locked) ... as that's what
! does for 2nd (password hash/salt) field of /etc/shadow - it locks the
account.

Anyway, thought some might find that useful/informative.  Many often
get, e.g. policy (or want to do best practice of) of, must lock account
after N hours/days, if after reset or creating initial account, user
still hasn't logged in and changed their password.  Anyway, the
example bits shown would cover that.  Could also do a bit of catch-all
similar with cron/crontab ... run some kind of check, capture state,
recheck ... if after the number of hours/days, user still hasn't
changed their password, lock the account.  The only possible slight
gotcha, with either approach, is when finding 0 for the days since
epoch of last password change, there's no way, retroactively, to
know for sure when that 0 was set in there.  E.g. did the user
get a password reset on Monday, totally mess up, get yet another
reset on Wednesday, then system locks them out on Thursday (72 hr.
limit from Monday) - while user was (rightfully) thinking they had
'till sometime on Saturday to change their password.

But wait, there's more!  (Left as exercise :-))
2nd field (password hash/salt) in shadow(5), if it is or starts with !,
locks the password (makes it invalid / impossible to match).  It also
generally disables scheduled at/batch/cron jobs.  But that doesn't
fully lock the account out in all ways.  We bit more is needed to
fully cover that.  (And yes, I've written programs that do exactly
that - fully and securely lock user out of a given host).

As another slight exercise, hash field of "!", but bit better
would be "!*" - can you explain why?

Some might also wonder/ask - why not just remove the account?
While that does securely lock the user out, it also has some
security disadvantages - and some policies (e.g. C2) instead
require the account be securely locked (or "retired"), but
not removed.  Why?  Audit trails and file ownership, etc.
For sake of argument, let's say you remove a user, that has
UID 3333.  Maybe you removed all their files, maybe you
didn't.  Now there's nothing to prevent creating another user
with the same UID (3333).  For the most part, the system cares
about UIDs and GIDs.  The names are mostly there to make life
easier for us mere mortal humans.  So, a new user is
created, and happens to get UID 3333.  Now they own any files
left by the earlier user.  Oops - security issue.  Oh, no issue
with files?  Two years later, you've also gotten rid of that second
user that had UID 3333.  Then a year later, you end up needing to
investigate a security issue.  UID 3333 was somehow involved.
Which user was it?  Now that becomes messier to determine.
Ah, it was UID 3333's file!  Which one of them created it?
Okay, so maybe you don't hit that issue.  Some weeks/months
later a bunch of files need to be restored (novice admin did
something bad on a filesystem - oops).  No problem, you've got
backups.  And UID 3333's files also get restored.  But which user
do they belong to?  The former user with UID 3333, or the current
one?  Anyway, by not removing the account, but instead securely
locking it, one avoids all these additional gotchas.  "Of course",
securely locking - one needs do that properly, lest there be
remnant security issues from that.

Semi-random: Automation - generally a good thing, recent handy example:
https://lists.balug.org/pipermail/balug-talk/2020-April/000205.html




More information about the sf-lug mailing list