💾 Archived View for gemini.rmf-dev.com › repo › Vaati › dkee › files › a86297d9f7d117c0e6a9712570698… captured on 2023-04-26 at 13:15:13. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-03-20)
-=-=-=-=-=-=-
0 /*
1 * Copyright (c) 2022 RMF <rawmonk@firemail.cc>
2 *
3 * Permission to use, copy, modify, and distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15 #include <unistd.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <termios.h>
20 #include <signal.h>
21
22 #ifdef __linux__
23 size_t strlcpy(char*, const char*, size_t);
24 #endif
25 int text_box(char*, size_t);
26
27 int popen2(const char *cmd, int *to, int *from, pid_t* pid) {
28 pid_t id;
29 int in[2], out[2];
30
31 if(pipe(in)) return -1;
32 if(pipe(out)) return -1;
33
34 id = fork();
35 if(id < 0) return -1;
36 if(id == 0) {
37 close(in[1]);
38 dup2(in[0], 0);
39 close(out[0]);
40 dup2(out[1], 1);
41 execl("/bin/sh", "sh", "-c", cmd, NULL);
42 exit(-1);
43 }
44 *to = in[1];
45 *from = out[0];
46 close(in[0]);
47 close(out[1]);
48 if (pid) *pid = id;
49 return 0;
50 }
51
52 int start(const char* safe, const char* password, pid_t* pid) {
53 char* data = NULL;
54 char cmd[4096], path[4096], tmp[4096], *ptr;
55 int length = 0, i = 0, j = 0, path_len = 0;
56 int to, from;
57
58 /* read output from keepassxc */
59 snprintf(cmd, sizeof(cmd), "keepassxc-cli ls -R %s", safe);
60
61 if (popen2(cmd, &to, &from, NULL)) return -1;
62 write(to, password, strlen(password));
63 close(to);
64
65 while (1) {
66 int ret;
67 char buf[1024];
68 ret = read(from, buf, sizeof(buf));
69 if (ret < 1) break;
70 data = realloc(data, length + ret);
71 if (!data) return -1;
72 memcpy(&data[length], buf, ret);
73 length += ret;
74 }
75 close(from);
76 if (length <= 0) return -1;
77
78 /* start dmenu and send it formatted password lists */
79 popen2("dmenu -i", &to, &from, NULL);
80
81 /* format keypassxc output */
82 path[0] = '\0';
83 while (i < length) {
84 tmp[j] = data[i];
85 if (!j || tmp[j] != '\n') goto increment;
86 if (tmp[j - 1] == '/') {
87 int depth, pos, slash;
88 tmp[j] = '\0';
89 j = -1;
90 ptr = tmp;
91 while (*ptr == ' ') ptr++;
92 depth = (ptr - tmp)/2;
93
94 pos = 0;
95 slash = 0;
96 if (!depth)
97 path_len = 0;
98 while (depth && pos < path_len) {
99 if (path[pos] == '/') slash++;
100 if (slash == depth) {
101 /* format string... */
102 path_len = pos + 1;
103 break;
104 }
105 pos++;
106 }
107
108 path_len += strlcpy(&path[path_len], ptr,
109 sizeof(path) - path_len);
110 goto increment;
111 }
112 tmp[j + 1] = '\0';
113 ptr = tmp;
114 while (*ptr == ' ') ptr++;
115 write(to, path, path_len);
116 write(to, ptr, j + 1 - (ptr - tmp));
117 j = -1;
118 increment:
119 j++;
120 i++;
121 }
122 close(to);
123
124 /* read dmenu output from dmenu */
125 length = read(from, path, sizeof(path));
126 if (length < 1) return -1;
127 close(from);
128 path[length - 1] = 0;
129
130 /* send dmenu output keypassxc */
131 snprintf(cmd, sizeof(cmd),
132 "keepassxc-cli clip \"%s\" \"%s\"",
133 safe, path);
134 if (popen2(cmd, &to, &from, pid)) return -1;
135 write(to, password, strlen(password));
136 close(to);
137 close(from);
138
139 return 0;
140 }
141
142 int passwd(char* buf, int max) {
143 struct termios term;
144 int c, pos = 0;
145
146 tcgetattr(1, &term);
147 term.c_lflag &= ~ECHO;
148 tcsetattr(1, TCSANOW, &term);
149
150 buf[0] = '\0';
151 while ((c = fgetc(stdin)) != '\n') {
152 buf[pos++] = (char)c;
153 if (pos + 1 >= max)
154 break;
155 }
156 buf[pos] = '\0';
157
158 term.c_lflag |= ECHO;
159 tcsetattr(1, TCSANOW, &term);
160 return pos;
161 }
162
163 int main(int argc, char* argv[]) {
164
165 char password[64];
166 char pid_path[1024];
167 const char* safe = argv[1];
168 sigset_t set;
169 int sig;
170 FILE *f;
171 pid_t pid = -1;
172 int x11 = 1;
173
174 if (argc < 2) {
175 wrong_args:
176 printf("%s [-t] <safe>\n", argv[0]);
177 return -1;
178 }
179 if (argc > 2) {
180 if (strcmp("-t", argv[1])) goto wrong_args;
181 x11 = 0;
182 safe = argv[2];
183 }
184
185 if (x11) {
186 /* X11 */
187 if (text_box(password, sizeof(password))) return -1;
188 } else {
189 /* terminal */
190 printf("Password : ");
191 fflush(stdout);
192 passwd(password, sizeof(password));
193 printf("\n");
194 }
195
196 /* prevent zombie processes */
197 signal(SIGCHLD, SIG_IGN);
198
199 /* exit if invalid password */
200 if (start(safe, password, NULL)) {
201 return -1;
202 }
203
204 /* write pid to file */
205 snprintf(pid_path, sizeof(pid_path),
206 "%s/.cache/.dkee.pid", getenv("HOME"));
207 f = fopen(pid_path, "wb");
208 if (!f) {
209 printf("unable to write pid to : %s\n", pid_path);
210 return -1;
211 }
212
213 daemon(1, 1);
214 fprintf(f, "%d", getpid());
215 fclose(f);
216
217 sigemptyset(&set);
218 sigaddset(&set, SIGUSR1);
219 sigprocmask(SIG_BLOCK, &set, NULL);
220 while (1) {
221 sigwait(&set, &sig);
222 if (pid > 0)
223 kill(pid, SIGKILL);
224 if (sig != SIGUSR1) break;
225 start(safe, password, &pid);
226 }
227
228 remove(pid_path);
229 return 0;
230 }
231