xref: /aosp_15_r20/external/selinux/restorecond/watch.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker #define _GNU_SOURCE
2*2d543d20SAndroid Build Coastguard Worker #include <sys/inotify.h>
3*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
4*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
5*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
6*2d543d20SAndroid Build Coastguard Worker #include <string.h>
7*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
8*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
9*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
10*2d543d20SAndroid Build Coastguard Worker #include <syslog.h>
11*2d543d20SAndroid Build Coastguard Worker #include "restore.h"
12*2d543d20SAndroid Build Coastguard Worker #include <glob.h>
13*2d543d20SAndroid Build Coastguard Worker #include <libgen.h>
14*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
15*2d543d20SAndroid Build Coastguard Worker #include <string.h>
16*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
17*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
18*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
19*2d543d20SAndroid Build Coastguard Worker #include "restorecond.h"
20*2d543d20SAndroid Build Coastguard Worker #include "stringslist.h"
21*2d543d20SAndroid Build Coastguard Worker #include "utmpwatcher.h"
22*2d543d20SAndroid Build Coastguard Worker 
23*2d543d20SAndroid Build Coastguard Worker #ifndef GLOB_TILDE
24*2d543d20SAndroid Build Coastguard Worker #define GLOB_TILDE 0
25*2d543d20SAndroid Build Coastguard Worker #endif
26*2d543d20SAndroid Build Coastguard Worker 
27*2d543d20SAndroid Build Coastguard Worker #ifndef GLOB_BRACE
28*2d543d20SAndroid Build Coastguard Worker #define GLOB_BRACE 0
29*2d543d20SAndroid Build Coastguard Worker #endif
30*2d543d20SAndroid Build Coastguard Worker 
31*2d543d20SAndroid Build Coastguard Worker /* size of the event structure, not counting name */
32*2d543d20SAndroid Build Coastguard Worker #define EVENT_SIZE  (sizeof (struct inotify_event))
33*2d543d20SAndroid Build Coastguard Worker /* reasonable guess as to size of 1024 events */
34*2d543d20SAndroid Build Coastguard Worker #define BUF_LEN        (1024 * (EVENT_SIZE + 16))
35*2d543d20SAndroid Build Coastguard Worker 
36*2d543d20SAndroid Build Coastguard Worker struct watchList {
37*2d543d20SAndroid Build Coastguard Worker 	struct watchList *next;
38*2d543d20SAndroid Build Coastguard Worker 	int wd;
39*2d543d20SAndroid Build Coastguard Worker 	char *dir;
40*2d543d20SAndroid Build Coastguard Worker 	struct stringsList *files;
41*2d543d20SAndroid Build Coastguard Worker };
42*2d543d20SAndroid Build Coastguard Worker struct watchList *firstDir = NULL;
43*2d543d20SAndroid Build Coastguard Worker 
watch_list_isempty(void)44*2d543d20SAndroid Build Coastguard Worker int watch_list_isempty(void) {
45*2d543d20SAndroid Build Coastguard Worker 	return firstDir == NULL;
46*2d543d20SAndroid Build Coastguard Worker }
47*2d543d20SAndroid Build Coastguard Worker 
watch_list_add(int fd,const char * path)48*2d543d20SAndroid Build Coastguard Worker void watch_list_add(int fd, const char *path)
49*2d543d20SAndroid Build Coastguard Worker {
50*2d543d20SAndroid Build Coastguard Worker 	struct watchList *ptr = NULL;
51*2d543d20SAndroid Build Coastguard Worker 	size_t i = 0;
52*2d543d20SAndroid Build Coastguard Worker 	struct watchList *prev = NULL;
53*2d543d20SAndroid Build Coastguard Worker 	glob_t globbuf;
54*2d543d20SAndroid Build Coastguard Worker 	char *x = strdup(path);
55*2d543d20SAndroid Build Coastguard Worker 	if (!x) exitApp("Out of Memory");
56*2d543d20SAndroid Build Coastguard Worker 	char *file = basename(x);
57*2d543d20SAndroid Build Coastguard Worker 	char *dir = dirname(x);
58*2d543d20SAndroid Build Coastguard Worker 	ptr = firstDir;
59*2d543d20SAndroid Build Coastguard Worker 	int len;
60*2d543d20SAndroid Build Coastguard Worker 
61*2d543d20SAndroid Build Coastguard Worker 	globbuf.gl_offs = 1;
62*2d543d20SAndroid Build Coastguard Worker 	if (glob(path,
63*2d543d20SAndroid Build Coastguard Worker 		 GLOB_TILDE | GLOB_PERIOD,
64*2d543d20SAndroid Build Coastguard Worker 		 NULL,
65*2d543d20SAndroid Build Coastguard Worker 		 &globbuf) >= 0) {
66*2d543d20SAndroid Build Coastguard Worker 		for (i = 0; i < globbuf.gl_pathc; i++) {
67*2d543d20SAndroid Build Coastguard Worker 			len = strlen(globbuf.gl_pathv[i]) - 2;
68*2d543d20SAndroid Build Coastguard Worker 			if (len > 0 &&
69*2d543d20SAndroid Build Coastguard Worker 			    strcmp(&globbuf.gl_pathv[i][len--], "/.") == 0)
70*2d543d20SAndroid Build Coastguard Worker 				continue;
71*2d543d20SAndroid Build Coastguard Worker 			if (len > 0 &&
72*2d543d20SAndroid Build Coastguard Worker 			    strcmp(&globbuf.gl_pathv[i][len], "/..") == 0)
73*2d543d20SAndroid Build Coastguard Worker 				continue;
74*2d543d20SAndroid Build Coastguard Worker 			selinux_restorecon(globbuf.gl_pathv[i],
75*2d543d20SAndroid Build Coastguard Worker 					   r_opts.restorecon_flags);
76*2d543d20SAndroid Build Coastguard Worker 		}
77*2d543d20SAndroid Build Coastguard Worker 		globfree(&globbuf);
78*2d543d20SAndroid Build Coastguard Worker 	}
79*2d543d20SAndroid Build Coastguard Worker 
80*2d543d20SAndroid Build Coastguard Worker 	while (ptr != NULL) {
81*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(dir, ptr->dir) == 0) {
82*2d543d20SAndroid Build Coastguard Worker 			strings_list_add(&ptr->files, file);
83*2d543d20SAndroid Build Coastguard Worker 			goto end;
84*2d543d20SAndroid Build Coastguard Worker 		}
85*2d543d20SAndroid Build Coastguard Worker 		prev = ptr;
86*2d543d20SAndroid Build Coastguard Worker 		ptr = ptr->next;
87*2d543d20SAndroid Build Coastguard Worker 	}
88*2d543d20SAndroid Build Coastguard Worker 	ptr = calloc(1, sizeof(struct watchList));
89*2d543d20SAndroid Build Coastguard Worker 
90*2d543d20SAndroid Build Coastguard Worker 	if (!ptr) exitApp("Out of Memory");
91*2d543d20SAndroid Build Coastguard Worker 
92*2d543d20SAndroid Build Coastguard Worker 	ptr->wd = inotify_add_watch(fd, dir, IN_CREATE | IN_MOVED_TO);
93*2d543d20SAndroid Build Coastguard Worker 	if (ptr->wd == -1) {
94*2d543d20SAndroid Build Coastguard Worker 		free(ptr);
95*2d543d20SAndroid Build Coastguard Worker 		if (! run_as_user)
96*2d543d20SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "Unable to watch (%s) %s\n",
97*2d543d20SAndroid Build Coastguard Worker 			       path, strerror(errno));
98*2d543d20SAndroid Build Coastguard Worker 		goto end;
99*2d543d20SAndroid Build Coastguard Worker 	}
100*2d543d20SAndroid Build Coastguard Worker 
101*2d543d20SAndroid Build Coastguard Worker 	ptr->dir = strdup(dir);
102*2d543d20SAndroid Build Coastguard Worker 	if (!ptr->dir)
103*2d543d20SAndroid Build Coastguard Worker 		exitApp("Out of Memory");
104*2d543d20SAndroid Build Coastguard Worker 
105*2d543d20SAndroid Build Coastguard Worker 	strings_list_add(&ptr->files, file);
106*2d543d20SAndroid Build Coastguard Worker 	if (prev)
107*2d543d20SAndroid Build Coastguard Worker 		prev->next = ptr;
108*2d543d20SAndroid Build Coastguard Worker 	else
109*2d543d20SAndroid Build Coastguard Worker 		firstDir = ptr;
110*2d543d20SAndroid Build Coastguard Worker 
111*2d543d20SAndroid Build Coastguard Worker 	if (debug_mode)
112*2d543d20SAndroid Build Coastguard Worker 		printf("%d: Dir=%s, File=%s\n", ptr->wd, ptr->dir, file);
113*2d543d20SAndroid Build Coastguard Worker 
114*2d543d20SAndroid Build Coastguard Worker end:
115*2d543d20SAndroid Build Coastguard Worker 	free(x);
116*2d543d20SAndroid Build Coastguard Worker 	return;
117*2d543d20SAndroid Build Coastguard Worker }
118*2d543d20SAndroid Build Coastguard Worker 
119*2d543d20SAndroid Build Coastguard Worker /*
120*2d543d20SAndroid Build Coastguard Worker    A file was in a direcroty has been created. This function checks to
121*2d543d20SAndroid Build Coastguard Worker    see if it is one that we are watching.
122*2d543d20SAndroid Build Coastguard Worker */
123*2d543d20SAndroid Build Coastguard Worker 
watch_list_find(int wd,const char * file)124*2d543d20SAndroid Build Coastguard Worker int watch_list_find(int wd, const char *file)
125*2d543d20SAndroid Build Coastguard Worker {
126*2d543d20SAndroid Build Coastguard Worker 	struct watchList *ptr = NULL;
127*2d543d20SAndroid Build Coastguard Worker 
128*2d543d20SAndroid Build Coastguard Worker 	ptr = firstDir;
129*2d543d20SAndroid Build Coastguard Worker 
130*2d543d20SAndroid Build Coastguard Worker 	if (debug_mode)
131*2d543d20SAndroid Build Coastguard Worker 		printf("%d: File=%s\n", wd, file);
132*2d543d20SAndroid Build Coastguard Worker 	while (ptr != NULL) {
133*2d543d20SAndroid Build Coastguard Worker 		if (ptr->wd == wd) {
134*2d543d20SAndroid Build Coastguard Worker 			int exact=0;
135*2d543d20SAndroid Build Coastguard Worker 			if (strings_list_find(ptr->files, file, &exact) == 0) {
136*2d543d20SAndroid Build Coastguard Worker 				char *path = NULL;
137*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&path, "%s/%s", ptr->dir, file) <
138*2d543d20SAndroid Build Coastguard Worker 				    0)
139*2d543d20SAndroid Build Coastguard Worker 					exitApp("Error allocating memory.");
140*2d543d20SAndroid Build Coastguard Worker 
141*2d543d20SAndroid Build Coastguard Worker 				selinux_restorecon(path,
142*2d543d20SAndroid Build Coastguard Worker 						   r_opts.restorecon_flags);
143*2d543d20SAndroid Build Coastguard Worker 				free(path);
144*2d543d20SAndroid Build Coastguard Worker 				return 0;
145*2d543d20SAndroid Build Coastguard Worker 			}
146*2d543d20SAndroid Build Coastguard Worker 			if (debug_mode)
147*2d543d20SAndroid Build Coastguard Worker 				strings_list_print(ptr->files);
148*2d543d20SAndroid Build Coastguard Worker 
149*2d543d20SAndroid Build Coastguard Worker 			/* Not found in this directory */
150*2d543d20SAndroid Build Coastguard Worker 			return -1;
151*2d543d20SAndroid Build Coastguard Worker 		}
152*2d543d20SAndroid Build Coastguard Worker 		ptr = ptr->next;
153*2d543d20SAndroid Build Coastguard Worker 	}
154*2d543d20SAndroid Build Coastguard Worker 	/* Did not find a directory */
155*2d543d20SAndroid Build Coastguard Worker 	return -1;
156*2d543d20SAndroid Build Coastguard Worker }
157*2d543d20SAndroid Build Coastguard Worker 
watch_list_free(int fd)158*2d543d20SAndroid Build Coastguard Worker void watch_list_free(int fd)
159*2d543d20SAndroid Build Coastguard Worker {
160*2d543d20SAndroid Build Coastguard Worker 	struct watchList *ptr = NULL;
161*2d543d20SAndroid Build Coastguard Worker 	struct watchList *prev = NULL;
162*2d543d20SAndroid Build Coastguard Worker 	ptr = firstDir;
163*2d543d20SAndroid Build Coastguard Worker 
164*2d543d20SAndroid Build Coastguard Worker 	while (ptr != NULL) {
165*2d543d20SAndroid Build Coastguard Worker 		inotify_rm_watch(fd, ptr->wd);
166*2d543d20SAndroid Build Coastguard Worker 		strings_list_free(ptr->files);
167*2d543d20SAndroid Build Coastguard Worker 		free(ptr->dir);
168*2d543d20SAndroid Build Coastguard Worker 		prev = ptr;
169*2d543d20SAndroid Build Coastguard Worker 		ptr = ptr->next;
170*2d543d20SAndroid Build Coastguard Worker 		free(prev);
171*2d543d20SAndroid Build Coastguard Worker 	}
172*2d543d20SAndroid Build Coastguard Worker 	firstDir = NULL;
173*2d543d20SAndroid Build Coastguard Worker }
174*2d543d20SAndroid Build Coastguard Worker 
175*2d543d20SAndroid Build Coastguard Worker /*
176*2d543d20SAndroid Build Coastguard Worker    Inotify watch loop
177*2d543d20SAndroid Build Coastguard Worker */
watch(int fd,const char * watch_file)178*2d543d20SAndroid Build Coastguard Worker int watch(int fd, const char *watch_file)
179*2d543d20SAndroid Build Coastguard Worker {
180*2d543d20SAndroid Build Coastguard Worker 	char buf[BUF_LEN];
181*2d543d20SAndroid Build Coastguard Worker 	int len, i = 0;
182*2d543d20SAndroid Build Coastguard Worker 	if (firstDir == NULL) return 0;
183*2d543d20SAndroid Build Coastguard Worker 
184*2d543d20SAndroid Build Coastguard Worker 	len = read(fd, buf, BUF_LEN);
185*2d543d20SAndroid Build Coastguard Worker 	if (len < 0) {
186*2d543d20SAndroid Build Coastguard Worker 		if (terminate == 0) {
187*2d543d20SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "Read error (%s)", strerror(errno));
188*2d543d20SAndroid Build Coastguard Worker 			return 0;
189*2d543d20SAndroid Build Coastguard Worker 		}
190*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_INFO, "terminated");
191*2d543d20SAndroid Build Coastguard Worker 		return -1;
192*2d543d20SAndroid Build Coastguard Worker 	} else if (!len)
193*2d543d20SAndroid Build Coastguard Worker 		/* BUF_LEN too small? */
194*2d543d20SAndroid Build Coastguard Worker 		return -1;
195*2d543d20SAndroid Build Coastguard Worker 	while (i < len) {
196*2d543d20SAndroid Build Coastguard Worker 		struct inotify_event *event;
197*2d543d20SAndroid Build Coastguard Worker 		event = (struct inotify_event *)&buf[i];
198*2d543d20SAndroid Build Coastguard Worker 		if (debug_mode)
199*2d543d20SAndroid Build Coastguard Worker 			printf("wd=%d mask=%u cookie=%u len=%u\n",
200*2d543d20SAndroid Build Coastguard Worker 			       event->wd, event->mask,
201*2d543d20SAndroid Build Coastguard Worker 			       event->cookie, event->len);
202*2d543d20SAndroid Build Coastguard Worker 		if (event->mask & ~IN_IGNORED) {
203*2d543d20SAndroid Build Coastguard Worker 			if (event->wd == master_wd)
204*2d543d20SAndroid Build Coastguard Worker 				read_config(fd, watch_file);
205*2d543d20SAndroid Build Coastguard Worker 			else {
206*2d543d20SAndroid Build Coastguard Worker 				switch (utmpwatcher_handle(fd, event->wd)) {
207*2d543d20SAndroid Build Coastguard Worker 				case -1:	/* Message was not for utmpwatcher */
208*2d543d20SAndroid Build Coastguard Worker 					if (event->len)
209*2d543d20SAndroid Build Coastguard Worker 						watch_list_find(event->wd, event->name);
210*2d543d20SAndroid Build Coastguard Worker 					break;
211*2d543d20SAndroid Build Coastguard Worker 				case 1:	/* utmp has changed need to reload */
212*2d543d20SAndroid Build Coastguard Worker 					read_config(fd, watch_file);
213*2d543d20SAndroid Build Coastguard Worker 					break;
214*2d543d20SAndroid Build Coastguard Worker 
215*2d543d20SAndroid Build Coastguard Worker 				default:	/* No users logged in or out */
216*2d543d20SAndroid Build Coastguard Worker 					break;
217*2d543d20SAndroid Build Coastguard Worker 				}
218*2d543d20SAndroid Build Coastguard Worker 			}
219*2d543d20SAndroid Build Coastguard Worker 		}
220*2d543d20SAndroid Build Coastguard Worker 
221*2d543d20SAndroid Build Coastguard Worker 		i += EVENT_SIZE + event->len;
222*2d543d20SAndroid Build Coastguard Worker 	}
223*2d543d20SAndroid Build Coastguard Worker 	return 0;
224*2d543d20SAndroid Build Coastguard Worker }
225*2d543d20SAndroid Build Coastguard Worker 
process_config(int fd,FILE * cfg)226*2d543d20SAndroid Build Coastguard Worker static void process_config(int fd, FILE * cfg)
227*2d543d20SAndroid Build Coastguard Worker {
228*2d543d20SAndroid Build Coastguard Worker 	char *line_buf = NULL;
229*2d543d20SAndroid Build Coastguard Worker 	size_t len = 0;
230*2d543d20SAndroid Build Coastguard Worker 
231*2d543d20SAndroid Build Coastguard Worker 	while (getline(&line_buf, &len, cfg) > 0) {
232*2d543d20SAndroid Build Coastguard Worker 		char *buffer = line_buf;
233*2d543d20SAndroid Build Coastguard Worker 		while (isspace(*buffer))
234*2d543d20SAndroid Build Coastguard Worker 			buffer++;
235*2d543d20SAndroid Build Coastguard Worker 		if (buffer[0] == '#')
236*2d543d20SAndroid Build Coastguard Worker 			continue;
237*2d543d20SAndroid Build Coastguard Worker 		int l = strlen(buffer) - 1;
238*2d543d20SAndroid Build Coastguard Worker 		if (l <= 0)
239*2d543d20SAndroid Build Coastguard Worker 			continue;
240*2d543d20SAndroid Build Coastguard Worker 		buffer[l] = 0;
241*2d543d20SAndroid Build Coastguard Worker 		if (buffer[0] == '~') {
242*2d543d20SAndroid Build Coastguard Worker 			if (run_as_user) {
243*2d543d20SAndroid Build Coastguard Worker 				char *ptr=NULL;
244*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&ptr, "%s%s", homedir, &buffer[1]) < 0)
245*2d543d20SAndroid Build Coastguard Worker 					exitApp("Error allocating memory.");
246*2d543d20SAndroid Build Coastguard Worker 
247*2d543d20SAndroid Build Coastguard Worker 				watch_list_add(fd, ptr);
248*2d543d20SAndroid Build Coastguard Worker 				free(ptr);
249*2d543d20SAndroid Build Coastguard Worker 			} else {
250*2d543d20SAndroid Build Coastguard Worker 				utmpwatcher_add(fd, &buffer[1]);
251*2d543d20SAndroid Build Coastguard Worker 			}
252*2d543d20SAndroid Build Coastguard Worker 		} else {
253*2d543d20SAndroid Build Coastguard Worker 			watch_list_add(fd, buffer);
254*2d543d20SAndroid Build Coastguard Worker 		}
255*2d543d20SAndroid Build Coastguard Worker 	}
256*2d543d20SAndroid Build Coastguard Worker 	free(line_buf);
257*2d543d20SAndroid Build Coastguard Worker }
258*2d543d20SAndroid Build Coastguard Worker 
259*2d543d20SAndroid Build Coastguard Worker /*
260*2d543d20SAndroid Build Coastguard Worker    Read config file ignoring Comment lines
261*2d543d20SAndroid Build Coastguard Worker    Files specified one per line.  Files with "~" will be expanded to the logged in users
262*2d543d20SAndroid Build Coastguard Worker    homedirs.
263*2d543d20SAndroid Build Coastguard Worker */
264*2d543d20SAndroid Build Coastguard Worker 
read_config(int fd,const char * watch_file_path)265*2d543d20SAndroid Build Coastguard Worker void read_config(int fd, const char *watch_file_path)
266*2d543d20SAndroid Build Coastguard Worker {
267*2d543d20SAndroid Build Coastguard Worker 
268*2d543d20SAndroid Build Coastguard Worker 	FILE *cfg = NULL;
269*2d543d20SAndroid Build Coastguard Worker 	if (debug_mode)
270*2d543d20SAndroid Build Coastguard Worker 		printf("Read Config\n");
271*2d543d20SAndroid Build Coastguard Worker 
272*2d543d20SAndroid Build Coastguard Worker 	watch_list_free(fd);
273*2d543d20SAndroid Build Coastguard Worker 
274*2d543d20SAndroid Build Coastguard Worker 	cfg = fopen(watch_file_path, "r");
275*2d543d20SAndroid Build Coastguard Worker 	if (!cfg){
276*2d543d20SAndroid Build Coastguard Worker 		perror(watch_file_path);
277*2d543d20SAndroid Build Coastguard Worker 		exitApp("Error reading config file");
278*2d543d20SAndroid Build Coastguard Worker 	}
279*2d543d20SAndroid Build Coastguard Worker 	process_config(fd, cfg);
280*2d543d20SAndroid Build Coastguard Worker 	fclose(cfg);
281*2d543d20SAndroid Build Coastguard Worker 
282*2d543d20SAndroid Build Coastguard Worker 	inotify_rm_watch(fd, master_wd);
283*2d543d20SAndroid Build Coastguard Worker 	master_wd =
284*2d543d20SAndroid Build Coastguard Worker 	    inotify_add_watch(fd, watch_file_path, IN_MOVED_FROM | IN_MODIFY);
285*2d543d20SAndroid Build Coastguard Worker 	if (master_wd == -1)
286*2d543d20SAndroid Build Coastguard Worker 		exitApp("Error watching config file.");
287*2d543d20SAndroid Build Coastguard Worker }
288