Also apply two security measures for OpenBSD:
- use explicit_bzero(3)
- mlock(2) works for non-root users too
INSTALL=install
PREFIX=/usr
INSTALL=install
PREFIX=/usr
CFLAGS += -pipe
CFLAGS += -Wall
CPPFLAGS += -D_GNU_SOURCE
CFLAGS += -pipe
CFLAGS += -Wall
CPPFLAGS += -D_GNU_SOURCE
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)
+# 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)
- 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
------------
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
#include <xcb/xkb.h>
#include <err.h>
#include <assert.h>
#include <xcb/xkb.h>
#include <err.h>
#include <assert.h>
+#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>
#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"
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;
static pam_handle_t *pam_handle;
#endif
int input_position = 0;
static pam_handle_t *pam_handle;
#endif
int input_position = 0;
*
*/
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;
* 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;
}
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) {
unlock_state = STATE_STARTED;
redraw_screen();
unlock_state = STATE_STARTED;
redraw_screen();
+#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();
/*
* Callback function for PAM. We only react on password request callbacks.
*
/*
* Callback function for PAM. We only react on password request callbacks.
*
struct passwd *pw;
char *username;
char *image_path = NULL;
struct passwd *pw;
char *username;
char *image_path = NULL;
int ret;
struct pam_conv conv = {conv_callback, NULL};
#endif
int ret;
struct pam_conv conv = {conv_callback, NULL};
#endif
* the unlock indicator upon keypresses. */
srand(time(NULL));
* the unlock indicator upon keypresses. */
srand(time(NULL));
/* 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));
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. */
} 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;