File: [local] / src / usr.bin / bgplg / bgplg.c (download)
Revision 1.19, Mon Mar 5 10:53:37 2018 UTC (6 years, 3 months ago) by denis
Branch: MAIN
CVS Tags: OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, OPENBSD_7_2_BASE, OPENBSD_7_2, OPENBSD_7_1_BASE, OPENBSD_7_1, OPENBSD_7_0_BASE, OPENBSD_7_0, OPENBSD_6_9_BASE, OPENBSD_6_9, OPENBSD_6_8_BASE, OPENBSD_6_8, OPENBSD_6_7_BASE, OPENBSD_6_7, OPENBSD_6_6_BASE, OPENBSD_6_6, OPENBSD_6_5_BASE, OPENBSD_6_5, OPENBSD_6_4_BASE, OPENBSD_6_4, OPENBSD_6_3_BASE, OPENBSD_6_3 Changes since 1.18: +3 -3 lines
Fix failure when AS number is < 10
Thanks to Pierre Emeriaud for reporting & testing.
OK benno@
|
/* $OpenBSD: bgplg.c,v 1.19 2018/03/05 10:53:37 denis Exp $ */
/*
* Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <err.h>
#include "bgplg.h"
#define INC_STYLE "/conf/bgplg.css"
#define INC_HEAD "/conf/bgplg.head"
#define INC_FOOT "/conf/bgplg.foot"
#define BGPDSOCK "/run/bgpd.rsock"
#define BGPCTL "/bin/bgpctl", "-s", BGPDSOCK
#define PING "/bin/ping"
#define TRACEROUTE "/bin/traceroute"
#define PING6 "/bin/ping6"
#define TRACEROUTE6 "/bin/traceroute6"
#define CONTENT_TYPE "text/html"
static struct cmd cmds[] = CMDS;
char *lg_getenv(const char *, int *);
void lg_urldecode(char *);
char **lg_arg2argv(char *, int *);
char **lg_argextra(char **, int, struct cmd *);
char *lg_getarg(const char *, char *, int);
int lg_incl(const char *);
void
lg_urldecode(char *str)
{
size_t i, c, len;
char code[3];
long result;
if (str && *str) {
len = strlen(str);
i = c = 0;
while (i < len) {
if (str[i] == '%' && i <= (len - 2)) {
if (isxdigit((unsigned char)str[i + 1]) &&
isxdigit((unsigned char)str[i + 2])) {
code[0] = str[i + 1];
code[1] = str[i + 2];
code[2] = 0;
result = strtol(code, NULL, 16);
/* Replace NUL chars with a space */
if (result == 0)
result = ' ';
str[c++] = result;
i += 3;
} else {
str[c++] = '%';
i++;
}
} else if (str[i] == '+') {
str[i] = ' ';
} else {
if (c != i)
str[c] = str[i];
c++;
i++;
}
}
str[c] = 0x0;
}
}
char *
lg_getenv(const char *name, int *lenp)
{
size_t len;
u_int i;
char *ptr;
if ((ptr = getenv(name)) == NULL)
return (NULL);
lg_urldecode(ptr);
if (!(len = strlen(ptr)))
return (NULL);
if (lenp != NULL)
*lenp = len;
#define allowed_in_string(_x) \
(isalnum((unsigned char)_x) || strchr("-_.:/= ", _x))
for (i = 0; i < len; i++) {
if (ptr[i] == '&')
ptr[i] = '\0';
if (!allowed_in_string(ptr[i])) {
printf("invalid character in input\n");
return (NULL);
}
}
return (ptr);
#undef allowed_in_string
}
char *
lg_getarg(const char *name, char *arg, int len)
{
char *ptr = arg;
size_t namelen, ptrlen;
int i;
namelen = strlen(name);
for (i = 0; i < len; i++) {
if (arg[i] == '\0')
continue;
ptr = arg + i;
ptrlen = strlen(ptr);
if (namelen >= ptrlen)
continue;
if (strncmp(name, ptr, namelen) == 0)
return (ptr + namelen);
}
return (NULL);
}
char **
lg_arg2argv(char *arg, int *argc)
{
char **argv, *ptr = arg;
size_t len;
u_int i, c = 1;
len = strlen(arg);
/* Count elements */
for (i = 0; i < len; i++) {
if (isspace((unsigned char)arg[i])) {
/* filter out additional options */
if (arg[i + 1] == '-') {
printf("invalid input\n");
return (NULL);
}
arg[i] = '\0';
c++;
}
}
/* Generate array */
if ((argv = calloc(c + 1, sizeof(char *))) == NULL) {
printf("fatal error: %s\n", strerror(errno));
return (NULL);
}
argv[c] = NULL;
*argc = c;
/* Fill array */
for (i = c = 0; i < len; i++) {
if (arg[i] == '\0' || i == 0) {
if (i != 0)
ptr = &arg[i + 1];
argv[c++] = ptr;
}
}
return (argv);
}
char **
lg_argextra(char **argv, int argc, struct cmd *cmdp)
{
char **new_argv;
int i, c = 0;
/* Count elements */
for (i = 0; cmdp->earg[i] != NULL; i++)
c++;
/* Generate array */
if ((new_argv = calloc(c + argc + 1, sizeof(char *))) == NULL) {
printf("fatal error: %s\n", strerror(errno));
return (NULL);
}
/* Fill array */
for (i = c = 0; cmdp->earg[i] != NULL; i++)
new_argv[c++] = cmdp->earg[i];
/* Append old array */
for (i = 0; i < argc; i++)
new_argv[c++] = argv[i];
new_argv[c] = NULL;
free(argv);
return (new_argv);
}
int
lg_incl(const char *file)
{
char buf[BUFSIZ];
int fd, len;
if ((fd = open(file, O_RDONLY)) == -1)
return (errno);
do {
len = read(fd, buf, sizeof(buf));
fwrite(buf, len, 1, stdout);
} while(len == BUFSIZ);
close(fd);
return (0);
}
int
main(void)
{
char *query, *myname, *self, *cmd = NULL, *req;
char **argv = NULL;
int ret = 1, argc = 0, query_length = 0;
struct stat st;
u_int i;
struct cmd *cmdp = NULL;
if (pledge("stdio rpath proc exec", NULL) == -1)
err(1, "pledge");
if ((myname = lg_getenv("SERVER_NAME", NULL)) == NULL)
return (1);
printf("Content-Type: %s\n"
"Cache-Control: no-cache\n\n"
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
"\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
"<head>\n"
"<title>%s</title>\n",
CONTENT_TYPE, myname);
if (stat(INC_STYLE, &st) == 0) {
printf("<style type='text/css'><!--\n");
lg_incl(INC_STYLE);
printf("--></style>\n");
}
if (stat(INC_HEAD, &st) != 0 || lg_incl(INC_HEAD) != 0) {
printf("</head>\n"
"<body>\n");
}
/* print a form with possible options */
if ((self = lg_getenv("SCRIPT_NAME", NULL)) == NULL) {
printf("fatal error: invalid request\n");
goto err;
}
if ((query = lg_getenv("QUERY_STRING", &query_length)) != NULL)
cmd = lg_getarg("cmd=", query, query_length);
printf(
"<form action='%s'>\n"
"<div class=\"command\">\n"
"<select name='cmd'>\n",
self);
for (i = 0; cmds[i].name != NULL; i++) {
if (!lg_checkperm(&cmds[i]))
continue;
if (cmd != NULL && strcmp(cmd, cmds[i].name) == 0)
printf("<option value='%s' selected='selected'>%s"
"</option>\n",
cmds[i].name, cmds[i].name);
else
printf("<option value='%s'>%s</option>\n",
cmds[i].name, cmds[i].name);
}
if ((req = lg_getarg("req=", query, query_length)) != NULL) {
/* Could be NULL */
argv = lg_arg2argv(req, &argc);
}
printf("</select>\n"
"<input type='text' value='%s' name='req'/>\n"
"<input type='submit' value='submit'/>\n"
"</div>\n"
"</form>\n"
"<pre>\n", req ? req : "");
fflush(stdout);
#ifdef DEBUG
if (close(2) == -1 || dup2(1, 2) == -1)
#else
if (close(2) == -1)
#endif
{
printf("fatal error: %s\n", strerror(errno));
goto err;
}
if (query == NULL)
goto err;
if (cmd == NULL) {
printf("unspecified command\n");
goto err;
}
for (i = 0; cmds[i].name != NULL; i++) {
if (strcmp(cmd, cmds[i].name) == 0) {
cmdp = &cmds[i];
break;
}
}
if (cmdp == NULL) {
printf("invalid command: %s\n", cmd);
goto err;
}
if (argc > cmdp->maxargs) {
printf("superfluous argument(s): %s %s\n",
cmd, cmdp->args ? cmdp->args : "");
goto err;
}
if (argc < cmdp->minargs) {
printf("missing argument(s): %s %s\n", cmd, cmdp->args);
goto err;
}
if (cmdp->func != NULL) {
ret = cmdp->func(cmds, argv);
} else {
if ((argv = lg_argextra(argv, argc, cmdp)) == NULL)
goto err;
ret = lg_exec(cmdp->earg[0], argv);
}
if (ret != 0)
printf("\nfailed%s\n", ret == 127 ? ": file not found" : ".");
else
printf("\nsuccess.\n");
err:
fflush(stdout);
free(argv);
printf("</pre>\n");
if (stat(INC_FOOT, &st) != 0 || lg_incl(INC_FOOT) != 0)
printf("<hr/>\n");
printf("<div class='footer'>\n"
"</div>\n"
"</body>\n"
"</html>\n");
return (ret);
}