forcefully end user sessions nightly

I used to use this script to nightly terminate all user sessions and it seemed to work for quite a while, but it is no longer clearing out my sessions:

Code:
who | awk {'print$1'} | xargs -L 1 -I _USER_ pkill -KILL -u _USER_
who | awk {'print$2'} | xargs -L 1 -I _TTY_ pkill -KILL -t _TTY_

Xorg is no longer terminated, I have always started that after logging in via the console via startx. To remedy that recently, I added this:

killall Xorg

I also noticed that my ssh-agent was not being killed, so I added this:
killall ssh-agent

While that seems to have killed X and ssh-agent so I need to reenter my passphrase, it doesn't forcefully log me out of the console. I had thought about restarting the getty processes and tried sending a SIGHUP, but that seems to have messed it up rather than force me to logout.

What do others do to clear out user sessions nightly?

I'm the only user on this system, and my thought process from the start was that by limiting how long the sessions were, I would at least force the user to start a new session if somehow a malicious user obtained access and by doing so, it would at least potentially trigger more alerts than if they had maintained a session the entire time.
 
Look at 'idle' timeouts, every shell has it. After an X amount of time of no activity you're simply logged off. Not sure about Xorg but that should have one too, though I've never used it (typically use a locking screensaver there).
 
How about this? It might not work on vt(4) though.
/etc/rc.conf
blanktime="120"

I guess that does your users no good though.

Edit: Or does it? It should blank any user of the system.
 
I updated /etc/login.conf, setting the default sessiontime to 5m and idletime to 5m just to see how it would work. I should also note that I ran:

Code:
cap_mkdb -f /etc/login.conf.db /etc/login.conf

With -v, I see that it thinks there are 9 capability records, but I should have ~29. Excluding the unlimited ones, ~14.

Code:
:sessiontime=5m:\
:idletime=5m:



I also logged out of the X session and console, then logged back in. Nothing.
 
At first I had read "forcefully end user session rightly", and that has a rather different meaning.
Normally it should be enough to find the login shell of that user and terminate that, no?
 
Yes, that is what I was originally doing with the script I've had running for about 2 years:

who | awk {'print$1'} | xargs -L 1 -I _USER_ pkill -KILL -u _USER_
who | awk {'print$2'} | xargs -L 1 -I _TTY_ pkill -KILL -t _TTY_

The recent change I made was to send a KILL. I am still not logged out though.

I suppose I changed something recently to where that is ineffective. The only thing that comes to mind is that I've written a bunch of scripts that are trapping signals to cleanup properly. A kill though cannot be trapped, so I am doubtful that is it in particular.

I am looking for a clean way to do this, while pkill worked in the past and seems simple enough, it also seems hackish. If login.conf is more elegant, then I'd prefer to go that route. I'm still investigating why pkill isn't working.
 
How about "doas user kill -9 -1"? Kill all processes that belong to that user?
 
How about "doas user kill -9 -1"? Kill all processes that belong to that user?
Yes, but I don't want to do that:

1. any running processes are not properly cleaned up, files in /tmp may linger, yes they'll be cleaned up by another process, but I'd prefer not to wait ...
2. that doesn't handle startx, I can handle that separately.

My main complaint is #1, it isn't clean.
 
Can you explain what underlying problem you are trying to solve?

Most importantly: Why end user sessions? An idle shell, sitting at the prompt, uses virtually no resources. Matter of fact, if the same user needs to use the computer again in the morning, the overhead of logging out and logging back in probably exceeds the cost of tying up a few resources over night. With X sessions, that argument still applies, except the total resources are larger, but the overhead (in particular in user time) are also much larger.

Is there a reason you need to maximize availability of something (CPU? memory? swap space?) at night, and having logins still active reduces that availability? That doesn't seem to make sense, unless your limiting resource is swap space; the others are unused by an idle session.

There are several ways user sessions can be started. The most common three are the console (the physical keyboard and screen attached to the PC), serial ports with terminals, and network logins via ssh. For console sessions, wouldn't it be easier to talk to the humans who have physical access to the machine, and teach them to log out before nightfall? I don't know whether you use serial terminals (they are quite unusual today), but for those autologout in the shell seems like a sensible solution. For ssh CLI sessions, the automatic timeout of ssh culls unused logins automatically.
 
The problem (I think) I am trying to solve is allowing users (myself) to remain logged in indefinitely where an account may be compromised. I occasionally look for anything abnormal, but of course I am trying to be more methodical about it.

Yes, it is more efficient to leave resources where they are as opposed to closing and reopening, but that is not the problem I'm trying to solve.

I used to use a graphical login, xdm, slim, gdm, etc., but now, I login directly through console for simplicity of configuration and I don't need those bells and whistles.

I am the only user, this is only on my box :) ...
 
... where an account may be compromised.
...
I am the only user, this is only on my box :) ...
I think I understand: Officially, you are supposed to be the only human who uses this machine. But you're worried that a hacker has compromised your account (managed to log in, perhaps by stealing your password), and as a defense against the hacker, you want to log them out once every 24 hours, in the middle of the night. If this is a correct interpretation, it seems like closing the bathroom window a day after the horse left the barn. The damage a hacker can do in the ~12 hours before their session is stopped is immense. And given that they managed to log in once, it is likely they will be able to log in again.

Another possible interpretation: You like to log in on the console (in shell mode), and not log out. You are worried that in the middle of the night, while you are sleeping, someone could physically walk up to the console, and use the existing shell prompt. Honestly, my answer to that would be: (a) Set the autologout in the shell, (b) get a dog. But killing all processes that are shells that logged in from a physical console would also work to stop the shell. For that, it should be as easy as "ps -jaux", look for all processes that have a non-trivial entry in the TT column, then filter out those that are running login or getty; the remaining ones are the logged in user processes.

As you point out in your initial post, that works pretty well, but it doesn't catch processes that have detached from the controlling terminal. For that, you may have to go a little further: In the ps output, first record the PID of the login processes (which will typically be a shell). Then rescan the ps output for all processes that have a PPID or PGID that is identical to the shell's PID, and kill them.

Finally, it is quite possible that some of those processes are resistant to normal kill (with TERM or QUIT). I think standard practice is to first try TERM and QUIT, then give the process a reasonable grace period to perform cleanup (like 10 seconds), and then use KILL (a.k.a. kill -9) on it.

Does this make some sense to you?
 
How about "doas user kill -9 -1"? Kill all processes that belong to that user?
Signal 9 can't be caught and can't be ignored. So that's going to terminate all processes with extreme prejudice, allowing no opportunity to preserve state. Anything resembling a database is likely to get corrupted. Signal 15 is almost always a better choice...
 
I think I understand: Officially, you are supposed to be the only human who uses this machine. But you're worried that a hacker has compromised your account (managed to log in, perhaps by stealing your password), and as a defense against the hacker, you want to log them out once every 24 hours, in the middle of the night. If this is a correct interpretation, it seems like closing the bathroom window a day after the horse left the barn. The damage a hacker can do in the ~12 hours before their session is stopped is immense. And given that they managed to log in once, it is likely they will be able to log in again.

Another possible interpretation: You like to log in on the console (in shell mode), and not log out. You are worried that in the middle of the night, while you are sleeping, someone could physically walk up to the console, and use the existing shell prompt. Honestly, my answer to that would be: (a) Set the autologout in the shell, (b) get a dog. But killing all processes that are shells that logged in from a physical console would also work to stop the shell. For that, it should be as easy as "ps -jaux", look for all processes that have a non-trivial entry in the TT column, then filter out those that are running login or getty; the remaining ones are the logged in user processes.

As you point out in your initial post, that works pretty well, but it doesn't catch processes that have detached from the controlling terminal. For that, you may have to go a little further: In the ps output, first record the PID of the login processes (which will typically be a shell). Then rescan the ps output for all processes that have a PPID or PGID that is identical to the shell's PID, and kill them.

Finally, it is quite possible that some of those processes are resistant to normal kill (with TERM or QUIT). I think standard practice is to first try TERM and QUIT, then give the process a reasonable grace period to perform cleanup (like 10 seconds), and then use KILL (a.k.a. kill -9) on it.

Does this make some sense to you?
That is it, yes, that is true, but at least it can slow them down, some ... and perhaps make it more evident. Who knows, if they're in, maybe they will stop the timeouts ...

Yes, that makes sense. I am still wondering what I must have done recently to my system for the initial script I posted to have stopped working. It works with the -KILL, but then I need to cleanup /tmp :(. And, it is possible that files do get corrupt.
 
I restored my system and it is working properly again without the kill:

who | awk {'print$1'} | xargs -L 1 -I _USER_ pkill -u _USER_
who | awk {'print$2'} | xargs -L 1 -I _TTY_ pkill -t _TTY_
 
  • Like
Reactions: mer
I am revisiting this thread because the above approach kills all sessions, including root, so I had services being stopped overnight. I am dumbfounded as to why this occurred recently, but I didn't observe it then (over 2 years ago).

That said, merely updating login.conf and setting a sessiontime or idletime does not seem to have any effect.

In addition, according to the man page:

It is not supported in the base system, which means, I need some 3rd party software to handle that. Does anyone know which one would support that?
 
I am revisiting this thread because the above approach kills all sessions, including root, so I had services being stopped overnight. I am dumbfounded as to why this occurred recently, but I didn't observe it then (over 2 years ago).
... (<= quoted for context)
It is not supported in the base system, which means, I need some 3rd party software to handle that. Does anyone know which one would support that?
This looks like an awesome challenge to me. I have no idea what you're trying to accomplish here but that's the fun for me: looking beyond your own comfort zone or "bubble" so to speak.

So let me get this straight: your intent, even after 3 years (!) (loving it!) is still the same? => A script that can (gently!) kill all user processes? But now for more modern setups (I'll focus on 14.2 / 14.3)?

Gimme feedback and I'll give it a good try.
 
Yeah, so my solution from above excluding root works:

who | awk {'print$1'} | grep -v '^root$' | sort -u | xargs -L 1 -I _USER_ pkill -u _USER_
who | awk {'print$2'} | grep -v '^root$' | sort -u | xargs -L 1 -I _TTY_ pkill -t _TTY_

However, I wish there were a better solution utilizing the system itself. Secondly, perhaps it is an error in my thinking, but I want to end root too except for valid services. My reasoning is that I want to clear everything out to ensure resources are freed up and perhaps if a malicious user were connected, they'd be forced off. For the resource bit, I can start/stop services via cron jobs as needed for a particular schedule (which I do).

For the malicious user bit, perhaps that unrealistic, my main problem is perhaps myself and not others.

The less I have to write, the better. Or, if it can become an internal system component where others maintain it too, great.
 
Well, just my 2 cents here, but bsdconfig(8) does offer an option to clear /tmp on every boot...

Besides, if you're the only user, uptime is overrated, unless you're running a web server that kind of needs to stay on 24/7.

Another idea is to put all those commands [that do the cleanup that OP wants] into a script, and either put that script into cron or write a daemon that runs those cleanup commands once in a while or on a schedule... 🤔
 
This is the present incarnation of my script:

#!/bin/sh

_info "clearing user sessions"

_kill_user_sessions() {
for TTY in $(who | awk {'print$2'} | sort -u); do
kill $1 $(ps -t $TTY -o pid | sed 1d)
done
}

_has_user_sessions() {
[ $(who | awk {'print$2'} | sort -u | wc -l) -gt 0 ] && return 0

return 1
}

# -j only kill processes in this jail
pkill -j none Xorg
pkill -j none ssh-agent

_kill_user_sessions
sleep 1

_has_user_sessions && {
sleep 30
_kill_user_sessions -9
}

_info "cleared user sessions"

This handles users logged into a console or remotely via SSH. If a user upgrades to root via sudo, then that will be handled too since they have either logged in via console or remotely via SSH.

Agreed about uptime, perhaps I used the wrong word. What I really mean is not having to 'fix' the system, it just works. Yes, cron and periodic are my best friends.
 
I would recommend to rewrite script and add logs
  • at the begin - dump processes with states
  • analyze exit codes of all kill and pkill + log them
  • at the end - dump processes with states
 
Back
Top