xref: /openbsd-src/usr.bin/bgplg/misc.c (revision d7da19ca6f6c025db92455cdbe3de3d7e9ab5905)
1*d7da19caSderaadt /*	$OpenBSD: misc.c,v 1.9 2024/07/01 18:43:50 deraadt Exp $	*/
2bc5366b8Sreyk 
3bc5366b8Sreyk /*
49cf8e0eaSreyk  * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org>
5bc5366b8Sreyk  *
6bc5366b8Sreyk  * Permission to use, copy, modify, and distribute this software for any
7bc5366b8Sreyk  * purpose with or without fee is hereby granted, provided that the above
8bc5366b8Sreyk  * copyright notice and this permission notice appear in all copies.
9bc5366b8Sreyk  *
10bc5366b8Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11bc5366b8Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12bc5366b8Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13bc5366b8Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14bc5366b8Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15bc5366b8Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16bc5366b8Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17bc5366b8Sreyk  */
18bc5366b8Sreyk 
19bc5366b8Sreyk #include <sys/stat.h>
20bc5366b8Sreyk #include <sys/types.h>
21bc5366b8Sreyk #include <sys/utsname.h>
22bc5366b8Sreyk #include <sys/wait.h>
23bc5366b8Sreyk #include <sys/time.h>
24bc5366b8Sreyk 
25bc5366b8Sreyk #include <stdio.h>
26bc5366b8Sreyk #include <stdlib.h>
27bc5366b8Sreyk #include <signal.h>
28bc5366b8Sreyk #include <string.h>
29bc5366b8Sreyk #include <unistd.h>
30bc5366b8Sreyk #include <ctype.h>
31bc5366b8Sreyk #include <errno.h>
32bc5366b8Sreyk #include <fcntl.h>
33bc5366b8Sreyk 
34bc5366b8Sreyk #include "bgplg.h"
35bc5366b8Sreyk 
36bc5366b8Sreyk static volatile pid_t child = -1;
37bc5366b8Sreyk 
38bc5366b8Sreyk int
lg_checkperm(struct cmd * cmd)39bc5366b8Sreyk lg_checkperm(struct cmd *cmd)
40bc5366b8Sreyk {
41bc5366b8Sreyk 	struct stat stbuf;
42bc5366b8Sreyk 
43bc5366b8Sreyk 	/* No external command to execute, this is always valid */
446020324cSflorian 	if (cmd->earg[0] == NULL)
45bc5366b8Sreyk 		return (1);
46bc5366b8Sreyk 
47bc5366b8Sreyk 	/*
48bc5366b8Sreyk 	 * Skip commands if the executable is missing or
49bc5366b8Sreyk 	 * the permission mode has been set to zero (the default
50bc5366b8Sreyk 	 * in a CGI environment).
51bc5366b8Sreyk 	 */
52bc5366b8Sreyk 	if (stat(cmd->earg[0], &stbuf) != 0 ||
53bc5366b8Sreyk 	    (stbuf.st_mode & ~S_IFMT) == 0)
54bc5366b8Sreyk 		return (0);
55bc5366b8Sreyk 
56bc5366b8Sreyk 	return (1);
57bc5366b8Sreyk }
58bc5366b8Sreyk 
59bc5366b8Sreyk int
lg_help(struct cmd * cmds,char ** argv)60bc5366b8Sreyk lg_help(struct cmd *cmds, char **argv)
61bc5366b8Sreyk {
62bc5366b8Sreyk 	u_int i;
63bc5366b8Sreyk 
64bc5366b8Sreyk 	printf("valid commands:\n");
65bc5366b8Sreyk 	for (i = 0; cmds[i].name != NULL; i++) {
66bc5366b8Sreyk 		if (!lg_checkperm(&cmds[i]))
67bc5366b8Sreyk 			continue;
68bc5366b8Sreyk 
69bc5366b8Sreyk 		printf("  %s", cmds[i].name);
70bc5366b8Sreyk 		if (cmds[i].minargs > 0)
71bc5366b8Sreyk 			printf(" { arg }");
72bc5366b8Sreyk 		else if (cmds[i].maxargs > 0)
73bc5366b8Sreyk 			printf(" [ arg ]");
74bc5366b8Sreyk 		printf("\n");
75bc5366b8Sreyk 	}
76bc5366b8Sreyk 	return (0);
77bc5366b8Sreyk }
78bc5366b8Sreyk 
79bc5366b8Sreyk void
lg_sig_alarm(int sig)80bc5366b8Sreyk lg_sig_alarm(int sig)
81bc5366b8Sreyk {
82*d7da19caSderaadt 	int save_errno = errno;
83*d7da19caSderaadt 
84bc5366b8Sreyk 	if (child != -1) {
85d8e0d0a2Ssthen 		/* Forcibly kill the child, no excuse... */
86bc5366b8Sreyk 		kill(child, SIGKILL);
87bc5366b8Sreyk 	}
88*d7da19caSderaadt 	errno = save_errno;
89bc5366b8Sreyk }
90bc5366b8Sreyk 
91bc5366b8Sreyk int
lg_exec(const char * file,char ** new_argv)92bc5366b8Sreyk lg_exec(const char *file, char **new_argv)
93bc5366b8Sreyk {
94bc5366b8Sreyk 	int status = 0, ret = 0;
95bc5366b8Sreyk 	sig_t save_quit, save_int, save_chld;
96bc5366b8Sreyk 	struct itimerval it;
97bc5366b8Sreyk 
98bc5366b8Sreyk 	if (new_argv == NULL)
99bc5366b8Sreyk 		return (EFAULT);
100bc5366b8Sreyk 
101bc5366b8Sreyk 	save_quit = signal(SIGQUIT, SIG_IGN);
102bc5366b8Sreyk 	save_int = signal(SIGINT, SIG_IGN);
103bc5366b8Sreyk 	save_chld = signal(SIGCHLD, SIG_DFL);
104bc5366b8Sreyk 
105bc5366b8Sreyk 	switch (child = fork()) {
106bc5366b8Sreyk 	case -1:
107bc5366b8Sreyk 		ret = errno;
108bc5366b8Sreyk 		goto done;
109bc5366b8Sreyk 	case 0:
110bc5366b8Sreyk 		signal(SIGQUIT, SIG_DFL);
111bc5366b8Sreyk 		signal(SIGINT, SIG_DFL);
112bc5366b8Sreyk 		signal(SIGCHLD, SIG_DFL);
113bc5366b8Sreyk 
114bc5366b8Sreyk 		execvp(file, new_argv);
115bc5366b8Sreyk 		_exit(127);
116bc5366b8Sreyk 		break;
117bc5366b8Sreyk 	default:
118bc5366b8Sreyk 		/* Kill the process after a timeout */
119bc5366b8Sreyk 		signal(SIGALRM, lg_sig_alarm);
120bc5366b8Sreyk 		bzero(&it, sizeof(it));
121bc5366b8Sreyk 		it.it_value.tv_sec = BGPLG_TIMEOUT;
122bc5366b8Sreyk 		setitimer(ITIMER_REAL, &it, NULL);
123bc5366b8Sreyk 
124bc5366b8Sreyk 		waitpid(child, &status, 0);
125bc5366b8Sreyk 		break;
126bc5366b8Sreyk 	}
127bc5366b8Sreyk 
128bc5366b8Sreyk 	switch (ret) {
129bc5366b8Sreyk 	case -1:
130bc5366b8Sreyk 		ret = ECHILD;
131bc5366b8Sreyk 		break;
132bc5366b8Sreyk 	default:
133bc5366b8Sreyk 		if (WIFEXITED(status))
134bc5366b8Sreyk 			ret = WEXITSTATUS(status);
135bc5366b8Sreyk 		else
136bc5366b8Sreyk 			ret = ECHILD;
137bc5366b8Sreyk 	}
138bc5366b8Sreyk 
139bc5366b8Sreyk  done:
140bc5366b8Sreyk 	/* Disable the process timeout timer */
141bc5366b8Sreyk 	bzero(&it, sizeof(it));
142bc5366b8Sreyk 	setitimer(ITIMER_REAL, &it, NULL);
143bc5366b8Sreyk 	child = -1;
144bc5366b8Sreyk 
145bc5366b8Sreyk 	signal(SIGQUIT, save_quit);
146bc5366b8Sreyk 	signal(SIGINT, save_int);
147bc5366b8Sreyk 	signal(SIGCHLD, save_chld);
148bc5366b8Sreyk 	signal(SIGALRM, SIG_DFL);
149bc5366b8Sreyk 
150bc5366b8Sreyk 	return (ret);
151bc5366b8Sreyk }
152bc5366b8Sreyk 
153bc5366b8Sreyk ssize_t
lg_strip(char * str)154bc5366b8Sreyk lg_strip(char *str)
155bc5366b8Sreyk {
156bc5366b8Sreyk 	size_t len;
157bc5366b8Sreyk 
158bc5366b8Sreyk 	if ((len = strlen(str)) < 1)
159bc5366b8Sreyk 		return (0); /* XXX EINVAL? */
160bc5366b8Sreyk 
1616d73225dSderaadt 	if (isspace((unsigned char)str[len - 1])) {
162bc5366b8Sreyk 		str[len - 1] = '\0';
163bc5366b8Sreyk 		return (lg_strip(str));
164bc5366b8Sreyk 	}
165bc5366b8Sreyk 
166bc5366b8Sreyk 	return (strlen(str));
167bc5366b8Sreyk }
168