Annotation of src/usr.bin/bgplg/bgplg.c, Revision 1.17
1.17 ! job 1: /* $OpenBSD: bgplg.c,v 1.16 2016/04/05 21:57:58 sthen Exp $ */
1.1 reyk 2:
3: /*
1.10 reyk 4: * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org>
1.1 reyk 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:
1.13 deraadt 19: #include <sys/types.h>
1.1 reyk 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>
1.13 deraadt 27: #include <limits.h>
1.1 reyk 28: #include <ctype.h>
29: #include <errno.h>
30: #include <fcntl.h>
1.14 benno 31: #include <err.h>
1.1 reyk 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:
1.11 florian 39: #define BGPDSOCK "/run/bgpd.rsock"
1.1 reyk 40: #define BGPCTL "/bin/bgpctl", "-s", BGPDSOCK
41: #define PING "/bin/ping"
42: #define TRACEROUTE "/bin/traceroute"
1.9 sthen 43: #define PING6 "/bin/ping6"
44: #define TRACEROUTE6 "/bin/traceroute6"
1.4 reyk 45: #define CONTENT_TYPE "text/html"
1.1 reyk 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)) {
1.12 deraadt 68: if (isxdigit((unsigned char)str[i + 1]) &&
69: isxdigit((unsigned char)str[i + 2])) {
1.1 reyk 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) \
1.12 deraadt 115: (isalnum((unsigned char)_x) || strchr("-_.:/= ", _x))
1.1 reyk 116:
117: for (i = 0; i < len; i++) {
1.7 claudio 118: if (ptr[i] == '&')
119: ptr[i] = '\0';
1.1 reyk 120: if (!allowed_in_string(ptr[i])) {
121: printf("invalid character in input\n");
122: return (NULL);
123: }
124: }
125:
126: return (ptr);
1.12 deraadt 127: #undef allowed_in_string
1.1 reyk 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++) {
1.12 deraadt 164: if (isspace((unsigned char)arg[i])) {
1.1 reyk 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:
1.15 mmcc 222: free(argv);
1.1 reyk 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:
1.8 claudio 241: close(fd);
1.1 reyk 242: return (0);
243: }
244:
245: int
246: main(void)
247: {
1.16 sthen 248: char *query, *myname, *self, *cmd = NULL, *req;
1.1 reyk 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;
1.14 benno 254:
255: if (pledge("stdio rpath proc exec", NULL) == -1)
256: err(1, "pledge");
1.1 reyk 257:
1.16 sthen 258: if ((myname = lg_getenv("SERVER_NAME", NULL)) == NULL)
1.4 reyk 259: return (1);
260:
261: printf("Content-Type: %s\n"
1.1 reyk 262: "Cache-Control: no-cache\n\n"
1.2 reyk 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"
1.1 reyk 267: "<head>\n"
1.4 reyk 268: "<title>%s: %s</title>\n",
269: CONTENT_TYPE, NAME, myname);
1.1 reyk 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);
1.2 reyk 290: printf(
291: "<form action='%s'>\n"
1.5 claudio 292: "<div class=\"command\">\n"
1.1 reyk 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: }
1.17 ! job 307:
! 308: if ((req = lg_getarg("req=", query, query_length)) != NULL) {
! 309: /* Could be NULL */
! 310: argv = lg_arg2argv(req, &argc);
! 311: }
! 312:
1.1 reyk 313: printf("</select>\n"
1.17 ! job 314: "<input type='text' value='%s' name='req'/>\n"
1.1 reyk 315: "<input type='submit' value='submit'/>\n"
1.2 reyk 316: "</div>\n"
1.1 reyk 317: "</form>\n"
1.17 ! job 318: "<pre>\n", req ? req : "");
1.1 reyk 319: fflush(stdout);
320:
321: #ifdef DEBUG
322: if (close(2) == -1 || dup2(1, 2) == -1)
323: #else
324: if (close(2) == -1)
325: #endif
326: {
327: printf("fatal error: %s\n", strerror(errno));
328: goto err;
329: }
330:
331: if (query == NULL)
332: goto err;
333: if (cmd == NULL) {
334: printf("unspecified command\n");
335: goto err;
336: }
337:
338: for (i = 0; cmds[i].name != NULL; i++) {
339: if (strcmp(cmd, cmds[i].name) == 0) {
340: cmdp = &cmds[i];
341: break;
342: }
343: }
344:
345: if (cmdp == NULL) {
346: printf("invalid command: %s\n", cmd);
347: goto err;
348: }
349: if (argc > cmdp->maxargs) {
350: printf("superfluous argument(s): %s %s\n",
351: cmd, cmdp->args ? cmdp->args : "");
352: goto err;
353: }
354: if (argc < cmdp->minargs) {
355: printf("missing argument(s): %s %s\n", cmd, cmdp->args);
356: goto err;
357: }
358:
359: if (cmdp->func != NULL) {
360: ret = cmdp->func(cmds, argv);
361: } else {
362: if ((argv = lg_argextra(argv, argc, cmdp)) == NULL)
363: goto err;
364: ret = lg_exec(cmdp->earg[0], argv);
365: }
366: if (ret != 0)
367: printf("\nfailed%s\n", ret == 127 ? ": file not found" : ".");
368: else
369: printf("\nsuccess.\n");
370:
371: err:
372: fflush(stdout);
373:
1.15 mmcc 374: free(argv);
1.1 reyk 375:
376: printf("</pre>\n");
377:
378: if (stat(INC_FOOT, &st) != 0 || lg_incl(INC_FOOT) != 0)
379: printf("<hr/>\n");
380:
381: printf("<div class='footer'>\n"
382: "<small>%s - %s<br/>Copyright (c) %s</small>\n"
383: "</div>\n"
384: "</body>\n"
385: "</html>\n", NAME, BRIEF, COPYRIGHT);
386:
387: return (ret);
388: }