diff -Nru physlock-0.4.5/auth.c physlock-11/auth.c --- physlock-0.4.5/auth.c 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/auth.c 2017-08-17 09:27:46.000000000 +0000 @@ -1,5 +1,5 @@ /* physlock: auth.c - * Copyright (c) 2013 Bert Muennich + * Copyright (c) 2013,2015 Bert Muennich * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,61 +16,87 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#define _POSIX_C_SOURCE 200112L -#define _XOPEN_SOURCE 500 /* for crypt() and strdup() */ - +#include +#include +#include #include -#include #include #include +#include #include +#include #include "auth.h" #include "util.h" -void get_uname(userinfo_t *uinfo, uid_t uid) { - struct passwd *pw; +static struct pam_conv conv = { + misc_conv, + NULL +}; + +static void get_pam(userinfo_t *uinfo) { + if (pam_start("physlock", uinfo->name, &conv, &uinfo->pamh) != PAM_SUCCESS) + error(EXIT_FAILURE, 0, "no pam for user %s", uinfo->name); +} - if (uinfo == NULL) - return; +void get_user(userinfo_t *uinfo, int vt, uid_t owner) { + FILE *uf; + struct utmp r; + struct passwd *pw; + char tty[16], name[UT_NAMESIZE+1]; - pw = getpwuid(uid); - if (pw == NULL) - die("could not get user info for uid %u\n", uid); - - uinfo->name = strdup(pw->pw_name); - if (uinfo->name == NULL) - die("could not allocate memory"); -} + uinfo->name = NULL; + while ((uf = fopen(_PATH_UTMP, "r")) == NULL && errno == EINTR); -void get_pwhash(userinfo_t *uinfo) { - struct spwd *spw; + if (uf != NULL) { + snprintf(tty, sizeof(tty), "tty%d", vt); + while (!feof(uf) && !ferror(uf)) { + if (fread(&r, sizeof(r), 1, uf) != 1) + continue; + if (r.ut_type != USER_PROCESS || r.ut_user[0] == '\0') + continue; + if (strcmp(r.ut_line, tty) == 0) { + strncpy(name, r.ut_user, UT_NAMESIZE); + name[UT_NAMESIZE] = '\0'; + uinfo->name = estrdup(name); + break; + } + } + fclose(uf); + } + + if (uinfo->name == NULL) { + if (owner != (uid_t)-1 && (pw = getpwuid(owner)) != NULL) + uinfo->name = estrdup(pw->pw_name); + else + error(EXIT_FAILURE, 0, "Unable to detect user of tty%d", vt); + } - if (uinfo == NULL || uinfo->name == NULL) - return; + get_pam(uinfo); +} - setspent(); +void get_root(userinfo_t *uinfo) { + struct passwd *pw; - spw = getspnam(uinfo->name); - if (spw == NULL) - die("could not get password hash of user %s", uinfo->name); + while (errno = 0, (pw = getpwuid(0)) == NULL && errno == EINTR); + if (pw == NULL) + error(EXIT_FAILURE, 0, "No password file entry for uid 0 found"); - uinfo->pwhash = strdup(spw->sp_pwdp); - if (uinfo->pwhash == NULL) - die("could not allocate memory"); + uinfo->name = estrdup(pw->pw_name); - endspent(); + get_pam(uinfo); } -int authenticate(const userinfo_t *uinfo, const char *pw) { - char *cryptpw; +CLEANUP void free_user(userinfo_t *uinfo) { + if (uinfo->pamh != NULL) + pam_end(uinfo->pamh, uinfo->pam_status); +} - if (uinfo == NULL || uinfo->pwhash == NULL || pw == NULL) - return 0; +int authenticate(userinfo_t *uinfo) { + uinfo->pam_status = pam_authenticate(uinfo->pamh, 0); - cryptpw = crypt(pw, uinfo->pwhash); - if (cryptpw == NULL) - die("could not hash password for user %s", uinfo->name); + if (uinfo->pam_status == PAM_SUCCESS) + uinfo->pam_status = pam_acct_mgmt(uinfo->pamh, 0); - return strcmp(cryptpw, uinfo->pwhash) == 0; + return uinfo->pam_status == PAM_SUCCESS ? 0 : -1; } diff -Nru physlock-0.4.5/auth.h physlock-11/auth.h --- physlock-0.4.5/auth.h 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/auth.h 2017-08-17 09:27:46.000000000 +0000 @@ -19,15 +19,19 @@ #ifndef AUTH_H #define AUTH_H -#include +#include + +#define CLEANUP typedef struct userinfo_s { const char *name; - const char *pwhash; + int pam_status; + pam_handle_t *pamh; } userinfo_t; -void get_uname(userinfo_t*, uid_t); -void get_pwhash(userinfo_t*); -int authenticate(const userinfo_t*, const char*); +void get_user(userinfo_t*, int, uid_t); +void get_root(userinfo_t*); +CLEANUP void free_user(userinfo_t*); +int authenticate(userinfo_t*); #endif /* AUTH_H */ diff -Nru physlock-0.4.5/config.h physlock-11/config.h --- physlock-0.4.5/config.h 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/config.h 2017-08-17 09:27:46.000000000 +0000 @@ -8,6 +8,6 @@ /* full path to kernel sysrq control file: */ static const char * const SYSRQ_PATH = "/proc/sys/kernel/sysrq"; -/* timeout (seconds) after failed authentication try: */ -enum { AUTH_FAIL_TIMEOUT = 2 }; +/* full path to kernel printk file: */ +static const char * const PRINTK_PATH = "/proc/sys/kernel/printk"; diff -Nru physlock-0.4.5/debian/changelog physlock-11/debian/changelog --- physlock-0.4.5/debian/changelog 2016-12-14 10:17:08.000000000 +0000 +++ physlock-11/debian/changelog 2017-08-17 12:06:44.000000000 +0000 @@ -1,3 +1,14 @@ +physlock (11-1) unstable; urgency=medium + + * [22f432c] New upstream version 11 (Closes: #863611) + (By switching to utmp/libpam handling, also: Closes: #869585) + * [dca45ef] Add libpam0g-dev as Build-Dependency + * [df68875] Bump Standards-Version to 4.0.1 + * [678e6f1] Drop debian/patches, no longer necessary with new upstream + versions + + -- Michael Prokop Thu, 17 Aug 2017 14:06:44 +0200 + physlock (0.4.5-2) unstable; urgency=medium * [d721a25] Bump Standards-Version to 3.9.8 diff -Nru physlock-0.4.5/debian/control physlock-11/debian/control --- physlock-0.4.5/debian/control 2016-12-14 10:06:53.000000000 +0000 +++ physlock-11/debian/control 2017-08-17 12:04:45.000000000 +0000 @@ -2,16 +2,19 @@ Section: utils Priority: optional Maintainer: Michael Prokop -Build-Depends: debhelper (>= 9) -Standards-Version: 3.9.8 +Build-Depends: + debhelper (>= 9), + libpam0g-dev, +Standards-Version: 4.0.1 Homepage: https://github.com/muennich/physlock Vcs-git: https://anonscm.debian.org/git/collab-maint/physlock.git Vcs-Browser: https://anonscm.debian.org/git/collab-maint/physlock.git Package: physlock Architecture: any -Depends: ${misc:Depends}, - ${shlibs:Depends} +Depends: + ${misc:Depends}, + ${shlibs:Depends}, Description: lightweight Linux console locking tool physlock is an alternative to vlock, it is equivalent to `vlock -an'. It is written because vlock blocks some Linux diff -Nru physlock-0.4.5/debian/patches/series physlock-11/debian/patches/series --- physlock-0.4.5/debian/patches/series 2016-12-14 10:06:53.000000000 +0000 +++ physlock-11/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -support_overwriting_cflags.patch -support_overwriting_ldflags.patch diff -Nru physlock-0.4.5/debian/patches/support_overwriting_cflags.patch physlock-11/debian/patches/support_overwriting_cflags.patch --- physlock-0.4.5/debian/patches/support_overwriting_cflags.patch 2016-12-14 10:06:53.000000000 +0000 +++ physlock-11/debian/patches/support_overwriting_cflags.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -Description: support overwriting CFLAGS - The version number needs to be defined via $VERSION in the Makefile, - though we don't want to handle this on our own, instead we need to - extend CFLAGS to enable e.g. hardening features. - . - physlock (0.4.5-1) unstable; urgency=low - . - * Initial release. -Author: Michael Prokop - ---- -Forwarded: no -Last-Update: 2015-07-08 - ---- physlock-0.4.5.orig/Makefile -+++ physlock-0.4.5/Makefile -@@ -4,7 +4,7 @@ VERSION = 0.4.5 - - CC = gcc - PREFIX = /usr/local --CFLAGS = -Wall -pedantic -DVERSION=\"$(VERSION)\" -+CFLAGS += -Wall -pedantic -DVERSION=\"$(VERSION)\" - LDFLAGS = - LIBS = -lcrypt - diff -Nru physlock-0.4.5/debian/patches/support_overwriting_ldflags.patch physlock-11/debian/patches/support_overwriting_ldflags.patch --- physlock-0.4.5/debian/patches/support_overwriting_ldflags.patch 2016-12-14 10:06:53.000000000 +0000 +++ physlock-11/debian/patches/support_overwriting_ldflags.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ -Description: support overwriting LDFLAGS - For extending LDFLAGS e.g. for hardening features we need to extend LDFLAGS. - . - physlock (0.4.5-1) unstable; urgency=low - . - * Initial release. -Author: Michael Prokop - ---- -Forwarded: no -Last-Update: 2015-07-08 - ---- physlock-0.4.5.orig/Makefile -+++ physlock-0.4.5/Makefile -@@ -5,7 +5,7 @@ VERSION = 0.4.5 - CC = gcc - PREFIX = /usr/local - CFLAGS += -Wall -pedantic -DVERSION=\"$(VERSION)\" --LDFLAGS = -+LDFLAGS += - LIBS = -lcrypt - - SRC = auth.c main.c options.c util.c vt.c diff -Nru physlock-0.4.5/.gitignore physlock-11/.gitignore --- physlock-0.4.5/.gitignore 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/.gitignore 2017-08-17 09:27:46.000000000 +0000 @@ -1,5 +1,3 @@ +*.d *.o physlock -cscope.out -release -tags diff -Nru physlock-0.4.5/main.c physlock-11/main.c --- physlock-0.4.5/main.c 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/main.c 2017-08-17 09:27:46.000000000 +0000 @@ -16,8 +16,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#define _POSIX_C_SOURCE 200112L - #include #include #include @@ -25,6 +23,7 @@ #include #include #include +#include #include "auth.h" #include "config.h" @@ -32,82 +31,80 @@ #include "util.h" #include "vt.h" -enum { BUFLEN = 1024 }; - -static char buf[BUFLEN]; +static char buf[1024]; static int oldvt; static vt_t vt; static int oldsysrq; +static int oldprintk; +static pid_t chpid; -void cleanup() { - static int in = 0; +static userinfo_t root, user; - if (!in++) { - if (oldsysrq > 0) - set_sysrq_state(SYSRQ_PATH, oldsysrq); - if (vt.fd >= 0) - reset_vt(&vt); - unlock_vt_switch(); - release_vt(&vt, oldvt); - vt_destroy(); - memset(buf, 0, sizeof(buf)); - } +void cleanup() { + if (options->detach && chpid > 0) + /* No cleanup in parent after successful fork */ + return; + free_user(&user); + free_user(&root); + if (oldsysrq > 0) + write_int_to_file(SYSRQ_PATH, oldsysrq); + if (oldprintk > 1) + write_int_to_file(PRINTK_PATH, oldprintk); + if (vt.fd >= 0) + vt_reset(&vt); + vt_lock_switch(0); + vt_release(&vt, oldvt); + vt_destroy(); } void sa_handler_exit(int signum) { - cleanup(); exit(0); } -int setup_signal(int signum, void (*handler)(int)) { +void setup_signal(int signum, void (*handler)(int)) { struct sigaction sigact; sigact.sa_flags = 0; sigact.sa_handler = handler; sigemptyset(&sigact.sa_mask); - if (sigaction(signum, &sigact, NULL) < 0) { - warn("could not set handler for signal %d: %s", signum, strerror(errno)); - return -1; - } else { - return 0; - } + if (sigaction(signum, &sigact, NULL) < 0) + error(0, errno, "signal %d", signum); } void prompt(FILE *stream, const char *fmt, ...) { va_list args; unsigned int c, i = 0; - if (!stream || !fmt) - return; - va_start(args, fmt); vfprintf(stream, fmt, args); va_end(args); - while ((c = fgetc(stream)) != EOF && c != '\n') { - if (c != '\0' && i + 1 < BUFLEN) + for (;;) { + while ((c = fgetc(stream)) == EOF && errno == EINTR); + if (c == EOF || c == '\n') + break; + if (c != '\0' && i + 1 < sizeof(buf)) buf[i++] = (char) c; } if (ferror(stream)) - die("could not read from console: %s", strerror(errno)); + error(EXIT_FAILURE, 0, "Error reading from console"); buf[i] = '\0'; } int main(int argc, char **argv) { - int only_root, auth = 0, chpid; - uid_t uid; - userinfo_t *as, root, user; + int try = 0, user_only = 1; + uid_t owner; + userinfo_t *u = &user; - oldvt = oldsysrq = vt.nr = vt.fd = -1; + oldvt = oldsysrq = oldprintk = vt.nr = vt.fd = -1; vt.ios = NULL; + error_init(2); parse_options(argc, argv); - if (geteuid() != 0) { - fprintf(stderr, "physlock: must be root!\n"); - return 1; - } + if (geteuid() != 0) + error(EXIT_FAILURE, 0, "Must be root!"); setup_signal(SIGTERM, sa_handler_exit); setup_signal(SIGQUIT, sa_handler_exit); @@ -116,88 +113,78 @@ setup_signal(SIGUSR1, SIG_IGN); setup_signal(SIGUSR2, SIG_IGN); - close(0); - close(1); - vt_init(); - get_current_vt(&oldvt); + vt_get_current(&oldvt, &owner); - if (options->only_lock) { - lock_vt_switch(); - vt_destroy(); - return 0; - } else if (options->only_unlock) { - unlock_vt_switch(); + if (options->lock_switch != -1) { + if (vt_lock_switch(options->lock_switch) == -1) + exit(EXIT_FAILURE); vt_destroy(); return 0; } + get_user(&user, oldvt, owner); + get_root(&root); + if (strcmp(user.name, root.name) != 0) + user_only = 0; + + atexit(cleanup); + if (options->disable_sysrq) { - oldsysrq = get_sysrq_state(SYSRQ_PATH); + oldsysrq = read_int_from_file(SYSRQ_PATH, '\n'); if (oldsysrq > 0) - set_sysrq_state(SYSRQ_PATH, 0); - } - - if (options->user) { - user.name = options->user; - } else { - uid = getuid(); - get_uname(&user, uid); + if (write_int_to_file(SYSRQ_PATH, 0) == -1) + exit(EXIT_FAILURE); } - get_uname(&root, 0); - get_pwhash(&root); - only_root = strcmp(user.name, root.name) == 0; - if (!only_root) { - get_pwhash(&user); - authenticate(&user, ""); /* test authentication */ + if (options->mute_kernel_messages) { + oldprintk = read_int_from_file(PRINTK_PATH, '\t'); + if (oldprintk > 1) + if (write_int_to_file(PRINTK_PATH, 1) == -1) + exit(EXIT_FAILURE); } - acquire_new_vt(&vt); - lock_vt_switch(); + vt_acquire(&vt); + vt_lock_switch(1); if (options->detach) { chpid = fork(); if (chpid < 0) { - die("could not spawn background process: %s", strerror(errno)); + error(EXIT_FAILURE, errno, "fork"); } else if (chpid > 0) { return 0; } else { setsid(); sleep(1); /* w/o this, accessing the vt might fail */ - reopen_vt(&vt); + vt_reopen(&vt); } } - secure_vt(&vt); + vt_secure(&vt); - while (!auth) { - as = &root; - flush_vt(&vt); - if (!only_root) { - tty_echo_on(&vt); - while (1) { - prompt(vt.ios, "\nUnlock as [%s/%s]: ", user.name, root.name); - if (!*buf || !strcmp(buf, user.name)) { - as = &user; - break; - } else if (!strcmp(buf, root.name)) { - break; - } - } - tty_echo_off(&vt); - } else { - prompt(vt.ios, "\nPress [Enter] to unlock.\n"); - } + dup2(vt.fd, 0); + dup2(vt.fd, 1); + dup2(vt.fd, 2); + + openlog(progname, LOG_PID, LOG_AUTH); - prompt(vt.ios, "%s's password: ", as->name); - auth = authenticate(as, buf); - memset(buf, 0, sizeof(buf)); - if (!auth) { - fprintf(vt.ios, "\nAuthentication failed\n"); - sleep(AUTH_FAIL_TIMEOUT); + if (options->prompt != NULL && options->prompt[0] != '\0') { + fprintf(vt.ios, "%s\n\n", options->prompt); + } + + for (;;) { + if (u == &root) { + fputs("root: ", vt.ios); + fflush(vt.ios); + } + if (authenticate(u) == 0) + break; + if (!user_only && (u == &root || ++try == 3)) { + u = u == &root ? &user : &root; + try = 0; } + fprintf(vt.ios, "Authentication failed\n\n"); + syslog(LOG_WARNING, "Authentication failure"); } - cleanup(); return 0; } diff -Nru physlock-0.4.5/Makefile physlock-11/Makefile --- physlock-0.4.5/Makefile 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/Makefile 2017-08-17 09:27:46.000000000 +0000 @@ -1,21 +1,29 @@ -all: physlock +VERSION := 11 + +CC ?= gcc +PREFIX := /usr/local +CFLAGS += -Wall -pedantic +CPPFLAGS += -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=500 +LDFLAGS += +LIBS := -lpam -lpam_misc + +.PHONY: clean install uninstall + +SRC := auth.c main.c options.c util.c vt.c +DEP := $(SRC:.c=.d) +OBJ := $(SRC:.c=.o) -VERSION = 0.4.5 +all: physlock -CC = gcc -PREFIX = /usr/local -CFLAGS = -Wall -pedantic -DVERSION=\"$(VERSION)\" -LDFLAGS = -LIBS = -lcrypt +$(OBJ): Makefile -SRC = auth.c main.c options.c util.c vt.c -OBJ = $(SRC:.c=.o) +-include $(DEP) -physlock: $(OBJ) +physlock: $(OBJ) $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -.c.o: Makefile - $(CC) $(CFLAGS) -c -o $@ $< +%.o: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) -MMD -MP -c -o $@ $< install: all install -D -m 4755 -o root -g root physlock $(DESTDIR)$(PREFIX)/bin/physlock @@ -24,7 +32,7 @@ chmod 644 $(DESTDIR)$(PREFIX)/share/man/man1/physlock.1 clean: - rm -f physlock $(OBJ) + rm -f physlock $(DEP) $(OBJ) uninstall: rm -f $(DESTDIR)$(PREFIX)/bin/physlock diff -Nru physlock-0.4.5/options.c physlock-11/options.c --- physlock-0.4.5/options.c 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/options.c 2017-08-17 09:27:46.000000000 +0000 @@ -16,19 +16,19 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#define _POSIX_C_SOURCE 200112L - #include #include +#include #include #include "options.h" +#include "util.h" static options_t _options; const options_t *options = (const options_t*) &_options; void print_usage() { - printf("usage: physlock [-dhLlsv] [-u user]\n"); + printf("usage: physlock [-dhLlmsv] [-p MSG]\n"); } void print_version() { @@ -38,13 +38,15 @@ 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.only_lock = 0; - _options.only_unlock = 0; - _options.user = NULL; + _options.lock_switch = -1; + _options.mute_kernel_messages = 0; - while ((opt = getopt(argc, argv, "dhLlsu:v")) != -1) { + while ((opt = getopt(argc, argv, "dhLlmp:sv")) != -1) { switch (opt) { case '?': print_usage(); @@ -56,15 +58,19 @@ print_usage(); exit(0); case 'L': - _options.only_unlock = 1; + _options.lock_switch = 0; break; case 'l': - _options.only_lock = 1; + _options.lock_switch = 1; + break; + case 'm': + _options.mute_kernel_messages = 1; + break; + case 'p': + _options.prompt = optarg; break; case 's': _options.disable_sysrq = 1; - case 'u': - _options.user = optarg; break; case 'v': print_version(); diff -Nru physlock-0.4.5/options.h physlock-11/options.h --- physlock-0.4.5/options.h 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/options.h 2017-08-17 09:27:46.000000000 +0000 @@ -22,9 +22,9 @@ typedef struct options_s { int detach; int disable_sysrq; - int only_lock; - int only_unlock; - const char *user; + int lock_switch; + int mute_kernel_messages; + const char *prompt; } options_t; extern const options_t *options; diff -Nru physlock-0.4.5/physlock.1 physlock-11/physlock.1 --- physlock-0.4.5/physlock.1 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/physlock.1 2017-08-17 09:27:46.000000000 +0000 @@ -3,9 +3,9 @@ physlock \- lock all consoles / virtual terminals .SH SYNOPSIS .B physlock -.RB [ \-dhLlsv ] -.RB [ \-u -.IR USER ] +.RB [ \-dhLlmsv ] +.RB [ \-p +.IR MSG ] .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 @@ -16,8 +16,8 @@ .P The behaviour of physlock is completely controlled via command-line arguments, it does not rely on environment variables. -It always allows unlocking as root and as a specified user. If no username is -given on the command line, then physlock uses the name of the calling user. +physlock uses the utmp file to identify the owner of the current session (i.e. +active tty) and prompts for her password to unlock the computer. .SH OPTIONS .TP .B \-d @@ -36,13 +36,17 @@ instance of physlock has crashed and leaved the console switching mechanism locked. .TP +.B \-m +Mute kernel messages on console while physlock is running. +.TP +.BI "\-p " MSG +Display +.I MSG +before the password prompt. +.TP .B \-s Disable SysRq mechanism while physlock is running. .TP -.B \-u USER -Allow the given user to unlock the computer. Using this option prevents physlock -from using the name of the calling user. -.TP .B \-v Print version information to standard output and exit. .SH AUTHORS diff -Nru physlock-0.4.5/README.md physlock-11/README.md --- physlock-0.4.5/README.md 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/README.md 2017-08-17 09:27:46.000000000 +0000 @@ -7,6 +7,14 @@ physlock is designed to be more lightweight, it does not have a plugin interface and it is not started using a shell script wrapper. +physlock tries to detect the user logged in on the active console by first +searching the utmp file for an entry whose `ut_line` field equals the device +name of the active console, e.g. "tty1". If no such entry is found, then +physlock falls back to the owner of the device file of the active console. Some +graphical login managers do neither write an appropriate utmp entry nor set the +owner of the device file. You have to manually set up `sessreg(1)` in order to +use physlock with such a graphical login manager. + Installation ------------ physlock is built using the commands: @@ -16,12 +24,12 @@ Please note, that the latter one requires root privileges. By default, physlock is installed using the prefix "/usr/local", so the full -path of the executable will be "/usr/local/sbin/physlock". +path of the executable will be "/usr/local/bin/physlock". You can install it into a directory of your choice by changing the second command to: - # PREFIX="/your/dir" make install + # make PREFIX="/your/dir" install Please also note, that the physlock executable will have root ownership and the setuid bit set. @@ -33,8 +41,8 @@ ----- The behaviour of physlock is completely controlled via command-line arguments, it does not rely on environment variables. -It always allows unlocking as root and as a specified user. If no username is -given on the command line, then physlock uses the name of the calling user. +physlock uses the utmp file to identify the owner of the current session (i.e. +active tty) and prompts for her password to unlock the computer. The following command-line arguments are supported: @@ -43,5 +51,7 @@ -h print short usage help and exit -l only lock console switching -L only enable console switching - -u USER allow the given user to unlock the computer + -m mute kernel messages on console while physlock is running + -p MSG Display MSG before the password prompt + -s disable sysrq key while physlock is running -v print version information and exit diff -Nru physlock-0.4.5/util.c physlock-11/util.c --- physlock-0.4.5/util.c 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/util.c 2017-08-17 09:27:46.000000000 +0000 @@ -16,90 +16,126 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#define _POSIX_C_SOURCE 200112L - #include #include #include #include +#include #include "util.h" -enum { BUFLEN = 32 }; - -void cleanup(); +const char *progname; -void warn(const char *fmt, ...) { - va_list args; +static FILE *Stderr; - if (!fmt) - return; - - va_start(args, fmt); - fprintf(stderr, "physlock: warning: "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - va_end(args); +void error_init(int fd) +{ + if ((fd = dup(fd)) == -1 || (Stderr = fdopen(fd, "w")) == NULL) + Stderr = stderr; } -void die(const char *fmt, ...) { - va_list args; - - if (!fmt) - return; +void error(int eval, int err, const char* fmt, ...) +{ + va_list ap; + + fflush(stdout); + fprintf(Stderr, "%s: ", progname); + va_start(ap, fmt); + if (fmt != NULL) + vfprintf(Stderr, fmt, ap); + va_end(ap); + if (err != 0) + fprintf(Stderr, "%s%s", fmt != NULL ? ": " : "", strerror(err)); + fputc('\n', Stderr); - va_start(args, fmt); - fprintf(stderr, "physlock: error: "); - vfprintf(stderr, fmt, args); - fprintf(stderr, "\n"); - va_end(args); + if (eval != 0) + exit(eval); +} - cleanup(); - exit(1); +char* estrdup(const char *s) { + char *d; + size_t n = strlen(s) + 1; + + d = malloc(n); + if (d == NULL) + error(EXIT_FAILURE, errno, NULL); + memcpy(d, s, n); + return d; } -int get_sysrq_state(const char *path) { - char buf[BUFLEN], *end; - int len, state; +/* + * Read a file to a buffer. + * The buffer is ensured to be NULL-terminated. + * The call always succeeds (it dies() on failure). + * Returns the number of characters read. + */ +size_t read_file(const char *path, char *buf, size_t len) { FILE *ctl_file; + size_t nread; - if (!path) - return -1; - - ctl_file = fopen(path, "r"); + while ((ctl_file = fopen(path, "r")) == NULL && errno == EINTR); if (ctl_file == NULL) - die("could not open file: %s", path); + error(EXIT_FAILURE, errno, "%s", path); - len = fread(buf, 1, BUFLEN - 1, ctl_file); + nread = fread(buf, 1, len - 1, ctl_file); if (ferror(ctl_file)) - die("could not read file: %s: %s", path, strerror(errno)); + error(EXIT_FAILURE, 0, "%s: Error reading file", path); fclose(ctl_file); + buf[nread] = '\0'; - buf[len] = '\0'; - state = strtol(buf, &end, 0); - if (*end && *end != '\n') - die("invalid file content: %s: %s", path, buf); - - return state; + return nread; } -void set_sysrq_state(const char *path, int new_state) { - char buf[BUFLEN]; +/* + * Write a buffer into a file. + * Returns the number of characters written or -1 on failure. + */ +CLEANUP ssize_t write_file(const char *path, char *buf, size_t len) { FILE *ctl_file; + size_t nwritten; - if (!path) - return; + while ((ctl_file = fopen(path, "w+")) == NULL && errno == EINTR); + if (ctl_file == NULL) { + error(0, errno, "%s", path); + return -1; + } - ctl_file = fopen(path, "w+"); - if (ctl_file == NULL) - die("could not open file: %s", path); + nwritten = fwrite(buf, 1, len, ctl_file); + if (ferror(ctl_file)) { + error(0, 0, "%s: Error writing file", path); + return -1; + } + fclose(ctl_file); - snprintf(buf, BUFLEN, "%d\n", new_state); + return nwritten; +} - fwrite(buf, 1, strlen(buf), ctl_file); - if (ferror(ctl_file)) - die("could not write file: %s: %s", path, strerror(errno)); +/* + * Read integer from file, and ensure the next character is as expected. + * The call always succeeds (it dies() on failure). + */ +int read_int_from_file(const char *path, char ending_char) { + char buf[32], *end; + int value; - fclose(ctl_file); + read_file(path, buf, sizeof(buf)); + + value = strtol(buf, &end, 0); + if (*end && *end != ending_char) + error(EXIT_FAILURE, 0, "%s: Invalid file content", path); + + return value; +} + +/* + * Write integer to file. + * Returns the number of characters written or -1 on failure. + */ +CLEANUP ssize_t write_int_to_file(const char *path, int value) { + char buf[32]; + + snprintf(buf, sizeof(buf), "%d\n", value); + return write_file(path, buf, strlen(buf)); } + diff -Nru physlock-0.4.5/util.h physlock-11/util.h --- physlock-0.4.5/util.h 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/util.h 2017-08-17 09:27:46.000000000 +0000 @@ -20,11 +20,18 @@ #define UTIL_H #include +#include -void warn(const char*, ...); -void die(const char*, ...); +#define CLEANUP -int get_sysrq_state(const char*); -void set_sysrq_state(const char*, int); +extern const char *progname; + +void error_init(int); +void error(int, int, const char*, ...); + +char* estrdup(const char*); + +int read_int_from_file(const char*, char); +CLEANUP ssize_t write_int_to_file(const char*, int); #endif /* UTIL_H */ diff -Nru physlock-0.4.5/vt.c physlock-11/vt.c --- physlock-0.4.5/vt.c 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/vt.c 2017-08-17 09:27:46.000000000 +0000 @@ -16,10 +16,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#define _POSIX_C_SOURCE 200112L - #include -#include +#include #include #include #include @@ -32,78 +30,101 @@ #include "util.h" #include "vt.h" -enum { FNAME_LEN = 1024 }; - static int fd = -1; -static char filename[FNAME_LEN]; +static char filename[1024]; void vt_init() { - fd = open(CONSOLE_DEVICE, O_RDWR); + while ((fd = open(CONSOLE_DEVICE, O_RDWR)) == -1 && errno == EINTR); if (fd < 0) - die("could not open console device %s: %s", CONSOLE_DEVICE, - strerror(errno)); + error(EXIT_FAILURE, errno, "%s", CONSOLE_DEVICE); } -void vt_destroy() { +CLEANUP void vt_destroy() { if (fd >= 0) { close(fd); fd = -1; } } -void get_current_vt(int *nr) { +void vt_get_current(int *nr, uid_t *owner) { + int ret; + struct stat fstat; struct vt_stat vtstat; - if (fd < 0) - die("get_current_vt() called without vt_init()"); - - if (ioctl(fd, VT_GETSTATE, &vtstat) < 0) - die("could not get state of active console: %s", strerror(errno)); + while ((ret = ioctl(fd, VT_GETSTATE, &vtstat)) == -1 && errno == EINTR); + if (ret == -1) + error(EXIT_FAILURE, errno, "%s: VT_GETSTATE", CONSOLE_DEVICE); *nr = vtstat.v_active; + snprintf(filename, sizeof(filename), "%s%d", TTY_DEVICE_BASE, *nr); + *owner = stat(filename, &fstat) == 0 ? fstat.st_uid : (uid_t)-1; } -void acquire_new_vt(vt_t *vt) { +CLEANUP int vt_lock_switch(int set) { + int ret; + + if (set) { + while ((ret = ioctl(fd, VT_LOCKSWITCH, 1)) == -1 && errno == EINTR); + if (ret == -1) + error(0, errno, "%s: VT_LOCKSWITCH", CONSOLE_DEVICE); + } else { + while ((ret = ioctl(fd, VT_UNLOCKSWITCH, 1)) == -1 && errno == EINTR); + if (ret == -1) + error(0, errno, "%s: VT_UNLOCKSWITCH", CONSOLE_DEVICE); + } + return ret; +} + +void vt_acquire(vt_t *vt) { + int ret; + vt->nr = -1; vt->ios = NULL; vt->fd = -1; - if (fd < 0) - die("acquire_new_vt() called without vt_init()"); - if (ioctl(fd, VT_OPENQRY, &vt->nr) < 0) - die("could not open new console: %s", strerror(errno)); + while ((ret = ioctl(fd, VT_OPENQRY, &vt->nr)) == -1 && errno == EINTR); + if (ret == -1) + error(EXIT_FAILURE, errno, "%s: VT_OPENQRY", CONSOLE_DEVICE); - snprintf(filename, FNAME_LEN, "%s%d", TTY_DEVICE_BASE, vt->nr); - vt->ios = fopen(filename, "r+"); + snprintf(filename, sizeof(filename), "%s%d", TTY_DEVICE_BASE, vt->nr); + while ((vt->ios = fopen(filename, "r+")) == NULL && errno == EINTR); if (vt->ios == NULL) - die("could not open %s: %s", filename, strerror(errno)); + error(EXIT_FAILURE, errno, "%s", filename); vt->fd = fileno(vt->ios); - if (ioctl(fd, VT_ACTIVATE, vt->nr) < 0 || - ioctl(fd, VT_WAITACTIVE, vt->nr) < 0) - die("could not activate console # %d: %s", vt->nr, strerror(errno)); + while ((ret = ioctl(fd, VT_ACTIVATE, vt->nr)) == -1 && errno == EINTR); + if (ret == -1) + error(EXIT_FAILURE, errno, "%s: VT_ACTIVATE", CONSOLE_DEVICE); + while ((ret = ioctl(fd, VT_WAITACTIVE, vt->nr)) == -1 && errno == EINTR); + if (ret == -1) + error(EXIT_FAILURE, errno, "%s: VT_WAITACTIVE", CONSOLE_DEVICE); tcgetattr(vt->fd, &vt->term); vt->rlflag = vt->term.c_lflag; } -void reopen_vt(vt_t *vt) { - if (vt->nr < 0) - die("reopen_vt() called without acquire_new_vt()"); +void vt_reopen(vt_t *vt) { + FILE *ios = vt->ios; + vt->fd = -1; - vt->ios = freopen(filename, "r+", vt->ios); + while ((vt->ios = freopen(filename, "r+", ios)) == NULL && errno == EINTR); if (vt->ios == NULL) - die("could not open %s: %s", filename, strerror(errno)); + error(EXIT_FAILURE, errno, "%s", filename); vt->fd = fileno(vt->ios); } -void release_vt(vt_t *vt, int nr) { - if (fd < 0) - die("release_vt() called without vt_init()"); - if (nr <= 0) - die("release_vt() called with invalid argument"); - if (ioctl(fd, VT_ACTIVATE, nr) < 0 || - ioctl(fd, VT_WAITACTIVE, nr) < 0) - die("could not activate console # %d: %s", vt->nr, strerror(errno)); +CLEANUP int vt_release(vt_t *vt, int nr) { + int ret; + + while ((ret = ioctl(fd, VT_ACTIVATE, nr)) == -1 && errno == EINTR); + if (ret == -1) { + error(0, errno, "%s: VT_ACTIVATE", CONSOLE_DEVICE); + return -1; + } + while ((ret = ioctl(fd, VT_WAITACTIVE, nr)) == -1 && errno == EINTR); + if (ret == -1) { + error(0, errno, "%s: VT_WAITACTIVE", CONSOLE_DEVICE); + return -1; + } if (vt->ios != NULL) { fclose(vt->ios); @@ -112,63 +133,23 @@ } if (vt->nr > 0) { - if (ioctl(fd, VT_DISALLOCATE, vt->nr) < 0) - die("could not deallocate console # %d: %s", vt->nr, strerror(errno)); + while ((ret = ioctl(fd, VT_DISALLOCATE, vt->nr)) == -1 && errno == EINTR); + if (ret == -1) { + error(0, errno, "%s: VT_DISALLOCATE", CONSOLE_DEVICE); + return -1; + } vt->nr = -1; } + return 0; } -void lock_vt_switch() { - if (fd < 0) - die("lock_vt_switch() called without vt_init()"); - if (ioctl(fd, VT_LOCKSWITCH, 1) < 0) - die("could not lock console switching: %s", strerror(errno)); -} - -void unlock_vt_switch() { - if (fd < 0) - die("unlock_vt_switch() called without vt_init()"); - if (ioctl(fd, VT_UNLOCKSWITCH, 1) < 0) - die("could not enable console switching: %s", strerror(errno)); -} - -void secure_vt(vt_t *vt) { - if (vt->fd < 0) - die("secure_vt() called with invalid argument"); +void vt_secure(vt_t *vt) { vt->term.c_lflag &= ~(ECHO | ISIG); tcsetattr(vt->fd, TCSANOW, &vt->term); } -void tty_echo_on(vt_t *vt) { - if (vt->fd < 0) { - warn("tty_break_on() called with invalid argument"); - return; - } - vt->term.c_lflag |= ECHO; - tcsetattr(vt->fd, TCSANOW, &vt->term); -} - -void tty_echo_off(vt_t *vt) { - if (vt->fd < 0) { - warn("tty_break_off() called with invalid argument"); - return; - } - vt->term.c_lflag &= ~ECHO; - tcsetattr(vt->fd, TCSANOW, &vt->term); -} - -void flush_vt(vt_t *vt) { - if (vt->fd >= 0) - tcflush(vt->fd, TCIFLUSH); -} - -void reset_vt(vt_t *vt) { - if (vt->fd < 0) - die("reset_vt() called with invalid argument"); - - /* clear the screen: */ - fprintf(vt->ios, "\033[H\033[J"); - +CLEANUP void vt_reset(vt_t *vt) { + fprintf(vt->ios, "\033[H\033[J"); /* clear the screen */ vt->term.c_lflag = vt->rlflag; tcsetattr(vt->fd, TCSANOW, &vt->term); } diff -Nru physlock-0.4.5/vt.h physlock-11/vt.h --- physlock-0.4.5/vt.h 2015-07-08 11:02:37.000000000 +0000 +++ physlock-11/vt.h 2017-08-17 09:27:46.000000000 +0000 @@ -22,6 +22,8 @@ #include #include +#define CLEANUP + typedef struct vt_s { int nr; FILE *ios; @@ -31,20 +33,16 @@ } vt_t; void vt_init(); -void vt_destroy(); +CLEANUP void vt_destroy(); + +void vt_get_current(int*, uid_t*); +CLEANUP int vt_lock_switch(int); + +void vt_acquire(vt_t*); +void vt_reopen(vt_t*); +CLEANUP int vt_release(vt_t*, int); -void get_current_vt(int*); -void acquire_new_vt(vt_t*); -void reopen_vt(vt_t*); -void release_vt(vt_t*, int); - -void lock_vt_switch(); -void unlock_vt_switch(); - -void secure_vt(vt_t*); -void tty_echo_on(vt_t*); -void tty_echo_off(vt_t*); -void flush_vt(vt_t*); -void reset_vt(vt_t*); +void vt_secure(vt_t*); +CLEANUP void vt_reset(vt_t*); #endif /* VT_H */