1 /* direvent - directory content watcher daemon
2    Copyright (C) 2012-2016 Sergey Poznyakoff
3 
4    Direvent is free software; you can redistribute it and/or modify it
5    under the terms of the GNU General Public License as published by the
6    Free Software Foundation; either version 3 of the License, or (at your
7    option) any later version.
8 
9    Direvent is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License along
15    with direvent. If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include "direvent.h"
18 #include <time.h>
19 #include <pwd.h>
20 #include <grp.h>
21 #include <signal.h>
22 #include <sys/wait.h>
23 #include "wordsplit.h"
24 
25 /* Process list */
26 
27 /* Redirector codes */
28 #define REDIR_OUT 0
29 #define REDIR_ERR 1
30 
31 #define PROC_HANDLER 0
32 #define PROC_REDIR   1
33 
34 /* A running process is described by this structure */
35 struct process {
36 	struct process *next, *prev;
37 	int type;               /* Process type */
38 	unsigned timeout;       /* Timeout in seconds */
39 	pid_t pid;              /* PID */
40 	time_t start;           /* Time when the process started */
41 	union {
42 		struct process *redir[2];
43                 /* Pointers to the redirector processes, if
44 		   type == PROC_HANDLER (NULL if no redirector) */
45 		struct process *master;
46                 /* Master process, if type == PROC_REDIR */
47 	} v;
48 };
49 
50 /* List of running processes */
51 struct process *proc_list;
52 /* List of available process slots */
53 struct process *proc_avail;
54 
55 /* Declare functions for handling process lists */
56 struct process *
proc_unlink(struct process ** root,struct process * p)57 proc_unlink(struct process **root, struct process *p)
58 {
59 	if (p->prev)
60 		p->prev->next = p->next;
61 	else
62 		*root = p->next;
63 	if (p->next)
64 		p->next->prev = p->prev;
65 	p->next = p->prev = NULL;
66 	return p;
67 }
68 
69 struct process *
proc_pop(struct process ** pp)70 proc_pop(struct process **pp)
71 {
72 	if (*pp)
73 		return proc_unlink(pp, *pp);
74 	return NULL;
75 }
76 
77 void
proc_push(struct process ** pp,struct process * p)78 proc_push(struct process **pp, struct process *p)
79 {
80 	p->prev = NULL;
81 	p->next = *pp;
82 	if (*pp)
83 		(*pp)->prev = p;
84 	*pp = p;
85 }
86 
87 
88 /* Process list handling (high-level) */
89 
90 struct process *
register_process(int type,pid_t pid,time_t t,unsigned timeout)91 register_process(int type, pid_t pid, time_t t, unsigned timeout)
92 {
93 	struct process *p;
94 
95 	if (proc_avail)
96 		p = proc_pop(&proc_avail);
97 	else
98 		p = emalloc(sizeof(*p));
99 	memset(p, 0, sizeof(*p));
100 	p->type = type;
101 	p->timeout = timeout;
102 	p->pid = pid;
103 	p->start = t;
104 	proc_push(&proc_list, p);
105 	return p;
106 }
107 
108 void
deregister_process(pid_t pid,time_t t)109 deregister_process(pid_t pid, time_t t)
110 {
111 	struct process *p;
112 
113 	for (p = proc_list; p; p = p->next)
114 		if (p->pid == pid) {
115 			if (p->prev)
116 				p->prev->next = p->next;
117 			else
118 				proc_list = p;
119 			if (p->next)
120 				p->next->prev = p->prev;
121 			free(p);
122 			break;
123 		}
124 }
125 
126 struct process *
process_lookup(pid_t pid)127 process_lookup(pid_t pid)
128 {
129 	struct process *p;
130 
131 	for (p = proc_list; p; p = p->next)
132 		if (p->pid == pid)
133 			return p;
134 	return NULL;
135 }
136 
137 static void
print_status(pid_t pid,int status,sigset_t * mask)138 print_status(pid_t pid, int status, sigset_t *mask)
139 {
140 	if (WIFEXITED(status)) {
141 		if (WEXITSTATUS(status) == 0)
142 			debug(1, (_("process %lu exited successfully"),
143 				  (unsigned long) pid));
144 		else
145 			diag(LOG_ERR, _("process %lu failed with status %d"),
146 			     (unsigned long) pid, WEXITSTATUS(status));
147 	} else if (WIFSIGNALED(status)) {
148 		int prio;
149 
150 		if (sigismember(mask, WTERMSIG(status)))
151 			prio = LOG_DEBUG;
152 		else
153 			prio = LOG_ERR;
154 
155 		diag(prio, _("process %lu terminated on signal %d"),
156 		     (unsigned long) pid, WTERMSIG(status));
157 	} else if (WIFSTOPPED(status))
158 		diag(LOG_ERR, _("process %lu stopped on signal %d"),
159 		     (unsigned long) pid, WSTOPSIG(status));
160 #ifdef WCOREDUMP
161 	else if (WCOREDUMP(status))
162 		diag(LOG_ERR,
163 		     _("process %lu dumped core"), (unsigned long) pid);
164 #endif
165 	else
166 		diag(LOG_ERR,
167 		     _("process %lu terminated with unrecognized status"),
168 		     (unsigned long) pid);
169 }
170 
171 void
process_cleanup(int expect_term)172 process_cleanup(int expect_term)
173 {
174 	pid_t pid;
175 	int status;
176 
177 	while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
178 		sigset_t set;
179 		sigemptyset(&set);
180 
181 		if (pid == self_test_pid) {
182 			sigaddset(&set, SIGHUP);
183 			print_status(pid, status, &set);
184 
185 			if (WIFEXITED(status))
186 				exit_code = WEXITSTATUS(status);
187 			else if (WIFSIGNALED(status)) {
188 				if (WTERMSIG(status) == SIGHUP)
189 					exit_code = 0;
190 				else
191 					exit_code = 2;
192 			} else
193 				exit_code = 2;
194 			stop = 1;
195 		} else {
196 			struct process *p = process_lookup(pid);
197 
198 			if (expect_term)
199 				sigaddset(&set, SIGTERM);
200 			if (!p) {
201 				sigaddset(&set, SIGTERM);
202 				sigaddset(&set, SIGKILL);
203 			}
204 			print_status(pid, status, &set);
205 			if (!p)
206 				continue;
207 
208 			if (p->type == PROC_HANDLER) {
209 				if (p->v.redir[REDIR_OUT])
210 					p->v.redir[REDIR_OUT]->v.master = NULL;
211 				if (p->v.redir[REDIR_ERR])
212 					p->v.redir[REDIR_ERR]->v.master = NULL;
213 			}
214 			p->pid = 0;
215 			proc_unlink(&proc_list, p);
216 			proc_push(&proc_avail, p);
217 		}
218 	}
219 }
220 
221 void
process_timeouts()222 process_timeouts()
223 {
224 	struct process *p;
225 	time_t now = time(NULL);
226 	time_t alarm_time = 0, x;
227 
228 	debug(2, (_("begin scanning process list")));
229 	for (p = proc_list; p; p = p->next) {
230 		x = now - p->start;
231 		if (x >= p->timeout) {
232 			diag(LOG_ERR, _("process %lu timed out"),
233 			     (unsigned long) p->pid);
234 			kill(p->pid, SIGKILL);
235 		} else if (alarm_time == 0 ||
236 			   p->timeout - x < alarm_time)
237 			alarm_time = p->timeout - x;
238 	}
239 
240 	if (alarm_time) {
241 		debug(2, (_("scheduling alarm in %lu seconds"),
242 			  (unsigned long) alarm_time));
243 		alarm(alarm_time);
244 	}
245 	debug(2, ("end scanning process list"));
246 }
247 
248 int
switchpriv(struct prog_handler * hp)249 switchpriv(struct prog_handler *hp)
250 {
251 	if (hp->uid == 0 || hp->uid == getuid())
252 		return 0;
253 
254 	if (setgroups(hp->gidc, hp->gidv) < 0) {
255 		diag(LOG_CRIT, "setgroups: %s",
256 		     strerror(errno));
257 		return 1;
258 	}
259 	if (setregid(hp->gidv[0], hp->gidv[0]) < 0) {
260 		diag(LOG_CRIT, "setregid(%lu,%lu): %s",
261 		     (unsigned long) hp->gidv[0],
262 		     (unsigned long) hp->gidv[0],
263 		     strerror(errno));
264 		return 1;
265 	}
266 	if (setreuid(hp->uid, hp->uid) < 0) {
267 		diag(LOG_CRIT, "setreuid(%lu,%lu): %s",
268 		     (unsigned long) hp->uid,
269 		     (unsigned long) hp->uid,
270 		     strerror(errno));
271 		return 1;
272 	}
273 	return 0;
274 }
275 
276 typedef fd_set *bigfd_set;
277 
278 #define BIGFD_SET_COUNT \
279 	((sysconf(_SC_OPEN_MAX) + FD_SETSIZE - 1) / FD_SETSIZE)
280 
281 #define BIGFD_SET_ALLOC() \
282 	ecalloc(BIGFD_SET_COUNT, sizeof(fd_set))
283 
284 #define BIGFD_ZERO(fds) \
285 	memset(fds, 0, sizeof(*bigfd_set) * BIGFD_SET_COUNT)
286 #define BIGFD_SET(n, fds) \
287 	FD_SET((n) % FD_SETSIZE, (fds) + (n) / FD_SETSIZE)
288 #define BIGFD_ISSET(n, fds) \
289 	FD_ISSET((n) % FD_SETSIZE, (fds) + (n) / FD_SETSIZE)
290 
291 static void
close_fds(bigfd_set fdset)292 close_fds(bigfd_set fdset)
293 {
294 	int i;
295 
296 	for (i = dup(0); i >= 0; i--) {
297 		if (fdset && BIGFD_ISSET(i, fdset))
298 			continue;
299 		close(i);
300 	}
301 }
302 
303 /* Operations with handlers and redirections */
304 
305 static void
redir_exit(int sig)306 redir_exit(int sig)
307 {
308 	_exit(0);
309 }
310 
311 int
open_redirector(const char * tag,int prio,struct process ** return_proc)312 open_redirector(const char *tag, int prio, struct process **return_proc)
313 {
314 	int p[2];
315 	FILE *fp;
316 	char buf[512];
317 	pid_t pid;
318 	bigfd_set fdset;
319 
320 	if (pipe(p)) {
321 		diag(LOG_ERR,
322 		     _("cannot start redirector for %s, pipe failed: %s"),
323 		     tag, strerror(errno));
324 		return -1;
325 	}
326 	switch (pid = fork()) {
327 	case 0:
328 		/* Redirector process */
329 		fdset = BIGFD_SET_ALLOC();
330 		BIGFD_SET(p[0], fdset);
331 		if (facility <= 0)
332 			BIGFD_SET(2, fdset);
333 		close_fds(fdset);
334 
335 		alarm(0);
336 		signal_setup(redir_exit);
337 
338 		fp = fdopen(p[0], "r");
339 		if (fp == NULL)
340 			_exit(1);
341 		if (facility > 0)
342 			openlog(tag, LOG_PID, facility);
343 
344 		while (fgets(buf, sizeof(buf), fp) > 0) {
345 			int len = strlen(buf);
346 			if (len && buf[len-1] == '\n')
347 				buf[len-1] = 0;
348 			diag(prio, "%s", buf);
349 		}
350 		_exit(0);
351 
352 	case -1:
353 		diag(LOG_CRIT,
354 		     _("cannot run redirector `%s': fork failed: %s"),
355 		     tag, strerror(errno));
356 		return -1;
357 
358 	default:
359 		debug(1, (_("redirector for %s started, pid=%lu"),
360 			  tag, (unsigned long) pid));
361 		close(p[0]);
362 		*return_proc = register_process(PROC_REDIR, pid,
363 						time(NULL), 0);
364 		return p[1];
365 	}
366 }
367 
368 static void
runcmd(const char * cmd,char ** envhint,event_mask * event,const char * file,int shell)369 runcmd(const char *cmd, char **envhint, event_mask *event, const char *file,
370        int shell)
371 {
372 	char *kve[13];
373 	char *p,*q;
374 	char buf[1024];
375 	int i = 0, j;
376 	char **argv;
377 	char *xargv[4];
378 	struct wordsplit ws;
379 
380 	kve[i++] = "file";
381 	kve[i++] = (char*) file;
382 
383 	snprintf(buf, sizeof buf, "%d", event->sys_mask);
384 	kve[i++] = "sysev_code";
385 	kve[i++] = estrdup(buf);
386 
387 	if (self_test_pid) {
388 		snprintf(buf, sizeof buf, "%lu", (unsigned long)self_test_pid);
389 		kve[i++] = "self_test_pid";
390 		kve[i++] = estrdup(buf);
391 	}
392 
393 	q = buf;
394 	for (p = trans_tokfirst(sysev_transtab, event->sys_mask, &j); p;
395 	     p = trans_toknext(sysev_transtab, event->sys_mask, &j)) {
396 		if (q > buf)
397 			*q++ = ' ';
398 		while (*p)
399 			*q++ = *p++;
400 	}
401 	*q = 0;
402 	if (q > buf) {
403 		kve[i++] = "sysev_name";
404 		kve[i++] = estrdup(buf);
405 	}
406 	p = trans_toktostr(genev_transtab, event->gen_mask);
407 	if (p) {
408 		snprintf(buf, sizeof buf, "%d", event->gen_mask);
409 		kve[i++] = "genev_code";
410 		kve[i++] = estrdup(buf);
411 		kve[i++] = "genev_name";
412 		kve[i++] = p;
413 	}
414 	kve[i++] = 0;
415 
416 	ws.ws_env = (const char **) kve;
417 	if (wordsplit(cmd, &ws,
418 		      WRDSF_NOCMD | WRDSF_QUOTE
419 		      | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES
420 		      | WRDSF_ENV | WRDSF_ENV_KV
421 		      | (shell ? WRDSF_NOSPLIT : 0))) {
422 		diag(LOG_CRIT, "wordsplit: %s",
423 		     wordsplit_strerror (&ws));
424 		_exit(127);
425 	}
426 
427 	if (shell) {
428 		xargv[0] = "/bin/sh";
429 		xargv[1] = "-c";
430 		xargv[2] = ws.ws_wordv[0];
431 		xargv[3] = NULL;
432 		argv = xargv;
433 	} else
434 		argv = ws.ws_wordv;
435 
436 	execve(argv[0], argv, environ_setup(envhint, kve));
437 
438 	diag(LOG_ERR, "execve: %s \"%s\": %s", argv[0], cmd, strerror(errno));
439 	_exit(127);
440 }
441 
442 static int
prog_handler_run(struct watchpoint * wp,event_mask * event,const char * dirname,const char * file,void * data)443 prog_handler_run(struct watchpoint *wp, event_mask *event,
444 		 const char *dirname, const char *file, void *data)
445 {
446 	pid_t pid;
447 	int redir_fd[2] = { -1, -1 };
448 	struct process *redir_proc[2] = { NULL, NULL };
449 	struct process *p;
450 	struct prog_handler *hp = data;
451 
452 	if (!hp->command)
453 		return 0;
454 
455 	debug(1, (_("starting %s, dir=%s, file=%s"),
456 		  hp->command, dirname, file));
457 	if (hp->flags & HF_STDERR)
458 		redir_fd[REDIR_ERR] = open_redirector(hp->command, LOG_ERR,
459 						      &redir_proc[REDIR_ERR]);
460 	if (hp->flags & HF_STDOUT)
461 		redir_fd[REDIR_OUT] = open_redirector(hp->command, LOG_INFO,
462 						      &redir_proc[REDIR_OUT]);
463 
464 	pid = fork();
465 	if (pid == -1) {
466 		diag(LOG_ERR, "fork: %s", strerror(errno));
467 		close(redir_fd[REDIR_OUT]);
468 		close(redir_fd[REDIR_ERR]);
469 		if (redir_proc[REDIR_OUT])
470 			kill(redir_proc[REDIR_OUT]->pid, SIGKILL);
471 		if (redir_proc[REDIR_ERR])
472 			kill(redir_proc[REDIR_ERR]->pid, SIGKILL);
473 		return -1;
474 	}
475 
476 	if (pid == 0) {
477 		/* child */
478 		bigfd_set fdset = BIGFD_SET_ALLOC();
479 
480 		if (switchpriv(hp))
481 			_exit(127);
482 
483 		if (chdir(dirname)) {
484 			diag(LOG_CRIT, _("cannot change to %s: %s"),
485 			     dirname, strerror(errno));
486 			_exit(127);
487 		}
488 
489 		if (redir_fd[REDIR_OUT] != -1) {
490 			if (redir_fd[REDIR_OUT] != 1 &&
491 			    dup2(redir_fd[REDIR_OUT], 1) == -1) {
492 				diag(LOG_ERR, "dup2: %s", strerror(errno));
493 				_exit(127);
494 			}
495 			BIGFD_SET(1, fdset);
496 		}
497 		if (redir_fd[REDIR_ERR] != -1) {
498 			if (redir_fd[REDIR_ERR] != 2 &&
499 			    dup2(redir_fd[REDIR_ERR], 2) == -1) {
500 				diag(LOG_ERR, "dup2: %s", strerror(errno));
501 				_exit(127);
502 			}
503 			BIGFD_SET(2, fdset);
504 		}
505 		close_fds(fdset);
506 		alarm(0);
507 		signal_setup(SIG_DFL);
508 		runcmd(hp->command, hp->env, event, file, hp->flags & HF_SHELL);
509 	}
510 
511 	/* master */
512 	debug(1, (_("%s running; dir=%s, file=%s, pid=%lu"),
513 		  hp->command, dirname, file, (unsigned long)pid));
514 
515 	p = register_process(PROC_HANDLER, pid, time(NULL), hp->timeout);
516 
517 	if (redir_proc[REDIR_OUT]) {
518 		redir_proc[REDIR_OUT]->v.master = p;
519 		redir_proc[REDIR_OUT]->timeout = hp->timeout;
520 	}
521 	if (redir_proc[REDIR_ERR]) {
522 		redir_proc[REDIR_ERR]->v.master = p;
523 		redir_proc[REDIR_ERR]->timeout = hp->timeout;
524 	}
525 	memcpy(p->v.redir, redir_proc, sizeof(p->v.redir));
526 
527 	close(redir_fd[REDIR_OUT]);
528 	close(redir_fd[REDIR_ERR]);
529 
530 	if (hp->flags & HF_NOWAIT) {
531 		return 0;
532 	}
533 
534 	debug(1, (_("waiting for %s (%lu) to terminate"),
535 		  hp->command, (unsigned long)pid));
536 	while (time(NULL) - p->start < 2 * p->timeout) {
537 		sleep(1);
538 		process_cleanup(1);
539 		if (p->pid == 0)
540 			break;
541 	}
542 	return 0;
543 }
544 
545 static void
envfree(char ** env)546 envfree(char **env)
547 {
548 	int i;
549 
550 	if (!env)
551 		return;
552 	for (i = 0; env[i]; i++)
553 		free(env[i]);
554 	free(env);
555 }
556 
557 void
prog_handler_free(struct prog_handler * hp)558 prog_handler_free(struct prog_handler *hp)
559 {
560 	free(hp->command);
561 	free(hp->gidv);
562 	envfree(hp->env);
563 }
564 
565 static void
prog_handler_free_data(void * ptr)566 prog_handler_free_data(void *ptr)
567 {
568 	prog_handler_free((struct prog_handler *)ptr);
569 }
570 
571 struct handler *
prog_handler_alloc(event_mask ev_mask,filpatlist_t fpat,struct prog_handler * p)572 prog_handler_alloc(event_mask ev_mask, filpatlist_t fpat,
573 		   struct prog_handler *p)
574 {
575 	struct handler *hp = handler_alloc(ev_mask);
576 	struct prog_handler *mem;
577 
578 	hp->fnames = fpat;
579 	hp->run = prog_handler_run;
580 	hp->free = prog_handler_free_data;
581 	mem = emalloc(sizeof(*mem));
582 	*mem = *p;
583 	hp->data = mem;
584 	memset(p, 0, sizeof(*p));
585 	return hp;
586 }
587 
588 /* Reallocate environment of handler HP to accomodate COUNT more
589    entries (not bytes) plus a final NULL entry.
590 
591    Return offset of the first unused entry.
592 */
593 size_t
prog_handler_envrealloc(struct prog_handler * hp,size_t count)594 prog_handler_envrealloc(struct prog_handler *hp, size_t count)
595 {
596 	size_t i;
597 
598 	if (!hp->env) {
599 		hp->env = ecalloc(count + 1, sizeof(hp->env[0]));
600 		i = 0;
601 	} else {
602 		for (i = 0; hp->env[i]; i++)
603 			;
604 		hp->env = erealloc(hp->env,
605 				   (i + count + 1) * sizeof(hp->env[0]));
606 		memset(hp->env + i, 0, (count + 1) * sizeof(hp->env[0]));
607 	}
608 	return i;
609 }
610 
611 
612 
613 
614 
615