xref: /aosp_15_r20/external/selinux/sandbox/seunshare.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker  * Authors: Dan Walsh <[email protected]>
3*2d543d20SAndroid Build Coastguard Worker  * Authors: Thomas Liu <[email protected]>
4*2d543d20SAndroid Build Coastguard Worker  */
5*2d543d20SAndroid Build Coastguard Worker 
6*2d543d20SAndroid Build Coastguard Worker #define _GNU_SOURCE
7*2d543d20SAndroid Build Coastguard Worker #include <signal.h>
8*2d543d20SAndroid Build Coastguard Worker #include <sys/fsuid.h>
9*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
10*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
11*2d543d20SAndroid Build Coastguard Worker #include <sys/wait.h>
12*2d543d20SAndroid Build Coastguard Worker #include <syslog.h>
13*2d543d20SAndroid Build Coastguard Worker #include <sys/mount.h>
14*2d543d20SAndroid Build Coastguard Worker #include <glob.h>
15*2d543d20SAndroid Build Coastguard Worker #include <pwd.h>
16*2d543d20SAndroid Build Coastguard Worker #include <sched.h>
17*2d543d20SAndroid Build Coastguard Worker #include <string.h>
18*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
19*2d543d20SAndroid Build Coastguard Worker #include <regex.h>
20*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
21*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
22*2d543d20SAndroid Build Coastguard Worker #include <cap-ng.h>
23*2d543d20SAndroid Build Coastguard Worker #include <getopt.h>		/* for getopt_long() form of getopt() */
24*2d543d20SAndroid Build Coastguard Worker #include <limits.h>
25*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
26*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
27*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
28*2d543d20SAndroid Build Coastguard Worker 
29*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
30*2d543d20SAndroid Build Coastguard Worker #include <selinux/context.h>	/* for context-mangling functions */
31*2d543d20SAndroid Build Coastguard Worker #include <dirent.h>
32*2d543d20SAndroid Build Coastguard Worker 
33*2d543d20SAndroid Build Coastguard Worker #ifdef USE_NLS
34*2d543d20SAndroid Build Coastguard Worker #include <locale.h>		/* for setlocale() */
35*2d543d20SAndroid Build Coastguard Worker #include <libintl.h>		/* for gettext() */
36*2d543d20SAndroid Build Coastguard Worker #define _(msgid) gettext (msgid)
37*2d543d20SAndroid Build Coastguard Worker #else
38*2d543d20SAndroid Build Coastguard Worker #define _(msgid) (msgid)
39*2d543d20SAndroid Build Coastguard Worker #endif
40*2d543d20SAndroid Build Coastguard Worker 
41*2d543d20SAndroid Build Coastguard Worker #ifndef MS_REC
42*2d543d20SAndroid Build Coastguard Worker #define MS_REC 1<<14
43*2d543d20SAndroid Build Coastguard Worker #endif
44*2d543d20SAndroid Build Coastguard Worker 
45*2d543d20SAndroid Build Coastguard Worker #ifndef MS_SLAVE
46*2d543d20SAndroid Build Coastguard Worker #define MS_SLAVE 1<<19
47*2d543d20SAndroid Build Coastguard Worker #endif
48*2d543d20SAndroid Build Coastguard Worker 
49*2d543d20SAndroid Build Coastguard Worker #ifndef PACKAGE
50*2d543d20SAndroid Build Coastguard Worker #define PACKAGE "policycoreutils"	/* the name of this package lang translation */
51*2d543d20SAndroid Build Coastguard Worker #endif
52*2d543d20SAndroid Build Coastguard Worker 
53*2d543d20SAndroid Build Coastguard Worker #define BUF_SIZE 1024
54*2d543d20SAndroid Build Coastguard Worker #define DEFAULT_PATH "/usr/bin:/bin"
55*2d543d20SAndroid Build Coastguard Worker #define USAGE_STRING _("USAGE: seunshare [ -v ] [ -C ] [ -k ] [ -t tmpdir ] [ -h homedir ] \
56*2d543d20SAndroid Build Coastguard Worker [ -r runuserdir ] [ -P pipewiresocket ] [ -W waylandsocket ] [ -Z CONTEXT ] -- executable [args] ")
57*2d543d20SAndroid Build Coastguard Worker 
58*2d543d20SAndroid Build Coastguard Worker static int verbose = 0;
59*2d543d20SAndroid Build Coastguard Worker static int child = 0;
60*2d543d20SAndroid Build Coastguard Worker 
61*2d543d20SAndroid Build Coastguard Worker static capng_select_t cap_set = CAPNG_SELECT_CAPS;
62*2d543d20SAndroid Build Coastguard Worker 
63*2d543d20SAndroid Build Coastguard Worker /**
64*2d543d20SAndroid Build Coastguard Worker  * This function will drop all capabilities.
65*2d543d20SAndroid Build Coastguard Worker  */
drop_caps(void)66*2d543d20SAndroid Build Coastguard Worker static int drop_caps(void)
67*2d543d20SAndroid Build Coastguard Worker {
68*2d543d20SAndroid Build Coastguard Worker 	if (capng_have_capabilities(cap_set) == CAPNG_NONE)
69*2d543d20SAndroid Build Coastguard Worker 		return 0;
70*2d543d20SAndroid Build Coastguard Worker 	capng_clear(cap_set);
71*2d543d20SAndroid Build Coastguard Worker 	if (capng_lock() == -1 || capng_apply(cap_set) == -1) {
72*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to drop all capabilities\n"));
73*2d543d20SAndroid Build Coastguard Worker 		return -1;
74*2d543d20SAndroid Build Coastguard Worker 	}
75*2d543d20SAndroid Build Coastguard Worker 	return 0;
76*2d543d20SAndroid Build Coastguard Worker }
77*2d543d20SAndroid Build Coastguard Worker 
78*2d543d20SAndroid Build Coastguard Worker /**
79*2d543d20SAndroid Build Coastguard Worker  * This function will drop all privileges.
80*2d543d20SAndroid Build Coastguard Worker  */
drop_privs(uid_t uid)81*2d543d20SAndroid Build Coastguard Worker static int drop_privs(uid_t uid)
82*2d543d20SAndroid Build Coastguard Worker {
83*2d543d20SAndroid Build Coastguard Worker 	if (drop_caps() == -1 || setresuid(uid, uid, uid) == -1) {
84*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to drop privileges\n"));
85*2d543d20SAndroid Build Coastguard Worker 		return -1;
86*2d543d20SAndroid Build Coastguard Worker 	}
87*2d543d20SAndroid Build Coastguard Worker 	return 0;
88*2d543d20SAndroid Build Coastguard Worker }
89*2d543d20SAndroid Build Coastguard Worker 
90*2d543d20SAndroid Build Coastguard Worker /**
91*2d543d20SAndroid Build Coastguard Worker  * If the user sends a siginto to seunshare, kill the child's session
92*2d543d20SAndroid Build Coastguard Worker  */
handler(int sig)93*2d543d20SAndroid Build Coastguard Worker static void handler(int sig) {
94*2d543d20SAndroid Build Coastguard Worker 	if (child > 0) kill(-child,sig);
95*2d543d20SAndroid Build Coastguard Worker }
96*2d543d20SAndroid Build Coastguard Worker 
97*2d543d20SAndroid Build Coastguard Worker /**
98*2d543d20SAndroid Build Coastguard Worker  * Take care of any signal setup.
99*2d543d20SAndroid Build Coastguard Worker  */
set_signal_handles(void)100*2d543d20SAndroid Build Coastguard Worker static int set_signal_handles(void)
101*2d543d20SAndroid Build Coastguard Worker {
102*2d543d20SAndroid Build Coastguard Worker 	sigset_t empty;
103*2d543d20SAndroid Build Coastguard Worker 
104*2d543d20SAndroid Build Coastguard Worker 	/* Empty the signal mask in case someone is blocking a signal */
105*2d543d20SAndroid Build Coastguard Worker 	if (sigemptyset(&empty)) {
106*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "Unable to obtain empty signal set\n");
107*2d543d20SAndroid Build Coastguard Worker 		return -1;
108*2d543d20SAndroid Build Coastguard Worker 	}
109*2d543d20SAndroid Build Coastguard Worker 
110*2d543d20SAndroid Build Coastguard Worker 	(void)sigprocmask(SIG_SETMASK, &empty, NULL);
111*2d543d20SAndroid Build Coastguard Worker 
112*2d543d20SAndroid Build Coastguard Worker 	/* Terminate on SIGHUP */
113*2d543d20SAndroid Build Coastguard Worker 	if (signal(SIGHUP, SIG_DFL) == SIG_ERR) {
114*2d543d20SAndroid Build Coastguard Worker 		perror("Unable to set SIGHUP handler");
115*2d543d20SAndroid Build Coastguard Worker 		return -1;
116*2d543d20SAndroid Build Coastguard Worker 	}
117*2d543d20SAndroid Build Coastguard Worker 
118*2d543d20SAndroid Build Coastguard Worker 	if (signal(SIGINT, handler) == SIG_ERR) {
119*2d543d20SAndroid Build Coastguard Worker 		perror("Unable to set SIGINT handler");
120*2d543d20SAndroid Build Coastguard Worker 		return -1;
121*2d543d20SAndroid Build Coastguard Worker 	}
122*2d543d20SAndroid Build Coastguard Worker 
123*2d543d20SAndroid Build Coastguard Worker 	return 0;
124*2d543d20SAndroid Build Coastguard Worker }
125*2d543d20SAndroid Build Coastguard Worker 
126*2d543d20SAndroid Build Coastguard Worker #define status_to_retval(status,retval) do { \
127*2d543d20SAndroid Build Coastguard Worker 	if ((status) == -1) \
128*2d543d20SAndroid Build Coastguard Worker 		retval = -1; \
129*2d543d20SAndroid Build Coastguard Worker 	else if (WIFEXITED((status))) \
130*2d543d20SAndroid Build Coastguard Worker 		retval = WEXITSTATUS((status)); \
131*2d543d20SAndroid Build Coastguard Worker 	else if (WIFSIGNALED((status))) \
132*2d543d20SAndroid Build Coastguard Worker 		retval = 128 + WTERMSIG((status)); \
133*2d543d20SAndroid Build Coastguard Worker 	else \
134*2d543d20SAndroid Build Coastguard Worker 		retval = -1; \
135*2d543d20SAndroid Build Coastguard Worker 	} while(0)
136*2d543d20SAndroid Build Coastguard Worker 
137*2d543d20SAndroid Build Coastguard Worker /**
138*2d543d20SAndroid Build Coastguard Worker  * Spawn external command using system() with dropped privileges.
139*2d543d20SAndroid Build Coastguard Worker  * TODO: avoid system() and use exec*() instead
140*2d543d20SAndroid Build Coastguard Worker  */
spawn_command(const char * cmd,uid_t uid)141*2d543d20SAndroid Build Coastguard Worker static int spawn_command(const char *cmd, uid_t uid){
142*2d543d20SAndroid Build Coastguard Worker 	int childpid;
143*2d543d20SAndroid Build Coastguard Worker 	int status = -1;
144*2d543d20SAndroid Build Coastguard Worker 
145*2d543d20SAndroid Build Coastguard Worker 	if (verbose > 1)
146*2d543d20SAndroid Build Coastguard Worker 		printf("spawn_command: %s\n", cmd);
147*2d543d20SAndroid Build Coastguard Worker 
148*2d543d20SAndroid Build Coastguard Worker 	childpid = fork();
149*2d543d20SAndroid Build Coastguard Worker 	if (childpid == -1) {
150*2d543d20SAndroid Build Coastguard Worker 		perror(_("Unable to fork"));
151*2d543d20SAndroid Build Coastguard Worker 		return status;
152*2d543d20SAndroid Build Coastguard Worker 	}
153*2d543d20SAndroid Build Coastguard Worker 
154*2d543d20SAndroid Build Coastguard Worker 	if (childpid == 0) {
155*2d543d20SAndroid Build Coastguard Worker 		if (drop_privs(uid) != 0) exit(-1);
156*2d543d20SAndroid Build Coastguard Worker 
157*2d543d20SAndroid Build Coastguard Worker 		status = system(cmd);
158*2d543d20SAndroid Build Coastguard Worker 		status_to_retval(status, status);
159*2d543d20SAndroid Build Coastguard Worker 		exit(status);
160*2d543d20SAndroid Build Coastguard Worker 	}
161*2d543d20SAndroid Build Coastguard Worker 
162*2d543d20SAndroid Build Coastguard Worker 	waitpid(childpid, &status, 0);
163*2d543d20SAndroid Build Coastguard Worker 	status_to_retval(status, status);
164*2d543d20SAndroid Build Coastguard Worker 	return status;
165*2d543d20SAndroid Build Coastguard Worker }
166*2d543d20SAndroid Build Coastguard Worker 
167*2d543d20SAndroid Build Coastguard Worker /**
168*2d543d20SAndroid Build Coastguard Worker  * Check file/directory ownership, struct stat * must be passed to the
169*2d543d20SAndroid Build Coastguard Worker  * functions.
170*2d543d20SAndroid Build Coastguard Worker  */
check_owner_uid(uid_t uid,const char * file,struct stat * st)171*2d543d20SAndroid Build Coastguard Worker static int check_owner_uid(uid_t uid, const char *file, struct stat *st) {
172*2d543d20SAndroid Build Coastguard Worker 	if (S_ISLNK(st->st_mode)) {
173*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
174*2d543d20SAndroid Build Coastguard Worker 		return -1;
175*2d543d20SAndroid Build Coastguard Worker 	}
176*2d543d20SAndroid Build Coastguard Worker 	if (st->st_uid != uid) {
177*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: %s not owned by UID %d\n"), file, uid);
178*2d543d20SAndroid Build Coastguard Worker 		return -1;
179*2d543d20SAndroid Build Coastguard Worker 	}
180*2d543d20SAndroid Build Coastguard Worker 	return 0;
181*2d543d20SAndroid Build Coastguard Worker }
182*2d543d20SAndroid Build Coastguard Worker 
check_owner_gid(gid_t gid,const char * file,struct stat * st)183*2d543d20SAndroid Build Coastguard Worker static int check_owner_gid(gid_t gid, const char *file, struct stat *st) {
184*2d543d20SAndroid Build Coastguard Worker 	if (S_ISLNK(st->st_mode)) {
185*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: %s must not be a symbolic link\n"), file);
186*2d543d20SAndroid Build Coastguard Worker 		return -1;
187*2d543d20SAndroid Build Coastguard Worker 	}
188*2d543d20SAndroid Build Coastguard Worker 	if (st->st_gid != gid) {
189*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: %s not owned by GID %d\n"), file, gid);
190*2d543d20SAndroid Build Coastguard Worker 		return -1;
191*2d543d20SAndroid Build Coastguard Worker 	}
192*2d543d20SAndroid Build Coastguard Worker 	return 0;
193*2d543d20SAndroid Build Coastguard Worker }
194*2d543d20SAndroid Build Coastguard Worker 
195*2d543d20SAndroid Build Coastguard Worker #define equal_stats(one,two) \
196*2d543d20SAndroid Build Coastguard Worker 	((one)->st_dev == (two)->st_dev && (one)->st_ino == (two)->st_ino && \
197*2d543d20SAndroid Build Coastguard Worker 	 (one)->st_uid == (two)->st_uid && (one)->st_gid == (two)->st_gid && \
198*2d543d20SAndroid Build Coastguard Worker 	 (one)->st_mode == (two)->st_mode)
199*2d543d20SAndroid Build Coastguard Worker 
200*2d543d20SAndroid Build Coastguard Worker /**
201*2d543d20SAndroid Build Coastguard Worker  * Sanity check specified directory.  Store stat info for future comparison, or
202*2d543d20SAndroid Build Coastguard Worker  * compare with previously saved info to detect replaced directories.
203*2d543d20SAndroid Build Coastguard Worker  * Note: This function does not perform owner checks.
204*2d543d20SAndroid Build Coastguard Worker  */
verify_directory(const char * dir,struct stat * st_in,struct stat * st_out)205*2d543d20SAndroid Build Coastguard Worker static int verify_directory(const char *dir, struct stat *st_in, struct stat *st_out) {
206*2d543d20SAndroid Build Coastguard Worker 	struct stat sb;
207*2d543d20SAndroid Build Coastguard Worker 
208*2d543d20SAndroid Build Coastguard Worker 	if (st_out == NULL) st_out = &sb;
209*2d543d20SAndroid Build Coastguard Worker 
210*2d543d20SAndroid Build Coastguard Worker 	if (lstat(dir, st_out) == -1) {
211*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to stat %s: %s\n"), dir, strerror(errno));
212*2d543d20SAndroid Build Coastguard Worker 		return -1;
213*2d543d20SAndroid Build Coastguard Worker 	}
214*2d543d20SAndroid Build Coastguard Worker 	if (! S_ISDIR(st_out->st_mode)) {
215*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: %s is not a directory: %s\n"), dir, strerror(errno));
216*2d543d20SAndroid Build Coastguard Worker 		return -1;
217*2d543d20SAndroid Build Coastguard Worker 	}
218*2d543d20SAndroid Build Coastguard Worker 	if (st_in && !equal_stats(st_in, st_out)) {
219*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: %s was replaced by a different directory\n"), dir);
220*2d543d20SAndroid Build Coastguard Worker 		return -1;
221*2d543d20SAndroid Build Coastguard Worker 	}
222*2d543d20SAndroid Build Coastguard Worker 
223*2d543d20SAndroid Build Coastguard Worker 	return 0;
224*2d543d20SAndroid Build Coastguard Worker }
225*2d543d20SAndroid Build Coastguard Worker 
226*2d543d20SAndroid Build Coastguard Worker /**
227*2d543d20SAndroid Build Coastguard Worker  * This function checks to see if the shell is known in /etc/shells.
228*2d543d20SAndroid Build Coastguard Worker  * If so, it returns 0. On error or illegal shell, it returns -1.
229*2d543d20SAndroid Build Coastguard Worker  */
verify_shell(const char * shell_name)230*2d543d20SAndroid Build Coastguard Worker static int verify_shell(const char *shell_name)
231*2d543d20SAndroid Build Coastguard Worker {
232*2d543d20SAndroid Build Coastguard Worker 	int rc = -1;
233*2d543d20SAndroid Build Coastguard Worker 	const char *buf;
234*2d543d20SAndroid Build Coastguard Worker 
235*2d543d20SAndroid Build Coastguard Worker 	if (!(shell_name && shell_name[0]))
236*2d543d20SAndroid Build Coastguard Worker 		return rc;
237*2d543d20SAndroid Build Coastguard Worker 
238*2d543d20SAndroid Build Coastguard Worker 	while ((buf = getusershell()) != NULL) {
239*2d543d20SAndroid Build Coastguard Worker 		/* ignore comments */
240*2d543d20SAndroid Build Coastguard Worker 		if (*buf == '#')
241*2d543d20SAndroid Build Coastguard Worker 			continue;
242*2d543d20SAndroid Build Coastguard Worker 
243*2d543d20SAndroid Build Coastguard Worker 		/* check the shell skipping newline char */
244*2d543d20SAndroid Build Coastguard Worker 		if (!strcmp(shell_name, buf)) {
245*2d543d20SAndroid Build Coastguard Worker 			rc = 0;
246*2d543d20SAndroid Build Coastguard Worker 			break;
247*2d543d20SAndroid Build Coastguard Worker 		}
248*2d543d20SAndroid Build Coastguard Worker 	}
249*2d543d20SAndroid Build Coastguard Worker 	endusershell();
250*2d543d20SAndroid Build Coastguard Worker 	return rc;
251*2d543d20SAndroid Build Coastguard Worker }
252*2d543d20SAndroid Build Coastguard Worker 
253*2d543d20SAndroid Build Coastguard Worker /**
254*2d543d20SAndroid Build Coastguard Worker  * Mount directory and check that we mounted the right directory.
255*2d543d20SAndroid Build Coastguard Worker  */
seunshare_mount(const char * src,const char * dst,struct stat * src_st)256*2d543d20SAndroid Build Coastguard Worker static int seunshare_mount(const char *src, const char *dst, struct stat *src_st)
257*2d543d20SAndroid Build Coastguard Worker {
258*2d543d20SAndroid Build Coastguard Worker 	int flags = 0;
259*2d543d20SAndroid Build Coastguard Worker 	int is_tmp = 0;
260*2d543d20SAndroid Build Coastguard Worker 
261*2d543d20SAndroid Build Coastguard Worker 	if (verbose)
262*2d543d20SAndroid Build Coastguard Worker 		printf(_("Mounting %s on %s\n"), src, dst);
263*2d543d20SAndroid Build Coastguard Worker 
264*2d543d20SAndroid Build Coastguard Worker 	if (strcmp("/tmp", dst) == 0) {
265*2d543d20SAndroid Build Coastguard Worker 		flags = flags | MS_NODEV | MS_NOSUID | MS_NOEXEC;
266*2d543d20SAndroid Build Coastguard Worker 		is_tmp = 1;
267*2d543d20SAndroid Build Coastguard Worker 	}
268*2d543d20SAndroid Build Coastguard Worker 
269*2d543d20SAndroid Build Coastguard Worker 	if (strncmp("/run/user", dst, 9) == 0) {
270*2d543d20SAndroid Build Coastguard Worker 		flags = flags | MS_REC;
271*2d543d20SAndroid Build Coastguard Worker 	}
272*2d543d20SAndroid Build Coastguard Worker 
273*2d543d20SAndroid Build Coastguard Worker 	/* mount directory */
274*2d543d20SAndroid Build Coastguard Worker 	if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) {
275*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno));
276*2d543d20SAndroid Build Coastguard Worker 		return -1;
277*2d543d20SAndroid Build Coastguard Worker 	}
278*2d543d20SAndroid Build Coastguard Worker 
279*2d543d20SAndroid Build Coastguard Worker 	/* verify whether we mounted what we expected to mount */
280*2d543d20SAndroid Build Coastguard Worker 	if (verify_directory(dst, src_st, NULL) < 0) return -1;
281*2d543d20SAndroid Build Coastguard Worker 
282*2d543d20SAndroid Build Coastguard Worker 	/* bind mount /tmp on /var/tmp too */
283*2d543d20SAndroid Build Coastguard Worker 	if (is_tmp) {
284*2d543d20SAndroid Build Coastguard Worker 		if (verbose)
285*2d543d20SAndroid Build Coastguard Worker 			printf(_("Mounting /tmp on /var/tmp\n"));
286*2d543d20SAndroid Build Coastguard Worker 
287*2d543d20SAndroid Build Coastguard Worker 		if (mount("/tmp", "/var/tmp",  NULL, MS_BIND | flags, NULL) < 0) {
288*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, _("Failed to mount /tmp on /var/tmp: %s\n"), strerror(errno));
289*2d543d20SAndroid Build Coastguard Worker 			return -1;
290*2d543d20SAndroid Build Coastguard Worker 		}
291*2d543d20SAndroid Build Coastguard Worker 	}
292*2d543d20SAndroid Build Coastguard Worker 
293*2d543d20SAndroid Build Coastguard Worker 	return 0;
294*2d543d20SAndroid Build Coastguard Worker 
295*2d543d20SAndroid Build Coastguard Worker }
296*2d543d20SAndroid Build Coastguard Worker 
297*2d543d20SAndroid Build Coastguard Worker /**
298*2d543d20SAndroid Build Coastguard Worker  * Mount directory and check that we mounted the right directory.
299*2d543d20SAndroid Build Coastguard Worker  */
seunshare_mount_file(const char * src,const char * dst)300*2d543d20SAndroid Build Coastguard Worker static int seunshare_mount_file(const char *src, const char *dst)
301*2d543d20SAndroid Build Coastguard Worker {
302*2d543d20SAndroid Build Coastguard Worker 	int flags = 0;
303*2d543d20SAndroid Build Coastguard Worker 
304*2d543d20SAndroid Build Coastguard Worker 	if (verbose)
305*2d543d20SAndroid Build Coastguard Worker 		printf(_("Mounting %s on %s\n"), src, dst);
306*2d543d20SAndroid Build Coastguard Worker 
307*2d543d20SAndroid Build Coastguard Worker 	if (access(dst, F_OK) == -1) {
308*2d543d20SAndroid Build Coastguard Worker 		 FILE *fptr;
309*2d543d20SAndroid Build Coastguard Worker          fptr = fopen(dst, "w");
310*2d543d20SAndroid Build Coastguard Worker 		 fclose(fptr);
311*2d543d20SAndroid Build Coastguard Worker 	}
312*2d543d20SAndroid Build Coastguard Worker 	/* mount file */
313*2d543d20SAndroid Build Coastguard Worker 	if (mount(src, dst, NULL, MS_BIND | flags, NULL) < 0) {
314*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to mount %s on %s: %s\n"), src, dst, strerror(errno));
315*2d543d20SAndroid Build Coastguard Worker 		return -1;
316*2d543d20SAndroid Build Coastguard Worker 	}
317*2d543d20SAndroid Build Coastguard Worker 
318*2d543d20SAndroid Build Coastguard Worker 	return 0;
319*2d543d20SAndroid Build Coastguard Worker 
320*2d543d20SAndroid Build Coastguard Worker }
321*2d543d20SAndroid Build Coastguard Worker 
322*2d543d20SAndroid Build Coastguard Worker /*
323*2d543d20SAndroid Build Coastguard Worker    If path is empty or ends with  "/." or "/.. return -1 else return 0;
324*2d543d20SAndroid Build Coastguard Worker  */
bad_path(const char * path)325*2d543d20SAndroid Build Coastguard Worker static int bad_path(const char *path) {
326*2d543d20SAndroid Build Coastguard Worker 	const char *ptr;
327*2d543d20SAndroid Build Coastguard Worker 	ptr = path;
328*2d543d20SAndroid Build Coastguard Worker 	while (*ptr) ptr++;
329*2d543d20SAndroid Build Coastguard Worker 	if (ptr == path) return -1; // ptr null
330*2d543d20SAndroid Build Coastguard Worker 	ptr--;
331*2d543d20SAndroid Build Coastguard Worker 	if (ptr != path && *ptr  == '.') {
332*2d543d20SAndroid Build Coastguard Worker 		ptr--;
333*2d543d20SAndroid Build Coastguard Worker 		if (*ptr  == '/') return -1; // path ends in /.
334*2d543d20SAndroid Build Coastguard Worker 		if (*ptr  == '.') {
335*2d543d20SAndroid Build Coastguard Worker 			if (ptr != path) {
336*2d543d20SAndroid Build Coastguard Worker 				ptr--;
337*2d543d20SAndroid Build Coastguard Worker 				if (*ptr  == '/') return -1; // path ends in /..
338*2d543d20SAndroid Build Coastguard Worker 			}
339*2d543d20SAndroid Build Coastguard Worker 		}
340*2d543d20SAndroid Build Coastguard Worker 	}
341*2d543d20SAndroid Build Coastguard Worker 	return 0;
342*2d543d20SAndroid Build Coastguard Worker }
343*2d543d20SAndroid Build Coastguard Worker 
rsynccmd(const char * src,const char * dst,char ** cmdbuf)344*2d543d20SAndroid Build Coastguard Worker static int rsynccmd(const char * src, const char *dst, char **cmdbuf)
345*2d543d20SAndroid Build Coastguard Worker {
346*2d543d20SAndroid Build Coastguard Worker 	char *buf = NULL;
347*2d543d20SAndroid Build Coastguard Worker 	char *newbuf = NULL;
348*2d543d20SAndroid Build Coastguard Worker 	glob_t fglob;
349*2d543d20SAndroid Build Coastguard Worker 	fglob.gl_offs = 0;
350*2d543d20SAndroid Build Coastguard Worker 	int flags = GLOB_PERIOD;
351*2d543d20SAndroid Build Coastguard Worker 	unsigned int i = 0;
352*2d543d20SAndroid Build Coastguard Worker 	int rc = -1;
353*2d543d20SAndroid Build Coastguard Worker 
354*2d543d20SAndroid Build Coastguard Worker 	/* match glob for all files in src dir */
355*2d543d20SAndroid Build Coastguard Worker 	if (asprintf(&buf, "%s/*", src) == -1) {
356*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, "Out of memory\n");
357*2d543d20SAndroid Build Coastguard Worker 		return -1;
358*2d543d20SAndroid Build Coastguard Worker 	}
359*2d543d20SAndroid Build Coastguard Worker 
360*2d543d20SAndroid Build Coastguard Worker 	if (glob(buf, flags, NULL, &fglob) != 0) {
361*2d543d20SAndroid Build Coastguard Worker 		free(buf); buf = NULL;
362*2d543d20SAndroid Build Coastguard Worker 		return -1;
363*2d543d20SAndroid Build Coastguard Worker 	}
364*2d543d20SAndroid Build Coastguard Worker 
365*2d543d20SAndroid Build Coastguard Worker 	free(buf); buf = NULL;
366*2d543d20SAndroid Build Coastguard Worker 
367*2d543d20SAndroid Build Coastguard Worker 	for ( i=0; i < fglob.gl_pathc; i++) {
368*2d543d20SAndroid Build Coastguard Worker 		const char *path = fglob.gl_pathv[i];
369*2d543d20SAndroid Build Coastguard Worker 
370*2d543d20SAndroid Build Coastguard Worker 		if (bad_path(path)) continue;
371*2d543d20SAndroid Build Coastguard Worker 
372*2d543d20SAndroid Build Coastguard Worker 		if (!buf) {
373*2d543d20SAndroid Build Coastguard Worker 			if (asprintf(&newbuf, "\'%s\'", path) == -1) {
374*2d543d20SAndroid Build Coastguard Worker 				fprintf(stderr, "Out of memory\n");
375*2d543d20SAndroid Build Coastguard Worker 				goto err;
376*2d543d20SAndroid Build Coastguard Worker 			}
377*2d543d20SAndroid Build Coastguard Worker 		} else {
378*2d543d20SAndroid Build Coastguard Worker 			if (asprintf(&newbuf, "%s  \'%s\'", buf, path) == -1) {
379*2d543d20SAndroid Build Coastguard Worker 				fprintf(stderr, "Out of memory\n");
380*2d543d20SAndroid Build Coastguard Worker 				goto err;
381*2d543d20SAndroid Build Coastguard Worker 			}
382*2d543d20SAndroid Build Coastguard Worker 		}
383*2d543d20SAndroid Build Coastguard Worker 
384*2d543d20SAndroid Build Coastguard Worker 		free(buf); buf = newbuf;
385*2d543d20SAndroid Build Coastguard Worker 		newbuf = NULL;
386*2d543d20SAndroid Build Coastguard Worker 	}
387*2d543d20SAndroid Build Coastguard Worker 
388*2d543d20SAndroid Build Coastguard Worker 	if (buf) {
389*2d543d20SAndroid Build Coastguard Worker 		if (asprintf(&newbuf, "/usr/bin/rsync -trlHDq %s '%s'", buf, dst) == -1) {
390*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, "Out of memory\n");
391*2d543d20SAndroid Build Coastguard Worker 			goto err;
392*2d543d20SAndroid Build Coastguard Worker 		}
393*2d543d20SAndroid Build Coastguard Worker 		*cmdbuf=newbuf;
394*2d543d20SAndroid Build Coastguard Worker 	}
395*2d543d20SAndroid Build Coastguard Worker 	else {
396*2d543d20SAndroid Build Coastguard Worker 		*cmdbuf=NULL;
397*2d543d20SAndroid Build Coastguard Worker 	}
398*2d543d20SAndroid Build Coastguard Worker 	rc = 0;
399*2d543d20SAndroid Build Coastguard Worker 
400*2d543d20SAndroid Build Coastguard Worker err:
401*2d543d20SAndroid Build Coastguard Worker 	free(buf); buf = NULL;
402*2d543d20SAndroid Build Coastguard Worker 	globfree(&fglob);
403*2d543d20SAndroid Build Coastguard Worker 	return rc;
404*2d543d20SAndroid Build Coastguard Worker }
405*2d543d20SAndroid Build Coastguard Worker 
406*2d543d20SAndroid Build Coastguard Worker /**
407*2d543d20SAndroid Build Coastguard Worker  * Clean up runtime temporary directory.  Returns 0 if no problem was detected,
408*2d543d20SAndroid Build Coastguard Worker  * >0 if some error was detected, but errors here are treated as non-fatal and
409*2d543d20SAndroid Build Coastguard Worker  * left to tmpwatch to finish incomplete cleanup.
410*2d543d20SAndroid Build Coastguard Worker  */
cleanup_tmpdir(const char * tmpdir,const char * src,struct passwd * pwd,int copy_content)411*2d543d20SAndroid Build Coastguard Worker static int cleanup_tmpdir(const char *tmpdir, const char *src,
412*2d543d20SAndroid Build Coastguard Worker 	struct passwd *pwd, int copy_content)
413*2d543d20SAndroid Build Coastguard Worker {
414*2d543d20SAndroid Build Coastguard Worker 	char *cmdbuf = NULL;
415*2d543d20SAndroid Build Coastguard Worker 	int rc = 0;
416*2d543d20SAndroid Build Coastguard Worker 
417*2d543d20SAndroid Build Coastguard Worker 	/* rsync files back */
418*2d543d20SAndroid Build Coastguard Worker 	if (copy_content) {
419*2d543d20SAndroid Build Coastguard Worker 		if (asprintf(&cmdbuf, "/usr/bin/rsync --exclude=.X11-unix -utrlHDq --delete '%s/' '%s/'", tmpdir, src) == -1) {
420*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, _("Out of memory\n"));
421*2d543d20SAndroid Build Coastguard Worker 			cmdbuf = NULL;
422*2d543d20SAndroid Build Coastguard Worker 			rc++;
423*2d543d20SAndroid Build Coastguard Worker 		}
424*2d543d20SAndroid Build Coastguard Worker 		if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
425*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, _("Failed to copy files from the runtime temporary directory\n"));
426*2d543d20SAndroid Build Coastguard Worker 			rc++;
427*2d543d20SAndroid Build Coastguard Worker 		}
428*2d543d20SAndroid Build Coastguard Worker 		free(cmdbuf); cmdbuf = NULL;
429*2d543d20SAndroid Build Coastguard Worker 	}
430*2d543d20SAndroid Build Coastguard Worker 
431*2d543d20SAndroid Build Coastguard Worker 	/* remove files from the runtime temporary directory */
432*2d543d20SAndroid Build Coastguard Worker 	if (asprintf(&cmdbuf, "/bin/rm -r '%s/' 2>/dev/null", tmpdir) == -1) {
433*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Out of memory\n"));
434*2d543d20SAndroid Build Coastguard Worker 		cmdbuf = NULL;
435*2d543d20SAndroid Build Coastguard Worker 		rc++;
436*2d543d20SAndroid Build Coastguard Worker 	}
437*2d543d20SAndroid Build Coastguard Worker 	/* this may fail if there's root-owned file left in the runtime tmpdir */
438*2d543d20SAndroid Build Coastguard Worker 	if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) rc++;
439*2d543d20SAndroid Build Coastguard Worker 	free(cmdbuf); cmdbuf = NULL;
440*2d543d20SAndroid Build Coastguard Worker 
441*2d543d20SAndroid Build Coastguard Worker 	/* remove runtime temporary directory */
442*2d543d20SAndroid Build Coastguard Worker 	if ((uid_t)setfsuid(0) != 0) {
443*2d543d20SAndroid Build Coastguard Worker 		/* setfsuid does not return error, but this check makes code checkers happy */
444*2d543d20SAndroid Build Coastguard Worker 		rc++;
445*2d543d20SAndroid Build Coastguard Worker 	}
446*2d543d20SAndroid Build Coastguard Worker 
447*2d543d20SAndroid Build Coastguard Worker 	if (pwd->pw_uid != 0 && rmdir(tmpdir) == -1)
448*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to remove directory %s: %s\n"), tmpdir, strerror(errno));
449*2d543d20SAndroid Build Coastguard Worker 	if ((uid_t)setfsuid(pwd->pw_uid) != 0) {
450*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("unable to switch back to user after clearing tmp dir\n"));
451*2d543d20SAndroid Build Coastguard Worker 		rc++;
452*2d543d20SAndroid Build Coastguard Worker 	}
453*2d543d20SAndroid Build Coastguard Worker 
454*2d543d20SAndroid Build Coastguard Worker 	return rc;
455*2d543d20SAndroid Build Coastguard Worker }
456*2d543d20SAndroid Build Coastguard Worker 
457*2d543d20SAndroid Build Coastguard Worker /**
458*2d543d20SAndroid Build Coastguard Worker  * seunshare will create a tmpdir in /tmp, with root ownership.  The parent
459*2d543d20SAndroid Build Coastguard Worker  * process waits for it child to exit to attempt to remove the directory.  If
460*2d543d20SAndroid Build Coastguard Worker  * it fails to remove the directory, we will need to rely on tmpreaper/tmpwatch
461*2d543d20SAndroid Build Coastguard Worker  * to clean it up.
462*2d543d20SAndroid Build Coastguard Worker  */
create_tmpdir(const char * src,struct stat * src_st,struct stat * out_st,struct passwd * pwd,const char * execcon)463*2d543d20SAndroid Build Coastguard Worker static char *create_tmpdir(const char *src, struct stat *src_st,
464*2d543d20SAndroid Build Coastguard Worker 	struct stat *out_st, struct passwd *pwd, const char *execcon)
465*2d543d20SAndroid Build Coastguard Worker {
466*2d543d20SAndroid Build Coastguard Worker 	char *tmpdir = NULL;
467*2d543d20SAndroid Build Coastguard Worker 	char *cmdbuf = NULL;
468*2d543d20SAndroid Build Coastguard Worker 	int fd_t = -1, fd_s = -1;
469*2d543d20SAndroid Build Coastguard Worker 	struct stat tmp_st;
470*2d543d20SAndroid Build Coastguard Worker 	char *con = NULL;
471*2d543d20SAndroid Build Coastguard Worker 
472*2d543d20SAndroid Build Coastguard Worker 	/* get selinux context */
473*2d543d20SAndroid Build Coastguard Worker 	if (execcon) {
474*2d543d20SAndroid Build Coastguard Worker 		if ((uid_t)setfsuid(pwd->pw_uid) != 0)
475*2d543d20SAndroid Build Coastguard Worker 			goto err;
476*2d543d20SAndroid Build Coastguard Worker 
477*2d543d20SAndroid Build Coastguard Worker 		if ((fd_s = open(src, O_RDONLY)) < 0) {
478*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, _("Failed to open directory %s: %s\n"), src, strerror(errno));
479*2d543d20SAndroid Build Coastguard Worker 			goto err;
480*2d543d20SAndroid Build Coastguard Worker 		}
481*2d543d20SAndroid Build Coastguard Worker 		if (fstat(fd_s, &tmp_st) == -1) {
482*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, _("Failed to stat directory %s: %s\n"), src, strerror(errno));
483*2d543d20SAndroid Build Coastguard Worker 			goto err;
484*2d543d20SAndroid Build Coastguard Worker 		}
485*2d543d20SAndroid Build Coastguard Worker 		if (!equal_stats(src_st, &tmp_st)) {
486*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, _("Error: %s was replaced by a different directory\n"), src);
487*2d543d20SAndroid Build Coastguard Worker 			goto err;
488*2d543d20SAndroid Build Coastguard Worker 		}
489*2d543d20SAndroid Build Coastguard Worker 		if (fgetfilecon(fd_s, &con) == -1) {
490*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, _("Failed to get context of the directory %s: %s\n"), src, strerror(errno));
491*2d543d20SAndroid Build Coastguard Worker 			goto err;
492*2d543d20SAndroid Build Coastguard Worker 		}
493*2d543d20SAndroid Build Coastguard Worker 
494*2d543d20SAndroid Build Coastguard Worker 		/* ok to not reach this if there is an error */
495*2d543d20SAndroid Build Coastguard Worker 		if ((uid_t)setfsuid(0) != pwd->pw_uid)
496*2d543d20SAndroid Build Coastguard Worker 			goto err;
497*2d543d20SAndroid Build Coastguard Worker 	}
498*2d543d20SAndroid Build Coastguard Worker 
499*2d543d20SAndroid Build Coastguard Worker 	if (asprintf(&tmpdir, "/tmp/.sandbox-%s-XXXXXX", pwd->pw_name) == -1) {
500*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Out of memory\n"));
501*2d543d20SAndroid Build Coastguard Worker 		tmpdir = NULL;
502*2d543d20SAndroid Build Coastguard Worker 		goto err;
503*2d543d20SAndroid Build Coastguard Worker 	}
504*2d543d20SAndroid Build Coastguard Worker 	if (mkdtemp(tmpdir) == NULL) {
505*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to create temporary directory: %s\n"), strerror(errno));
506*2d543d20SAndroid Build Coastguard Worker 		goto err;
507*2d543d20SAndroid Build Coastguard Worker 	}
508*2d543d20SAndroid Build Coastguard Worker 
509*2d543d20SAndroid Build Coastguard Worker 	/* temporary directory must be owned by root:user */
510*2d543d20SAndroid Build Coastguard Worker 	if (verify_directory(tmpdir, NULL, out_st) < 0) {
511*2d543d20SAndroid Build Coastguard Worker 		goto err;
512*2d543d20SAndroid Build Coastguard Worker 	}
513*2d543d20SAndroid Build Coastguard Worker 
514*2d543d20SAndroid Build Coastguard Worker 	if (check_owner_uid(0, tmpdir, out_st) < 0)
515*2d543d20SAndroid Build Coastguard Worker 		goto err;
516*2d543d20SAndroid Build Coastguard Worker 
517*2d543d20SAndroid Build Coastguard Worker 	if (check_owner_gid(getgid(), tmpdir, out_st) < 0)
518*2d543d20SAndroid Build Coastguard Worker 		goto err;
519*2d543d20SAndroid Build Coastguard Worker 
520*2d543d20SAndroid Build Coastguard Worker 	/* change permissions of the temporary directory */
521*2d543d20SAndroid Build Coastguard Worker 	if ((fd_t = open(tmpdir, O_RDONLY)) < 0) {
522*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to open directory %s: %s\n"), tmpdir, strerror(errno));
523*2d543d20SAndroid Build Coastguard Worker 		goto err;
524*2d543d20SAndroid Build Coastguard Worker 	}
525*2d543d20SAndroid Build Coastguard Worker 	if (fstat(fd_t, &tmp_st) == -1) {
526*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
527*2d543d20SAndroid Build Coastguard Worker 		goto err;
528*2d543d20SAndroid Build Coastguard Worker 	}
529*2d543d20SAndroid Build Coastguard Worker 	if (!equal_stats(out_st, &tmp_st)) {
530*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: %s was replaced by a different directory\n"), tmpdir);
531*2d543d20SAndroid Build Coastguard Worker 		goto err;
532*2d543d20SAndroid Build Coastguard Worker 	}
533*2d543d20SAndroid Build Coastguard Worker 	if (fchmod(fd_t, 01770) == -1) {
534*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Unable to change mode on %s: %s\n"), tmpdir, strerror(errno));
535*2d543d20SAndroid Build Coastguard Worker 		goto err;
536*2d543d20SAndroid Build Coastguard Worker 	}
537*2d543d20SAndroid Build Coastguard Worker 	/* re-stat again to pick change mode */
538*2d543d20SAndroid Build Coastguard Worker 	if (fstat(fd_t, out_st) == -1) {
539*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to stat directory %s: %s\n"), tmpdir, strerror(errno));
540*2d543d20SAndroid Build Coastguard Worker 		goto err;
541*2d543d20SAndroid Build Coastguard Worker 	}
542*2d543d20SAndroid Build Coastguard Worker 
543*2d543d20SAndroid Build Coastguard Worker 	/* copy selinux context */
544*2d543d20SAndroid Build Coastguard Worker 	if (execcon) {
545*2d543d20SAndroid Build Coastguard Worker 		if (fsetfilecon(fd_t, con) == -1) {
546*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, _("Failed to set context of the directory %s: %s\n"), tmpdir, strerror(errno));
547*2d543d20SAndroid Build Coastguard Worker 			goto err;
548*2d543d20SAndroid Build Coastguard Worker 		}
549*2d543d20SAndroid Build Coastguard Worker 	}
550*2d543d20SAndroid Build Coastguard Worker 
551*2d543d20SAndroid Build Coastguard Worker 	if ((uid_t)setfsuid(pwd->pw_uid) != 0)
552*2d543d20SAndroid Build Coastguard Worker 		goto err;
553*2d543d20SAndroid Build Coastguard Worker 
554*2d543d20SAndroid Build Coastguard Worker 	if (rsynccmd(src, tmpdir, &cmdbuf) < 0) {
555*2d543d20SAndroid Build Coastguard Worker 		goto err;
556*2d543d20SAndroid Build Coastguard Worker 	}
557*2d543d20SAndroid Build Coastguard Worker 
558*2d543d20SAndroid Build Coastguard Worker 	/* ok to not reach this if there is an error */
559*2d543d20SAndroid Build Coastguard Worker 	if ((uid_t)setfsuid(0) != pwd->pw_uid)
560*2d543d20SAndroid Build Coastguard Worker 		goto err;
561*2d543d20SAndroid Build Coastguard Worker 
562*2d543d20SAndroid Build Coastguard Worker 	if (cmdbuf && spawn_command(cmdbuf, pwd->pw_uid) != 0) {
563*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to populate runtime temporary directory\n"));
564*2d543d20SAndroid Build Coastguard Worker 		cleanup_tmpdir(tmpdir, src, pwd, 0);
565*2d543d20SAndroid Build Coastguard Worker 		goto err;
566*2d543d20SAndroid Build Coastguard Worker 	}
567*2d543d20SAndroid Build Coastguard Worker 
568*2d543d20SAndroid Build Coastguard Worker 	goto good;
569*2d543d20SAndroid Build Coastguard Worker err:
570*2d543d20SAndroid Build Coastguard Worker 	free(tmpdir); tmpdir = NULL;
571*2d543d20SAndroid Build Coastguard Worker good:
572*2d543d20SAndroid Build Coastguard Worker 	free(cmdbuf); cmdbuf = NULL;
573*2d543d20SAndroid Build Coastguard Worker 	freecon(con); con = NULL;
574*2d543d20SAndroid Build Coastguard Worker 	if (fd_t >= 0) close(fd_t);
575*2d543d20SAndroid Build Coastguard Worker 	if (fd_s >= 0) close(fd_s);
576*2d543d20SAndroid Build Coastguard Worker 	return tmpdir;
577*2d543d20SAndroid Build Coastguard Worker }
578*2d543d20SAndroid Build Coastguard Worker 
579*2d543d20SAndroid Build Coastguard Worker #define PROC_BASE "/proc"
580*2d543d20SAndroid Build Coastguard Worker 
581*2d543d20SAndroid Build Coastguard Worker static int
killall(const char * execcon)582*2d543d20SAndroid Build Coastguard Worker killall (const char *execcon)
583*2d543d20SAndroid Build Coastguard Worker {
584*2d543d20SAndroid Build Coastguard Worker 	DIR *dir;
585*2d543d20SAndroid Build Coastguard Worker 	char *scon;
586*2d543d20SAndroid Build Coastguard Worker 	struct dirent *de;
587*2d543d20SAndroid Build Coastguard Worker 	pid_t *pid_table, pid, self;
588*2d543d20SAndroid Build Coastguard Worker 	int i;
589*2d543d20SAndroid Build Coastguard Worker 	int pids, max_pids;
590*2d543d20SAndroid Build Coastguard Worker 	int running = 0;
591*2d543d20SAndroid Build Coastguard Worker 	self = getpid();
592*2d543d20SAndroid Build Coastguard Worker 	if (!(dir = opendir(PROC_BASE))) {
593*2d543d20SAndroid Build Coastguard Worker 		return -1;
594*2d543d20SAndroid Build Coastguard Worker 	}
595*2d543d20SAndroid Build Coastguard Worker 	max_pids = 256;
596*2d543d20SAndroid Build Coastguard Worker 	pid_table = malloc(max_pids * sizeof (pid_t));
597*2d543d20SAndroid Build Coastguard Worker 	if (!pid_table) {
598*2d543d20SAndroid Build Coastguard Worker 		(void)closedir(dir);
599*2d543d20SAndroid Build Coastguard Worker 		return -1;
600*2d543d20SAndroid Build Coastguard Worker 	}
601*2d543d20SAndroid Build Coastguard Worker 	pids = 0;
602*2d543d20SAndroid Build Coastguard Worker 	context_t con;
603*2d543d20SAndroid Build Coastguard Worker 	con = context_new(execcon);
604*2d543d20SAndroid Build Coastguard Worker 	const char *mcs = context_range_get(con);
605*2d543d20SAndroid Build Coastguard Worker 	printf("mcs=%s\n", mcs);
606*2d543d20SAndroid Build Coastguard Worker 	while ((de = readdir (dir)) != NULL) {
607*2d543d20SAndroid Build Coastguard Worker 		if (!(pid = (pid_t)atoi(de->d_name)) || pid == self)
608*2d543d20SAndroid Build Coastguard Worker 			continue;
609*2d543d20SAndroid Build Coastguard Worker 
610*2d543d20SAndroid Build Coastguard Worker 		if (pids == max_pids) {
611*2d543d20SAndroid Build Coastguard Worker 			pid_t *new_pid_table = realloc(pid_table, 2*pids*sizeof(pid_t));
612*2d543d20SAndroid Build Coastguard Worker 			if (!new_pid_table) {
613*2d543d20SAndroid Build Coastguard Worker 				free(pid_table);
614*2d543d20SAndroid Build Coastguard Worker 				(void)closedir(dir);
615*2d543d20SAndroid Build Coastguard Worker 				return -1;
616*2d543d20SAndroid Build Coastguard Worker 			}
617*2d543d20SAndroid Build Coastguard Worker 			pid_table = new_pid_table;
618*2d543d20SAndroid Build Coastguard Worker 			max_pids *= 2;
619*2d543d20SAndroid Build Coastguard Worker 		}
620*2d543d20SAndroid Build Coastguard Worker 		pid_table[pids++] = pid;
621*2d543d20SAndroid Build Coastguard Worker 	}
622*2d543d20SAndroid Build Coastguard Worker 
623*2d543d20SAndroid Build Coastguard Worker 	(void)closedir(dir);
624*2d543d20SAndroid Build Coastguard Worker 
625*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < pids; i++) {
626*2d543d20SAndroid Build Coastguard Worker 		pid_t id = pid_table[i];
627*2d543d20SAndroid Build Coastguard Worker 
628*2d543d20SAndroid Build Coastguard Worker 		if (getpidcon(id, &scon) == 0) {
629*2d543d20SAndroid Build Coastguard Worker 
630*2d543d20SAndroid Build Coastguard Worker 			context_t pidcon = context_new(scon);
631*2d543d20SAndroid Build Coastguard Worker 			/* Attempt to kill remaining processes */
632*2d543d20SAndroid Build Coastguard Worker 			if (strcmp(context_range_get(pidcon), mcs) == 0)
633*2d543d20SAndroid Build Coastguard Worker 				kill(id, SIGKILL);
634*2d543d20SAndroid Build Coastguard Worker 
635*2d543d20SAndroid Build Coastguard Worker 			context_free(pidcon);
636*2d543d20SAndroid Build Coastguard Worker 			freecon(scon);
637*2d543d20SAndroid Build Coastguard Worker 		}
638*2d543d20SAndroid Build Coastguard Worker 		running++;
639*2d543d20SAndroid Build Coastguard Worker 	}
640*2d543d20SAndroid Build Coastguard Worker 
641*2d543d20SAndroid Build Coastguard Worker 	context_free(con);
642*2d543d20SAndroid Build Coastguard Worker 	free(pid_table);
643*2d543d20SAndroid Build Coastguard Worker 	return running;
644*2d543d20SAndroid Build Coastguard Worker }
645*2d543d20SAndroid Build Coastguard Worker 
main(int argc,char ** argv)646*2d543d20SAndroid Build Coastguard Worker int main(int argc, char **argv) {
647*2d543d20SAndroid Build Coastguard Worker 	int status = -1;
648*2d543d20SAndroid Build Coastguard Worker 	const char *execcon = NULL;
649*2d543d20SAndroid Build Coastguard Worker 	const char *pipewire_socket = NULL;
650*2d543d20SAndroid Build Coastguard Worker 	const char *wayland_display = NULL;
651*2d543d20SAndroid Build Coastguard Worker 
652*2d543d20SAndroid Build Coastguard Worker 	int clflag;		/* holds codes for command line flags */
653*2d543d20SAndroid Build Coastguard Worker 	int kill_all = 0;
654*2d543d20SAndroid Build Coastguard Worker 
655*2d543d20SAndroid Build Coastguard Worker 	char *homedir_s = NULL;	/* homedir spec'd by user in argv[] */
656*2d543d20SAndroid Build Coastguard Worker 	char *tmpdir_s = NULL;	/* tmpdir spec'd by user in argv[] */
657*2d543d20SAndroid Build Coastguard Worker 	char *tmpdir_r = NULL;	/* tmpdir created by seunshare */
658*2d543d20SAndroid Build Coastguard Worker 	char *runuserdir_s = NULL;	/* /var/run/user/UID spec'd by user in argv[] */
659*2d543d20SAndroid Build Coastguard Worker 	char *runuserdir_r = NULL;	/* /var/run/user/UID created by seunshare */
660*2d543d20SAndroid Build Coastguard Worker 
661*2d543d20SAndroid Build Coastguard Worker 	struct stat st_curhomedir;
662*2d543d20SAndroid Build Coastguard Worker 	struct stat st_homedir;
663*2d543d20SAndroid Build Coastguard Worker 	struct stat st_tmpdir_s;
664*2d543d20SAndroid Build Coastguard Worker 	struct stat st_tmpdir_r;
665*2d543d20SAndroid Build Coastguard Worker 	struct stat st_runuserdir_s;
666*2d543d20SAndroid Build Coastguard Worker 	struct stat st_runuserdir_r;
667*2d543d20SAndroid Build Coastguard Worker 
668*2d543d20SAndroid Build Coastguard Worker 	const struct option long_options[] = {
669*2d543d20SAndroid Build Coastguard Worker 		{"homedir", 1, 0, 'h'},
670*2d543d20SAndroid Build Coastguard Worker 		{"tmpdir", 1, 0, 't'},
671*2d543d20SAndroid Build Coastguard Worker 		{"runuserdir", 1, 0, 'r'},
672*2d543d20SAndroid Build Coastguard Worker 		{"kill", 1, 0, 'k'},
673*2d543d20SAndroid Build Coastguard Worker 		{"verbose", 1, 0, 'v'},
674*2d543d20SAndroid Build Coastguard Worker 		{"context", 1, 0, 'Z'},
675*2d543d20SAndroid Build Coastguard Worker 		{"capabilities", 1, 0, 'C'},
676*2d543d20SAndroid Build Coastguard Worker 		{"wayland", 1, 0, 'W'},
677*2d543d20SAndroid Build Coastguard Worker 		{"pipewire", 1, 0, 'P'},
678*2d543d20SAndroid Build Coastguard Worker 		{NULL, 0, 0, 0}
679*2d543d20SAndroid Build Coastguard Worker 	};
680*2d543d20SAndroid Build Coastguard Worker 
681*2d543d20SAndroid Build Coastguard Worker 	uid_t uid = getuid();
682*2d543d20SAndroid Build Coastguard Worker /*
683*2d543d20SAndroid Build Coastguard Worker 	if (!uid) {
684*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Must not be root"));
685*2d543d20SAndroid Build Coastguard Worker 		return -1;
686*2d543d20SAndroid Build Coastguard Worker 	}
687*2d543d20SAndroid Build Coastguard Worker */
688*2d543d20SAndroid Build Coastguard Worker 
689*2d543d20SAndroid Build Coastguard Worker #ifdef USE_NLS
690*2d543d20SAndroid Build Coastguard Worker 	setlocale(LC_ALL, "");
691*2d543d20SAndroid Build Coastguard Worker 	bindtextdomain(PACKAGE, LOCALEDIR);
692*2d543d20SAndroid Build Coastguard Worker 	textdomain(PACKAGE);
693*2d543d20SAndroid Build Coastguard Worker #endif
694*2d543d20SAndroid Build Coastguard Worker 
695*2d543d20SAndroid Build Coastguard Worker 	struct passwd *pwd=getpwuid(uid);
696*2d543d20SAndroid Build Coastguard Worker 	if (!pwd) {
697*2d543d20SAndroid Build Coastguard Worker 		perror(_("getpwduid failed"));
698*2d543d20SAndroid Build Coastguard Worker 		return -1;
699*2d543d20SAndroid Build Coastguard Worker 	}
700*2d543d20SAndroid Build Coastguard Worker 
701*2d543d20SAndroid Build Coastguard Worker 	if (verify_shell(pwd->pw_shell) < 0) {
702*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: User shell is not valid\n"));
703*2d543d20SAndroid Build Coastguard Worker 		return -1;
704*2d543d20SAndroid Build Coastguard Worker 	}
705*2d543d20SAndroid Build Coastguard Worker 
706*2d543d20SAndroid Build Coastguard Worker 	while (1) {
707*2d543d20SAndroid Build Coastguard Worker 		clflag = getopt_long(argc, argv, "Ccvh:r:t:W:Z:", long_options, NULL);
708*2d543d20SAndroid Build Coastguard Worker 		if (clflag == -1)
709*2d543d20SAndroid Build Coastguard Worker 			break;
710*2d543d20SAndroid Build Coastguard Worker 
711*2d543d20SAndroid Build Coastguard Worker 		switch (clflag) {
712*2d543d20SAndroid Build Coastguard Worker 		case 't':
713*2d543d20SAndroid Build Coastguard Worker 			tmpdir_s = optarg;
714*2d543d20SAndroid Build Coastguard Worker 			break;
715*2d543d20SAndroid Build Coastguard Worker 		case 'k':
716*2d543d20SAndroid Build Coastguard Worker 			kill_all = 1;
717*2d543d20SAndroid Build Coastguard Worker 			break;
718*2d543d20SAndroid Build Coastguard Worker 		case 'h':
719*2d543d20SAndroid Build Coastguard Worker 			homedir_s = optarg;
720*2d543d20SAndroid Build Coastguard Worker 			break;
721*2d543d20SAndroid Build Coastguard Worker 		case 'r':
722*2d543d20SAndroid Build Coastguard Worker 			runuserdir_s = optarg;
723*2d543d20SAndroid Build Coastguard Worker 			break;
724*2d543d20SAndroid Build Coastguard Worker 		case 'v':
725*2d543d20SAndroid Build Coastguard Worker 			verbose++;
726*2d543d20SAndroid Build Coastguard Worker 			break;
727*2d543d20SAndroid Build Coastguard Worker 		case 'C':
728*2d543d20SAndroid Build Coastguard Worker 			cap_set = CAPNG_SELECT_CAPS;
729*2d543d20SAndroid Build Coastguard Worker 			break;
730*2d543d20SAndroid Build Coastguard Worker 		case 'P':
731*2d543d20SAndroid Build Coastguard Worker 			pipewire_socket = optarg;
732*2d543d20SAndroid Build Coastguard Worker 			break;
733*2d543d20SAndroid Build Coastguard Worker 		case 'W':
734*2d543d20SAndroid Build Coastguard Worker 			wayland_display = optarg;
735*2d543d20SAndroid Build Coastguard Worker 			break;
736*2d543d20SAndroid Build Coastguard Worker 		case 'Z':
737*2d543d20SAndroid Build Coastguard Worker 			execcon = optarg;
738*2d543d20SAndroid Build Coastguard Worker 			break;
739*2d543d20SAndroid Build Coastguard Worker 		default:
740*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, "%s\n", USAGE_STRING);
741*2d543d20SAndroid Build Coastguard Worker 			return -1;
742*2d543d20SAndroid Build Coastguard Worker 		}
743*2d543d20SAndroid Build Coastguard Worker 	}
744*2d543d20SAndroid Build Coastguard Worker 
745*2d543d20SAndroid Build Coastguard Worker 	if (! homedir_s && ! tmpdir_s) {
746*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: tmpdir and/or homedir required\n %s\n"), USAGE_STRING);
747*2d543d20SAndroid Build Coastguard Worker 		return -1;
748*2d543d20SAndroid Build Coastguard Worker 	}
749*2d543d20SAndroid Build Coastguard Worker 
750*2d543d20SAndroid Build Coastguard Worker 	if (argc - optind < 1) {
751*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: executable required\n %s\n"), USAGE_STRING);
752*2d543d20SAndroid Build Coastguard Worker 		return -1;
753*2d543d20SAndroid Build Coastguard Worker 	}
754*2d543d20SAndroid Build Coastguard Worker 
755*2d543d20SAndroid Build Coastguard Worker 	if (execcon && is_selinux_enabled() != 1) {
756*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: execution context specified, but SELinux is not enabled\n"));
757*2d543d20SAndroid Build Coastguard Worker 		return -1;
758*2d543d20SAndroid Build Coastguard Worker 	}
759*2d543d20SAndroid Build Coastguard Worker 
760*2d543d20SAndroid Build Coastguard Worker 	if (set_signal_handles())
761*2d543d20SAndroid Build Coastguard Worker 		return -1;
762*2d543d20SAndroid Build Coastguard Worker 
763*2d543d20SAndroid Build Coastguard Worker 	/* set fsuid to ruid */
764*2d543d20SAndroid Build Coastguard Worker 	/* Changing fsuid is usually required when user-specified directory is
765*2d543d20SAndroid Build Coastguard Worker 	 * on an NFS mount.  It's also desired to avoid leaking info about
766*2d543d20SAndroid Build Coastguard Worker 	 * existence of the files not accessible to the user. */
767*2d543d20SAndroid Build Coastguard Worker 	if (((uid_t)setfsuid(uid) != 0)   && (errno != 0)) {
768*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Error: unable to setfsuid %m\n"));
769*2d543d20SAndroid Build Coastguard Worker 
770*2d543d20SAndroid Build Coastguard Worker 		return -1;
771*2d543d20SAndroid Build Coastguard Worker 	}
772*2d543d20SAndroid Build Coastguard Worker 
773*2d543d20SAndroid Build Coastguard Worker 	/* verify homedir and tmpdir */
774*2d543d20SAndroid Build Coastguard Worker 	if (homedir_s && (
775*2d543d20SAndroid Build Coastguard Worker 		verify_directory(homedir_s, NULL, &st_homedir) < 0 ||
776*2d543d20SAndroid Build Coastguard Worker 		check_owner_uid(uid, homedir_s, &st_homedir))) return -1;
777*2d543d20SAndroid Build Coastguard Worker 	if (tmpdir_s && (
778*2d543d20SAndroid Build Coastguard Worker 		verify_directory(tmpdir_s, NULL, &st_tmpdir_s) < 0 ||
779*2d543d20SAndroid Build Coastguard Worker 		check_owner_uid(uid, tmpdir_s, &st_tmpdir_s))) return -1;
780*2d543d20SAndroid Build Coastguard Worker 	if (runuserdir_s && (
781*2d543d20SAndroid Build Coastguard Worker 		verify_directory(runuserdir_s, NULL, &st_runuserdir_s) < 0 ||
782*2d543d20SAndroid Build Coastguard Worker 		check_owner_uid(uid, runuserdir_s, &st_runuserdir_s))) return -1;
783*2d543d20SAndroid Build Coastguard Worker 
784*2d543d20SAndroid Build Coastguard Worker 	if ((uid_t)setfsuid(0) != uid) return -1;
785*2d543d20SAndroid Build Coastguard Worker 
786*2d543d20SAndroid Build Coastguard Worker 	/* create runtime tmpdir */
787*2d543d20SAndroid Build Coastguard Worker 	if (tmpdir_s && (tmpdir_r = create_tmpdir(tmpdir_s, &st_tmpdir_s,
788*2d543d20SAndroid Build Coastguard Worker 						  &st_tmpdir_r, pwd, execcon)) == NULL) {
789*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to create runtime temporary directory\n"));
790*2d543d20SAndroid Build Coastguard Worker 		return -1;
791*2d543d20SAndroid Build Coastguard Worker 	}
792*2d543d20SAndroid Build Coastguard Worker 	/* create runtime runuserdir */
793*2d543d20SAndroid Build Coastguard Worker 	if (runuserdir_s && (runuserdir_r = create_tmpdir(runuserdir_s, &st_runuserdir_s,
794*2d543d20SAndroid Build Coastguard Worker 						  &st_runuserdir_r, pwd, execcon)) == NULL) {
795*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to create runtime $XDG_RUNTIME_DIR directory\n"));
796*2d543d20SAndroid Build Coastguard Worker 		return -1;
797*2d543d20SAndroid Build Coastguard Worker 	}
798*2d543d20SAndroid Build Coastguard Worker 
799*2d543d20SAndroid Build Coastguard Worker 	/* spawn child process */
800*2d543d20SAndroid Build Coastguard Worker 	child = fork();
801*2d543d20SAndroid Build Coastguard Worker 	if (child == -1) {
802*2d543d20SAndroid Build Coastguard Worker 		perror(_("Unable to fork"));
803*2d543d20SAndroid Build Coastguard Worker 		goto err;
804*2d543d20SAndroid Build Coastguard Worker 	}
805*2d543d20SAndroid Build Coastguard Worker 
806*2d543d20SAndroid Build Coastguard Worker 	if (child == 0) {
807*2d543d20SAndroid Build Coastguard Worker 		char *display = NULL;
808*2d543d20SAndroid Build Coastguard Worker 		char *LANG = NULL;
809*2d543d20SAndroid Build Coastguard Worker 		char *RUNTIME_DIR = NULL;
810*2d543d20SAndroid Build Coastguard Worker 		char *XDG_SESSION_TYPE = NULL;
811*2d543d20SAndroid Build Coastguard Worker 		int rc = -1;
812*2d543d20SAndroid Build Coastguard Worker 		char *resolved_path = NULL;
813*2d543d20SAndroid Build Coastguard Worker 		char *wayland_path_s = NULL; /* /tmp/.../wayland-0 */
814*2d543d20SAndroid Build Coastguard Worker 		char *wayland_path = NULL; /* /run/user/UID/wayland-0 */
815*2d543d20SAndroid Build Coastguard Worker 		char *pipewire_path_s = NULL; /* /tmp/.../pipewire-0 */
816*2d543d20SAndroid Build Coastguard Worker 		char *pipewire_path = NULL; /* /run/user/UID/pipewire-0 */
817*2d543d20SAndroid Build Coastguard Worker 
818*2d543d20SAndroid Build Coastguard Worker 
819*2d543d20SAndroid Build Coastguard Worker 		if (unshare(CLONE_NEWNS) < 0) {
820*2d543d20SAndroid Build Coastguard Worker 			perror(_("Failed to unshare"));
821*2d543d20SAndroid Build Coastguard Worker 			goto childerr;
822*2d543d20SAndroid Build Coastguard Worker 		}
823*2d543d20SAndroid Build Coastguard Worker 
824*2d543d20SAndroid Build Coastguard Worker 		/* Remount / as SLAVE so that nothing mounted in the namespace
825*2d543d20SAndroid Build Coastguard Worker 		   shows up in the parent */
826*2d543d20SAndroid Build Coastguard Worker 		if (mount("none", "/", NULL, MS_SLAVE | MS_REC , NULL) < 0) {
827*2d543d20SAndroid Build Coastguard Worker 			perror(_("Failed to make / a SLAVE mountpoint\n"));
828*2d543d20SAndroid Build Coastguard Worker 			goto childerr;
829*2d543d20SAndroid Build Coastguard Worker 		}
830*2d543d20SAndroid Build Coastguard Worker 
831*2d543d20SAndroid Build Coastguard Worker 		/* assume fsuid==ruid after this point */
832*2d543d20SAndroid Build Coastguard Worker 		if ((uid_t)setfsuid(uid) != 0) goto childerr;
833*2d543d20SAndroid Build Coastguard Worker 
834*2d543d20SAndroid Build Coastguard Worker 		resolved_path = realpath(pwd->pw_dir,NULL);
835*2d543d20SAndroid Build Coastguard Worker 		if (! resolved_path) goto childerr;
836*2d543d20SAndroid Build Coastguard Worker 
837*2d543d20SAndroid Build Coastguard Worker 		if (verify_directory(resolved_path, NULL, &st_curhomedir) < 0)
838*2d543d20SAndroid Build Coastguard Worker 			goto childerr;
839*2d543d20SAndroid Build Coastguard Worker 		if (check_owner_uid(uid, resolved_path, &st_curhomedir) < 0)
840*2d543d20SAndroid Build Coastguard Worker 			goto childerr;
841*2d543d20SAndroid Build Coastguard Worker 
842*2d543d20SAndroid Build Coastguard Worker 		if ((RUNTIME_DIR = getenv("XDG_RUNTIME_DIR")) != NULL) {
843*2d543d20SAndroid Build Coastguard Worker 			if ((RUNTIME_DIR = strdup(RUNTIME_DIR)) == NULL) {
844*2d543d20SAndroid Build Coastguard Worker 				perror(_("Out of memory"));
845*2d543d20SAndroid Build Coastguard Worker 				goto childerr;
846*2d543d20SAndroid Build Coastguard Worker 			}
847*2d543d20SAndroid Build Coastguard Worker 		} else {
848*2d543d20SAndroid Build Coastguard Worker 			if (asprintf(&RUNTIME_DIR, "/run/user/%d", uid) == -1) {
849*2d543d20SAndroid Build Coastguard Worker 				perror(_("Out of memory\n"));
850*2d543d20SAndroid Build Coastguard Worker 				goto childerr;
851*2d543d20SAndroid Build Coastguard Worker 			}
852*2d543d20SAndroid Build Coastguard Worker 		}
853*2d543d20SAndroid Build Coastguard Worker 
854*2d543d20SAndroid Build Coastguard Worker 		if ((XDG_SESSION_TYPE = getenv("XDG_SESSION_TYPE")) != NULL) {
855*2d543d20SAndroid Build Coastguard Worker 			if ((XDG_SESSION_TYPE = strdup(XDG_SESSION_TYPE)) == NULL) {
856*2d543d20SAndroid Build Coastguard Worker 				perror(_("Out of memory"));
857*2d543d20SAndroid Build Coastguard Worker 				goto childerr;
858*2d543d20SAndroid Build Coastguard Worker 			}
859*2d543d20SAndroid Build Coastguard Worker 		}
860*2d543d20SAndroid Build Coastguard Worker 
861*2d543d20SAndroid Build Coastguard Worker 		if (runuserdir_s && (wayland_display || pipewire_socket)) {
862*2d543d20SAndroid Build Coastguard Worker 			if (wayland_display) {
863*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&wayland_path_s, "%s/%s", runuserdir_s, wayland_display) == -1) {
864*2d543d20SAndroid Build Coastguard Worker 					perror(_("Out of memory"));
865*2d543d20SAndroid Build Coastguard Worker 					goto childerr;
866*2d543d20SAndroid Build Coastguard Worker 				}
867*2d543d20SAndroid Build Coastguard Worker 
868*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&wayland_path, "%s/%s", RUNTIME_DIR, wayland_display) == -1) {
869*2d543d20SAndroid Build Coastguard Worker 					perror(_("Out of memory"));
870*2d543d20SAndroid Build Coastguard Worker 					goto childerr;
871*2d543d20SAndroid Build Coastguard Worker 				}
872*2d543d20SAndroid Build Coastguard Worker 
873*2d543d20SAndroid Build Coastguard Worker 				if (seunshare_mount_file(wayland_path, wayland_path_s) == -1)
874*2d543d20SAndroid Build Coastguard Worker 					goto childerr;
875*2d543d20SAndroid Build Coastguard Worker 			}
876*2d543d20SAndroid Build Coastguard Worker 
877*2d543d20SAndroid Build Coastguard Worker 			if (pipewire_socket) {
878*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&pipewire_path_s, "%s/%s", runuserdir_s, pipewire_socket) == -1) {
879*2d543d20SAndroid Build Coastguard Worker 					perror(_("Out of memory"));
880*2d543d20SAndroid Build Coastguard Worker 					goto childerr;
881*2d543d20SAndroid Build Coastguard Worker 				}
882*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&pipewire_path, "%s/pipewire-0", RUNTIME_DIR) == -1) {
883*2d543d20SAndroid Build Coastguard Worker 					perror(_("Out of memory"));
884*2d543d20SAndroid Build Coastguard Worker 					goto childerr;
885*2d543d20SAndroid Build Coastguard Worker 				}
886*2d543d20SAndroid Build Coastguard Worker 				seunshare_mount_file(pipewire_path, pipewire_path_s);
887*2d543d20SAndroid Build Coastguard Worker 			}
888*2d543d20SAndroid Build Coastguard Worker 		}
889*2d543d20SAndroid Build Coastguard Worker 
890*2d543d20SAndroid Build Coastguard Worker 		/* mount homedir, runuserdir and tmpdir, in this order */
891*2d543d20SAndroid Build Coastguard Worker 		if (runuserdir_s &&	seunshare_mount(runuserdir_s, RUNTIME_DIR,
892*2d543d20SAndroid Build Coastguard Worker 			&st_runuserdir_s) != 0) goto childerr;
893*2d543d20SAndroid Build Coastguard Worker 		if (homedir_s && seunshare_mount(homedir_s, resolved_path,
894*2d543d20SAndroid Build Coastguard Worker 			&st_homedir) != 0) goto childerr;
895*2d543d20SAndroid Build Coastguard Worker 		if (tmpdir_s &&	seunshare_mount(tmpdir_r, "/tmp",
896*2d543d20SAndroid Build Coastguard Worker 			&st_tmpdir_r) != 0) goto childerr;
897*2d543d20SAndroid Build Coastguard Worker 
898*2d543d20SAndroid Build Coastguard Worker 		if (drop_privs(uid) != 0) goto childerr;
899*2d543d20SAndroid Build Coastguard Worker 
900*2d543d20SAndroid Build Coastguard Worker 		/* construct a new environment */
901*2d543d20SAndroid Build Coastguard Worker 
902*2d543d20SAndroid Build Coastguard Worker 		if (XDG_SESSION_TYPE && strcmp(XDG_SESSION_TYPE, "wayland") == 0) {
903*2d543d20SAndroid Build Coastguard Worker 			if (wayland_display == NULL && (wayland_display = getenv("WAYLAND_DISPLAY")) != NULL) {
904*2d543d20SAndroid Build Coastguard Worker 				if ((wayland_display = strdup(wayland_display)) == NULL) {
905*2d543d20SAndroid Build Coastguard Worker 					perror(_("Out of memory"));
906*2d543d20SAndroid Build Coastguard Worker 					goto childerr;
907*2d543d20SAndroid Build Coastguard Worker 				}
908*2d543d20SAndroid Build Coastguard Worker 			}
909*2d543d20SAndroid Build Coastguard Worker 		}
910*2d543d20SAndroid Build Coastguard Worker 		else {
911*2d543d20SAndroid Build Coastguard Worker 			if ((display = getenv("DISPLAY")) != NULL) {
912*2d543d20SAndroid Build Coastguard Worker 				if ((display = strdup(display)) == NULL) {
913*2d543d20SAndroid Build Coastguard Worker 					perror(_("Out of memory"));
914*2d543d20SAndroid Build Coastguard Worker 					goto childerr;
915*2d543d20SAndroid Build Coastguard Worker 				}
916*2d543d20SAndroid Build Coastguard Worker 			}
917*2d543d20SAndroid Build Coastguard Worker 		}
918*2d543d20SAndroid Build Coastguard Worker 
919*2d543d20SAndroid Build Coastguard Worker 		/* construct a new environment */
920*2d543d20SAndroid Build Coastguard Worker 		if ((LANG = getenv("LANG")) != NULL) {
921*2d543d20SAndroid Build Coastguard Worker 			if ((LANG = strdup(LANG)) == NULL) {
922*2d543d20SAndroid Build Coastguard Worker 				perror(_("Out of memory"));
923*2d543d20SAndroid Build Coastguard Worker 				goto childerr;
924*2d543d20SAndroid Build Coastguard Worker 			}
925*2d543d20SAndroid Build Coastguard Worker 		}
926*2d543d20SAndroid Build Coastguard Worker 
927*2d543d20SAndroid Build Coastguard Worker 		if ((rc = clearenv()) != 0) {
928*2d543d20SAndroid Build Coastguard Worker 			perror(_("Failed to clear environment"));
929*2d543d20SAndroid Build Coastguard Worker 			goto childerr;
930*2d543d20SAndroid Build Coastguard Worker 		}
931*2d543d20SAndroid Build Coastguard Worker 		if (display) {
932*2d543d20SAndroid Build Coastguard Worker 			rc |= setenv("DISPLAY", display, 1);
933*2d543d20SAndroid Build Coastguard Worker 		}
934*2d543d20SAndroid Build Coastguard Worker 		if (wayland_display) {
935*2d543d20SAndroid Build Coastguard Worker 			rc |= setenv("WAYLAND_DISPLAY", wayland_display, 1);
936*2d543d20SAndroid Build Coastguard Worker 		}
937*2d543d20SAndroid Build Coastguard Worker 
938*2d543d20SAndroid Build Coastguard Worker 		if (XDG_SESSION_TYPE)
939*2d543d20SAndroid Build Coastguard Worker 			rc |= setenv("XDG_SESSION_TYPE", XDG_SESSION_TYPE, 1);
940*2d543d20SAndroid Build Coastguard Worker 
941*2d543d20SAndroid Build Coastguard Worker 		if (LANG)
942*2d543d20SAndroid Build Coastguard Worker 			rc |= setenv("LANG", LANG, 1);
943*2d543d20SAndroid Build Coastguard Worker 		if (RUNTIME_DIR)
944*2d543d20SAndroid Build Coastguard Worker 			rc |= setenv("XDG_RUNTIME_DIR", RUNTIME_DIR, 1);
945*2d543d20SAndroid Build Coastguard Worker 		rc |= setenv("HOME", pwd->pw_dir, 1);
946*2d543d20SAndroid Build Coastguard Worker 		rc |= setenv("SHELL", pwd->pw_shell, 1);
947*2d543d20SAndroid Build Coastguard Worker 		rc |= setenv("USER", pwd->pw_name, 1);
948*2d543d20SAndroid Build Coastguard Worker 		rc |= setenv("LOGNAME", pwd->pw_name, 1);
949*2d543d20SAndroid Build Coastguard Worker 		rc |= setenv("PATH", DEFAULT_PATH, 1);
950*2d543d20SAndroid Build Coastguard Worker 		if (rc != 0) {
951*2d543d20SAndroid Build Coastguard Worker 			fprintf(stderr, _("Failed to construct environment\n"));
952*2d543d20SAndroid Build Coastguard Worker 			goto childerr;
953*2d543d20SAndroid Build Coastguard Worker 		}
954*2d543d20SAndroid Build Coastguard Worker 
955*2d543d20SAndroid Build Coastguard Worker 		if (chdir(pwd->pw_dir)) {
956*2d543d20SAndroid Build Coastguard Worker 			perror(_("Failed to change dir to homedir"));
957*2d543d20SAndroid Build Coastguard Worker 			goto childerr;
958*2d543d20SAndroid Build Coastguard Worker 		}
959*2d543d20SAndroid Build Coastguard Worker 		setsid();
960*2d543d20SAndroid Build Coastguard Worker 
961*2d543d20SAndroid Build Coastguard Worker 		/* selinux context */
962*2d543d20SAndroid Build Coastguard Worker 		if (execcon) {
963*2d543d20SAndroid Build Coastguard Worker 			/* try dyntransition, since no_new_privs can interfere
964*2d543d20SAndroid Build Coastguard Worker 			 * with setexeccon */
965*2d543d20SAndroid Build Coastguard Worker 			if (setcon(execcon) != 0) {
966*2d543d20SAndroid Build Coastguard Worker 				/* failed; fall back to setexeccon */
967*2d543d20SAndroid Build Coastguard Worker 				if (setexeccon(execcon) != 0) {
968*2d543d20SAndroid Build Coastguard Worker 					fprintf(stderr, _("Could not set exec context to %s. %s\n"), execcon, strerror(errno));
969*2d543d20SAndroid Build Coastguard Worker 					goto childerr;
970*2d543d20SAndroid Build Coastguard Worker 				}
971*2d543d20SAndroid Build Coastguard Worker 			}
972*2d543d20SAndroid Build Coastguard Worker 		}
973*2d543d20SAndroid Build Coastguard Worker 
974*2d543d20SAndroid Build Coastguard Worker 		execv(argv[optind], argv + optind);
975*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, _("Failed to execute command %s: %s\n"), argv[optind], strerror(errno));
976*2d543d20SAndroid Build Coastguard Worker childerr:
977*2d543d20SAndroid Build Coastguard Worker 		free(resolved_path);
978*2d543d20SAndroid Build Coastguard Worker 		free(wayland_path);
979*2d543d20SAndroid Build Coastguard Worker 		free(wayland_path_s);
980*2d543d20SAndroid Build Coastguard Worker 		free(pipewire_path);
981*2d543d20SAndroid Build Coastguard Worker 		free(pipewire_path_s);
982*2d543d20SAndroid Build Coastguard Worker 		free(display);
983*2d543d20SAndroid Build Coastguard Worker 		free(LANG);
984*2d543d20SAndroid Build Coastguard Worker 		free(RUNTIME_DIR);
985*2d543d20SAndroid Build Coastguard Worker 		free(XDG_SESSION_TYPE);
986*2d543d20SAndroid Build Coastguard Worker 		exit(-1);
987*2d543d20SAndroid Build Coastguard Worker 	}
988*2d543d20SAndroid Build Coastguard Worker 
989*2d543d20SAndroid Build Coastguard Worker 	drop_caps();
990*2d543d20SAndroid Build Coastguard Worker 
991*2d543d20SAndroid Build Coastguard Worker 	/* parent waits for child exit to do the cleanup */
992*2d543d20SAndroid Build Coastguard Worker 	waitpid(child, &status, 0);
993*2d543d20SAndroid Build Coastguard Worker 	status_to_retval(status, status);
994*2d543d20SAndroid Build Coastguard Worker 
995*2d543d20SAndroid Build Coastguard Worker 	/* Make sure all child processes exit */
996*2d543d20SAndroid Build Coastguard Worker 	kill(-child,SIGTERM);
997*2d543d20SAndroid Build Coastguard Worker 
998*2d543d20SAndroid Build Coastguard Worker 	if (execcon && kill_all)
999*2d543d20SAndroid Build Coastguard Worker 		killall(execcon);
1000*2d543d20SAndroid Build Coastguard Worker 
1001*2d543d20SAndroid Build Coastguard Worker 	if (tmpdir_r) cleanup_tmpdir(tmpdir_r, tmpdir_s, pwd, 1);
1002*2d543d20SAndroid Build Coastguard Worker 
1003*2d543d20SAndroid Build Coastguard Worker err:
1004*2d543d20SAndroid Build Coastguard Worker 	free(tmpdir_r);
1005*2d543d20SAndroid Build Coastguard Worker 	return status;
1006*2d543d20SAndroid Build Coastguard Worker }
1007