1 /*
2  * A simple interface to executing programs from other programs, using an
3  * optimized and safer popen()-like implementation. It is considered safer in
4  * that no shell needs to be spawned for simple commands, and the environment
5  * passed to the execve()'d program is essentially empty.
6  *
7  * This code is based on popen.c, which in turn was taken from
8  * "Advanced Programming in the UNIX Environment" by W. Richard Stevens.
9  *
10  * Care has been taken to make sure the functions are async-safe. The exception
11  * is runcmd_init() which multithreaded applications or plugins must call in a
12  * non-reentrant manner before calling any other runcmd function.
13  */
14 
15 #define NAGIOSPLUG_API_C 1
16 
17 /* includes **/
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <sys/wait.h>
23 #include <sys/time.h>
24 #include <sys/resource.h>
25 #include <errno.h>
26 #include "runcmd.h"
27 
28 
29 /** macros **/
30 #ifndef WEXITSTATUS
31 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
32 #endif
33 
34 #ifndef WIFEXITED
35 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
36 #endif
37 
38 /* Determine whether we have setenv()/unsetenv() (see setenv(3) on Linux) */
39 #if defined(__DragonFly__) || __FreeBSD__ || _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
40 # define HAVE_SETENV
41 #endif
42 
43 /*
44  * This variable must be global, since there's no way the caller
45  * can forcibly slay a dead or ungainly running program otherwise.
46  *
47  * The check for initialized values and allocation is not atomic, and can
48  * potentially occur in any number of threads simultaneously.
49  *
50  * Multithreaded apps and plugins must initialize it (via runcmd_init())
51  * in an async safe manner  before calling any other runcmd function.
52  */
53 static pid_t *pids = NULL;
54 
55 /* If OPEN_MAX isn't defined, we try the sysconf syscall first.
56  * If that fails, we fall back to an educated guess which is accurate
57  * on Linux and some other systems. There's no guarantee that our guess is
58  * adequate and the program will die with SIGSEGV if it isn't and the
59  * upper boundary is breached. */
60 #ifdef OPEN_MAX
61 # define maxfd OPEN_MAX
62 #else
63 # ifndef _SC_OPEN_MAX /* sysconf macro unavailable, so guess */
64 #  define maxfd 256
65 # else
66 static int maxfd = 0;
67 # endif /* _SC_OPEN_MAX */
68 #endif /* OPEN_MAX */
69 
70 
runcmd_strerror(int code)71 const char *runcmd_strerror(int code)
72 {
73 	switch (code) {
74 	case RUNCMD_EFD:
75 		return "pipe() or open() failed";
76 	case RUNCMD_EALLOC:
77 		return "memory allocation failed";
78 	case RUNCMD_ECMD:
79 		return "command too complicated";
80 	case RUNCMD_EFORK:
81 		return "failed to fork()";
82 	case RUNCMD_EINVAL:
83 		return "invalid parameters";
84 	case RUNCMD_EWAIT:
85 		return "wait() failed";
86 	}
87 	return "unknown";
88 }
89 
90 /* yield the pid belonging to a particular file descriptor */
runcmd_pid(int fd)91 pid_t runcmd_pid(int fd)
92 {
93 	if(!pids || fd >= maxfd || fd < 0)
94 		return 0;
95 
96 	return pids[fd];
97 }
98 
99 /*
100  * Simple command parser which is still tolerably accurate for our
101  * simple needs. It might serve as a useful example on how to program
102  * a state-machine though.
103  *
104  * It's up to the caller to handle output redirection, job control,
105  * conditional statements, variable substitution, nested commands and
106  * function execution. We do mark such occasions with the return code
107  * though, which is to be interpreted as a bitfield with potentially
108  * multiple flags set.
109  */
110 #define STATE_NONE  0
111 #define STATE_WHITE (1 << 0)
112 #define STATE_INARG (1 << 1)
113 #define STATE_INSQ  (1 << 2)
114 #define STATE_INDQ  (1 << 3)
115 #define STATE_SPECIAL (1 << 4)
116 #define STATE_BSLASH (1 << 5)
117 #define in_quotes (state & (STATE_INSQ | STATE_INDQ))
118 #define is_state(s) (state == s)
119 #define set_state(s) (state = s)
120 #define have_state(s) ((state & s) == s)
121 #define add_state(s) (state |= s)
122 #define del_state(s) (state &= ~s)
123 #define add_ret(r) (ret |= r)
runcmd_cmd2strv(const char * str,int * out_argc,char ** out_argv)124 int runcmd_cmd2strv(const char *str, int *out_argc, char **out_argv)
125 {
126 	int arg = 0;
127 	int a = 0;
128 	unsigned int i;
129 	int state;
130 	int ret = 0;
131 	size_t len;
132 	char *argz;
133 
134 	set_state(STATE_NONE);
135 
136 	if (!str || !*str || !out_argc || !out_argv)
137 		return RUNCMD_EINVAL;
138 
139 	len = strlen(str);
140 	argz = malloc(len + 1);
141 	if (!argz)
142 		return RUNCMD_EALLOC;
143 
144 	/* Point argv[0] at the parsed argument string argz so we don't leak. */
145 	out_argv[0] = argz;
146 	out_argv[1] = NULL;
147 
148 	for (i = 0; i < len; i++) {
149 		const char *p = &str[i];
150 
151 		switch (*p) {
152 		case 0:
153 			if (arg == 0) free(out_argv[0]);
154 			out_argv[arg] = NULL;
155 			*out_argc = arg;
156 			return ret;
157 
158 		case ' ': case '\t': case '\r': case '\n':
159 			if (is_state(STATE_INARG)) {
160 				set_state(STATE_NONE);
161 				argz[a++] = 0;
162 				continue;
163 			}
164 			if (!in_quotes)
165 				continue;
166 
167 			break;
168 
169 		case '\\':
170 			/* single-quoted strings never interpolate backslashes */
171 			if (have_state(STATE_INSQ) || have_state(STATE_BSLASH)) {
172 				break;
173 			}
174 			/*
175 			 * double-quoted strings let backslashes escape
176 			 * a few, but not all, shell specials
177 			 */
178 			if (have_state(STATE_INDQ)) {
179 				const char next = str[i + 1];
180 				switch (next) {
181 				case '"': case '\\': case '$': case '`':
182 					add_state(STATE_BSLASH);
183 					continue;
184 				}
185 				break;
186 			}
187 			/*
188 			 * unquoted strings remove unescaped backslashes,
189 			 * but backslashes escape anything and everything
190 			 */
191 			i++;
192 			break;
193 
194 		case '\'':
195 			if (have_state(STATE_INDQ))
196 				break;
197 			if (have_state(STATE_INSQ)) {
198 				del_state(STATE_INSQ);
199 				continue;
200 			}
201 
202 			/*
203 			 * quotes can come inside arguments or
204 			 * at the start of them
205 			 */
206 			if (is_state(STATE_NONE) || is_state(STATE_INARG)) {
207 				if (is_state(STATE_NONE)) {
208 					/* starting a new argument */
209 					out_argv[arg++] = &argz[a];
210 				}
211 				set_state(STATE_INSQ | STATE_INARG);
212 				continue;
213 			}
214 		case '"':
215 			if (have_state(STATE_INSQ))
216 				break;
217 			if (have_state(STATE_INDQ)) {
218 				del_state(STATE_INDQ);
219 				continue;
220 			}
221 			if (is_state(STATE_NONE) || is_state(STATE_INARG)) {
222 				if (is_state(STATE_NONE)) {
223 					out_argv[arg++] = &argz[a];
224 				}
225 				set_state(STATE_INDQ | STATE_INARG);
226 				continue;
227 			}
228 			break;
229 
230 		case '|':
231 		case '<':
232 		case '>':
233 			if (!in_quotes) {
234 				add_ret(RUNCMD_HAS_REDIR);
235 			}
236 			break;
237 		case '&': case ';':
238 			if (!in_quotes) {
239 				set_state(STATE_SPECIAL);
240 				add_ret(RUNCMD_HAS_JOBCONTROL);
241 			}
242 			break;
243 
244 		case '`':
245 			if (!have_state(STATE_INSQ) && !have_state(STATE_BSLASH)) {
246 				add_ret(RUNCMD_HAS_SUBCOMMAND);
247 			}
248 			break;
249 
250 		case '(': case ')':
251 			if (!in_quotes) {
252 				add_ret(RUNCMD_HAS_PAREN);
253 			}
254 			break;
255 
256 		case '$':
257 			if (!have_state(STATE_INSQ) && !have_state(STATE_BSLASH)) {
258 				if (p[1] == '(')
259 					add_ret(RUNCMD_HAS_SUBCOMMAND);
260 				else
261 					add_ret(RUNCMD_HAS_SHVAR);
262 			}
263 			break;
264 
265 		case '*': case '?':
266 			if (!in_quotes) {
267 				add_ret(RUNCMD_HAS_WILDCARD);
268 			}
269 			break;
270 
271 		default:
272 			break;
273 		}
274 
275 		/* here, we're limited to escaped backslashes, so remove STATE_BSLASH */
276 		del_state(STATE_BSLASH);
277 
278 		if (is_state(STATE_NONE)) {
279 			set_state(STATE_INARG);
280 			out_argv[arg++] = &argz[a];
281 		}
282 
283 		/* by default we simply copy the byte */
284 		argz[a++] = str[i];
285 	}
286 
287 	/* make sure we nul-terminate the last argument */
288 	argz[a++] = 0;
289 
290 	if (have_state(STATE_INSQ))
291 		add_ret(RUNCMD_HAS_UBSQ);
292 	if (have_state(STATE_INDQ))
293 		add_ret(RUNCMD_HAS_UBDQ);
294 
295 	out_argv[arg] = NULL;
296 	*out_argc = arg;
297 
298 	return ret;
299 }
300 
301 
302 /* This function is NOT async-safe. It is exported so multithreaded
303  * plugins (or other apps) can call it prior to running any commands
304  * through this API and thus achieve async-safeness throughout the API. */
runcmd_init(void)305 void runcmd_init(void)
306 {
307 #if defined(RLIMIT_NOFILE)
308 	if (!maxfd) {
309 		struct rlimit rlim;
310 		getrlimit(RLIMIT_NOFILE, &rlim);
311 		maxfd = rlim.rlim_cur;
312 	}
313 #elif !defined(OPEN_MAX) && !defined(IOV_MAX) && defined(_SC_OPEN_MAX)
314 	if(!maxfd) {
315 		if((maxfd = sysconf(_SC_OPEN_MAX)) < 0) {
316 			/* possibly log or emit a warning here, since there's no
317 			 * guarantee that our guess at maxfd will be adequate */
318 			maxfd = 256;
319 		}
320 	}
321 #endif
322 
323 	if (!pids)
324 		pids = calloc(maxfd, sizeof(pid_t));
325 }
326 
327 
328 static int runcmd_setenv(const char *name, const char *value);
329 int update_environment(char *name, char *value, int set);
330 
331 /* Start running a command */
332 /* The definition declares nonnull arguments, so checking for these
333    arguments as null results in a compiler warning. */
runcmd_open(const char * cmd,int * pfd,int * pfderr,char ** env,void (* iobreg)(int,int,void *),void * iobregarg)334 int runcmd_open(const char *cmd, int *pfd, int *pfderr, char **env,
335 		void (*iobreg)(int, int, void *), void *iobregarg)
336 {
337 	char **argv = NULL;
338 	int argc = 0;
339 	int cmd2strv_errors;
340 	size_t cmdlen;
341 	pid_t pid;
342 
343 	int i = 0;
344 
345 	if (!pids) {
346 		runcmd_init();
347 	}
348 
349 	/* We can't do anything without a command, or FD arrays. */
350 	if (cmd == NULL || pfd == NULL || pfderr == NULL) {
351 		return RUNCMD_EINVAL;
352 	}
353 
354 	cmdlen = strlen(cmd);
355 	argv = calloc((cmdlen / 2) + 5, sizeof(char *));
356 	if (!argv) {
357 		return RUNCMD_EALLOC;
358 	}
359 
360 	cmd2strv_errors = runcmd_cmd2strv(cmd, &argc, argv);
361 
362 	/* We couldn't allocate the parsed argument array. */
363 	if (cmd2strv_errors == RUNCMD_EALLOC) {
364 		free(argv);
365 		return RUNCMD_EALLOC;
366 	}
367 
368 	/* Run complex commands via the shell. */
369 	if (cmd2strv_errors) {
370 
371 		free(argv[0]);
372 		argv[0] = "/bin/sh";
373 		argv[1] = "-c";
374 		argv[2] = strdup(cmd);
375 		if (!argv[2]) {
376 			free(argv);
377 			return RUNCMD_EALLOC;
378 		}
379 		argv[3] = NULL;
380 	}
381 
382 	if (pipe(pfd) < 0) {
383 		free(!cmd2strv_errors ? argv[0] : argv[2]);
384 		free(argv);
385 		return RUNCMD_EFD;
386 	}
387 
388 	if (pipe(pfderr) < 0) {
389 		free(!cmd2strv_errors ? argv[0] : argv[2]);
390 		free(argv);
391 		close(pfd[0]);
392 		close(pfd[1]);
393 		return RUNCMD_EFD;
394 	}
395 
396 	if (iobreg) {
397 		iobreg(pfd[0], pfderr[0], iobregarg);
398 	}
399 
400 	pid = fork();
401 	if (pid < 0) {
402 		free(!cmd2strv_errors ? argv[0] : argv[2]);
403 		free(argv);
404 		close(pfd[0]);
405 		close(pfd[1]);
406 		close(pfderr[0]);
407 		close(pfderr[1]);
408 		return RUNCMD_EFORK; /* errno set by the failing function */
409 	}
410 
411 	/* Child runs excevp() and _exit(). */
412 	if (pid == 0) {
413 		int exit_status = EXIT_SUCCESS; /* To preserve errno when _exit()ing. */
414 
415 		/* Make our children their own process group leaders so they are killable
416 		 * by their parent (word of the day: filicide / prolicide). */
417 		if (setpgid(getpid(), getpid()) == -1) {
418 			exit_status = errno;
419 			fprintf(stderr, "setpgid(...) errno %d: %s\n", errno, strerror(errno));
420 			goto child_error_exit;
421 		}
422 
423 		close (pfd[0]);
424 		if (pfd[1] != STDOUT_FILENO) {
425 			if (dup2(pfd[1], STDOUT_FILENO) == -1) {
426 				exit_status = errno;
427 				fprintf(stderr, "dup2(pfd[1], STDOUT_FILENO) errno %d: %s\n", errno, strerror(errno));
428 				goto child_error_exit;
429 			}
430 			close(pfd[1]);
431 		}
432 
433 		close (pfderr[0]);
434 		if (pfderr[1] != STDERR_FILENO) {
435 			if (dup2(pfderr[1], STDERR_FILENO) == -1) {
436 				exit_status = errno;
437 				fprintf(stderr, "dup2(pfderr[1], STDERR_FILENO) errno %d: %s\n", errno, strerror(errno));
438 				goto child_error_exit;
439 			}
440 			close(pfderr[1]);
441 		}
442 
443 		/* Close all descriptors in pids[], the child shouldn't see these. */
444 		for (i = 0; i < maxfd; i++) {
445 			if (pids[i] > 0) {
446 				close(i);
447 			}
448 		}
449 
450 		/* Export the environment. */
451 		if (env) {
452 			for (; env[0] && env[1]; env += 2) {
453 				if (runcmd_setenv(env[0], env[1]) == -1) {
454 					exit_status = errno;
455 					fprintf(stderr, "runcmd_setenv(%s, ...) errno %d: %s\n",
456 						env[0], errno, strerror(errno));
457 					goto child_error_exit;
458 				}
459 			}
460 		}
461 
462 		/* Add VAR=value arguments from simple commands to the environment. */
463 		i = 0;
464 		if (!cmd2strv_errors) {
465 			char *ev;
466 			for (; i < argc && (ev = strchr(argv[i], '=')); ++i) {
467 				if (*ev) *ev++ = '\0';
468 				if (runcmd_setenv(argv[i], ev) == -1) {
469 					exit_status = errno;
470 					fprintf(stderr, "runcmd_setenv(%s, ev) errno %d: %s\n",
471 						argv[i], errno, strerror(errno));
472 					goto child_error_exit;
473 				}
474 			}
475 			if (i == argc) {
476 				exit_status = EXIT_FAILURE;
477 				fprintf(stderr, "No command after variables.\n");
478 				goto child_error_exit;
479 			}
480 		}
481 
482 		execvp(argv[i], argv + i);
483 
484 		exit_status = errno;
485 		fprintf(stderr, "execvp(%s, ...) failed. errno is %d: %s\n", argv[i], errno, strerror(errno));
486 
487 child_error_exit:
488 		/* Free argv memory before exiting so valgrind doesn't see it as a leak. */
489 		free(!cmd2strv_errors ? argv[0] : argv[2]);
490 		free(argv);
491 		_exit(exit_status);
492 	}
493 
494 	/* parent picks up execution here */
495 	/*
496 	 * close child's file descriptors in our address space and
497 	 * release the memory we used that won't get passed to the
498 	 * caller.
499 	 */
500 	close(pfd[1]);
501 	close(pfderr[1]);
502 	free(!cmd2strv_errors ? argv[0] : argv[2]);
503 	free(argv);
504 
505 	/* tag our file's entry in the pid-list and return it */
506 	pids[pfd[0]] = pid;
507 
508 	return pfd[0];
509 }
510 
511 
runcmd_close(int fd)512 int runcmd_close(int fd)
513 {
514 	int status;
515 	pid_t pid;
516 
517 	/* make sure this fd was opened by runcmd_open() */
518 	if(fd < 0 || fd > maxfd || !pids || (pid = pids[fd]) == 0)
519 		return RUNCMD_EINVAL;
520 
521 	pids[fd] = 0;
522 	if (close(fd) == -1)
523 		return -1;
524 
525 	/* EINTR is ok (sort of), everything else is bad */
526 	while (waitpid(pid, &status, 0) < 0)
527 		if (errno != EINTR)
528 			return RUNCMD_EWAIT;
529 
530 	/* return child's termination status */
531 	return (WIFEXITED(status)) ? WEXITSTATUS(status) : -1;
532 }
533 
534 
runcmd_try_close(int fd,int * status,int sig)535 int runcmd_try_close(int fd, int *status, int sig)
536 {
537 	pid_t pid;
538 	int result;
539 
540 	/* make sure this fd was opened by popen() */
541 	if(fd < 0 || fd > maxfd || !pids || !pids[fd])
542 		return RUNCMD_EINVAL;
543 
544 	pid = pids[fd];
545 	while((result = waitpid(pid, status, WNOHANG)) != pid) {
546 		if(!result) return 0;
547 		if(result == -1) {
548 			switch(errno) {
549 			case EINTR:
550 				continue;
551 			case EINVAL:
552 				return -1;
553 			case ECHILD:
554 				if(sig) {
555 					result = kill(pid, sig);
556 					sig = 0;
557 					continue;
558 				}
559 				else return -1;
560 			} /* switch */
561 		}
562 	}
563 
564 	pids[fd] = 0;
565 	close(fd);
566 	return result;
567 }
568 
569 /**
570  * Sets an environment variable.
571  * This is for runcmd_open() to set the child environment.
572  * @param naem Variable name to set.
573  * @param value Value to set.
574  * @return 0 on success, -1 on error with errno set to: EINVAL if name is NULL;
575  * or the value set by setenv() or asprintf()/putenv().
576  * @note If setenv() is unavailable (e.g. Solaris), a "name=vale" string is
577  * allocated to pass to putenv(), which is retained by the environment. This
578  * 'leaked' memory will be on the heap at program exit.
579  */
runcmd_setenv(const char * name,const char * value)580 static int runcmd_setenv(const char *name, const char *value) {
581 #ifndef HAVE_SETENV
582 	char *env_string = NULL;
583 #endif
584 
585 	/* We won't mess with null variable names or values. */
586 	if (!name || !value) {
587 		errno = EINVAL;
588 		return -1;
589 	}
590 
591 	errno = 0;
592 #ifdef HAVE_SETENV
593 	return setenv(name, value, 1);
594 #else
595 	/* For Solaris and systems that don't have setenv().
596 	 * This will leak memory, but in a "controlled" way, since the memory
597 	 * should be freed when the child process exits. */
598 	if (asprintf(&env_string, "%s=%s", name, value) == -1) return -1;
599 	if (!env_string) {
600 		errno = ENOMEM;
601 		return -1;
602 	}
603 	return putenv(env_string);
604 #endif
605 }
606 
607 /* sets or unsets an environment variable */
update_environment(char * name,char * value,int set)608 int update_environment(char *name, char *value, int set) {
609 #ifndef HAVE_SETENV
610 	char *env_string = NULL;
611 #endif
612 
613 	/* we won't mess with null variable names */
614 	if(name == NULL) return -1;
615 
616 	/* set the environment variable */
617 	if(set == 1) {
618 
619 #ifdef HAVE_SETENV
620 		setenv(name, (value == NULL) ? "" : value, 1);
621 #else
622 		/* needed for Solaris and systems that don't have setenv() */
623 		/* this will leak memory, but in a "controlled" way, since lost memory should be freed when the child process exits */
624 		asprintf(&env_string, "%s=%s", name, (value == NULL) ? "" : value);
625 		if(env_string) putenv(env_string);
626 #endif
627 	}
628 	/* clear the variable */
629 	else {
630 #ifdef HAVE_UNSETENV
631 		unsetenv(name);
632 #endif
633 	}
634 
635 	return 0;
636 }
637 
638 /**
639  * This will free pids if non-null
640  * Useful for external applications that rely on libnagios to
641  * keep a lid on potential memory leaks
642  */
runcmd_free_pids(void)643 void runcmd_free_pids(void) {
644 	if (pids)
645 		free(pids);
646 }
647 
648