💾 Archived View for gemini.rmf-dev.com › repo › Vaati › dkee › files › 63073a2ba1a9e84913402a95d3291… captured on 2023-07-22 at 16:56:32. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
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 #define MENU "dmenu -i"
23
24 #ifdef __linux__
25 size_t strlcpy(char*, const char*, size_t);
26 #endif
27 int text_box(char*, size_t);
28
29 int popen2(const char *cmd, int *to, int *from, pid_t* pid) {
30 pid_t id;
31 int in[2], out[2];
32
33 if(pipe(in)) return -1;
34 if(pipe(out)) return -1;
35
36 id = fork();
37 if(id < 0) return -1;
38 if(id == 0) {
39 close(in[1]);
40 dup2(in[0], 0);
41 close(out[0]);
42 dup2(out[1], 1);
43 execl("/bin/sh", "sh", "-c", cmd, NULL);
44 exit(-1);
45 }
46 *to = in[1];
47 *from = out[0];
48 close(in[0]);
49 close(out[1]);
50 if (pid) *pid = id;
51 return 0;
52 }
53
54 int start(const char* safe, const char* password, pid_t* pid) {
55 char* data = NULL;
56 char cmd[4096], path[4096], tmp[4096], *ptr;
57 int length = 0, i = 0, j = 0, path_len = 0;
58 int to, from;
59
60 /* read output from keepassxc */
61 snprintf(cmd, sizeof(cmd), "keepassxc-cli ls -R %s", safe);
62
63 if (popen2(cmd, &to, &from, NULL)) return -1;
64 write(to, password, strlen(password));
65 close(to);
66
67 while (1) {
68 int ret;
69 char buf[1024];
70 ret = read(from, buf, sizeof(buf));
71 if (ret < 1) break;
72 data = realloc(data, length + ret);
73 if (!data) return -1;
74 memcpy(&data[length], buf, ret);
75 length += ret;
76 }
77 close(from);
78 if (length <= 0) return -1;
79
80 /* start dmenu and send it formatted password lists */
81 popen2(MENU, &to, &from, NULL);
82
83 /* format keypassxc output */
84 path[0] = '\0';
85 while (i < length) {
86 tmp[j] = data[i];
87 if (!j || tmp[j] != '\n') goto increment;
88 if (tmp[j - 1] == '/') {
89 int depth, pos, slash;
90 tmp[j] = '\0';
91 j = -1;
92 ptr = tmp;
93 while (*ptr == ' ') ptr++;
94 depth = (ptr - tmp)/2;
95
96 pos = 0;
97 slash = 0;
98 if (!depth)
99 path_len = 0;
100 while (depth && pos < path_len) {
101 if (path[pos] == '/') slash++;
102 if (slash == depth) {
103 /* format string... */
104 path_len = pos + 1;
105 break;
106 }
107 pos++;
108 }
109
110 path_len += strlcpy(&path[path_len], ptr,
111 sizeof(path) - path_len);
112 goto increment;
113 }
114 tmp[j + 1] = '\0';
115 ptr = tmp;
116 while (*ptr == ' ') ptr++;
117 write(to, path, path_len);
118 write(to, ptr, j + 1 - (ptr - tmp));
119 j = -1;
120 increment:
121 j++;
122 i++;
123 }
124 close(to);
125
126 /* read dmenu output from dmenu */
127 length = read(from, path, sizeof(path));
128 if (length < 1) return -1;
129 close(from);
130 path[length - 1] = 0;
131
132 /* send dmenu output keypassxc */
133 snprintf(cmd, sizeof(cmd),
134 "keepassxc-cli clip \"%s\" \"%s\"",
135 safe, path);
136 if (popen2(cmd, &to, &from, pid)) return -1;
137 write(to, password, strlen(password));
138 close(to);
139 close(from);
140
141 return 0;
142 }
143
144 int passwd(char* buf, int max) {
145 struct termios term;
146 int c, pos = 0;
147
148 tcgetattr(1, &term);
149 term.c_lflag &= ~ECHO;
150 tcsetattr(1, TCSANOW, &term);
151
152 buf[0] = '\0';
153 while ((c = fgetc(stdin)) != '\n') {
154 buf[pos++] = (char)c;
155 if (pos + 1 >= max)
156 break;
157 }
158 buf[pos] = '\0';
159
160 term.c_lflag |= ECHO;
161 tcsetattr(1, TCSANOW, &term);
162 return pos;
163 }
164
165 int main(int argc, char* argv[]) {
166
167 char password[64];
168 char pid_path[1024];
169 const char* safe = argv[1];
170 sigset_t set;
171 int sig;
172 FILE *f;
173 pid_t pid = -1;
174 int x11 = 1;
175
176 if (argc < 2) {
177 wrong_args:
178 printf("%s [-t] <safe>\n", argv[0]);
179 return -1;
180 }
181 if (argc > 2) {
182 if (strcmp("-t", argv[1])) goto wrong_args;
183 x11 = 0;
184 safe = argv[2];
185 }
186
187 if (x11) {
188 /* X11 */
189 if (text_box(password, sizeof(password))) return -1;
190 } else {
191 /* terminal */
192 printf("Password : ");
193 fflush(stdout);
194 passwd(password, sizeof(password));
195 printf("\n");
196 }
197
198 /* prevent zombie processes */
199 signal(SIGCHLD, SIG_IGN);
200
201 /* exit if invalid password */
202 if (start(safe, password, NULL)) {
203 return -1;
204 }
205
206 /* write pid to file */
207 snprintf(pid_path, sizeof(pid_path),
208 "%s/.cache/.dkee.pid", getenv("HOME"));
209 f = fopen(pid_path, "wb");
210 if (!f) {
211 printf("unable to write pid to : %s\n", pid_path);
212 return -1;
213 }
214
215 daemon(1, 1);
216 fprintf(f, "%d", getpid());
217 fclose(f);
218
219 sigemptyset(&set);
220 sigaddset(&set, SIGUSR1);
221 sigprocmask(SIG_BLOCK, &set, NULL);
222 while (1) {
223 sigwait(&set, &sig);
224 if (pid > 0)
225 kill(pid, SIGKILL);
226 if (sig != SIGUSR1) break;
227 start(safe, password, &pid);
228 }
229
230 remove(pid_path);
231 return 0;
232 }
233