|
@ -25,16 +25,19 @@ |
|
|
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
+DEALINGS IN THE SOFTWARE.
|
|
|
+DEALINGS IN THE SOFTWARE.
|
|
|
+++ Makefile
|
|
|
+++ Makefile
|
|
|
@@ -14,7 +14,7 @@
|
|
|
@@ -20,9 +20,9 @@
|
|
|
CPPFLAGS += -D_GNU_SOURCE |
|
|
|
|
|
CFLAGS += $(shell $(PKG_CONFIG) --cflags cairo xcb-dpms xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11) |
|
|
|
|
|
LIBS += $(shell $(PKG_CONFIG) --libs cairo xcb-dpms xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11) |
|
|
|
|
|
-LIBS += -lpam
|
|
|
|
|
|
+LIBS += -lcrypt
|
|
|
|
|
|
LIBS += -lev |
|
|
LIBS += -lev |
|
|
LIBS += -lm |
|
|
LIBS += -lm |
|
|
|
|
|
|
|
|
@@ -37,9 +37,7 @@
|
|
|
-# OpenBSD lacks PAM, use bsd_auth(3) instead.
|
|
|
|
|
|
+# On OpenBSD we use bsd_auth(3) instead.
|
|
|
|
|
|
ifneq ($(UNAME),OpenBSD) |
|
|
|
|
|
- LIBS += -lpam
|
|
|
|
|
|
+ LIBS += -lcrypt
|
|
|
|
|
|
endif |
|
|
|
|
|
|
|
|
|
|
|
FILES:=$(wildcard *.c) |
|
|
|
|
|
@@ -50,9 +50,7 @@
|
|
|
|
|
|
|
|
|
install: all |
|
|
install: all |
|
|
$(INSTALL) -d $(DESTDIR)$(PREFIX)/bin |
|
|
$(INSTALL) -d $(DESTDIR)$(PREFIX)/bin |
|
@ -44,8 +47,17 @@ |
|
|
|
|
|
|
|
|
uninstall: |
|
|
uninstall: |
|
|
rm -f $(DESTDIR)$(PREFIX)/bin/i3lock |
|
|
rm -f $(DESTDIR)$(PREFIX)/bin/i3lock |
|
|
|
|
|
@@ -61,7 +59,7 @@
|
|
|
|
|
|
[ ! -d i3lock-${VERSION} ] || rm -rf i3lock-${VERSION} |
|
|
|
|
|
[ ! -e i3lock-${VERSION}.tar.bz2 ] || rm i3lock-${VERSION}.tar.bz2 |
|
|
|
|
|
mkdir i3lock-${VERSION} |
|
|
|
|
|
- cp *.c *.h i3lock.1 i3lock.pam Makefile LICENSE README.md CHANGELOG i3lock-${VERSION}
|
|
|
|
|
|
+ cp *.c *.h i3lock.1 Makefile LICENSE README.md CHANGELOG i3lock-${VERSION}
|
|
|
|
|
|
sed -e 's/^I3LOCK_VERSION:=\(.*\)/I3LOCK_VERSION:=$(shell /bin/echo '${I3LOCK_VERSION}' | sed 's/\\/\\\\/g')/g;s/^VERSION:=\(.*\)/VERSION:=${VERSION}/g' Makefile > i3lock-${VERSION}/Makefile |
|
|
|
|
|
tar cfj i3lock-${VERSION}.tar.bz2 i3lock-${VERSION} |
|
|
|
|
|
rm -rf i3lock-${VERSION} |
|
|
+++ i3lock.1
|
|
|
+++ i3lock.1
|
|
|
@@ -45,8 +45,6 @@
|
|
|
@@ -43,8 +43,6 @@
|
|
|
You can specify either a background color or a PNG image which will be displayed while your screen is locked. |
|
|
You can specify either a background color or a PNG image which will be displayed while your screen is locked. |
|
|
.IP \[bu] |
|
|
.IP \[bu] |
|
|
You can specify whether i3lock should bell upon a wrong password. |
|
|
You can specify whether i3lock should bell upon a wrong password. |
|
@ -54,55 +66,47 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.SH OPTIONS |
|
|
.SH OPTIONS |
|
|
@@ -75,7 +73,7 @@
|
|
|
@@ -66,8 +64,7 @@
|
|
|
.B \-u, \-\-no-unlock-indicator |
|
|
.B \-u, \-\-no-unlock-indicator |
|
|
Disable the unlock indicator. i3lock will by default show an unlock indicator |
|
|
Disable the unlock indicator. i3lock will by default show an unlock indicator |
|
|
after pressing keys. This will give feedback for every keypress and it will |
|
|
after pressing keys. This will give feedback for every keypress and it will |
|
|
-show you the current PAM state (whether your password is currently being
|
|
|
-show you the current PAM state (whether your password is currently being
|
|
|
+show you the current state (whether your password is currently being
|
|
|
-verified or whether it is wrong).
|
|
|
verified or whether it is wrong). |
|
|
+show you whether your password is currently being verified or whether it is wrong.
|
|
|
|
|
|
|
|
|
.TP |
|
|
.TP |
|
|
@@ -104,7 +102,7 @@
|
|
|
.BI \-i\ path \fR,\ \fB\-\-image= path |
|
|
|
|
|
@@ -95,7 +92,7 @@
|
|
|
.TP |
|
|
.TP |
|
|
.B \-e, \-\-ignore-empty-password |
|
|
.B \-e, \-\-ignore-empty-password |
|
|
When an empty password is provided by the user, do not validate |
|
|
When an empty password is provided by the user, do not validate |
|
|
-it. Without this option, the empty password will be provided to PAM
|
|
|
-it. Without this option, the empty password will be provided to PAM
|
|
|
+it. Without this option, the empty password will be checked
|
|
|
+it. Without this option, the empty password will be validated
|
|
|
and, if invalid, the user will have to wait a few seconds before |
|
|
and, if invalid, the user will have to wait a few seconds before |
|
|
another try. This can be useful if the XF86ScreenSaver key is used to |
|
|
another try. This can be useful if the XF86ScreenSaver key is used to |
|
|
put a laptop to sleep and bounce on resume or if you happen to wake up |
|
|
put a laptop to sleep and bounce on resume or if you happen to wake up |
|
|
+++ i3lock.c
|
|
|
+++ i3lock.c
|
|
|
@@ -18,7 +18,6 @@
|
|
|
@@ -21,7 +21,9 @@
|
|
|
#include <xcb/xkb.h> |
|
|
#ifdef __OpenBSD__ |
|
|
#include <err.h> |
|
|
#include <bsd_auth.h> |
|
|
#include <assert.h> |
|
|
#else |
|
|
-#include <security/pam_appl.h>
|
|
|
-#include <security/pam_appl.h>
|
|
|
|
|
|
+#include <shadow.h>
|
|
|
|
|
|
+#include <grp.h>
|
|
|
|
|
|
+#include <errno.h>
|
|
|
|
|
|
#endif |
|
|
#include <getopt.h> |
|
|
#include <getopt.h> |
|
|
#include <string.h> |
|
|
#include <string.h> |
|
|
#include <ev.h> |
|
|
@@ -57,7 +59,7 @@
|
|
|
@@ -28,6 +27,8 @@
|
|
|
|
|
|
#include <xkbcommon/xkbcommon-x11.h> |
|
|
|
|
|
#include <cairo.h> |
|
|
|
|
|
#include <cairo/cairo-xcb.h> |
|
|
|
|
|
+#include <unistd.h>
|
|
|
|
|
|
+#include <shadow.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include "i3lock.h" |
|
|
|
|
|
#include "xcb.h" |
|
|
|
|
|
@@ -49,10 +50,10 @@
|
|
|
|
|
|
uint32_t last_resolution[2]; |
|
|
|
|
|
xcb_window_t win; |
|
|
xcb_window_t win; |
|
|
static xcb_cursor_t cursor; |
|
|
static xcb_cursor_t cursor; |
|
|
|
|
|
#ifndef __OpenBSD__ |
|
|
-static pam_handle_t *pam_handle;
|
|
|
-static pam_handle_t *pam_handle;
|
|
|
|
|
|
+const char *hash = NULL;
|
|
|
|
|
|
#endif |
|
|
int input_position = 0; |
|
|
int input_position = 0; |
|
|
/* Holds the password you enter (in UTF-8). */ |
|
|
/* Holds the password you enter (in UTF-8). */ |
|
|
static char password[512]; |
|
|
@@ -90,6 +92,37 @@
|
|
|
+const char *pws = NULL;
|
|
|
|
|
|
static bool beep = false; |
|
|
|
|
|
bool debug_mode = false; |
|
|
|
|
|
bool unlock_indicator = true; |
|
|
|
|
|
@@ -80,6 +81,39 @@
|
|
|
|
|
|
bool ignore_empty_password = false; |
|
|
bool ignore_empty_password = false; |
|
|
bool skip_repeated_empty_password = false; |
|
|
bool skip_repeated_empty_password = false; |
|
|
|
|
|
|
|
@ -114,42 +118,43 @@ |
|
|
+#ifdef __linux__
|
|
|
+#ifdef __linux__
|
|
|
+#include <fcntl.h>
|
|
|
+#include <fcntl.h>
|
|
|
+#include <linux/oom.h>
|
|
|
+#include <linux/oom.h>
|
|
|
+#include <errno.h>
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+static void
|
|
|
+static void
|
|
|
+dontkillme(void)
|
|
|
+dontkillme(void)
|
|
|
+{
|
|
|
+{
|
|
|
+ int fd;
|
|
|
+ FILE *f;
|
|
|
+ int length;
|
|
|
+ const char oomfile[] = "/proc/self/oom_score_adj";
|
|
|
+ char value[64];
|
|
|
|
|
|
+
|
|
|
|
|
|
+ fd = open("/proc/self/oom_score_adj", O_WRONLY);
|
|
|
|
|
|
+ if (fd < 0 && errno == ENOENT)
|
|
|
|
|
|
+ return;
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+ /* convert OOM_SCORE_ADJ_MIN to string for writing */
|
|
|
+ if (!(f = fopen(oomfile, "w"))) {
|
|
|
+ length = snprintf(value, sizeof(value), "%d\n", OOM_SCORE_ADJ_MIN);
|
|
|
+ if (errno == ENOENT)
|
|
|
+
|
|
|
+ return;
|
|
|
+ /* bail on truncation */
|
|
|
+ errx(EXIT_FAILURE, "i3lock: fopen %s: %s", oomfile, strerror(errno));
|
|
|
+ if (length >= sizeof(value))
|
|
|
+ }
|
|
|
+ errx(EXIT_FAILURE, "buffer too small\n");
|
|
|
+ fprintf(f, "%d", OOM_SCORE_ADJ_MIN);
|
|
|
+
|
|
|
+ if (fclose(f)) {
|
|
|
+ if (fd < 0 || write(fd, value, length) != length || close(fd) != 0)
|
|
|
+ if (errno == EACCES)
|
|
|
+ errx(EXIT_FAILURE, "cannot disable the out-of-memory killer for this process (make sure to suid or sgid i3lock)\n");
|
|
|
+ errx(EXIT_FAILURE, "i3lock: unable to disable OOM killer. "
|
|
|
|
|
|
+ "Make sure to suid or sgid i3lock.");
|
|
|
|
|
|
+ else
|
|
|
|
|
|
+ errx(EXIT_FAILURE, "i3lock: fclose %s: %s", oomfile, strerror(errno));
|
|
|
|
|
|
+ }
|
|
|
+}
|
|
|
+}
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
/* isutf, u8_dec © 2005 Jeff Bezanson, public domain */ |
|
|
/* isutf, u8_dec © 2005 Jeff Bezanson, public domain */ |
|
|
#define isutf(c) (((c)&0xC0) != 0x80) |
|
|
#define isutf(c) (((c)&0xC0) != 0x80) |
|
|
|
|
|
|
|
|
@@ -235,17 +269,10 @@
|
|
|
@@ -281,16 +314,16 @@
|
|
|
unlock_state = STATE_STARTED; |
|
|
exit(0); |
|
|
redraw_screen(); |
|
|
} |
|
|
|
|
|
#else |
|
|
- if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
|
|
|
- if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
|
|
|
+ if (!strcmp(crypt(password, pws), pws)) {
|
|
|
- DEBUG("successfully authenticated\n");
|
|
|
DEBUG("successfully authenticated\n"); |
|
|
- clear_password_memory();
|
|
|
clear_password_memory(); |
|
|
+ /*
|
|
|
|
|
|
+ * Shamelessly stolen from slock. See LICENSE-slock.
|
|
|
|
|
|
+ */
|
|
|
|
|
|
+ char *inputhash;
|
|
|
|
|
|
|
|
|
- /* PAM credentials should be refreshed, this will for example update any kerberos tickets.
|
|
|
- /* PAM credentials should be refreshed, this will for example update any kerberos tickets.
|
|
|
- * Related to credentials pam_end() needs to be called to cleanup any temporary
|
|
|
- * Related to credentials pam_end() needs to be called to cleanup any temporary
|
|
@ -157,14 +162,20 @@ |
|
|
- * refresh of the credentials failed. */
|
|
|
- * refresh of the credentials failed. */
|
|
|
- pam_setcred(pam_handle, PAM_REFRESH_CRED);
|
|
|
- pam_setcred(pam_handle, PAM_REFRESH_CRED);
|
|
|
- pam_end(pam_handle, PAM_SUCCESS);
|
|
|
- pam_end(pam_handle, PAM_SUCCESS);
|
|
|
-
|
|
|
+ if (!(inputhash = crypt(password, hash)))
|
|
|
|
|
|
+ fprintf(stderr, "i3lock: crypt: %s", strerror(errno));
|
|
|
|
|
|
+ else if (!strcmp(inputhash, hash)) {
|
|
|
|
|
|
+ DEBUG("successfully authenticated");
|
|
|
|
|
|
+ clear_password_memory();
|
|
|
|
|
|
|
|
|
exit(0); |
|
|
exit(0); |
|
|
} |
|
|
} |
|
|
|
|
|
@@ -626,39 +659,6 @@
|
|
|
@@ -580,37 +607,6 @@
|
|
|
redraw_screen(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
-#ifndef __OpenBSD__
|
|
|
|
|
|
-/*
|
|
|
- * Callback function for PAM. We only react on password request callbacks.
|
|
|
- * Callback function for PAM. We only react on password request callbacks.
|
|
|
- *
|
|
|
- *
|
|
|
- */
|
|
|
- */
|
|
@ -194,65 +205,87 @@ |
|
|
-
|
|
|
-
|
|
|
- return 0;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-}
|
|
|
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
-/*
|
|
|
/* |
|
|
* This callback is only a dummy, see xcb_prepare_cb and xcb_check_cb. |
|
|
* This callback is only a dummy, see xcb_prepare_cb and xcb_check_cb. |
|
|
* See also man libev(3): "ev_prepare" and "ev_check" - customise your event loop |
|
|
* See also man libev(3): "ev_prepare" and "ev_check" - customise your event loop |
|
|
* |
|
|
@@ -813,10 +813,6 @@
|
|
|
@@ -764,8 +760,6 @@
|
|
|
|
|
|
struct passwd *pw; |
|
|
struct passwd *pw; |
|
|
char *username; |
|
|
char *username; |
|
|
char *image_path = NULL; |
|
|
char *image_path = NULL; |
|
|
|
|
|
-#ifndef __OpenBSD__
|
|
|
- int ret;
|
|
|
- int ret;
|
|
|
- struct pam_conv conv = {conv_callback, NULL};
|
|
|
- struct pam_conv conv = {conv_callback, NULL};
|
|
|
|
|
|
-#endif
|
|
|
int curs_choice = CURS_NONE; |
|
|
int curs_choice = CURS_NONE; |
|
|
int o; |
|
|
int o; |
|
|
int optind = 0; |
|
|
int optind = 0; |
|
|
@@ -791,6 +785,30 @@
|
|
|
@@ -842,6 +838,48 @@
|
|
|
if ((username = pw->pw_name) == NULL) |
|
|
if ((username = pw->pw_name) == NULL) |
|
|
errx(EXIT_FAILURE, "pw->pw_name is NULL.\n"); |
|
|
errx(EXIT_FAILURE, "pw->pw_name is NULL.\n"); |
|
|
|
|
|
|
|
|
|
|
|
+#ifndef __OpenBSD__
|
|
|
+ /*
|
|
|
+ /*
|
|
|
+ * This piece of code is shamelessly stolen from slock.
|
|
|
+ * Shamelessly stolen from slock. See LICENSE-slock.
|
|
|
+ * See LICENSE-slock.
|
|
|
+ *
|
|
|
|
|
|
+ * Slock has code to make it run as nobody:nogroup, which has the added
|
|
|
|
|
|
+ * security that the locker can only be killed by root.
|
|
|
|
|
|
+ * It causes problems with the xcb_connect in raise_loop, however,
|
|
|
|
|
|
+ * and I'm not aware of any other methods to keep the calling user from
|
|
|
|
|
|
+ * killing the locker.
|
|
|
|
|
|
+ * This means that a malicious program running as your user
|
|
|
|
|
|
+ * could easily bypass your locker by killing it.
|
|
|
|
|
|
+ * However, if such a program even manages to be running, you're pretty
|
|
|
|
|
|
+ * screwed regardless.
|
|
|
+ */
|
|
|
+ */
|
|
|
|
|
|
+
|
|
|
+#ifdef __linux__
|
|
|
+#ifdef __linux__
|
|
|
+ dontkillme();
|
|
|
+ dontkillme();
|
|
|
+#endif
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+ pws = pw->pw_passwd;
|
|
|
+ hash = pw->pw_passwd;
|
|
|
+
|
|
|
+
|
|
|
+ if (pws[0] == 'x' && pws[1] == '\0') {
|
|
|
+ if (!strcmp(hash, "x")) {
|
|
|
+ struct spwd *sp;
|
|
|
+ struct spwd *sp;
|
|
|
+ if (!(sp = getspnam(getenv("USER"))))
|
|
|
+ if (!(sp = getspnam(pw->pw_name)))
|
|
|
+ errx(EXIT_FAILURE, "cannot retrieve shadow entry (make sure to suid or sgid i3lock)\n");
|
|
|
+ errx(EXIT_FAILURE, "i3lock: getspnam: cannot retrieve shadow entry. "
|
|
|
+ pws = sp->sp_pwdp;
|
|
|
+ "Make sure to suid or sgid i3lock.");
|
|
|
|
|
|
+ hash = sp->sp_pwdp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /* drop privileges */
|
|
|
+ errno = 0;
|
|
|
+ if (geteuid() == 0 &&
|
|
|
+ if (!crypt("", hash))
|
|
|
+ ((getegid() != pw->pw_gid && setgid(pw->pw_gid) < 0) || setuid(pw->pw_uid) < 0))
|
|
|
+ errx(EXIT_FAILURE, "i3lock: crypt: %s", strerror(errno));
|
|
|
+ errx(EXIT_FAILURE, "cannot drop privileges\n");
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+ /* End of stolen code */
|
|
|
+ /* drop privileges */
|
|
|
|
|
|
+ if (setgroups(0, NULL) < 0)
|
|
|
|
|
|
+ errx(EXIT_FAILURE, "i3lock: setgroups: %s", strerror(errno));
|
|
|
|
|
|
+ if (setgid(pw->pw_gid) < 0)
|
|
|
|
|
|
+ errx(EXIT_FAILURE, "i3lock: setgid: %s", strerror(errno));
|
|
|
|
|
|
+ if (setuid(pw->pw_uid) < 0)
|
|
|
|
|
|
+ errx(EXIT_FAILURE, "i3lock: setuid: %s", strerror(errno));
|
|
|
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
char *optstring = "hvnbdc:p:ui:teI:f"; |
|
|
char *optstring = "hvnbdc:p:ui:teI:f"; |
|
|
while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) { |
|
|
while ((o = getopt_long(argc, argv, optstring, longopts, &optind)) != -1) { |
|
|
switch (o) { |
|
|
switch (o) { |
|
|
@@ -862,13 +880,6 @@
|
|
|
@@ -910,15 +948,6 @@
|
|
|
* the unlock indicator upon keypresses. */ |
|
|
* the unlock indicator upon keypresses. */ |
|
|
srand(time(NULL)); |
|
|
srand(time(NULL)); |
|
|
|
|
|
|
|
|
|
|
|
-#ifndef __OpenBSD__
|
|
|
- /* Initialize PAM */
|
|
|
- /* Initialize PAM */
|
|
|
- if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
|
|
|
- if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
|
|
|
- errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
|
|
|
- errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
|
|
|
-
|
|
|
-
|
|
|
- if ((ret = pam_set_item(pam_handle, PAM_TTY, getenv("DISPLAY"))) != PAM_SUCCESS)
|
|
|
- if ((ret = pam_set_item(pam_handle, PAM_TTY, getenv("DISPLAY"))) != PAM_SUCCESS)
|
|
|
- errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
|
|
|
- errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
|
|
|
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
/* Using mlock() as non-super-user seems only possible in Linux. Users of other |
|
|
/* Using mlock() as non-super-user seems only possible in Linux. |
|
|
* operating systems should use encrypted swap/no swap (or remove the ifdef and |
|
|
* Users of other operating systems should use encrypted swap/no swap |
|
|
* run i3lock as super-user). */ |
|
|
* (or remove the ifdef and run i3lock as super-user). |
|
|
+++ i3lock.pam
|
|
|
+++ i3lock.pam
|
|
|
@@ -1,6 +0,0 @@
|
|
|
@@ -1,6 +0,0 @@
|
|
|
-#
|
|
|
-#
|