You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
365 lines
12 KiB
365 lines
12 KiB
8 years ago
|
+++ LICENSE-slock
|
||
|
@@ -0,0 +1,24 @@
|
||
|
+MIT/X Consortium License
|
||
|
+
|
||
|
+© 2015-2016 Markus Teich <markus.teich@stusta.mhn.de>
|
||
|
+© 2014 Dimitris Papastamos <sin@2f30.org>
|
||
|
+© 2006-2014 Anselm R Garbe <anselm@garbe.us>
|
||
|
+© 2014-2016 Laslo Hunhold <dev@frign.de>
|
||
|
+
|
||
|
+Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
+copy of this software and associated documentation files (the "Software"),
|
||
|
+to deal in the Software without restriction, including without limitation
|
||
|
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
+and/or sell copies of the Software, and to permit persons to whom the
|
||
|
+Software is furnished to do so, subject to the following conditions:
|
||
|
+
|
||
|
+The above copyright notice and this permission notice shall be included in
|
||
|
+all copies or substantial portions of the Software.
|
||
|
+
|
||
|
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
+DEALINGS IN THE SOFTWARE.
|
||
|
+++ Makefile
|
||
7 years ago
|
@@ -22,7 +22,7 @@
|
||
8 years ago
|
|
||
7 years ago
|
# OpenBSD lacks PAM, use bsd_auth(3) instead.
|
||
8 years ago
|
ifneq ($(UNAME),OpenBSD)
|
||
|
- LIBS += -lpam
|
||
|
+ LIBS += -lcrypt
|
||
|
endif
|
||
|
|
||
|
FILES:=$(wildcard *.c)
|
||
7 years ago
|
@@ -50,9 +50,7 @@
|
||
8 years ago
|
|
||
|
install: all
|
||
|
$(INSTALL) -d $(DESTDIR)$(PREFIX)/bin
|
||
|
- $(INSTALL) -d $(DESTDIR)$(SYSCONFDIR)/pam.d
|
||
|
$(INSTALL) -m 755 i3lock $(DESTDIR)$(PREFIX)/bin/i3lock
|
||
|
- $(INSTALL) -m 644 i3lock.pam $(DESTDIR)$(SYSCONFDIR)/pam.d/i3lock
|
||
|
|
||
|
uninstall:
|
||
|
rm -f $(DESTDIR)$(PREFIX)/bin/i3lock
|
||
7 years ago
|
@@ -61,7 +59,7 @@
|
||
8 years ago
|
[ ! -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}
|
||
7 years ago
|
sed -e 's/^\s*I3LOCK_VERSION:=\(.*\)/I3LOCK_VERSION:=$(shell /bin/echo '${I3LOCK_VERSION}' | sed 's/\\/\\\\/g')/g;s/^VERSION:=\(.*\)/VERSION:=${VERSION}/g' Makefile > i3lock-${VERSION}/Makefile
|
||
8 years ago
|
tar cfj i3lock-${VERSION}.tar.bz2 i3lock-${VERSION}
|
||
|
rm -rf i3lock-${VERSION}
|
||
8 years ago
|
+++ i3lock.1
|
||
8 years ago
|
@@ -43,8 +43,6 @@
|
||
8 years ago
|
You can specify either a background color or a PNG image which will be displayed while your screen is locked.
|
||
|
.IP \[bu]
|
||
|
You can specify whether i3lock should bell upon a wrong password.
|
||
|
-.IP \[bu]
|
||
|
-i3lock uses PAM and therefore is compatible with LDAP, etc.
|
||
|
|
||
|
|
||
|
.SH OPTIONS
|
||
8 years ago
|
@@ -66,8 +64,7 @@
|
||
8 years ago
|
.B \-u, \-\-no-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
|
||
|
-show you the current PAM state (whether your password is currently being
|
||
8 years ago
|
-verified or whether it is wrong).
|
||
|
+show you whether your password is currently being verified or whether it is wrong.
|
||
8 years ago
|
|
||
|
.TP
|
||
8 years ago
|
.BI \-i\ path \fR,\ \fB\-\-image= path
|
||
|
@@ -95,7 +92,7 @@
|
||
8 years ago
|
.TP
|
||
|
.B \-e, \-\-ignore-empty-password
|
||
|
When an empty password is provided by the user, do not validate
|
||
|
-it. Without this option, the empty password will be provided to PAM
|
||
8 years ago
|
+it. Without this option, the empty password will be validated
|
||
8 years ago
|
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
|
||
|
put a laptop to sleep and bounce on resume or if you happen to wake up
|
||
|
+++ i3lock.c
|
||
8 years ago
|
@@ -21,7 +21,9 @@
|
||
|
#ifdef __OpenBSD__
|
||
|
#include <bsd_auth.h>
|
||
|
#else
|
||
8 years ago
|
-#include <security/pam_appl.h>
|
||
8 years ago
|
+#include <shadow.h>
|
||
|
+#include <grp.h>
|
||
|
+#include <errno.h>
|
||
|
#endif
|
||
8 years ago
|
#include <getopt.h>
|
||
|
#include <string.h>
|
||
7 years ago
|
@@ -59,7 +61,7 @@
|
||
8 years ago
|
xcb_window_t win;
|
||
|
static xcb_cursor_t cursor;
|
||
8 years ago
|
#ifndef __OpenBSD__
|
||
8 years ago
|
-static pam_handle_t *pam_handle;
|
||
8 years ago
|
+const char *hash = NULL;
|
||
|
#endif
|
||
8 years ago
|
int input_position = 0;
|
||
|
/* Holds the password you enter (in UTF-8). */
|
||
7 years ago
|
@@ -93,6 +95,37 @@
|
||
8 years ago
|
bool ignore_empty_password = false;
|
||
|
bool skip_repeated_empty_password = false;
|
||
|
|
||
|
+/*
|
||
|
+ * Shamelessly stolen from slock. See LICENSE-slock.
|
||
|
+ * This adjusts the process' out of memory score,
|
||
|
+ * so it isn't killed by the kernel under any circumstances.
|
||
|
+ */
|
||
|
+#ifdef __linux__
|
||
|
+#include <fcntl.h>
|
||
|
+#include <linux/oom.h>
|
||
|
+
|
||
|
+static void
|
||
|
+dontkillme(void)
|
||
|
+{
|
||
7 years ago
|
+ FILE *f;
|
||
|
+ const char oomfile[] = "/proc/self/oom_score_adj";
|
||
8 years ago
|
+
|
||
7 years ago
|
+ if (!(f = fopen(oomfile, "w"))) {
|
||
|
+ if (errno == ENOENT)
|
||
|
+ return;
|
||
|
+ errx(EXIT_FAILURE, "fopen %s: %s", oomfile, strerror(errno));
|
||
|
+ }
|
||
|
+ fprintf(f, "%d", OOM_SCORE_ADJ_MIN);
|
||
|
+ if (fclose(f)) {
|
||
|
+ if (errno == EACCES)
|
||
|
+ errx(EXIT_FAILURE, "unable to disable OOM killer. "
|
||
|
+ "Make sure to suid or sgid i3lock.");
|
||
|
+ else
|
||
|
+ errx(EXIT_FAILURE, "fclose %s: %s", oomfile, strerror(errno));
|
||
|
+ }
|
||
8 years ago
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
/* isutf, u8_dec © 2005 Jeff Bezanson, public domain */
|
||
|
#define isutf(c) (((c)&0xC0) != 0x80)
|
||
|
|
||
7 years ago
|
@@ -285,16 +318,16 @@
|
||
|
return;
|
||
8 years ago
|
}
|
||
|
#else
|
||
8 years ago
|
- if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) {
|
||
8 years ago
|
- DEBUG("successfully authenticated\n");
|
||
|
- clear_password_memory();
|
||
|
+ /*
|
||
|
+ * Shamelessly stolen from slock. See LICENSE-slock.
|
||
|
+ */
|
||
|
+ char *inputhash;
|
||
8 years ago
|
|
||
|
- /* 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
|
||
|
- * credentials like kerberos /tmp/krb5cc_pam_* files which may of been left behind if the
|
||
|
- * refresh of the credentials failed. */
|
||
|
- pam_setcred(pam_handle, PAM_REFRESH_CRED);
|
||
|
- pam_end(pam_handle, PAM_SUCCESS);
|
||
8 years ago
|
+ if (!(inputhash = crypt(password, hash)))
|
||
7 years ago
|
+ fprintf(stderr, "crypt: %s", strerror(errno));
|
||
8 years ago
|
+ else if (!strcmp(inputhash, hash)) {
|
||
|
+ DEBUG("successfully authenticated");
|
||
|
+ clear_password_memory();
|
||
|
|
||
7 years ago
|
ev_break(EV_DEFAULT, EVBREAK_ALL);
|
||
|
return;
|
||
8 years ago
|
@@ -626,39 +659,6 @@
|
||
|
redraw_screen();
|
||
8 years ago
|
}
|
||
|
|
||
8 years ago
|
-#ifndef __OpenBSD__
|
||
|
-/*
|
||
8 years ago
|
- * Callback function for PAM. We only react on password request callbacks.
|
||
|
- *
|
||
|
- */
|
||
|
-static int conv_callback(int num_msg, const struct pam_message **msg,
|
||
|
- struct pam_response **resp, void *appdata_ptr) {
|
||
|
- if (num_msg == 0)
|
||
|
- return 1;
|
||
|
-
|
||
|
- /* PAM expects an array of responses, one for each message */
|
||
|
- if ((*resp = calloc(num_msg, sizeof(struct pam_response))) == NULL) {
|
||
|
- perror("calloc");
|
||
|
- return 1;
|
||
|
- }
|
||
|
-
|
||
|
- for (int c = 0; c < num_msg; c++) {
|
||
|
- if (msg[c]->msg_style != PAM_PROMPT_ECHO_OFF &&
|
||
|
- msg[c]->msg_style != PAM_PROMPT_ECHO_ON)
|
||
|
- continue;
|
||
|
-
|
||
|
- /* return code is currently not used but should be set to zero */
|
||
|
- resp[c]->resp_retcode = 0;
|
||
|
- if ((resp[c]->resp = strdup(password)) == NULL) {
|
||
|
- perror("strdup");
|
||
|
- return 1;
|
||
|
- }
|
||
|
- }
|
||
|
-
|
||
|
- return 0;
|
||
|
-}
|
||
8 years ago
|
-#endif
|
||
8 years ago
|
-
|
||
8 years ago
|
/*
|
||
8 years ago
|
* 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
|
||
7 years ago
|
@@ -766,13 +766,15 @@
|
||
|
*
|
||
|
*/
|
||
|
static void raise_loop(xcb_window_t window) {
|
||
|
- xcb_connection_t *conn;
|
||
|
xcb_generic_event_t *event;
|
||
|
- int screens;
|
||
|
|
||
|
- if ((conn = xcb_connect(NULL, &screens)) == NULL ||
|
||
|
+#ifdef __OpenBSD__
|
||
|
+ xcb_connection_t *conn;
|
||
|
+
|
||
|
+ if ((conn = xcb_connect(NULL, NULL)) == NULL ||
|
||
|
xcb_connection_has_error(conn))
|
||
|
errx(EXIT_FAILURE, "Cannot open display\n");
|
||
|
+#endif
|
||
|
|
||
|
/* We need to know about the window being obscured or getting destroyed. */
|
||
|
xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK,
|
||
|
@@ -820,8 +822,11 @@
|
||
8 years ago
|
char *username;
|
||
|
char *image_path = NULL;
|
||
7 years ago
|
#ifndef __OpenBSD__
|
||
8 years ago
|
- int ret;
|
||
|
- struct pam_conv conv = {conv_callback, NULL};
|
||
7 years ago
|
+ struct passwd *pwd;
|
||
|
+ struct group *grp;
|
||
|
+ uid_t duid;
|
||
|
+ gid_t dgid;
|
||
|
+ xcb_connection_t *raise_conn;
|
||
|
#endif
|
||
8 years ago
|
int curs_choice = CURS_NONE;
|
||
|
int o;
|
||
7 years ago
|
@@ -848,6 +853,65 @@
|
||
8 years ago
|
if ((username = pw->pw_name) == NULL)
|
||
|
errx(EXIT_FAILURE, "pw->pw_name is NULL.\n");
|
||
|
|
||
8 years ago
|
+#ifndef __OpenBSD__
|
||
8 years ago
|
+ /*
|
||
8 years ago
|
+ * Shamelessly stolen from 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.
|
||
7 years ago
|
+ * It causes problems with the xcb_connect in raise_loop, and the main
|
||
|
+ * xcb_connect, however.
|
||
|
+ * Because of that, both xcb_connect are ran as root, before dropping the
|
||
|
+ * privileges to the user, much like is being done with XOpenDisplay
|
||
|
+ * in slock.
|
||
|
+ * I'm unsure of any security implications that may have, as it seems to
|
||
|
+ * run fine, otherwise.
|
||
|
+ * Please contact me if it's something I _really_ shouldn't do.
|
||
8 years ago
|
+ */
|
||
8 years ago
|
+
|
||
7 years ago
|
+ /* If the nobody:nogroup don't exist, just use the password's user */
|
||
|
+ duid = pw->pw_uid;
|
||
|
+ if ((pwd = getpwnam("nobody")))
|
||
|
+ duid = pwd->pw_uid;
|
||
|
+ dgid = pw->pw_gid;
|
||
|
+ if ((grp = getgrnam("nogroup")))
|
||
|
+ dgid = grp->gr_gid;
|
||
|
+
|
||
8 years ago
|
+#ifdef __linux__
|
||
|
+ dontkillme();
|
||
|
+#endif
|
||
|
+
|
||
8 years ago
|
+ hash = pw->pw_passwd;
|
||
8 years ago
|
+
|
||
8 years ago
|
+ if (!strcmp(hash, "x")) {
|
||
8 years ago
|
+ struct spwd *sp;
|
||
8 years ago
|
+ if (!(sp = getspnam(pw->pw_name)))
|
||
7 years ago
|
+ errx(EXIT_FAILURE, "getspnam: cannot retrieve shadow entry. "
|
||
8 years ago
|
+ "Make sure to suid or sgid i3lock.");
|
||
|
+ hash = sp->sp_pwdp;
|
||
8 years ago
|
+ }
|
||
|
+
|
||
8 years ago
|
+ errno = 0;
|
||
|
+ if (!crypt("", hash))
|
||
7 years ago
|
+ errx(EXIT_FAILURE, "crypt: %s", strerror(errno));
|
||
8 years ago
|
+
|
||
7 years ago
|
+ /* Create the necessary connections before dropping privileges */
|
||
|
+ if ((conn = xcb_connect(NULL, NULL)) == NULL ||
|
||
|
+ xcb_connection_has_error(conn))
|
||
|
+ errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?");
|
||
|
+ if ((raise_conn = xcb_connect(NULL, NULL)) == NULL ||
|
||
|
+ xcb_connection_has_error(raise_conn))
|
||
|
+ errx(EXIT_FAILURE, "Cannot open display\n");
|
||
|
+
|
||
8 years ago
|
+ /* drop privileges */
|
||
|
+ if (setgroups(0, NULL) < 0)
|
||
7 years ago
|
+ errx(EXIT_FAILURE, "setgroups: %s", strerror(errno));
|
||
7 years ago
|
+ if (setgid(dgid) < 0)
|
||
7 years ago
|
+ errx(EXIT_FAILURE, "setgid: %s", strerror(errno));
|
||
7 years ago
|
+ if (setuid(duid) < 0)
|
||
7 years ago
|
+ errx(EXIT_FAILURE, "setuid: %s", strerror(errno));
|
||
8 years ago
|
+#endif
|
||
8 years ago
|
+
|
||
|
char *optstring = "hvnbdc:p:ui:teI:f";
|
||
7 years ago
|
while ((o = getopt_long(argc, argv, optstring, longopts, &longoptind)) != -1) {
|
||
8 years ago
|
switch (o) {
|
||
7 years ago
|
@@ -916,15 +980,6 @@
|
||
8 years ago
|
* the unlock indicator upon keypresses. */
|
||
|
srand(time(NULL));
|
||
|
|
||
8 years ago
|
-#ifndef __OpenBSD__
|
||
8 years ago
|
- /* Initialize PAM */
|
||
|
- if ((ret = pam_start("i3lock", username, &conv, &pam_handle)) != PAM_SUCCESS)
|
||
|
- errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
|
||
|
-
|
||
|
- if ((ret = pam_set_item(pam_handle, PAM_TTY, getenv("DISPLAY"))) != PAM_SUCCESS)
|
||
|
- errx(EXIT_FAILURE, "PAM: %s", pam_strerror(pam_handle, ret));
|
||
8 years ago
|
-#endif
|
||
8 years ago
|
-
|
||
8 years ago
|
/* 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).
|
||
7 years ago
|
@@ -938,11 +993,12 @@
|
||
|
err(EXIT_FAILURE, "Could not lock page in memory, check RLIMIT_MEMLOCK");
|
||
|
#endif
|
||
|
|
||
|
+#ifdef __OpenBSD__
|
||
|
/* Double checking that connection is good and operatable with xcb */
|
||
|
- int screennr;
|
||
|
- if ((conn = xcb_connect(NULL, &screennr)) == NULL ||
|
||
|
+ if ((conn = xcb_connect(NULL, NULL)) == NULL ||
|
||
|
xcb_connection_has_error(conn))
|
||
|
errx(EXIT_FAILURE, "Could not connect to X11, maybe you need to set DISPLAY?");
|
||
|
+#endif
|
||
|
|
||
|
if (xkb_x11_setup_xkb_extension(conn,
|
||
|
XKB_X11_MIN_MAJOR_XKB_VERSION,
|
||
|
@@ -1056,10 +1112,16 @@
|
||
|
if (pid == 0) {
|
||
|
/* Child */
|
||
|
close(xcb_get_file_descriptor(conn));
|
||
|
+#ifndef __OpenBSD__
|
||
|
+ conn = raise_conn;
|
||
|
+#endif
|
||
|
maybe_close_sleep_lock_fd();
|
||
|
raise_loop(win);
|
||
|
exit(EXIT_SUCCESS);
|
||
|
}
|
||
|
+#ifndef __OpenBSD__
|
||
|
+ close(xcb_get_file_descriptor(raise_conn));
|
||
|
+#endif
|
||
|
|
||
|
/* Load the keymap again to sync the current modifier state. Since we first
|
||
|
* loaded the keymap, there might have been changes, but starting from now,
|
||
8 years ago
|
+++ i3lock.pam
|
||
|
@@ -1,6 +0,0 @@
|
||
|
-#
|
||
|
-# PAM configuration file for the i3lock screen locker. By default, it includes
|
||
|
-# the 'login' configuration file (see /etc/pam.d/login)
|
||
|
-#
|
||
|
-
|
||
|
-auth include login
|