Differences From
Artifact [6369b6f0d6]:
- File
xpriv.c
— part of check-in
[6a14de1811]
at
2019-07-20 23:37:03
on branch trunk
— udpate xpriv to use sysv shmem by default; give iaia an option to generate its own types, and allow selecting between 7-bit and 8-bit encodings for ascii (defaulting to 8-bit); update mkpw to work with new iaia; update ord to add flag controlling byte length (7 or 8) for iaia's ascii mode
(user:
lexi,
size: 13336)
[annotate]
[blame]
[check-ins using]
68 68
69 69 TODO add a randomizer call that works on BSD
70 70
71 71 TODO document flags
72 72
73 73 TODO implement/remove lock flag
74 74
75 - TODO add flag to bring window to current desktop */
75 + TODO add flag to bring window to current desktop
76 +
77 + TODO rewrite using sysv shmem */
76 78
77 79
78 80 #include <pwd.h>
79 81 #include <pty.h>
80 82 #include <fcntl.h>
81 83 #include <unistd.h>
82 84 #include <stdint.h>
................................................................................
83 85 #include <stdlib.h>
84 86 #include <string.h>
85 87 #include <signal.h>
86 88 #include <sys/mman.h>
87 89 #include <sys/stat.h>
88 90 #include <sys/wait.h>
89 91 #include <sys/types.h>
92 +#include <sys/shm.h>
90 93 #include <X11/Xlib.h>
91 94 #include <errno.h>
92 -#include <sys/random.h> //TODO bsd compat
95 +#include <sys/random.h>
93 96
94 -#define shmem_prefix "/k.xpriv:"
97 +#ifdef _RAND_SYSCALL
98 +# include <sys/syscall.h>
99 +# define getrandom(a,b,c) syscall(SYS_getrandom,a,b,c)
100 + /* this is necessary on certain platforms due to
101 + * certainly ungodly libc issues, i think. */
102 +#endif
95 103
96 -typedef enum { false, true } bool;
104 +#ifdef _SHM_LINUX
105 + /* xpriv was originally written with linux shared
106 + * memory in mind, because i'm an idiot. i've since
107 + * redesigned it to use the superior old sysv shm
108 + * api that works on every other unix, not just
109 + * linux, but if for some ungodly reason you want
110 + * to use the linux one, then just pass -D_SHM_LINUX */
111 +# define shmem_prefix "/k.xpriv:"
112 +# define shmlinux(...) __VA_ARGS__
113 +# define shmsysv(...)
114 +#else
115 +# define shmlinux(...)
116 +# define shmsysv(...) __VA_ARGS__
117 +#endif
118 +
119 +enum /* constants */ {
120 + false = 0, true = 1,
121 + shmsysv(shmem_key = 0x53373EC3,) /* ye olde magique numbre */
122 +};
123 +
124 +typedef _Bool bool;
97 125 enum mode { mode_usage, mode_go, mode_register,
98 126 mode_kill, mode_lock };
99 127
100 128 enum res { ok, fail_parse, fail_arg, fail_opt, fail_shm,
101 129 fail_mem, fail_pty, fail_nop, fail_win,
102 130 fail_wid, fail_x11};
103 131 enum res bad(enum res code) {
................................................................................
146 174 void sigusr(int a) { if (global -> op == mode_kill) run = false; }
147 175 void sigterm(int a) { run = false; }
148 176
149 177 void spawn(pid_t ssha, const char* const sockn) {
150 178 if (ssha = fork()) {
151 179 char pid_s_buf[16];
152 180 char* pid_s = itoa(ssha, pid_s_buf, sizeof(pid_s_buf));
153 - while (access(sockn, F_OK));
154 - // avoid nasty race condition
181 + while (access(sockn, F_OK)); // avoid nasty race condition
155 182 setenv("SSH_AGENT_PID", pid_s, true);
156 183 setenv("SSH_AUTH_SOCK", sockn, true);
157 184 global -> agent = ssha;
158 185 } else {
159 186 close(1); close(0);
160 - execlp("ssh-agent","ssh-agent","-D", "-a",sockn,0);
187 + execlp("ssh-agent","ssh-agent","-D","-a",sockn,0);
161 188 }
162 189 }
163 190
164 -enum res register_window(const char* const id, bool weak, const char* const name) {
191 +enum res register_window(shmlinux(const char* const id,) bool weak, const char* name) {
165 192 // the id field denotes the path to the shared memory
166 193 // in use, and allows the user to have multiple
167 194 // contexts by creating aliases to the binary
168 - int fd = shm_open(id, O_CREAT | O_EXCL | O_RDWR, 0600);
169 - ftruncate(fd, sizeof(struct signal));
170 - if (fd == -1) return fail_shm;
171 -
172 - struct signal* s = mmap(0, sizeof(struct signal),
173 - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
174 - if(s == MAP_FAILED) return fail_mem;
175 - else global = s;
195 + struct signal* s;
196 + shmlinux ({
197 + int fd = shm_open(id, O_CREAT | O_EXCL | O_RDWR, 0600);
198 + ftruncate(fd, sizeof(struct signal));
199 + if (fd == -1) return fail_shm;
200 +
201 + s = mmap(0, sizeof(struct signal),
202 + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
203 + if(s == MAP_FAILED) return fail_mem;
204 + else global = s;
205 + }) shmsysv (int shmem;
206 + shmem = shmget(shmem_key, sizeof (struct signal), IPC_CREAT | 0777);
207 + if (shmem == -1) return fail_shm;
208 +
209 + s = shmat(shmem, 0,0);
210 +
211 + if (s == (void*)-1) return fail_mem;
212 + else global = s;
213 + )
176 214
177 215 Display* xdpy = XOpenDisplay(NULL);
178 216 Atom xvital;
179 217
180 218 /* x11 */ {
181 219 if (xdpy == NULL) return fail_win;
182 220 Window win;
................................................................................
206 244 }
207 245
208 246 if(s -> op == mode_kill) {
209 247 kill(s -> pid, SIGTERM);
210 248 }
211 249 kill(s -> agent, SIGTERM);
212 250 sigprocmask(SIG_BLOCK, &mask, NULL);
213 - shm_unlink(id);
251 +
252 + shmlinux(shm_unlink(id));
253 + shmsysv({
254 + struct shmid_ds bleh; /* ?? */
255 + shmctl(shmem, IPC_RMID, &bleh);
256 + })
257 +
214 258 if (!weak) {
215 259 XDeleteProperty(xdpy,s -> wid,xvital);
216 260 XSync(xdpy,false);
217 261 }
218 262 XCloseDisplay(xdpy);
219 263 } else {
220 264 // now we start ssh-agent and set the proper environment
221 265 // variables
222 266 pid_t ssha;
223 267
224 268 if (name == NULL) {
225 269 /* messy part */
226 270 const char* tmp; //tmpdir defined?
227 - if (!(tmp = getenv("TMPDIR"))) tmp = "/tmp";
271 + if (!(tmp = getenv("XDG_RUNTIME_DIR")))
272 + if (!(tmp = getenv("TMPDIR"))) tmp = "/tmp";
273 +
228 274 size_t tmpsz = strlen(tmp);
229 275
230 276 char sockn[tmpsz + 1 + sizeof "ssh."
231 277 + 11];
232 278 strcpy(sockn, tmp);
233 279 sockn[tmpsz] = '/';
234 280 strcpy(sockn+tmpsz+1,"ssh.");
................................................................................
241 287 // assuming asciiā¦
242 288 for(uint8_t*i=rndid;i<rndid+11;++i) {
243 289 *i = '0' + (*i % (25 * 2 + 10));
244 290 if (*i > '9') *i += 7;
245 291 if (*i > 'Z') *i += ('a' - 'Z');
246 292 }
247 293
248 - spawn(ssha, sockn);
249 - } else spawn(ssha, name);
294 + name = sockn;
295 + }
296 + spawn(ssha, name);
250 297
251 298 pid_t sad;
252 299 int p;
253 300 if (sad = fork()) {
254 301 int added;
255 302 waitpid(sad, &added, 0);
256 303 if (added == 0) {
257 304 if (weak == false) {
258 305 XChangeProperty(xdpy,s -> wid,xvital,xvital,8,PropModeReplace,"\01", 1);
259 306 XSync(xdpy,false);
260 307 }
261 308 write(1,"\033c",3);
262 309 execlp("fish","fish",NULL);
263 - } else { return ok; }
310 + }
264 311 } else {
265 312 execlp("ssh-add","ssh-add",NULL);
266 313 }
267 314 }
268 315
269 - return ok; // this is kind of pointless but w/e
316 + return ok;
270 317 }
271 -enum res kill_window(const char* id) {
272 - int fd = shm_open(id, O_RDWR, 0600);
273 - if (fd == -1) return fail_nop;
318 +enum res kill_window(shmlinux(const char* id)) {
319 + struct signal* s;
320 + shmlinux({
321 + int fd = shm_open(id, O_RDWR, 0600);
322 + if (fd == -1) return fail_nop;
274 323
275 - struct signal* s = mmap(0, sizeof(struct signal),
276 - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
277 - if(s == MAP_FAILED) return fail_mem;
324 + s = mmap(0, sizeof(struct signal),
325 + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
326 + if(s == MAP_FAILED) return fail_mem;
327 + }) shmsysv (int shmem; {
328 + shmem = shmget(shmem_key, sizeof(struct signal), 0);
329 + if (shmem == -1) return fail_nop;
330 + s = shmat(shmem,0,0);
331 + if (s == (void*)-1) return fail_mem;
332 + })
333 +
334 + shmsysv({
335 + struct shmid_ds bleh; /* ?? */
336 + shmctl(shmem, IPC_RMID, &bleh);
337 + })
278 338
279 339 s -> op = mode_kill;
280 340 kill(s -> pid, SIGUSR1);
281 341
282 342 return ok;
283 343 }
284 344 enum res activate_window(Window w) {
................................................................................
299 359 if(!XSendEvent(dpy, DefaultRootWindow(dpy), False, mask, &ev)) return fail_x11;
300 360
301 361 XSync(dpy,false);
302 362 return ok;
303 363 }
304 364
305 365 int main(int sz, char** argv) {
366 + char* binname = "xpriv";
367 + if(sz > 0) binname = argv[0];
368 +
306 369 enum mode op = mode_go;
307 370 bool init_weak = false;
308 371 const char* init_named = NULL;
309 372
310 373 for(int i = 1; i<sz; ++i) {
311 374 char* v = argv[i];
312 375 if (*v != '-') return bad(fail_arg);
................................................................................
325 388 seen_string_arg = true;
326 389 ++ i; break;
327 390 default: return bad(fail_opt);
328 391 }
329 392 if(opt[1] != 0) { ++opt; goto read_opt; }
330 393 }
331 394
332 - size_t nsz;
333 - const char* basename = argv[0], *p;
334 - for (p = argv[0]; *p!=0; ++p) {
335 - if(*p == '/') basename = p + 1;
336 - }
337 - nsz = p - basename;
338 - char shid[nsz + sizeof shmem_prefix];
339 - strncpy(shid,shmem_prefix,sizeof shmem_prefix);
340 - strncpy(shid + sizeof shmem_prefix - 1, basename, nsz);
341 - shid[nsz + sizeof shmem_prefix - 1] = 0;
395 + shmlinux(
396 + size_t nsz;
397 + const char* basename = argv[0], *p;
398 + for (p = binname; *p!=0; ++p) {
399 + if(*p == '/') basename = p + 1;
400 + }
401 + nsz = p - basename;
402 + char shid[nsz + sizeof shmem_prefix];
403 + strncpy(shid,shmem_prefix,sizeof shmem_prefix);
404 + strncpy(shid + sizeof shmem_prefix - 1, basename, nsz);
405 + shid[nsz + sizeof shmem_prefix - 1] = 0;
406 + ) shmsysv ({
407 + /* TODO: implement ability to have multiple
408 + * keys based on the name of the binary */
409 + })
342 410
343 - if (op == mode_go) {
344 - int fd;
345 - if ((fd = shm_open(shid, O_RDWR, 0600)) == -1) {
411 + tryagain: if (op == mode_go) {
412 + int shm;
413 + if ((shm = shmlinux(
414 + shm_open(shid, O_RDWR, 0600)
415 + ) shmsysv (
416 + shmget(shmem_key,sizeof (struct signal),0)
417 + )) == -1) {
346 418 const char* args[] = {
347 419 "urxvtc", "-bg", "[90]#4b0024",
348 420 "-e", argv[0],
349 421 (init_weak?"-aw":"-a"), 0, 0, 0};
350 422
351 423 const uint8_t argsz = sizeof args/sizeof(const char*);
352 424 if (init_named != NULL) {
353 425 args[argsz - 3] = "-n"; // im sorry
354 426 args[argsz - 2] = init_named;
355 427 }
356 428
357 429 execvp("urxvtc", (char* const*)args);
358 430 } else {
359 - struct signal*s = mmap(0, sizeof(struct signal),
360 - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
431 + struct signal*s = shmlinux(
432 + mmap(0, sizeof(struct signal), PROT_READ | PROT_WRITE, MAP_SHARED, shm, 0)
433 + ) shmsysv (
434 + shmat(shm, 0, 0)
435 + );
436 +
437 + struct shmid_ds stat;
438 + shmctl(shm, IPC_STAT, &stat);
439 + if (stat.shm_nattch == 0) {
440 + /* if the shm segment is not attached to any
441 + * process, it's a relic that needs to be
442 + * cleaned up before we do anything else. on
443 + * a sane OS, there would be built-in non-
444 + * persistence mechanisms for shared mem, but
445 + * alas, as you already know, POSIX */
446 + shmctl(shm, IPC_RMID, &stat);
447 + goto tryagain;
448 + }
449 +
450 + if (s == shmlinux(MAP_FAILED) shmsysv((void*)-1))
451 + return bad(fail_mem);
361 452 return bad(activate_window(s->wid));
362 453 }
363 454 } else if (op == mode_register)
364 - return bad(register_window(shid,init_weak,init_named));
455 + return bad(register_window(shmlinux(shid,) init_weak,init_named));
365 456 else if (op == mode_kill)
366 - return bad(kill_window(shid));
457 + return bad(kill_window(shmlinux(shid)));
367 458 else if (op == mode_usage) {
368 459 write(1,"\e[1musage:\e[0m ",15);
369 460 write(1, argv[0], strlen(argv[0]));
370 461 write(1, " [-aklw [arg]]\n",16);
371 462 return fail_parse;
372 463 }
373 464 }
374 465