Skip to content

Commit

Permalink
New signal: SIGUSR1.
Browse files Browse the repository at this point in the history
This signal is now sent from the main program to the saver to reset possible
idle timers in the savers, without intending to restart the saver.

This is part of the effort to make the auth child protocol more flexible and to
properly run auth on top of the saver as a window.
  • Loading branch information
divVerent committed Feb 22, 2019
1 parent dfd3ca7 commit baf8754
Show file tree
Hide file tree
Showing 14 changed files with 63 additions and 30 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,12 @@ location: `/usr/local/libexec/xsecurelock/helpers`).
* Output: it may draw on or create windows below `$XSCREENSAVER_WINDOW`.
* Exit condition: the saver child will receive SIGTERM when the user wishes to
unlock the screen. It should exit promptly.
* Reset condition: the saver child will receive SIGUSR1 when the auth dialog
is closed. It then shall make sure to blank the screen after a timeout.
One way to implent this in shell script based implementations is to simply
ignore SIGUSR1 first, start the actual saver in a child processes, and to
finally exec `saver_blank`. Not implementing this will cause the entire
saver to reset on this condition.

# Security Design

Expand Down
13 changes: 7 additions & 6 deletions auth_child.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ limitations under the License.

#include "auth_child.h"

#include <stdlib.h> // for NULL, EXIT_FAILURE
#include <string.h> // for strlen
#include <unistd.h> // for close, _exit, dup2, execl, fork, pipe
#include <stdlib.h> // for NULL, EXIT_FAILURE
#include <string.h> // for strlen
#include <sys/signal.h> // for SIGTERM
#include <unistd.h> // for close, _exit, dup2, execl, fork, pipe

#include "env_settings.h" // for GetIntSetting
#include "logging.h" // for LogErrno, Log
Expand All @@ -31,11 +32,11 @@ static pid_t auth_child_pid = 0;
//! If auth_child_pid != 0, the FD which connects to stdin of the auth child.
static int auth_child_fd = 0;

void KillAuthChildSigHandler(void) {
void KillAuthChildSigHandler(int signo) {
// This is a signal handler, so we're not going to make this too complicated.
// Just kill it.
if (auth_child_pid != 0) {
KillPgrp(auth_child_pid);
KillPgrp(auth_child_pid, signo);
}
}

Expand Down Expand Up @@ -101,7 +102,7 @@ int WatchAuthChild(Window w, const char *executable, int force_auth,
pid_t pgrpid = auth_child_pid;
if (WaitPgrp("auth", &auth_child_pid, 0, 0, &status)) {
// Try taking its process group with it. Should normally not do anything.
KillPgrp(pgrpid);
KillPgrp(pgrpid, SIGTERM);

// Clean up.
close(auth_child_fd);
Expand Down
2 changes: 1 addition & 1 deletion auth_child.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ limitations under the License.
*
* This can be used from a signal handler.
*/
void KillAuthChildSigHandler(void);
void KillAuthChildSigHandler(int signo);

/*! \brief Checks whether an auth child should be running.
*
Expand Down
6 changes: 6 additions & 0 deletions helpers/saver_blank
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
: ${XSECURELOCK_BLANK_TIMEOUT:=600} # Seconds; -1 disables blanking.
: ${XSECURELOCK_BLANK_DPMS_STATE:=off} # Values: standby, suspend, off, on.

# In case of SIGUSR1, we want to restart the timer, but NOT kill the screen
# saver. How are we gonna do this? By having the other script ignore SIGUSR1
# (don't restart screen saver) before spawning its subprocesses, but having
# this script restart itself on SIGUSR1.
trap 'exec "$0"' USR1

if [ "$XSECURELOCK_BLANK_TIMEOUT" -ge 0 ]; then
# Wait 60 seconds before actually turning the screen off. Till then we have a
# black background managed by xsecurelock's main process anyway.
Expand Down
4 changes: 4 additions & 0 deletions helpers/saver_mplayer.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

: ${XSECURELOCK_LIST_VIDEOS_COMMAND:=find ~/Videos -type f}

# On SIGUSR1, we simply keep going, as this signal should only restart
# the sleep timer.
trap '' USR1

sh -c "$XSECURELOCK_LIST_VIDEOS_COMMAND" | shuf | head -n 256 |\
@path_to_mplayer@ \
-noconsolecontrols \
Expand Down
4 changes: 4 additions & 0 deletions helpers/saver_mpv.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

: ${XSECURELOCK_LIST_VIDEOS_COMMAND:=find ~/Videos -type f}

# On SIGUSR1, we simply keep going, as this signal should only restart
# the sleep timer.
trap '' USR1

sh -c "$XSECURELOCK_LIST_VIDEOS_COMMAND" | shuf | head -n 256 |\
@path_to_mpv@ \
--no-input-terminal \
Expand Down
12 changes: 10 additions & 2 deletions helpers/saver_multiplex.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ limitations under the License.
#include "../xscreensaver_api.h" // for ReadWindowID
#include "monitors.h" // for IsMonitorChangeEvent, Monitor, Sele...

static void HandleSIGUSR1(int signo) {
KillAllSaverChildrenSigHandler(signo); // Dirty, but quick.
}

static void HandleSIGTERM(int signo) {
KillAllSaverChildrenSigHandler(); // Dirty, but quick.
raise(signo); // Destroys windows we created anyway.
KillAllSaverChildrenSigHandler(signo); // Dirty, but quick.
raise(signo); // Destroys windows we created anyway.
}

static void HandleSIGCHLD(int unused_signo) {
Expand Down Expand Up @@ -126,6 +130,10 @@ int main(int argc, char** argv) {
if (sigaction(SIGCHLD, &sa, NULL) != 0) {
LogErrno("sigaction(SIGCHLD)");
}
sa.sa_handler = HandleSIGUSR1; // To kill children.
if (sigaction(SIGUSR1, &sa, NULL) != 0) {
LogErrno("sigaction(SIGUSR1)");
}
sa.sa_flags = SA_RESETHAND; // It re-raises to suicide.
sa.sa_handler = HandleSIGTERM; // To kill children.
if (sigaction(SIGTERM, &sa, NULL) != 0) {
Expand Down
4 changes: 4 additions & 0 deletions helpers/saver_xscreensaver.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

: ${XSECURELOCK_XSCREENSAVER_PATH:=@path_to_xscreensaver@}

# On SIGUSR1, we simply keep going, as this signal should only restart
# the sleep timer.
trap '' USR1

TAB=' '

# Note: the following logic is somewhat derived from parse_screenhack in
Expand Down
6 changes: 3 additions & 3 deletions helpers/until_nonidle.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pid_t childpid = 0;

static void HandleSIGTERM(int signo) {
if (childpid != 0) {
KillPgrp(childpid); // Dirty, but quick.
KillPgrp(childpid, signo); // Dirty, but quick.
}
raise(signo);
}
Expand Down Expand Up @@ -223,11 +223,11 @@ int main(int argc, char **argv) {
still_idle && (active_ms <= dim_time_ms + wait_time_ms);

if (!should_be_running) {
KillPgrp(childpid);
KillPgrp(childpid, SIGTERM);
}
int status;
WaitPgrp("idle", &childpid, !should_be_running, !should_be_running,
&status);
&status);
}

// This is the point where we can exit.
Expand Down
8 changes: 3 additions & 5 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ int debug_window_info = 0;
pid_t notify_command_pid = 0;

static void HandleSIGTERM(int signo) {
KillAllSaverChildrenSigHandler(); // Dirty, but quick.
KillAuthChildSigHandler(); // More dirty.
KillAllSaverChildrenSigHandler(signo); // Dirty, but quick.
KillAuthChildSigHandler(signo); // More dirty.
explicit_bzero(&priv, sizeof(priv));
raise(signo);
}
Expand Down Expand Up @@ -200,11 +200,9 @@ int WatchChildren(Display *dpy, Window auth_win, Window saver_win,

// If we wanted auth, but it's not running, auth just terminated. Unmap the
// auth window and poke the screensaver so that it can reset any timeouts.
// TODO(divVerent): Implement a nicer way to poke if supported (say,
// SIGUSR1).
if (!auth_running) {
XUnmapWindow(dpy, auth_win);
WatchSaverChild(dpy, saver_win, 0, saver_executable, 0);
KillAllSaverChildrenSigHandler(SIGUSR1);
}
}

Expand Down
15 changes: 8 additions & 7 deletions saver_child.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ limitations under the License.

#include "saver_child.h"

#include <signal.h> // for sigemptyset, sigprocmask, SIG_SETMASK
#include <stdlib.h> // for NULL, EXIT_FAILURE
#include <unistd.h> // for pid_t, _exit, execl, fork, setsid, sleep
#include <signal.h> // for sigemptyset, sigprocmask, SIG_SETMASK
#include <stdlib.h> // for NULL, EXIT_FAILURE
#include <sys/signal.h> // for SIGTERM
#include <unistd.h> // for pid_t, _exit, execl, fork, setsid, sleep

#include "logging.h" // for LogErrno, Log
#include "wait_pgrp.h" // for KillPgrp, WaitPgrp
Expand All @@ -27,13 +28,13 @@ limitations under the License.
//! The PIDs of currently running saver children, or 0 if not running.
static pid_t saver_child_pid[MAX_SAVERS] = {0};

void KillAllSaverChildrenSigHandler(void) {
void KillAllSaverChildrenSigHandler(int signo) {
// This is a signal handler, so we're not going to make this too
// complicated. Just kill 'em all.
int i;
for (i = 0; i < MAX_SAVERS; ++i) {
if (saver_child_pid[i] != 0) {
KillPgrp(saver_child_pid[i]);
KillPgrp(saver_child_pid[i], signo);
}
}
}
Expand All @@ -47,7 +48,7 @@ void WatchSaverChild(Display* dpy, Window w, int index, const char* executable,

if (saver_child_pid[index] != 0) {
if (!should_be_running) {
KillPgrp(saver_child_pid[index]);
KillPgrp(saver_child_pid[index], SIGTERM);
}

int status;
Expand All @@ -57,7 +58,7 @@ void WatchSaverChild(Display* dpy, Window w, int index, const char* executable,
if (should_be_running) {
// Try taking its process group with it. Should normally not do
// anything.
KillPgrp(pgrpid);
KillPgrp(pgrpid, SIGTERM);
}

// Now is the time to remove anything the child may have displayed.
Expand Down
2 changes: 1 addition & 1 deletion saver_child.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ limitations under the License.
*
* This can be used from a signal handler.
*/
void KillAllSaverChildrenSigHandler(void);
void KillAllSaverChildrenSigHandler(int signo);

/*! \brief Starts or stops the screen saver child process.
*
Expand Down
9 changes: 5 additions & 4 deletions wait_pgrp.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ limitations under the License.

#include "logging.h" // for Log, LogErrno

int KillPgrp(pid_t pid) {
int ret = kill(-pid, SIGTERM);
int KillPgrp(pid_t pid, int signo) {
int ret = kill(-pid, signo);
if (ret < 0 && errno == ESRCH) {
// Might mean the process is not a process group leader - but might also
// mean that the process is already dead. Try killing just the process then.
ret = kill(pid, SIGTERM);
ret = kill(pid, signo);
}
return ret;
}
Expand All @@ -39,8 +39,9 @@ int WaitPgrp(const char *name, pid_t *pid, int do_block, int already_killed,
int *exit_status) {
sigset_t oldset, set;
sigemptyset(&set);
// We're blocking the signal we may have a forwarding handler for as their
// We're blocking the signals we may have forwarding handlers for as their
// handling reads the pid variable we are changing here.
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGTERM);
// If we want to wait for a process to die, we must also block SIGCHLD
// so we can reliably wait for another child in case waitpid returned 0.
Expand Down
2 changes: 1 addition & 1 deletion wait_pgrp.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ limitations under the License.
#define WAIT_ALREADY_DEAD INT_MIN
#define WAIT_NONPOSITIVE_SIGNAL (INT_MIN + 1)

int KillPgrp(pid_t pid);
int KillPgrp(pid_t pid, int signo);
int WaitPgrp(const char *name, pid_t *pid, int do_block, int already_killed,
int *exit_status);

Expand Down

0 comments on commit baf8754

Please sign in to comment.