diff --git a/README.md b/README.md index 8d7da4f..9a408c8 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/main.c b/main.c index 31056bc..50b7786 100644 --- a/main.c +++ b/main.c @@ -26,6 +26,7 @@ #include #include #include +#include #include static int oldvt; @@ -33,6 +34,7 @@ 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; @@ -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); @@ -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); @@ -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)) { @@ -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; } diff --git a/options.c b/options.c index 6ec3634..225b22a 100644 --- a/options.c +++ b/options.c @@ -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() { @@ -37,7 +37,7 @@ void print_version() { void parse_options(int argc, char **argv) { int opt; - + progname = strrchr(argv[0], '/'); progname = progname != NULL ? progname + 1 : argv[0]; @@ -45,8 +45,9 @@ void parse_options(int argc, char **argv) { _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(); @@ -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; diff --git a/physlock.1 b/physlock.1 index 32e8547..71b1fe2 100644 --- a/physlock.1 +++ b/physlock.1 @@ -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 @@ -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 diff --git a/physlock.h b/physlock.h index 0eb42ee..703ba44 100644 --- a/physlock.h +++ b/physlock.h @@ -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;