Skip to content
This repository has been archived by the owner on Sep 23, 2021. It is now read-only.

Allow running of arbitrary commands before and after authentication #79

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ The following command-line arguments are supported:
-l only lock console switching
-L only enable console switching
-m mute kernel messages on console while physlock is running
-b CMD execute CMD before the password prompt
-a CMD execute CMD after successfully authenticating
-n don't actually authenticate: just execute commands
-p MSG Display MSG before the password prompt
-s disable sysrq key while physlock is running
-v print version information and exit
47 changes: 43 additions & 4 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
#include <errno.h>
#include <pwd.h>
#include <signal.h>
#include <sys/wait.h>
#include <security/pam_misc.h>

static int oldvt;
static vt_t vt;
static int oldsysrq;
static int oldprintk;
static pid_t chpid;
static int cmdpid;
static int locked;
static userinfo_t root, user;

Expand Down Expand Up @@ -67,8 +69,8 @@ CLEANUP void free_user(userinfo_t *uinfo) {
}

void cleanup() {
if (options->detach && chpid > 0)
/* No cleanup in parent after successful fork */
if ((options->detach && chpid > 0) || cmdpid == 0)
/* No cleanup in parent after successful fork or in failed forked command */
return;
free_user(&user);
free_user(&root);
Expand Down Expand Up @@ -98,17 +100,46 @@ void setup_signal(int signum, void (*handler)(int)) {
sigact.sa_flags = 0;
sigact.sa_handler = handler;
sigemptyset(&sigact.sa_mask);

if (sigaction(signum, &sigact, NULL) < 0)
error(0, errno, "signal %d", signum);
}

void drop_privileges(userinfo_t* user) {
struct passwd *p = getpwnam(user->name);
if (p == NULL) {
error(EXIT_FAILURE, errno, "get user passwd data");
}

if (setgid(p->pw_gid) != 0) {
error(EXIT_FAILURE, errno, "setgid");
}

if (setuid(p->pw_uid) != 0) {
error(EXIT_FAILURE, errno, "setuid");
}
}

void run_command(const char* cmd, userinfo_t* user) {
cmdpid = fork();
if (cmdpid < 0) {
error(EXIT_FAILURE, errno, "fork");
} else if (cmdpid > 0) {
wait(NULL);
} else {
drop_privileges(user);
execl("/bin/sh", "sh", "-c", cmd, NULL);
error(EXIT_FAILURE, errno, "exec");
}
}

int main(int argc, char **argv) {
int try = 0, root_user = 1;
uid_t owner;
userinfo_t *u = &user;

oldvt = oldsysrq = oldprintk = vt.nr = vt.fd = -1;
cmdpid = -1;
vt.ios = NULL;

error_init(2);
Expand Down Expand Up @@ -180,11 +211,15 @@ int main(int argc, char **argv) {
dup2(vt.fd, 1);
dup2(vt.fd, 2);

if (options->command_before != NULL && options->command_before[0] != '\0') {
run_command(options->command_before, &user);
}

if (options->prompt != NULL && options->prompt[0] != '\0') {
fprintf(vt.ios, "%s\n\n", options->prompt);
}

locked = 1;
locked = !options->no_auth;

while (locked) {
if (!root_user && try >= (u == &root ? 1 : 3)) {
Expand Down Expand Up @@ -218,6 +253,10 @@ int main(int argc, char **argv) {
}
}

if (options->command_after != NULL && options->command_after[0] != '\0') {
run_command(options->command_after, &user);
}

return 0;
}

16 changes: 13 additions & 3 deletions options.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static options_t _options;
const options_t *options = (const options_t*) &_options;

void print_usage() {
printf("usage: physlock [-dhLlmsv] [-p MSG]\n");
printf("usage: physlock [-dhLlmsbanv] [-p MSG]\n");
}

void print_version() {
Expand All @@ -37,16 +37,17 @@ void print_version() {

void parse_options(int argc, char **argv) {
int opt;

progname = strrchr(argv[0], '/');
progname = progname != NULL ? progname + 1 : argv[0];

_options.detach = 0;
_options.disable_sysrq = 0;
_options.lock_switch = -1;
_options.mute_kernel_messages = 0;
_options.no_auth = 0;

while ((opt = getopt(argc, argv, "dhLlmp:sv")) != -1) {
while ((opt = getopt(argc, argv, "dhLlmnp:svb:a:")) != -1) {
switch (opt) {
case '?':
print_usage();
Expand All @@ -66,9 +67,18 @@ void parse_options(int argc, char **argv) {
case 'm':
_options.mute_kernel_messages = 1;
break;
case 'n':
_options.no_auth = 1;
break;
case 'p':
_options.prompt = optarg;
break;
case 'b':
_options.command_before = optarg;
break;
case 'a':
_options.command_after = optarg;
break;
case 's':
_options.disable_sysrq = 1;
break;
Expand Down
15 changes: 14 additions & 1 deletion physlock.1
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
physlock \- lock all consoles / virtual terminals
.SH SYNOPSIS
.B physlock
.RB [ \-dhLlmsv ]
.RB [ \-dhLlmnsv ]
.RB [ \-p
.IR MSG ]
.RB [ \-b
.IR CMD ]
.RB [ \-a
.IR CMD ]
.SH DESCRIPTION
physlock is an alternative to vlock, it is equivalent to `vlock \-an'. It is
written because vlock blocks some linux kernel mechanisms like hibernate and
Expand Down Expand Up @@ -39,6 +43,15 @@ locked.
.B \-m
Mute kernel messages on console while physlock is running.
.TP
.B "\-b " CMD
Execute CMD before asking for password
.TP
.B "\-a " CMD
Execute CMD after asking for password
.TP
.B \-n
Don't ask for authentication: just execute commands
.TP
.BI "\-p " MSG
Display
.I MSG
Expand Down
3 changes: 3 additions & 0 deletions physlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ typedef struct options_s {
int disable_sysrq;
int lock_switch;
int mute_kernel_messages;
int no_auth;
const char *prompt;
const char *command_before;
const char *command_after;
} options_t;

extern const options_t *options;
Expand Down