diff options
author | emersion <contact@emersion.fr> | 2018-04-04 20:16:35 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-04 20:16:35 -0400 |
commit | f2153f3f28c8aa2e6738610abf09b2e2396d891a (patch) | |
tree | 4702abb406a59fb8588cbd2019741e99d40bcbfe /swaylock/password.c | |
parent | Merge pull request #1731 from acrisci/ipc-window-events (diff) | |
parent | Address review feedback from @emersion (diff) | |
download | sway-f2153f3f28c8aa2e6738610abf09b2e2396d891a.tar.gz sway-f2153f3f28c8aa2e6738610abf09b2e2396d891a.tar.zst sway-f2153f3f28c8aa2e6738610abf09b2e2396d891a.zip |
Merge pull request #1705 from swaywm/swaylock-layers
Port swaylock to layer shell
Diffstat (limited to 'swaylock/password.c')
-rw-r--r-- | swaylock/password.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/swaylock/password.c b/swaylock/password.c new file mode 100644 index 00000000..1839f991 --- /dev/null +++ b/swaylock/password.c | |||
@@ -0,0 +1,126 @@ | |||
1 | #include <assert.h> | ||
2 | #include <pwd.h> | ||
3 | #include <security/pam_appl.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <unistd.h> | ||
6 | #include <wlr/util/log.h> | ||
7 | #include <xkbcommon/xkbcommon.h> | ||
8 | #include "swaylock/swaylock.h" | ||
9 | #include "swaylock/seat.h" | ||
10 | #include "unicode.h" | ||
11 | |||
12 | static int function_conversation(int num_msg, const struct pam_message **msg, | ||
13 | struct pam_response **resp, void *data) { | ||
14 | struct swaylock_password *pw = data; | ||
15 | /* PAM expects an array of responses, one for each message */ | ||
16 | struct pam_response *pam_reply = calloc( | ||
17 | num_msg, sizeof(struct pam_response)); | ||
18 | *resp = pam_reply; | ||
19 | for (int i = 0; i < num_msg; ++i) { | ||
20 | switch (msg[i]->msg_style) { | ||
21 | case PAM_PROMPT_ECHO_OFF: | ||
22 | case PAM_PROMPT_ECHO_ON: | ||
23 | pam_reply[i].resp = pw->buffer; | ||
24 | break; | ||
25 | case PAM_ERROR_MSG: | ||
26 | case PAM_TEXT_INFO: | ||
27 | break; | ||
28 | } | ||
29 | } | ||
30 | return PAM_SUCCESS; | ||
31 | } | ||
32 | |||
33 | static bool attempt_password(struct swaylock_password *pw) { | ||
34 | struct passwd *passwd = getpwuid(getuid()); | ||
35 | char *username = passwd->pw_name; | ||
36 | const struct pam_conv local_conversation = { | ||
37 | function_conversation, pw | ||
38 | }; | ||
39 | pam_handle_t *local_auth_handle = NULL; | ||
40 | int pam_err; | ||
41 | if ((pam_err = pam_start("swaylock", username, | ||
42 | &local_conversation, &local_auth_handle)) != PAM_SUCCESS) { | ||
43 | wlr_log(L_ERROR, "PAM returned error %d", pam_err); | ||
44 | } | ||
45 | if ((pam_err = pam_authenticate(local_auth_handle, 0)) != PAM_SUCCESS) { | ||
46 | wlr_log(L_ERROR, "pam_authenticate failed"); | ||
47 | goto fail; | ||
48 | } | ||
49 | if ((pam_err = pam_end(local_auth_handle, pam_err)) != PAM_SUCCESS) { | ||
50 | wlr_log(L_ERROR, "pam_end failed"); | ||
51 | goto fail; | ||
52 | } | ||
53 | // PAM frees this | ||
54 | pw->buffer = NULL; | ||
55 | pw->len = pw->size = 0; | ||
56 | return true; | ||
57 | fail: | ||
58 | // PAM frees this | ||
59 | pw->buffer = NULL; | ||
60 | pw->len = pw->size = 0; | ||
61 | return false; | ||
62 | } | ||
63 | |||
64 | static bool backspace(struct swaylock_password *pw) { | ||
65 | if (pw->len != 0) { | ||
66 | pw->buffer[--pw->len] = 0; | ||
67 | return true; | ||
68 | } | ||
69 | return false; | ||
70 | } | ||
71 | |||
72 | static void append_ch(struct swaylock_password *pw, uint32_t codepoint) { | ||
73 | if (!pw->buffer) { | ||
74 | pw->size = 8; | ||
75 | if (!(pw->buffer = malloc(pw->size))) { | ||
76 | // TODO: Display error | ||
77 | return; | ||
78 | } | ||
79 | pw->buffer[0] = 0; | ||
80 | } | ||
81 | size_t utf8_size = utf8_chsize(codepoint); | ||
82 | if (pw->len + utf8_size + 1 >= pw->size) { | ||
83 | size_t size = pw->size * 2; | ||
84 | char *buffer = realloc(pw->buffer, size); | ||
85 | if (!buffer) { | ||
86 | // TODO: Display error | ||
87 | return; | ||
88 | } | ||
89 | pw->size = size; | ||
90 | pw->buffer = buffer; | ||
91 | } | ||
92 | utf8_encode(&pw->buffer[pw->len], codepoint); | ||
93 | pw->buffer[pw->len + utf8_size] = 0; | ||
94 | pw->len += utf8_size; | ||
95 | } | ||
96 | |||
97 | void swaylock_handle_key(struct swaylock_state *state, | ||
98 | xkb_keysym_t keysym, uint32_t codepoint) { | ||
99 | switch (keysym) { | ||
100 | case XKB_KEY_KP_Enter: /* fallthrough */ | ||
101 | case XKB_KEY_Return: | ||
102 | state->auth_state = AUTH_STATE_VALIDATING; | ||
103 | render_frames(state); | ||
104 | wl_display_roundtrip(state->display); | ||
105 | if (attempt_password(&state->password)) { | ||
106 | state->run_display = false; | ||
107 | break; | ||
108 | } | ||
109 | state->auth_state = AUTH_STATE_INVALID; | ||
110 | render_frames(state); | ||
111 | break; | ||
112 | case XKB_KEY_BackSpace: | ||
113 | if (backspace(&state->password)) { | ||
114 | state->auth_state = AUTH_STATE_BACKSPACE; | ||
115 | render_frames(state); | ||
116 | } | ||
117 | break; | ||
118 | default: | ||
119 | if (codepoint) { | ||
120 | append_ch(&state->password, codepoint); | ||
121 | state->auth_state = AUTH_STATE_INPUT; | ||
122 | render_frames(state); | ||
123 | } | ||
124 | break; | ||
125 | } | ||
126 | } | ||