GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/bgplg/bgplg/../bgplg.c Lines: 0 152 0.0 %
Date: 2017-11-07 Branches: 0 118 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: bgplg.c,v 1.16 2016/04/05 21:57:58 sthen Exp $	*/
2
3
/*
4
 * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/stat.h>
21
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <signal.h>
25
#include <string.h>
26
#include <unistd.h>
27
#include <limits.h>
28
#include <ctype.h>
29
#include <errno.h>
30
#include <fcntl.h>
31
#include <err.h>
32
33
#include "bgplg.h"
34
35
#define INC_STYLE	"/conf/bgplg.css"
36
#define INC_HEAD	"/conf/bgplg.head"
37
#define INC_FOOT	"/conf/bgplg.foot"
38
39
#define BGPDSOCK	"/run/bgpd.rsock"
40
#define BGPCTL		"/bin/bgpctl", "-s", BGPDSOCK
41
#define PING		"/bin/ping"
42
#define TRACEROUTE	"/bin/traceroute"
43
#define PING6		"/bin/ping6"
44
#define TRACEROUTE6	"/bin/traceroute6"
45
#define CONTENT_TYPE	"text/html"
46
47
static struct cmd cmds[] = CMDS;
48
49
char		 *lg_getenv(const char *, int *);
50
void		  lg_urldecode(char *);
51
char		**lg_arg2argv(char *, int *);
52
char		**lg_argextra(char **, int, struct cmd *);
53
char		 *lg_getarg(const char *, char *, int);
54
int		  lg_incl(const char *);
55
56
void
57
lg_urldecode(char *str)
58
{
59
	size_t i, c, len;
60
	char code[3];
61
	long result;
62
63
	if (str && *str) {
64
		len = strlen(str);
65
		i = c = 0;
66
		while (i < len) {
67
			if (str[i] == '%' && i <= (len - 2)) {
68
				if (isxdigit((unsigned char)str[i + 1]) &&
69
				    isxdigit((unsigned char)str[i + 2])) {
70
					code[0] = str[i + 1];
71
					code[1] = str[i + 2];
72
					code[2] = 0;
73
					result = strtol(code, NULL, 16);
74
					/* Replace NUL chars with a space */
75
					if (result == 0)
76
						result = ' ';
77
					str[c++] = result;
78
					i += 3;
79
				} else {
80
					str[c++] = '%';
81
					i++;
82
				}
83
			} else if (str[i] == '+') {
84
				str[i] = ' ';
85
			} else {
86
				if (c != i)
87
					str[c] = str[i];
88
				c++;
89
				i++;
90
			}
91
		}
92
		str[c] = 0x0;
93
	}
94
}
95
96
char *
97
lg_getenv(const char *name, int *lenp)
98
{
99
	size_t len;
100
	u_int i;
101
	char *ptr;
102
103
	if ((ptr = getenv(name)) == NULL)
104
		return (NULL);
105
106
	lg_urldecode(ptr);
107
108
	if (!(len = strlen(ptr)))
109
		return (NULL);
110
111
	if (lenp != NULL)
112
		*lenp = len;
113
114
#define allowed_in_string(_x)                                           \
115
	(isalnum((unsigned char)_x) || strchr("-_.:/= ", _x))
116
117
	for (i = 0; i < len; i++) {
118
		if (ptr[i] == '&')
119
			ptr[i] = '\0';
120
		if (!allowed_in_string(ptr[i])) {
121
			printf("invalid character in input\n");
122
			return (NULL);
123
		}
124
	}
125
126
	return (ptr);
127
#undef allowed_in_string
128
}
129
130
char *
131
lg_getarg(const char *name, char *arg, int len)
132
{
133
	char *ptr = arg;
134
	size_t namelen, ptrlen;
135
	int i;
136
137
	namelen = strlen(name);
138
139
	for (i = 0; i < len; i++) {
140
		if (arg[i] == '\0')
141
			continue;
142
		ptr = arg + i;
143
		ptrlen = strlen(ptr);
144
		if (namelen >= ptrlen)
145
			continue;
146
		if (strncmp(name, ptr, namelen) == 0)
147
			return (ptr + namelen);
148
	}
149
150
	return (NULL);
151
}
152
153
char **
154
lg_arg2argv(char *arg, int *argc)
155
{
156
	char **argv, *ptr = arg;
157
	size_t len;
158
	u_int i, c = 1;
159
160
	len = strlen(arg);
161
162
	/* Count elements */
163
	for (i = 0; i < (len - 1); i++) {
164
		if (isspace((unsigned char)arg[i])) {
165
			/* filter out additional options */
166
			if (arg[i + 1] == '-') {
167
				printf("invalid input\n");
168
				return (NULL);
169
			}
170
			arg[i] = '\0';
171
			c++;
172
		}
173
	}
174
175
	/* Generate array */
176
	if ((argv = calloc(c + 1, sizeof(char *))) == NULL) {
177
		printf("fatal error: %s\n", strerror(errno));
178
		return (NULL);
179
	}
180
181
	argv[c] = NULL;
182
	*argc = c;
183
184
	/* Fill array */
185
	for (i = c = 0; i < (len - 1); i++) {
186
		if (arg[i] == '\0' || i == 0) {
187
			if (i != 0)
188
				ptr = &arg[i + 1];
189
			argv[c++] = ptr;
190
		}
191
	}
192
193
	return (argv);
194
}
195
196
char **
197
lg_argextra(char **argv, int argc, struct cmd *cmdp)
198
{
199
	char **new_argv;
200
	int i, c = 0;
201
202
	/* Count elements */
203
	for (i = 0; cmdp->earg[i] != NULL; i++)
204
		c++;
205
206
	/* Generate array */
207
	if ((new_argv = calloc(c + argc + 1, sizeof(char *))) == NULL) {
208
		printf("fatal error: %s\n", strerror(errno));
209
		return (NULL);
210
	}
211
212
	/* Fill array */
213
	for (i = c = 0; cmdp->earg[i] != NULL; i++)
214
		new_argv[c++] = cmdp->earg[i];
215
216
	/* Append old array */
217
	for (i = 0; i < argc; i++)
218
		new_argv[c++] = argv[i];
219
220
	new_argv[c] = NULL;
221
222
	free(argv);
223
224
	return (new_argv);
225
}
226
227
int
228
lg_incl(const char *file)
229
{
230
	char buf[BUFSIZ];
231
	int fd, len;
232
233
	if ((fd = open(file, O_RDONLY)) == -1)
234
		return (errno);
235
236
	do {
237
		len = read(fd, buf, sizeof(buf));
238
		fwrite(buf, len, 1, stdout);
239
	} while(len == BUFSIZ);
240
241
	close(fd);
242
	return (0);
243
}
244
245
int
246
main(void)
247
{
248
	char *query, *myname, *self, *cmd = NULL, *req;
249
	char **argv = NULL;
250
	int ret = 1, argc = 0, query_length = 0;
251
	struct stat st;
252
	u_int i;
253
	struct cmd *cmdp = NULL;
254
255
	if (pledge("stdio rpath proc exec flock cpath wpath", NULL) == -1)
256
		err(1, "pledge");
257
258
	if ((myname = lg_getenv("SERVER_NAME", NULL)) == NULL)
259
		return (1);
260
261
	printf("Content-Type: %s\n"
262
	    "Cache-Control: no-cache\n\n"
263
	    "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
264
	    "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
265
	    "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
266
	    "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
267
	    "<head>\n"
268
	    "<title>%s: %s</title>\n",
269
	    CONTENT_TYPE, NAME, myname);
270
	if (stat(INC_STYLE, &st) == 0) {
271
		printf("<style type='text/css'><!--\n");
272
		lg_incl(INC_STYLE);
273
		printf("--></style>\n");
274
	}
275
	if (stat(INC_HEAD, &st) != 0 || lg_incl(INC_HEAD) != 0) {
276
		printf("</head>\n"
277
		    "<body>\n");
278
	}
279
280
	printf("<h1>%s: %s</h1>\n", NAME, myname);
281
	printf("<h2>%s</h2>\n", BRIEF);
282
283
	/* print a form with possible options */
284
	if ((self = lg_getenv("SCRIPT_NAME", NULL)) == NULL) {
285
		printf("fatal error: invalid request\n");
286
		goto err;
287
	}
288
	if ((query = lg_getenv("QUERY_STRING", &query_length)) != NULL)
289
		cmd = lg_getarg("cmd=", query, query_length);
290
	printf(
291
	    "<form action='%s'>\n"
292
	    "<div class=\"command\">\n"
293
	    "<select name='cmd'>\n",
294
	    self);
295
	for (i = 0; cmds[i].name != NULL; i++) {
296
		if (!lg_checkperm(&cmds[i]))
297
			continue;
298
299
		if (cmd != NULL && strcmp(cmd, cmds[i].name) == 0)
300
			printf("<option value='%s' selected='selected'>%s"
301
			    "</option>\n",
302
			    cmds[i].name, cmds[i].name);
303
		else
304
			printf("<option value='%s'>%s</option>\n",
305
			    cmds[i].name, cmds[i].name);
306
	}
307
	printf("</select>\n"
308
	    "<input type='text' name='req'/>\n"
309
	    "<input type='submit' value='submit'/>\n"
310
	    "</div>\n"
311
	    "</form>\n"
312
	    "<pre>\n");
313
	fflush(stdout);
314
315
#ifdef DEBUG
316
	if (close(2) == -1 || dup2(1, 2) == -1)
317
#else
318
	if (close(2) == -1)
319
#endif
320
	{
321
		printf("fatal error: %s\n", strerror(errno));
322
		goto err;
323
	}
324
325
	if (query == NULL)
326
		goto err;
327
	if (cmd == NULL) {
328
		printf("unspecified command\n");
329
		goto err;
330
	}
331
	if ((req = lg_getarg("req=", query, query_length)) != NULL) {
332
		/* Could be NULL */
333
		argv = lg_arg2argv(req, &argc);
334
	}
335
336
	for (i = 0; cmds[i].name != NULL; i++) {
337
		if (strcmp(cmd, cmds[i].name) == 0) {
338
			cmdp = &cmds[i];
339
			break;
340
		}
341
	}
342
343
	if (cmdp == NULL) {
344
		printf("invalid command: %s\n", cmd);
345
		goto err;
346
	}
347
	if (argc > cmdp->maxargs) {
348
		printf("superfluous argument(s): %s %s\n",
349
		    cmd, cmdp->args ? cmdp->args : "");
350
		goto err;
351
	}
352
	if (argc < cmdp->minargs) {
353
		printf("missing argument(s): %s %s\n", cmd, cmdp->args);
354
		goto err;
355
	}
356
357
	if (cmdp->func != NULL) {
358
		ret = cmdp->func(cmds, argv);
359
	} else {
360
		if ((argv = lg_argextra(argv, argc, cmdp)) == NULL)
361
			goto err;
362
		ret = lg_exec(cmdp->earg[0], argv);
363
	}
364
	if (ret != 0)
365
		printf("\nfailed%s\n", ret == 127 ? ": file not found" : ".");
366
	else
367
		printf("\nsuccess.\n");
368
369
 err:
370
	fflush(stdout);
371
372
	free(argv);
373
374
	printf("</pre>\n");
375
376
	if (stat(INC_FOOT, &st) != 0 || lg_incl(INC_FOOT) != 0)
377
		printf("<hr/>\n");
378
379
	printf("<div class='footer'>\n"
380
	    "<small>%s - %s<br/>Copyright (c) %s</small>\n"
381
	    "</div>\n"
382
	    "</body>\n"
383
	    "</html>\n", NAME, BRIEF, COPYRIGHT);
384
385
	return (ret);
386
}