A directory service doesn't make it easy to disable user accounts

July 28, 2011

A typical reaction on Reddit to my earlier entry on the complexity of disabling accounts is this:

Couldn't this be solved by moving to an LDAP based (or AD for windows environments) login?

Unfortunately, the answer is no; a directory service doesn't make disabling users much easier, not by itself. The problem is inherently complex.

Let's imagine that we have some directory service; it stores user information, including multiple passwords, and it has a 'disabled' flag. What has to pay attention to the 'disabled' flag in an environment like ours?

  • a disabled account should fail all password validation; this handles simple logins, Samba access, IMAP, and things like a VPN.

    (The directory service may handle this for you, or you can explicitly invalidate the passwords as well when you set the disabled flag.)

  • sshd must refuse to authenticate any disabled account, with or without passwords, even when it's not even running a program through the user's shell (as Dan Astoorian noted in a comment on the last entry).
  • crond and atd must ignore crontabs and at jobs for disabled users.
  • your MTA must refuse to run programs for disabled users; this handles pipes in the user's .forward et al.
  • the web server must refuse to run CGIs for disabled users.

    (Really it needs to refuse to run any code for disabled users, including in-server code in languages such as PHP. But let's assume that you don't allow users to do that; all of their code has to run under their UID in one way or another.)

(Because many of these daemons explicitly run things using /bin/sh, simply changing the user's shell to an invalid shell won't achieve this.)

  • your Unix systems need something that kills the processes of (newly) disabled users; this will handle both current logins and background processes that the user's left lying around.
  • your network (including VPNs and wireless authentication systems) need something to terminate the sessions of (newly) disabled users.

  • if you have authenticated web services that use cookie-based sessions, they need to invalidate the sessions of now-disabled users.

    (You can do this either preemptively or on the fly as you check the session during a HTTP request, but you have to do it.)

  • your DHCP server (or its database) needs to track the user associated with a machine and ignore the machine if it was registered by a disabled user. (If you allow users to register machines you probably should allow such machines to be re-registered by another user, which opens up interesting issues.)

So here's the question: today, how many of your daemons and systems actually support doing this as they come out of the box? The answer is almost certainly 'none' or 'very few' (and the example of sshd shows that support for this may be ad-hoc, inconsistent, and incomplete). Where they do not have out of the box support for this, you need to either add it or handle these cases by hand (eg checking for user crontabs, disabling the user's .forward).

Disabling a user using a directory system is only simple if you do not have services that do things on behalf of the user and the user cannot have lingering activity on your systems. This is the case in some environments (such as Windows desktop environments), but it's often not the case in a Unix environment. Where you do have 'on behalf of' services, they have to know to not do things for disabled users; where you have lingering or ongoing activity, something has to know to terminate it. Today this is generally not an integrated feature in anything (at least on Unix; Windows may have better integration for this with AD).

Some but not all of these cases get easier if you can hide (or delete) the disabled user's entry in your directory service. But it isn't a complete solution and it has (probably) undesirably side effects, and the Limoncelli test specifically talked about disabling a user, not deleting them (and hiding a user's entry is much closer to deleting them than simply disabling them).


Comments on this page:

From 70.26.87.112 at 2011-07-28 19:56:32:

The main areas of entry to disable could be taken care of by doing the following:

  • add a pre- or post-fix to their username: DIS-userid or userid-349
  • typing garbage into their password field
  • changing their shell to /bin/{false,nologin} or some such
  • slightly altering their homedir to something like /home/useridDISABLED-alkdfja

All of the above can also of course can be done with distributed flat files. One can add an account status attribute on top of this (active/disabled/locked/etc.) if so desired.

I think this takes care of a good portion of scenarios, as the user ID is changed to hopefully something less than easy-to-guess so simply logging in won't help, compounded by the fact of a 'reset' password. Cron and at jobs are taken care of because the user ID in question is no longer valid. Tweaking the permissions on the account's homedir (chown 0:0, chmod 000) could also be useful if it's centralized (or even renaming it as well).

Another handy thing would be to keep the sudo configuration in LDAP so the user's account can be removed there as well (or renamed to a different value, perhaps different to the passwd rename).

In the end using a non-DS solution for keeping track of users is probably no big deal if you already have a system in place, but for most sysadmins re-inventing the wheel is probably not a productive use of their time. Creating something simple may be simple, but the as time goes on one will probably find more corner cases that need taking care of.

The wheel has been invented, so just use it unless you have a really good need to re-invent it IMHO.

From 188.226.51.71 at 2011-07-31 23:04:04:

Note that if we're talking about Linux, there's systemd, which already has capabilities to supervise everything that user spawns for services that use PAM mechanism (pam_systemd) to initiate sessions - sshd and crons certainly fall into this category.

Killing user sessions then becomes as simple as "systemd-loginctl kill-session ..." or "systemd-loginctl kill-user ..." (or doing the same via python-dbus calls), and since pam module properly puts initial processes in a cgroups, it's easy to monitor, arbitrarily limit (resource throttling, weights, freezer, etc) or kill these, with no chance of escaping for unprivileged processes.

I don't know whether pam has the mechanism of invoking something like "kill-user" in logind on disabling, but I'm fairly sure you can hook such actions to directory service. Maybe such hook would be considered "not a directory service", but then I'm not much familiar with that term.

mail - open pam session in a delivery agent. web - just use pam auth, httpds support this, so are scripts. dhcpd - pam.

Problem solved? ;)

By cks at 2011-08-01 07:49:44:

The mechanisms to do all of this are generally there (with or without systemd). What's missing is the integration to actually do these things automatically; as it is, you have to either write code to handle it or do it by hand. Today, there is no way to just deploy LDAP, set a 'disabled' flag in a user's entry, and then have all of this happen for you automatically.

From 188.226.51.71 at 2011-08-01 23:49:20:

Agreed. There's no magic "I don't care how, just make it work" button (except the one that calls the sysadmin to do it for you). If that was the point, guess I managed to miss it.

Written on 28 July 2011.
« Another reason why version control systems should support history rewriting
Deciding the meaning of 'disabling' an account (and the value of procedures) »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Thu Jul 28 16:39:38 2011
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.