util  Diff

Differences From Artifact [6369b6f0d6]:

To Artifact [48a3d17a7c]:

  • 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