closeit: A Login Management Tool
Most system administrators work hard at keeping their
systems up and
available to users as much as possible. But there are
times when you
need to do just the opposite -- keep certain users off
I help support a UNIX system where I occasionally need
to bar users
from logging in for a short time while I make changes
to their applications
or profiles. I developed a quick script to let me do
this. I found
myself using the script often and eventually expanded
it into a more
It's easy enough to disable all logins on a UNIX system
or lock any
individual account, but I needed more. I wanted to be
able to disable
all accounts, just one account, or any list of accounts.
And I needed
to be able to reopen them quickly and selectively. Also,
while I wanted
to keep the users out, it was essential that I still
be able to log
in as those users or su to their accounts, since certain
could only be tested with their identities. Finally,
the system is
a commercial one, and the users pay for their access.
the need for occasional, and sometimes unexpected, maintenance,
appreciate knowing when they can expect to get access
again. To preserve
good customer relations I needed a way to tell them.
I call my script closeit, and it meets all of the above
It comes in two parts. The first and largest (see Listing
1) is comprised
of routines that let you identify the accounts you want
compose your message to the user, and flag the accounts
The second part (see Listing 2) is an addition to the
file, which is sourced by the login shell for every
user login. This
part detects the flagged condition of the account, displays
to the user, and aborts the login. It does not kill
an active user
session or abort current user processes; it simply prevents
logins until you reopen the account.
I wrote the script in the Korn Shell for a System V
UNIX, but it could
be implemented, with minor changes, in any UNIX environment.
script begins with some variable assignments, proceeds
definitions and then to the main line of its processing.
order of appearance, the separate functions do the following.
Usage() uses a fairly standard format for informing
of the purpose of the script and its proper syntax.
Getusers() looks at the /etc/passwd file and picks
out the lines that end in sh, i.e., the "real"
accounts. It sets the fields of each successive line
to the shell's
positional parameters, and from these selects the user
and home directory. It puts these in a file ($DIRECLIST),
with each line of the form
I explicitly exclude root and an account called sysnews.
You may have special exclusions you want to make at
your site. If
you prefer, you can make this user list into a static
the script, but I want to know it's up to date, so I
build it each
time the script runs. Doing this also reduces the chance
that it will
become corrupted or "inadvertently" modified.
MakeMessage() lets you compose the message the debarred
will see. I almost always use the same format, which
tells the user
when the account can be expected to reopen. This default
provided in the script. However, you can edit this into
a new message
with your favorite editor ($C_EDITOR).
WriteMessage() writes your message to a file called
(or a name of your choice) in the user's home directory;
serves both to contain the message and to flag the account
Before writing it it bundles the text into a here document
shell's "<<" redirection and passes
this to a subshell (lines
177-178). This has the effect of causing any shell variables
you include in the message to be evaluated. In my default
I use the variables $USERNAME and $OPENTIME. You can
edit these or add others of your own. Once again, I
create my message
in the script, rather than storing it in an external
file. Then I
don't worry that it will become corrupted or be modified
types who might get access to it (at least I don't worry
ListWho() lists all the accounts that are closed at
you invoke it. This is a standalone function and is
also tacked on
to other operations as additional confirmation of what
you have done.
Finally, GoAhead() is a routine that gives the user
to back out. If the user continues, the routine checks
to see if the
$OPENTIME variable is being used in the user message
if so, prompts for the reopening time.
The Main Program
The main line of programming is divided into two parts,
on the name it is invoked under, which can be "closeit"
"openit." The closeit section validates the
of the command and uses the Usage() routine if it needs
It then calls Getuser() and MakeMessage() and gives
you a chance to back out. If your command was "closeit
it then closes each account identified by GetUsers().
just entered "closeit," it will take user
names one at a time
from standard input, confirming each closure or giving
you a failure
message. Press your EOF key (usually Ctrl-D) when you
You can also invoke the script as "openit."
This line of the
program lets you reopen all accounts or a list of accounts
enter at standard input. It reports the results for
each one: either
the account reopened successfully, failed to do so,
or wasn't closed
in the first place. It will take input from standard
you invoke it as "openit all." In that case
< $DIRECLIST on line 285 will redirect input from
file and process each user account in turn.
When you give account names to this script, it will
act on the first
name in $DIRECLIST whose leading characters match what
give it. You don't need to enter the whole account name,
avoid ambiguity; it will report back the actual account
it is acting on.
Setting Up /etc/profile
The portion of this system that goes in /etc/profile
Listing 2. This should be at the head of your /etc/profile
file. It looks at the home directory of the user logging
in to see
if .closelogin exists there. If it does, it displays
and waits for user input. Your message should request
that the user
hit the Enter key. When input is received, the routine
looks to see
if what was entered matches a special string, which
it gets from another
file. If it does, login proceeds normally. Otherwise
a no-op program
(/bin/false) is exec'd by the shell, aborting the user's
System Administration Considerations
Using a password in closeit lets you log in to the account
even when the user can't. Note, however, that each user
must be able
to read /etc/profile; otherwise, /etc/profile is not
used at login, and your efforts here will have no effect.
is readable by users, however, they will know where
you store your
secret password (the file /nowrite/.secret in my example),
and this file must also be readable by them. In my case
not a problem, since users do not have access to a shell.
If your users do, they could easily find out what the
and circumvent the system. You may want to make this
less likely by
writing a new password to the file just before using
You could add this function to the script if you wish.
The file that
keeps the password is readable by all, but should be
If you want more protection you can consider using crypt
some other encryption mechanism to make the procedure
more like a
real password. But keep in mind that closeit is not
system, and you shouldn't try to make it one. Don't
use anyone's real
password with closeit, especially not root's. It will
be secure. A clever user could devise other ways to
system, such as starting a daemon to clear the flag
file from his
home directory every few minutes. You could change the
name of that
file from time to time, but if the user is that uncooperative,
for other methods to control access.
The message you display to the user should also be created
in a directory
writable only by root and should itself be writable
only by root.
This will help ensure that no one except you can modify
it. closeit should only be executable by root; it tests
this at the head of the script.
When you use closeit, be sure you know how the account
be opened again if you should be unable to reopen it
or forget to
do so. Before using closeit you can pass
openit all >&-
to the UNIX at command, to ensure that everything
gets opened up in, say, an hour, even if you aren't
there to do it.
And, of course, be sure that closeit can never close
account. If at some point you can't use openit for any
use the find command to find any flag files in users'
directories and remove them.
To use closeit, put it somewhere in root's path and
to openit in the same directory. Make sure only root
write, or execute it. Make changes to the variables
at the head of
the script if you need to, and set up your "password"
in the same root-writable-only directory where you will
message. Test closeit first on special accounts you
for that purpose. Put it into production only when you
that it works as you expect it to.
About the Author
Tom Everson is a partner in Nova Business Systems,
software developer and UNIX services company in Portland,
He got his start in computing with IBM in 1973 (when
program required a cruiser class mainframe), after receiving
in Philosophy from the Johns Hopkins University. He
has worked with
PC-based UNIX systems for the last five years.