added --verification-script option
Patch status: rejected
Patch by Michael Ensslin
Long description:
This option lets you specify a script that is run whenever a password has been accepted by PAM. The entered password is given to the script's standard input. If the script's exit code is zero, the password is accepted. otherwise, it is rejected as if PAM would have failed. If the can not be executed, the password is accepted as if no script was specified. I'm using this with a script that calls `cryptsetup luksResume` on my home partition, which is encrypted with my login password.
To apply this patch, use:
curl http://cr.i3wm.org/patch/665/raw.patch | git am
b/i3lock.c
25 |
@@ -22,6 +22,7 @@ |
26 |
#include <string.h> |
27 |
#include <ev.h> |
28 |
#include <sys/mman.h> |
29 |
+#include <sys/wait.h> |
30 |
#include <xkbcommon/xkbcommon.h> |
31 |
#include <xkbcommon/xkbcommon-x11.h> |
32 |
#include <cairo.h> |
33 |
@@ -66,6 +67,7 @@ extern unlock_state_t unlock_state; |
34 |
extern pam_state_t pam_state; |
35 |
int failed_attempts = 0; |
36 |
bool show_failed_attempts = false; |
37 |
+char *verification_script = NULL; |
38 |
|
39 |
static struct xkb_state *xkb_state; |
40 |
static struct xkb_context *xkb_context; |
41 |
@@ -223,13 +225,73 @@ static void discard_passwd_cb(EV_P_ ev_timer *w, int revents) { |
42 |
STOP_TIMER(discard_passwd_timeout); |
43 |
} |
44 |
|
45 |
+static bool run_verification_script(void) { |
46 |
+ if (verification_script == NULL) { |
47 |
+ return true; |
48 |
+ } |
49 |
+ |
50 |
+ DEBUG("running verification script\n"); |
51 |
+ |
52 |
+ int pipefd[2]; |
53 |
+ if (pipe(pipefd) == -1) { |
54 |
+ DEBUG("couldn't create pipe. skipping verification script\n"); |
55 |
+ return true; |
56 |
+ } |
57 |
+ |
58 |
+ pid_t pid = fork(); |
59 |
+ switch(pid) { |
60 |
+ case -1: |
61 |
+ DEBUG("couldn't fork. skipping verification script\n"); |
62 |
+ return true; |
63 |
+ break; |
64 |
+ case 0: |
65 |
+ /* we're the child */ |
66 |
+ close(pipefd[1]); |
67 |
+ dup2(pipefd[0], 0); |
68 |
+ execl(verification_script, verification_script, NULL); |
69 |
+ DEBUG("couldn't execute verification script\n"); |
70 |
+ exit(0); |
71 |
+ break; |
72 |
+ default: |
73 |
+ /* we're the parent */ |
74 |
+ close(pipefd[0]); |
75 |
+ size_t pos = 0; |
76 |
+ while (pos < input_position) { |
77 |
+ ssize_t written = write(pipefd[1], &password[pos], input_position - pos); |
78 |
+ if (written <= 0) { |
79 |
+ DEBUG("couldn't write password to verification script\n"); |
80 |
+ return true; |
81 |
+ } |
82 |
+ pos += written; |
83 |
+ } |
84 |
+ /* send EOF to child */ |
85 |
+ close(pipefd[1]); |
86 |
+ int status; |
87 |
+ if (waitpid(pid, &status, 0) == -1) { |
88 |
+ DEBUG("couldn't wait for verification script. assuming success\n"); |
89 |
+ return true; |
90 |
+ } |
91 |
+ |
92 |
+ if (WEXITSTATUS(status) == 0) { |
93 |
+ DEBUG("password accepted by verification script\n"); |
94 |
+ return true; |
95 |
+ } else { |
96 |
+ DEBUG("password rejected by verification script\n"); |
97 |
+ return false; |
98 |
+ } |
99 |
+ } |
100 |
+} |
101 |
+ |
102 |
static void input_done(void) { |
103 |
STOP_TIMER(clear_pam_wrong_timeout); |
104 |
pam_state = STATE_PAM_VERIFY; |
105 |
redraw_screen(); |
106 |
|
107 |
- if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS) { |
108 |
+ if (pam_authenticate(pam_handle, 0) == PAM_SUCCESS && |
109 |
+ run_verification_script()) { |
110 |
+ |
111 |
DEBUG("successfully authenticated\n"); |
112 |
+ |
113 |
clear_password_memory(); |
114 |
/* Turn the screen on, as it may have been turned off |
115 |
* on release of the 'enter' key. */ |
116 |
@@ -681,6 +743,7 @@ int main(int argc, char *argv[]) { |
117 |
{"ignore-empty-password", no_argument, NULL, 'e'}, |
118 |
{"inactivity-timeout", required_argument, NULL, 'I'}, |
119 |
{"show-failed-attempts", no_argument, NULL, 'f'}, |
120 |
+ {"verification-script", required_argument, NULL, 'V'}, |
121 |
{NULL, no_argument, NULL, 0} |
122 |
}; |
123 |
|
124 |
@@ -708,6 +771,14 @@ int main(int argc, char *argv[]) { |
125 |
inactivity_timeout = time; |
126 |
break; |
127 |
} |
128 |
+ case 'V': { |
129 |
+ verification_script = optarg; |
130 |
+ /* sanity check: is verification_script executable? */ |
131 |
+ if(access(verification_script, F_OK | X_OK) != 0) { |
132 |
+ errx(EXIT_FAILURE, "verification script is not executable\n"); |
133 |
+ } |
134 |
+ break; |
135 |
+ } |
136 |
case 'c': { |
137 |
char *arg = optarg; |
138 |
|
139 |
@@ -750,7 +821,7 @@ int main(int argc, char *argv[]) { |
140 |
break; |
141 |
default: |
142 |
errx(EXIT_FAILURE, "Syntax: i3lock [-v] [-n] [-b] [-d] [-c color] [-u] [-p win|default]" |
143 |
- " [-i image.png] [-t] [-e] [-I] [-f]" |
144 |
+ " [-i image.png] [-t] [-e] [-I] [-f] [--verification-script /bin/foo]" |
145 |
); |
146 |
} |
147 |
} |