Annotation of src/usr.bin/bgplg/bgplg.c, Revision 1.12
1.12 ! deraadt 1: /* $OpenBSD: bgplg.c,v 1.11 2013/06/02 14:11:38 florian 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:
19: #include <sys/stat.h>
20: #include <sys/types.h>
21: #include <sys/param.h>
22:
23: #include <stdio.h>
24: #include <stdlib.h>
25: #include <signal.h>
26: #include <string.h>
27: #include <unistd.h>
28: #include <ctype.h>
29: #include <errno.h>
30: #include <fcntl.h>
31:
32: #include "bgplg.h"
33:
34: #define INC_STYLE "/conf/bgplg.css"
35: #define INC_HEAD "/conf/bgplg.head"
36: #define INC_FOOT "/conf/bgplg.foot"
37:
1.11 florian 38: #define BGPDSOCK "/run/bgpd.rsock"
1.1 reyk 39: #define BGPCTL "/bin/bgpctl", "-s", BGPDSOCK
40: #define PING "/bin/ping"
41: #define TRACEROUTE "/bin/traceroute"
1.9 sthen 42: #define PING6 "/bin/ping6"
43: #define TRACEROUTE6 "/bin/traceroute6"
1.4 reyk 44: #define CONTENT_TYPE "text/html"
1.1 reyk 45:
46: static struct cmd cmds[] = CMDS;
47:
48: char *lg_getenv(const char *, int *);
49: void lg_urldecode(char *);
50: char **lg_arg2argv(char *, int *);
51: char **lg_argextra(char **, int, struct cmd *);
52: char *lg_getarg(const char *, char *, int);
53: int lg_incl(const char *);
54:
55: void
56: lg_urldecode(char *str)
57: {
58: size_t i, c, len;
59: char code[3];
60: long result;
61:
62: if (str && *str) {
63: len = strlen(str);
64: i = c = 0;
65: while (i < len) {
66: if (str[i] == '%' && i <= (len - 2)) {
1.12 ! deraadt 67: if (isxdigit((unsigned char)str[i + 1]) &&
! 68: isxdigit((unsigned char)str[i + 2])) {
1.1 reyk 69: code[0] = str[i + 1];
70: code[1] = str[i + 2];
71: code[2] = 0;
72: result = strtol(code, NULL, 16);
73: /* Replace NUL chars with a space */
74: if (result == 0)
75: result = ' ';
76: str[c++] = result;
77: i += 3;
78: } else {
79: str[c++] = '%';
80: i++;
81: }
82: } else if (str[i] == '+') {
83: str[i] = ' ';
84: } else {
85: if (c != i)
86: str[c] = str[i];
87: c++;
88: i++;
89: }
90: }
91: str[c] = 0x0;
92: }
93: }
94:
95: char *
96: lg_getenv(const char *name, int *lenp)
97: {
98: size_t len;
99: u_int i;
100: char *ptr;
101:
102: if ((ptr = getenv(name)) == NULL)
103: return (NULL);
104:
105: lg_urldecode(ptr);
106:
107: if (!(len = strlen(ptr)))
108: return (NULL);
109:
110: if (lenp != NULL)
111: *lenp = len;
112:
113: #define allowed_in_string(_x) \
1.12 ! deraadt 114: (isalnum((unsigned char)_x) || strchr("-_.:/= ", _x))
1.1 reyk 115:
116: for (i = 0; i < len; i++) {
1.7 claudio 117: if (ptr[i] == '&')
118: ptr[i] = '\0';
1.1 reyk 119: if (!allowed_in_string(ptr[i])) {
120: printf("invalid character in input\n");
121: return (NULL);
122: }
123: }
124:
125: return (ptr);
1.12 ! deraadt 126: #undef allowed_in_string
1.1 reyk 127: }
128:
129: char *
130: lg_getarg(const char *name, char *arg, int len)
131: {
132: char *ptr = arg;
133: size_t namelen, ptrlen;
134: int i;
135:
136: namelen = strlen(name);
137:
138: for (i = 0; i < len; i++) {
139: if (arg[i] == '\0')
140: continue;
141: ptr = arg + i;
142: ptrlen = strlen(ptr);
143: if (namelen >= ptrlen)
144: continue;
145: if (strncmp(name, ptr, namelen) == 0)
146: return (ptr + namelen);
147: }
148:
149: return (NULL);
150: }
151:
152: char **
153: lg_arg2argv(char *arg, int *argc)
154: {
155: char **argv, *ptr = arg;
156: size_t len;
157: u_int i, c = 1;
158:
159: len = strlen(arg);
160:
161: /* Count elements */
162: for (i = 0; i < (len - 1); i++) {
1.12 ! deraadt 163: if (isspace((unsigned char)arg[i])) {
1.1 reyk 164: /* filter out additional options */
165: if (arg[i + 1] == '-') {
166: printf("invalid input\n");
167: return (NULL);
168: }
169: arg[i] = '\0';
170: c++;
171: }
172: }
173:
174: /* Generate array */
175: if ((argv = calloc(c + 1, sizeof(char *))) == NULL) {
176: printf("fatal error: %s\n", strerror(errno));
177: return (NULL);
178: }
179:
180: argv[c] = NULL;
181: *argc = c;
182:
183: /* Fill array */
184: for (i = c = 0; i < (len - 1); i++) {
185: if (arg[i] == '\0' || i == 0) {
186: if (i != 0)
187: ptr = &arg[i + 1];
188: argv[c++] = ptr;
189: }
190: }
191:
192: return (argv);
193: }
194:
195: char **
196: lg_argextra(char **argv, int argc, struct cmd *cmdp)
197: {
198: char **new_argv;
199: int i, c = 0;
200:
201: /* Count elements */
202: for (i = 0; cmdp->earg[i] != NULL; i++)
203: c++;
204:
205: /* Generate array */
206: if ((new_argv = calloc(c + argc + 1, sizeof(char *))) == NULL) {
207: printf("fatal error: %s\n", strerror(errno));
208: return (NULL);
209: }
210:
211: /* Fill array */
212: for (i = c = 0; cmdp->earg[i] != NULL; i++)
213: new_argv[c++] = cmdp->earg[i];
214:
215: /* Append old array */
216: for (i = 0; i < argc; i++)
217: new_argv[c++] = argv[i];
218:
219: new_argv[c] = NULL;
220:
221: if (argv != NULL)
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:
1.8 claudio 241: close(fd);
1.1 reyk 242: return (0);
243: }
244:
245: int
246: main(void)
247: {
248: char *query, *self, *cmd = NULL, *req;
249: char **argv = NULL;
250: char myname[MAXHOSTNAMELEN];
251: int ret = 1, argc = 0, query_length = 0;
252: struct stat st;
253: u_int i;
254: struct cmd *cmdp = NULL;
255:
1.4 reyk 256: if (gethostname(myname, sizeof(myname)) != 0)
257: return (1);
258:
259: printf("Content-Type: %s\n"
1.1 reyk 260: "Cache-Control: no-cache\n\n"
1.2 reyk 261: "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
262: "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
263: "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
264: "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
1.1 reyk 265: "<head>\n"
1.4 reyk 266: "<title>%s: %s</title>\n",
267: CONTENT_TYPE, NAME, myname);
1.1 reyk 268: if (stat(INC_STYLE, &st) == 0) {
269: printf("<style type='text/css'><!--\n");
270: lg_incl(INC_STYLE);
271: printf("--></style>\n");
272: }
273: if (stat(INC_HEAD, &st) != 0 || lg_incl(INC_HEAD) != 0) {
274: printf("</head>\n"
275: "<body>\n");
276: }
277:
278: printf("<h1>%s: %s</h1>\n", NAME, myname);
279: printf("<h2>%s</h2>\n", BRIEF);
280:
281: /* print a form with possible options */
282: if ((self = lg_getenv("SCRIPT_NAME", NULL)) == NULL) {
283: printf("fatal error: invalid request\n");
284: goto err;
285: }
286: if ((query = lg_getenv("QUERY_STRING", &query_length)) != NULL)
287: cmd = lg_getarg("cmd=", query, query_length);
1.2 reyk 288: printf(
289: "<form action='%s'>\n"
1.5 claudio 290: "<div class=\"command\">\n"
1.1 reyk 291: "<select name='cmd'>\n",
292: self);
293: for (i = 0; cmds[i].name != NULL; i++) {
294: if (!lg_checkperm(&cmds[i]))
295: continue;
296:
297: if (cmd != NULL && strcmp(cmd, cmds[i].name) == 0)
298: printf("<option value='%s' selected='selected'>%s"
299: "</option>\n",
300: cmds[i].name, cmds[i].name);
301: else
302: printf("<option value='%s'>%s</option>\n",
303: cmds[i].name, cmds[i].name);
304: }
305: printf("</select>\n"
306: "<input type='text' name='req'/>\n"
307: "<input type='submit' value='submit'/>\n"
1.2 reyk 308: "</div>\n"
1.1 reyk 309: "</form>\n"
310: "<pre>\n");
311: fflush(stdout);
312:
313: #ifdef DEBUG
314: if (close(2) == -1 || dup2(1, 2) == -1)
315: #else
316: if (close(2) == -1)
317: #endif
318: {
319: printf("fatal error: %s\n", strerror(errno));
320: goto err;
321: }
322:
323: if (query == NULL)
324: goto err;
325: if (cmd == NULL) {
326: printf("unspecified command\n");
327: goto err;
328: }
329: if ((req = lg_getarg("req=", query, query_length)) != NULL) {
330: /* Could be NULL */
331: argv = lg_arg2argv(req, &argc);
332: }
333:
334: for (i = 0; cmds[i].name != NULL; i++) {
335: if (strcmp(cmd, cmds[i].name) == 0) {
336: cmdp = &cmds[i];
337: break;
338: }
339: }
340:
341: if (cmdp == NULL) {
342: printf("invalid command: %s\n", cmd);
343: goto err;
344: }
345: if (argc > cmdp->maxargs) {
346: printf("superfluous argument(s): %s %s\n",
347: cmd, cmdp->args ? cmdp->args : "");
348: goto err;
349: }
350: if (argc < cmdp->minargs) {
351: printf("missing argument(s): %s %s\n", cmd, cmdp->args);
352: goto err;
353: }
354:
355: if (cmdp->func != NULL) {
356: ret = cmdp->func(cmds, argv);
357: } else {
358: if ((argv = lg_argextra(argv, argc, cmdp)) == NULL)
359: goto err;
360: ret = lg_exec(cmdp->earg[0], argv);
361: }
362: if (ret != 0)
363: printf("\nfailed%s\n", ret == 127 ? ": file not found" : ".");
364: else
365: printf("\nsuccess.\n");
366:
367: err:
368: fflush(stdout);
369:
1.6 cloder 370: if (argv != NULL)
1.1 reyk 371: free(argv);
372:
373: printf("</pre>\n");
374:
375: if (stat(INC_FOOT, &st) != 0 || lg_incl(INC_FOOT) != 0)
376: printf("<hr/>\n");
377:
378: printf("<div class='footer'>\n"
379: "<small>%s - %s<br/>Copyright (c) %s</small>\n"
380: "</div>\n"
381: "</body>\n"
382: "</html>\n", NAME, BRIEF, COPYRIGHT);
383:
384: return (ret);
385: }