Timing Out Idle Users
All users should logout when they leave their workstations
extended period of time or when they leave at the end
of the day.
A workstation with a user logged in but not present
is an invitation
to a security breach. System administrators don't have
the time to
watch what everybody is doing and finger-wag when users
logout. Besides, after a certain amount of finger-wagging,
administrator loses credibility with the users.
The system knows how active the user's terminal is because
has to keep up with all of that activity. You could
make the system
monitor the users' activities and, if one of the terminals
for longer than a specific time, force the user to logout.
has a special program for this, named idleout. SVR4
such program, but a simple shell script can do the same
Run the idleout(ADM) program only once. idleout monitors
user activity on all tty lines to see when a line has
inactive for longer than the time you specified. Name
the idle time
in either minutes or hours:minutes. For instance, use
to force a logout on any tty line inactive for
more than 20 minutes, and use
to force a logout on any line inactive for more than
an hour and a half. You could also use
to force that same hour-and-a-half timeout. If you don't
provide an idle time threshold, idleout uses the default
in the textfile /etc/default/idleout. The textfile sets
environment variable named IDLETIME. The default setting
120, or two hours.
If you execute idleout manually, as root of course,
a shell, detaches from the shell you launched it from,
for 60 seconds. When it wakes up, it looks at the tty
to see if any of them have been idle for longer than
you named. If so, it kills the offending process.
The idleout program never finishes, even if it kills
tty processes. You can't just turn it off. It keeps
the tty processes, checking them once a minute and killing
any subsequent idle tty processes that come along. If
as root, want to kill the idleout process, you must
process status list using ps(1) and find the "sleep
process. You could track that process back to its parent
(ppid) and find the shell, usually identified as "-sh"
in the ps list. Then, kill the shell and the sleep process.
But rarely would you run idleout manually. Instead,
automatically every time you boot UNIX.
Monitor the tty idle time with every reboot. Install
in the bootstrap rc files. The /etc/rc* files are shell
scripts containing the run commands executed with every
or shutdown. There is a primary file named /etc/rc;
are named for the various system run levels:
/etc/rc0 Init level 0 for system shutdown
/etc/rc1 Init level 1 for single user mode
/etc/rc2 Init level 2 for multiuser mode
/etc/rc3 Init level 3 for networked multiuser mode
These scripts refer to the contents of one of the following
/etc/rc.d Contains common run command directories
/etc/rc0.d Contains init level 0 run commands
/etc/rc1.d Contains init level 1 run commands
/etc/rc2.d Contains init level 2 run commands
/etc/rc3.d Contains init level 3 run commands.
The directories named after the init levels represent
the usual way UNIX SVR4 handles the run commands. The
file names in
those directories begin with an S or a K to identify
scripts that start or kill processes. A two-digit sequence
that follows the S or K identifies which file in the
S or K group must run first. The rest of the file name
generally identifies what the script does. For example,
Table 1 shows
a sample rc2.d directory's contents, and Table 2 shows
rc0.d directory's contents.
Another method for handling the run commands uses the
The rc.d directory contains subdirectories named with
digits from 0 to 9, representing the execution sequence
of all scripts found in those directories. Put a script
in that directory
to execute it during system startup or shutdown.
Figure out which method your system uses and change
or /etc/rc2.d/S88USRDEFINE to start idleout with the
number of minutes you want to allow.
If you don't have SCO UNIX, you can still kill idle
with a shell script. The script combines who(1) and
The who command identifies the ttys in use and their
idle times. The awk script analyzes who's output, decides
which ttys are too old, and puts them out of our misery.
1 shows the killidle script.
The colon in the first line forces a Bourne shell to
execute the script.
The first code line,
sets the IDLEOUT variable to either the value in killidle's
first command line argument or 20. Instead of using
if tests to see
whether there is a $1 argument, I use the shell's own
substitution mechanism. This syntax says that if $1
has a value,
use it. If there is no $1 or it has a zero value, use
Whichever is selected, assign the result to the variable
The next step avoids trouble if the user gives a negative
chose to set IDLEOUT to the default 20 minutes if a
time is discovered. As another approach, you might use
to change the value's sign.
With IDLEOUT valid, the script uses the who command
to get the user list. The -u option limits the output
those people currently logged in. It also shows the
idle time for
each of those logins. The code pipes the output to the
program to process that idle time.
The awk script doesn't contain a pattern, just an action.
keep things easy, it extracts the column values needed
and output: the user's name, the terminal ID, the idle
time, and the
login's process ID.
If a user has pressed a key at the tty within the last
that tty's idle column shows a period. The script's
first if test
eliminates that condition from the script's concern.
Given some idle
time amount, who shows it in the format hours:minutes.
hours may be set to zero. Only the minutes are needed
for this script.
An easy way to isolate the minutes is to treat the colon
as a field
separator and split the idle time into an array. Awk's
function does that work. split's first parameter is
to be split. The second is the array to put the split
The third is the field separator. split creates the
the second parameter if the array doesn't already exist.
subscripts start at 1, so idletime holds the hours
and idletime holds the minutes. If the minutes idle
is greater than that specified in the IDLEOUT variable,
is time to kill the process.
Assuming that a warning message for killed processes
might be helpful,
a print statement identifies which user on which terminal
being logged out, how long the terminal was idle, and
the pid for
debugging the script. This output not only aids in debugging,
also allows you to build a log file from the output
to identify users
who tend to leave the terminal idle long enough to create
Having identified which pid has been idle too long,
script uses its system function to send a kill signal
to the pid.
The signal number 9 is the kill signal that can't be
by an application and can't be intercepted to make it
The only process that can withstand a signal 9 is a
trapped in the kernel. Processes trapped in the kernel
are often known
as zombie processes, because they live on after being
they just don't want to die.
Sending the signal 9 is an extreme measure. Its main
is that it can't be intercepted and it can't be ignored.
When a process
receives this signal, no matter what it was doing, it
means any cleanup actions it should have done won't
get done. You
might find it nicer to send a signal 15 instead. A process
can intercept signal 15 and trigger its cleanup operations.
Another nice signal to send is 1, the hangup signal.
will think there's no connection any more and should
These are weaker signals, though, and a process can
choose to ignore
them. The signal 9 gets through no matter what, except
those pesky zombies.
At the end of the script is the funny-looking syntax,
Notice that this appears on the awk command line
after the script has finished. awk doesn't use the shell's
environment variables directly. Getting a shell variable
or any other
value into an awk variable requires the use of an assignment
on awk's command line. I chose to use the same name
shell variable to keep references simple.
Several worthwhile changes would include:
accommodating the keyword old in the who's
idle column for idle times older than 24 hours
handling the full hours:minutes format for a large
number of minutes requested, such as 120, or for an
request format, such as 1:30
working from a table identifying certain users with
different idle times, allowing the fine-tuning of the
idle times for
certain special users.
You can run killidle any time manually. Just type
to use the default 20-minute idle time, or type
where minutes is any positive number for the idle
The script looks through the who output and kills any
idle for too long. If you're not root, though, you can
only kill your
own processes. The output messages tell you who else
has been idle
too long, but you can't do anything about it unless
Of course, running killidle manually is a bit silly.
have to remember to run it periodically, and it wouldn't
be much of
a security monitor run if you forget to run it. If you
run it from
root's crontab, you can set it to run around the clock.
a root cron job, it has root's privileges, so it could
other login processes without restriction. Finally,
since all cron
command output is automatically captured and mailed
to the user whose
crontab is executing, root would receive a mail message
all of the timeout warnings for each killidle run.
The simplest way to put killidle in the root crontab
is to use the
* * * * * /usr/local/bin/killidle
assuming that /usr/local/bin is the directory
holding the killidle script. The five asterisks tell
to run killidle once a minute every minute of every
is up. That could be extreme, but it would get the job
done. To reduce
the script's impact on system resources, run it only
a few times an
For example, the crontab line
0,15,30,45 * * * * /usr/local/bin/killidle
checks for idle ttys every 15 minutes. Considering
that the script's default is 20 minutes idle, the worst
time would be 29 minutes for a login started one minute
last run. Fourteen minutes later cron runs again, but
has run for only 14 minutes, which is less than killidle's
20, so killidle leaves it alone. Fifteen minutes later,
of 29 minutes, cron runs killidle again and catches
the old tty.
You could run killidle with a 15-minute option. If you
however, the same timing problem appears. A login that
is only 14
minutes old when cron runs killidle would survive this
run. killidle would eliminate the login 15 minutes later
the login were still idle. That login would have survived
for a total
of 29 minutes.
You could set killidle to test for an interval less
interval cron runs. For example,
0,20,40 * * * * /usr/local/bin/killidle 19
kills anything 19 minutes old or older. Because cron
runs every 20 minutes, a login that started one minute
after the last
cron run is 19 minutes old, qualifying for the kill.
still not eliminating the problem completely. If a tty
two minutes after the cron check, it will be only 18
and thus will pass the 19-minute test. Another 20 minutes
the cron job starts killidle again, allowing a total
of 38 minutes of idle time.
How long you let idle logins run depends on what you're
live with. On the one hand, it doesn't take very long
to use an account left idle to break into the system.
On the other
hand, you're not going to please everybody. Some programmers,
instance, work at their desks near the terminal and
are not on the
terminal every moment. It isn't nice to log them out
got important facts on the screen and are busy looking
through a listing.
This is where a table of user idle times that can be
used by killidle
comes in handy. You must find a balance between security
who need their temporary login environment changes and
to remain intact when they're only away from the terminal
for a moment.
You decide how long a moment lasts.
About the Author
Larry Reznick has been programming professionally since
1978. He is currently
working on systems programming in UNIX and DOS. He teaches
C language courses
at American River College in Sacramento. He can be reached
via email at: