]> git.sur5r.net Git - i3/i3lock/commitdiff
Use bsd_auth(3) instead of PAM on OpenBSD 123/head
authorJasper Lievisse Adriaanse <jasper@humppa.nl>
Sat, 15 Apr 2017 12:41:32 +0000 (14:41 +0200)
committerJasper Lievisse Adriaanse <jasper@humppa.nl>
Mon, 17 Apr 2017 13:06:59 +0000 (15:06 +0200)
Also apply two security measures for OpenBSD:
- use explicit_bzero(3)
- mlock(2) works for non-root users too

Makefile
README.md
i3lock.c
unlock_indicator.h

index b7eae33e8020ffc3cdb8aae9637bac7aa63ebf05..3acb272818892dd713a7605aece3152cff2dc7f2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
 TOPDIR=$(shell pwd)
 TOPDIR=$(shell pwd)
+UNAME=$(shell uname)
 
 INSTALL=install
 PREFIX=/usr
 
 INSTALL=install
 PREFIX=/usr
@@ -14,13 +15,16 @@ CFLAGS += -std=c99
 CFLAGS += -pipe
 CFLAGS += -Wall
 CPPFLAGS += -D_GNU_SOURCE
 CFLAGS += -pipe
 CFLAGS += -Wall
 CPPFLAGS += -D_GNU_SOURCE
-CPPFLAGS += -DUSE_PAM
 CFLAGS += $(shell $(PKG_CONFIG) --cflags cairo xcb-composite xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11)
 LIBS += $(shell $(PKG_CONFIG) --libs cairo xcb-composite xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11)
 CFLAGS += $(shell $(PKG_CONFIG) --cflags cairo xcb-composite xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11)
 LIBS += $(shell $(PKG_CONFIG) --libs cairo xcb-composite xcb-xinerama xcb-atom xcb-image xcb-xkb xkbcommon xkbcommon-x11)
-LIBS += -lpam
 LIBS += -lev
 LIBS += -lm
 
 LIBS += -lev
 LIBS += -lm
 
+# OpenBSD lacks PAM, use bsd_auth(3) instead.
+ifneq ($(UNAME),OpenBSD)
+  LIBS += -lpam
+endif
+
 FILES:=$(wildcard *.c)
 FILES:=$(FILES:.c=.o)
 
 FILES:=$(wildcard *.c)
 FILES:=$(FILES:.c=.o)
 
index fcecbfaca0df6074a424c22039a03dd26bd52e1b..fc486b238389255554039b3833939b19627391fb 100644 (file)
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@ Many little improvements have been made to i3lock over time:
 - You can specify whether i3lock should bell upon a wrong password.
 
 - i3lock uses PAM and therefore is compatible with LDAP etc.
 - You can specify whether i3lock should bell upon a wrong password.
 
 - i3lock uses PAM and therefore is compatible with LDAP etc.
+  On OpenBSD i3lock uses the bsd_auth(3) framework.
 
 Requirements
 ------------
 
 Requirements
 ------------
@@ -37,6 +38,9 @@ Running i3lock
 Simply invoke the 'i3lock' command. To get out of it, enter your password and
 press enter.
 
 Simply invoke the 'i3lock' command. To get out of it, enter your password and
 press enter.
 
+On OpenBSD the `i3lock` binary needs to be setgid `auth` to call the
+authentication helpers, e.g. `/usr/libexec/auth/login_passwd`.
+
 Upstream
 --------
 Please submit pull requests to https://github.com/i3/i3lock
 Upstream
 --------
 Please submit pull requests to https://github.com/i3/i3lock
index 26c5b9bf3ccee086d79f221c48d1dbe433f0b238..01f0436a1de6569689df2db980d3fbe588284d34 100644 (file)
--- a/i3lock.c
+++ b/i3lock.c
@@ -18,7 +18,9 @@
 #include <xcb/xkb.h>
 #include <err.h>
 #include <assert.h>
 #include <xcb/xkb.h>
 #include <err.h>
 #include <assert.h>
-#ifdef USE_PAM
+#ifdef __OpenBSD__
+#include <bsd_auth.h>
+#else
 #include <security/pam_appl.h>
 #endif
 #include <getopt.h>
 #include <security/pam_appl.h>
 #endif
 #include <getopt.h>
@@ -30,6 +32,9 @@
 #include <xkbcommon/xkbcommon-x11.h>
 #include <cairo.h>
 #include <cairo/cairo-xcb.h>
 #include <xkbcommon/xkbcommon-x11.h>
 #include <cairo.h>
 #include <cairo/cairo-xcb.h>
+#ifdef __OpenBSD__
+#include <strings.h> /* explicit_bzero(3) */
+#endif
 
 #include "i3lock.h"
 #include "xcb.h"
 
 #include "i3lock.h"
 #include "xcb.h"
@@ -51,7 +56,7 @@ char color[7] = "ffffff";
 uint32_t last_resolution[2];
 xcb_window_t win;
 static xcb_cursor_t cursor;
 uint32_t last_resolution[2];
 xcb_window_t win;
 static xcb_cursor_t cursor;
-#ifdef USE_PAM
+#ifndef __OpenBSD__
 static pam_handle_t *pam_handle;
 #endif
 int input_position = 0;
 static pam_handle_t *pam_handle;
 #endif
 int input_position = 0;
@@ -162,6 +167,11 @@ static bool load_compose_table(const char *locale) {
  *
  */
 static void clear_password_memory(void) {
  *
  */
 static void clear_password_memory(void) {
+#ifdef __OpenBSD__
+    /* Use explicit_bzero(3) which was explicitly designed not to be
+     * optimized out by the compiler. */
+    explicit_bzero(password, strlen(password));
+#else
     /* A volatile pointer to the password buffer to prevent the compiler from
      * optimizing this out. */
     volatile char *vpassword = password;
     /* A volatile pointer to the password buffer to prevent the compiler from
      * optimizing this out. */
     volatile char *vpassword = password;
@@ -171,6 +181,7 @@ static void clear_password_memory(void) {
          * compiler from optimizing the calls away, since the value of 'beep'
          * is not known at compile-time. */
         vpassword[c] = c + (int)beep;
          * compiler from optimizing the calls away, since the value of 'beep'
          * is not known at compile-time. */
         vpassword[c] = c + (int)beep;
+#endif
 }
 
 ev_timer *start_timer(ev_timer *timer_obj, ev_tstamp timeout, ev_callback_t callback) {
 }
 
 ev_timer *start_timer(ev_timer *timer_obj, ev_tstamp timeout, ev_callback_t callback) {
@@ -257,7 +268,19 @@ static void input_done(void) {
     unlock_state = STATE_STARTED;
     redraw_screen();
 
     unlock_state = STATE_STARTED;
     redraw_screen();
 
-#ifdef USE_PAM
+#ifdef __OpenBSD__
+    struct passwd *pw;
+
+    if (!(pw = getpwuid(getuid())))
+        errx(1, "unknown uid %u.", getuid());
+
+    if (auth_userokay(pw->pw_name, NULL, NULL, password) != 0) {
+        DEBUG("successfully authenticated\n");
+        clear_password_memory();
+
+        exit(0);
+    }
+#else
     if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
         DEBUG("successfully authenticated\n");
         clear_password_memory();
     if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
         DEBUG("successfully authenticated\n");
         clear_password_memory();
@@ -603,7 +626,7 @@ void handle_screen_resize(void) {
     redraw_screen();
 }
 
     redraw_screen();
 }
 
-#ifdef USE_PAM
+#ifndef __OpenBSD__
 /*
  * Callback function for PAM. We only react on password request callbacks.
  *
 /*
  * Callback function for PAM. We only react on password request callbacks.
  *
@@ -790,7 +813,7 @@ int main(int argc, char *argv[]) {
     struct passwd *pw;
     char *username;
     char *image_path = NULL;
     struct passwd *pw;
     char *username;
     char *image_path = NULL;
-#ifdef USE_PAM
+#ifndef __OpenBSD__
     int ret;
     struct pam_conv conv = {conv_callback, NULL};
 #endif
     int ret;
     struct pam_conv conv = {conv_callback, NULL};
 #endif
@@ -887,7 +910,7 @@ int main(int argc, char *argv[]) {
      * the unlock indicator upon keypresses. */
     srand(time(NULL));
 
      * the unlock indicator upon keypresses. */
     srand(time(NULL));
 
-#ifdef USE_PAM
+#ifndef __OpenBSD__
     /* Initialize PAM */
     if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
         errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
     /* Initialize PAM */
     if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
         errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
@@ -896,10 +919,12 @@ int main(int argc, char *argv[]) {
         errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
 #endif
 
         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
- * operating systems should use encrypted swap/no swap (or remove the ifdef and
- * run i3lock as super-user). */
-#if defined(__linux__)
+/* Using mlock() as non-super-user seems only possible in Linux and OpenBSD.
+ * Users of other operating systems should use encrypted swap/no swap
+ * (or remove the ifdef and run i3lock as super-user).
+ * NB: Alas, swap is encrypted by default on OpenBSD so swapping out
+ * is not necessarily an issue. */
+#if defined(__linux__) || defined(__OpenBSD__)
     /* Lock the area where we store the password in memory, we don’t want it to
      * be swapped to disk. Since Linux 2.6.9, this does not require any
      * privileges, just enough bytes in the RLIMIT_MEMLOCK limit. */
     /* Lock the area where we store the password in memory, we don’t want it to
      * be swapped to disk. Since Linux 2.6.9, this does not require any
      * privileges, just enough bytes in the RLIMIT_MEMLOCK limit. */
index e4a8d8ebc20491ba280b64ded58dcec70f984cc2..232162005b73bc0685979527297d19e7d6784030 100644 (file)
@@ -11,10 +11,10 @@ typedef enum {
 } unlock_state_t;
 
 typedef enum {
 } unlock_state_t;
 
 typedef enum {
-    STATE_AUTH_IDLE = 0,          /* no authenticator interaction at the moment */
-    STATE_AUTH_VERIFY = 1,        /* currently verifying the password via authenticator */
-    STATE_AUTH_LOCK = 2,          /* currently locking the screen */
-    STATE_AUTH_WRONG = 3,         /* the password was wrong */
+    STATE_AUTH_IDLE = 0,         /* no authenticator interaction at the moment */
+    STATE_AUTH_VERIFY = 1,       /* currently verifying the password via authenticator */
+    STATE_AUTH_LOCK = 2,         /* currently locking the screen */
+    STATE_AUTH_WRONG = 3,        /* the password was wrong */
     STATE_I3LOCK_LOCK_FAILED = 4 /* i3lock failed to load */
 } auth_state_t;
 
     STATE_I3LOCK_LOCK_FAILED = 4 /* i3lock failed to load */
 } auth_state_t;