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