Annotation of src/usr.bin/bgplg/bgplg.c, Revision 1.1
1.1 ! reyk 1: /* $OpenBSD$ */
! 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"
! 42:
! 43: static struct cmd cmds[] = CMDS;
! 44:
! 45: char *lg_getenv(const char *, int *);
! 46: void lg_urldecode(char *);
! 47: char **lg_arg2argv(char *, int *);
! 48: char **lg_argextra(char **, int, struct cmd *);
! 49: char *lg_getarg(const char *, char *, int);
! 50: int lg_incl(const char *);
! 51:
! 52: void
! 53: lg_urldecode(char *str)
! 54: {
! 55: size_t i, c, len;
! 56: char code[3];
! 57: long result;
! 58:
! 59: if (str && *str) {
! 60: len = strlen(str);
! 61: i = c = 0;
! 62: while (i < len) {
! 63: if (str[i] == '%' && i <= (len - 2)) {
! 64: if (isxdigit(str[i + 1]) &&
! 65: isxdigit(str[i + 2])) {
! 66: code[0] = str[i + 1];
! 67: code[1] = str[i + 2];
! 68: code[2] = 0;
! 69: result = strtol(code, NULL, 16);
! 70: /* Replace NUL chars with a space */
! 71: if (result == 0)
! 72: result = ' ';
! 73: str[c++] = result;
! 74: i += 3;
! 75: } else {
! 76: str[c++] = '%';
! 77: i++;
! 78: }
! 79: } else if (str[i] == '+') {
! 80: str[i] = ' ';
! 81: } else {
! 82: if (c != i)
! 83: str[c] = str[i];
! 84: c++;
! 85: i++;
! 86: }
! 87: }
! 88: str[c] = 0x0;
! 89: }
! 90: }
! 91:
! 92: char *
! 93: lg_getenv(const char *name, int *lenp)
! 94: {
! 95: size_t len;
! 96: u_int i;
! 97: char *ptr;
! 98:
! 99: if ((ptr = getenv(name)) == NULL)
! 100: return (NULL);
! 101:
! 102: lg_urldecode(ptr);
! 103:
! 104: if (!(len = strlen(ptr)))
! 105: return (NULL);
! 106:
! 107: if (lenp != NULL)
! 108: *lenp = len;
! 109:
! 110: #define allowed_in_string(_x) \
! 111: ((isalnum(_x) || isprint(_x)) && \
! 112: (_x != '%' && _x != '\\' && _x != ';' && _x != '|'))
! 113:
! 114: for (i = 0; i < len; i++) {
! 115: if (!allowed_in_string(ptr[i])) {
! 116: printf("invalid character in input\n");
! 117: return (NULL);
! 118: }
! 119: if (ptr[i] == '&')
! 120: ptr[i] = '\0';
! 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:
! 238: return (0);
! 239: }
! 240:
! 241: int
! 242: main(void)
! 243: {
! 244: char *query, *self, *cmd = NULL, *req;
! 245: char **argv = NULL;
! 246: char myname[MAXHOSTNAMELEN];
! 247: int ret = 1, argc = 0, query_length = 0;
! 248: struct stat st;
! 249: u_int i;
! 250: struct cmd *cmdp = NULL;
! 251:
! 252: printf("Content-Type: text/html\n"
! 253: "Cache-Control: no-cache\n\n"
! 254: "<html>\n"
! 255: "<head>\n"
! 256: "<title>bgplg</title>\n");
! 257: if (stat(INC_STYLE, &st) == 0) {
! 258: printf("<style type='text/css'><!--\n");
! 259: lg_incl(INC_STYLE);
! 260: printf("--></style>\n");
! 261: }
! 262: if (stat(INC_HEAD, &st) != 0 || lg_incl(INC_HEAD) != 0) {
! 263: printf("</head>\n"
! 264: "<body>\n");
! 265: }
! 266:
! 267: if (gethostname(myname, sizeof(myname)) != 0)
! 268: goto err;
! 269:
! 270: printf("<h1>%s: %s</h1>\n", NAME, myname);
! 271: printf("<h2>%s</h2>\n", BRIEF);
! 272:
! 273: /* print a form with possible options */
! 274: if ((self = lg_getenv("SCRIPT_NAME", NULL)) == NULL) {
! 275: printf("fatal error: invalid request\n");
! 276: goto err;
! 277: }
! 278: if ((query = lg_getenv("QUERY_STRING", &query_length)) != NULL)
! 279: cmd = lg_getarg("cmd=", query, query_length);
! 280: printf("<form action='%s'>\n"
! 281: "<select name='cmd'>\n",
! 282: self);
! 283: for (i = 0; cmds[i].name != NULL; i++) {
! 284: if (!lg_checkperm(&cmds[i]))
! 285: continue;
! 286:
! 287: if (cmd != NULL && strcmp(cmd, cmds[i].name) == 0)
! 288: printf("<option value='%s' selected='selected'>%s"
! 289: "</option>\n",
! 290: cmds[i].name, cmds[i].name);
! 291: else
! 292: printf("<option value='%s'>%s</option>\n",
! 293: cmds[i].name, cmds[i].name);
! 294: }
! 295: printf("</select>\n"
! 296: "<input type='text' name='req'/>\n"
! 297: "<input type='submit' value='submit'/>\n"
! 298: "</form>\n"
! 299: "<pre>\n");
! 300: fflush(stdout);
! 301:
! 302: #ifdef DEBUG
! 303: if (close(2) == -1 || dup2(1, 2) == -1)
! 304: #else
! 305: if (close(2) == -1)
! 306: #endif
! 307: {
! 308: printf("fatal error: %s\n", strerror(errno));
! 309: goto err;
! 310: }
! 311:
! 312: if (query == NULL)
! 313: goto err;
! 314: if (cmd == NULL) {
! 315: printf("unspecified command\n");
! 316: goto err;
! 317: }
! 318: if ((req = lg_getarg("req=", query, query_length)) != NULL) {
! 319: /* Could be NULL */
! 320: argv = lg_arg2argv(req, &argc);
! 321: }
! 322:
! 323: for (i = 0; cmds[i].name != NULL; i++) {
! 324: if (strcmp(cmd, cmds[i].name) == 0) {
! 325: cmdp = &cmds[i];
! 326: break;
! 327: }
! 328: }
! 329:
! 330: if (cmdp == NULL) {
! 331: printf("invalid command: %s\n", cmd);
! 332: goto err;
! 333: }
! 334: if (argc > cmdp->maxargs) {
! 335: printf("superfluous argument(s): %s %s\n",
! 336: cmd, cmdp->args ? cmdp->args : "");
! 337: goto err;
! 338: }
! 339: if (argc < cmdp->minargs) {
! 340: printf("missing argument(s): %s %s\n", cmd, cmdp->args);
! 341: goto err;
! 342: }
! 343:
! 344: if (cmdp->func != NULL) {
! 345: ret = cmdp->func(cmds, argv);
! 346: } else {
! 347: if ((argv = lg_argextra(argv, argc, cmdp)) == NULL)
! 348: goto err;
! 349: ret = lg_exec(cmdp->earg[0], argv);
! 350: }
! 351: if (ret != 0)
! 352: printf("\nfailed%s\n", ret == 127 ? ": file not found" : ".");
! 353: else
! 354: printf("\nsuccess.\n");
! 355:
! 356: err:
! 357: fflush(stdout);
! 358:
! 359: if (argv != NULL);
! 360: free(argv);
! 361:
! 362: printf("</pre>\n");
! 363:
! 364: if (stat(INC_FOOT, &st) != 0 || lg_incl(INC_FOOT) != 0)
! 365: printf("<hr/>\n");
! 366:
! 367: printf("<div class='footer'>\n"
! 368: "<small>%s - %s<br/>Copyright (c) %s</small>\n"
! 369: "</div>\n"
! 370: "</body>\n"
! 371: "</html>\n", NAME, BRIEF, COPYRIGHT);
! 372:
! 373: return (ret);
! 374: }