aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjørn Mork <bjorn@mork.no>2017-03-04 21:06:10 +0100
committerBjørn Mork <bjorn@mork.no>2017-03-04 21:06:10 +0100
commitbefdaa92d2c6ea36d6c3900b3882e7bf89934fb6 (patch)
tree8910dc1cd78b5c6e263c9bb42440edfac9430f68
parent8712f3f01a5acaa5426c03fc4510f18985b84b66 (diff)
ripe-atlas-fw: imported version 47604760
Signed-off-by: Bjørn Mork <bjorn@mork.no>
-rw-r--r--coreutils/condmv.c261
-rw-r--r--eperd/eooqd.c3
-rw-r--r--eperd/eperd.c3
-rw-r--r--eperd/evtdig.c341
-rw-r--r--eperd/ping.c24
-rw-r--r--eperd/sslgetcert.c12
-rw-r--r--eperd/traceroute.c100
-rw-r--r--include/libbb.h1
-rw-r--r--libbb/atlas_check_addr.c2
-rw-r--r--networking/httppost.c6
10 files changed, 623 insertions, 130 deletions
diff --git a/coreutils/condmv.c b/coreutils/condmv.c
index 0139779..2fd976f 100644
--- a/coreutils/condmv.c
+++ b/coreutils/condmv.c
@@ -6,23 +6,36 @@
#include "libbb.h"
-#define SAFE_PREFIX_FROM ATLAS_DATA_NEW
-#define SAFE_PREFIX_TO ATLAS_DATA_OUT
+#define SAFE_PREFIX_FROM1 ATLAS_DATA_NEW
+#define SAFE_PREFIX_FROM2 ATLAS_DATA_OUT
+#define SAFE_PREFIX_TO1 ATLAS_DATA_OUT
+#define SAFE_PREFIX_TO2 ATLAS_DATA_STORAGE
#define A_FLAG (1 << 0)
-#define F_FLAG (1 << 1)
+#define a_FLAG (1 << 1)
+#define D_FLAG (1 << 2)
+#define f_FLAG (1 << 3)
+#define t_FLAG (1 << 4)
+#define x_FLAG (1 << 5)
+
+static time_t age_value;
+static int cross_filesystems, append_timestamp;
+
+static int do_dir(char *from_dir, char *to_dir);
+static int do_cprm(char *from_file, char *to_file);
int condmv_main(int argc, char *argv[])
{
- char *opt_add, *from, *to;
+ char *opt_add, *opt_age, *from, *to, *check;
uint32_t opt;
struct stat sb;
FILE *file;
time_t mytime;
opt_add= NULL;
+ opt_age= NULL;
opt_complementary= NULL; /* For when we are called by crond */
- opt= getopt32(argv, "!A:f", &opt_add);
+ opt= getopt32(argv, "!A:a:Dftx", &opt_add, &opt_age);
if (opt == (uint32_t)-1)
{
@@ -39,19 +52,41 @@ int condmv_main(int argc, char *argv[])
from= argv[optind];
to= argv[optind+1];
- if (!validate_filename(from, SAFE_PREFIX_FROM))
+ if (!validate_filename(from, SAFE_PREFIX_FROM1) &&
+ !validate_filename(from, SAFE_PREFIX_FROM2))
{
fprintf(stderr, "insecure from file '%s'\n", from);
return 1;
}
- if (!validate_filename(to, SAFE_PREFIX_TO) &&
- !validate_filename(to, SAFE_PREFIX_FROM))
+ if (!validate_filename(to, SAFE_PREFIX_TO1) &&
+ !validate_filename(to, SAFE_PREFIX_TO2) &&
+ !validate_filename(to, SAFE_PREFIX_FROM1))
{
fprintf(stderr, "insecure to file '%s'\n", to);
return 1;
}
- if (stat(to, &sb) == 0 && !(opt & F_FLAG))
+ if (opt_age)
+ {
+ age_value= strtol(opt_age, &check, 0);
+ if (check[0] != '\0' || age_value <= 0)
+ {
+ fprintf(stderr, "bad age value '%s'\n", opt_age);
+ return 1;
+ }
+ }
+ else
+ age_value= 0;
+
+ cross_filesystems= !!(opt & x_FLAG);
+ append_timestamp= !!(opt & t_FLAG);
+
+ if (opt & D_FLAG)
+ {
+ return do_dir(from, to);
+ }
+
+ if (stat(to, &sb) == 0 && !(opt & f_FLAG))
{
/* Destination exists */
fprintf(stderr, "condmv: not moving, destination '%s' exists\n",
@@ -98,3 +133,211 @@ int condmv_main(int argc, char *argv[])
return 0;
}
+
+static int do_dir(char *from_dir, char *to_dir)
+{
+ int r, error;
+ size_t len, extra_len;
+ time_t now;
+ DIR *dir;
+ struct dirent *de;
+ char *from_file, *new_from_file;
+ char *to_file, *new_to_file;
+ size_t from_file_len, to_file_len;
+ struct stat sb;
+
+ from_file= NULL;
+ from_file_len= 0;
+ to_file= NULL;
+ to_file_len= 0;
+
+ dir= opendir(from_dir);
+ if (dir == NULL)
+ {
+ fprintf(stderr, "condmv: unable to open dir '%s': %s\n",
+ from_dir, strerror(errno));
+ return 1;
+ }
+
+ now= time (NULL); /* For age_value */
+
+ error= 0; /* Assume no failures */
+ while (de= readdir(dir), de != NULL)
+ {
+ len= strlen(from_dir) + 1 + strlen(de->d_name) + 1;
+ if (len > from_file_len)
+ {
+ new_from_file= realloc(from_file, len);
+ if (new_from_file == NULL)
+ {
+ fprintf(stderr,
+ "condmv: out of memory (from_file)\n");
+ error= 1;
+ break;
+ }
+ from_file= new_from_file; new_from_file= NULL;
+ from_file_len= len;
+ }
+ snprintf(from_file, from_file_len, "%s/%s",
+ from_dir, de->d_name);
+ r= stat(from_file, &sb);
+ if (r == -1)
+ {
+ fprintf(stderr, "condmv: stat %s failed: %sn",
+ from_file, strerror(errno));
+ error= 1;
+ break;
+ }
+ if (!S_ISREG(sb.st_mode))
+ {
+ /* Skip non-regular objects */
+ continue;
+ }
+
+ if (age_value)
+ {
+ if (sb.st_mtime + age_value > now)
+ continue;
+ }
+
+ if (append_timestamp)
+ {
+ /* A unix timestamp is currently 10 characters.
+ * Allocate an extra 16 characters to have enough
+ * space, also for the separator.
+ */
+ extra_len= 16;
+ }
+ else
+ extra_len= 0;
+ len= strlen(to_dir) + 1 + strlen(de->d_name) + extra_len + 1;
+ if (len > to_file_len)
+ {
+ new_to_file= realloc(to_file, len);
+ if (new_to_file == NULL)
+ {
+ fprintf(stderr,
+ "condmv: out of memory (to_file)\n");
+ error= 1;
+ break;
+ }
+ to_file= new_to_file; new_to_file= NULL;
+ to_file_len= len;
+ }
+ if (append_timestamp)
+ {
+ snprintf(to_file, to_file_len, "%s/%s.%lu",
+ to_dir, de->d_name, (unsigned long)now);
+ }
+ else
+ {
+ snprintf(to_file, to_file_len, "%s/%s",
+ to_dir, de->d_name);
+ }
+
+ /* Make sure to_file doesn't exist */
+ r= stat(to_file, &sb);
+ if (r == 0 || (r == -1 && errno != ENOENT))
+ {
+ /* Something wrong with to_file */
+ continue;
+ }
+
+ if (cross_filesystems)
+ {
+ r= do_cprm(from_file, to_file);
+ if (r == 0)
+ {
+ /* Okay, next one */
+ continue;
+ }
+ error= 1;
+ break;
+ }
+
+ r= rename(from_file, to_file);
+ if (r == -1)
+ {
+ fprintf(stderr,
+ "condmv: rename %s to %s failed: %s\n",
+ from_file, to_file, strerror(errno));
+ error= 1;
+ break;
+ }
+ }
+
+ closedir(dir);
+
+ if (from_file)
+ {
+ free(from_file);
+ from_file= NULL;
+ }
+ if (to_file)
+ {
+ free(to_file);
+ to_file= NULL;
+ }
+
+ return error;
+}
+
+static int do_cprm(char *from_file, char *to_file)
+{
+ FILE *fp_in, *fp_out;
+ size_t len_in, len_out;
+ char buf[1024];
+
+ fp_in= fopen(from_file, "rb");
+ if (fp_in == NULL)
+ {
+ fprintf(stderr, "condmv: cannot open '%s' for reading: %s\n",
+ from_file, strerror(errno));
+ return 1;
+ }
+
+ fp_out= fopen(to_file, "wb");
+ if (fp_out == NULL)
+ {
+ fprintf(stderr, "condmv: cannot open '%s' for writing: %s\n",
+ to_file, strerror(errno));
+ fclose(fp_in); fp_in= NULL;
+ return 1;
+ }
+
+ for (;;)
+ {
+ len_in= fread(buf, 1, sizeof(buf), fp_in);
+ if (len_in == 0)
+ break; /* EOF or error */
+
+ len_out= fwrite(buf, 1, len_in, fp_out);
+ if (len_out != len_in)
+ {
+ fprintf(stderr,
+ "condmv: error writing to '%s': %s\n",
+ to_file, strerror(errno));
+ fclose(fp_in); fp_in= NULL;
+ fclose(fp_out); fp_out= NULL;
+ unlink(to_file);
+ return 1;
+ }
+ }
+
+ if (ferror(fp_in))
+ {
+ fprintf(stderr,
+ "condmv: error reading from '%s': %s\n",
+ from_file, strerror(errno));
+ fclose(fp_in); fp_in= NULL;
+ fclose(fp_out); fp_out= NULL;
+ unlink(to_file);
+ return 1;
+ }
+
+ fclose(fp_in); fp_in= NULL;
+ fclose(fp_out); fp_out= NULL;
+ unlink(from_file);
+
+ return 0;
+}
diff --git a/eperd/eooqd.c b/eperd/eooqd.c
index 8c11f62..8f94614 100644
--- a/eperd/eooqd.c
+++ b/eperd/eooqd.c
@@ -185,6 +185,9 @@ int eooqd_main(int argc, char *argv[])
limit.rlim_max= RLIM_INFINITY;
setrlimit(RLIMIT_CORE, &limit);
+ /* Ignore SIGPIPE, broken TCP sessions may trigger them */
+ signal(SIGPIPE, SIG_IGN);
+
/* Create libevent event base */
EventBase= event_base_new();
if (!EventBase)
diff --git a/eperd/eperd.c b/eperd/eperd.c
index 83aff15..b126cce 100644
--- a/eperd/eperd.c
+++ b/eperd/eperd.c
@@ -336,6 +336,9 @@ int eperd_main(int argc UNUSED_PARAM, char **argv)
limit.rlim_max= RLIM_INFINITY;
setrlimit(RLIMIT_CORE, &limit);
+ /* Ignore SIGPIPE, broken TCP sessions may trigger them */
+ signal(SIGPIPE, SIG_IGN);
+
/* Create libevent event base */
EventBase= event_base_new();
if (!EventBase)
diff --git a/eperd/evtdig.c b/eperd/evtdig.c
index c5879de..d09d489 100644
--- a/eperd/evtdig.c
+++ b/eperd/evtdig.c
@@ -71,7 +71,7 @@
/* Intervals and timeouts (all are in milliseconds unless otherwise specified) */
#define DEFAULT_NOREPLY_TIMEOUT 5000 /* 5000 msec - 0 is illegal */
-#define DEFAULT_LINE_LENGTH 80
+#define DEFAULT_LINE_LENGTH 256
#define DEFAULT_STATS_REPORT_INTERVEL 180 /* in seconds */
#define CONN_TO 5 /* TCP connection time out in seconds */
#define DEFAULT_RETRY_MAX 0
@@ -387,14 +387,14 @@ struct EDNS0_HEADER
u_int8_t _edns_x; // combined rcode and edns version both zeros.
u_int8_t _edns_y; // combined rcode and edns version both zeros.
u_int16_t Z ; // first bit is the D0 bit.
+ uint16_t _edns_rdlen; // length of rdata
};
// EDNS OPT pseudo-RR : eg NSID RFC 5001
struct EDNS_NSID
{
- uint16_t len;
u_int16_t otype;
- u_int16_t odata;
+ u_int16_t olength; // length of option data
};
@@ -498,7 +498,7 @@ static char line[(DEFAULT_LINE_LENGTH+1)];
static void tdig_stats(int unused UNUSED_PARAM, const short event UNUSED_PARAM, void *h);
static int tdig_delete(void *state);
-static void ChangetoDnsNameFormat(u_char *dns, char * qry) ;
+static int ChangetoDnsNameFormat(u_char *dns, size_t maxlen, char* qry);
struct tdig_base *tdig_base_new(struct event_base *event_base);
void tdig_start (void *qry);
void printReply(struct query_state *qry, int wire_size, unsigned char *result);
@@ -506,20 +506,20 @@ void printErrorQuick (struct query_state *qry);
static void local_exit(void *state);
static void *tdig_init(int argc, char *argv[], void (*done)(void *state));
static void process_reply(void * arg, int nrecv, struct timespec now);
-static void mk_dns_buff(struct query_state *qry, u_char *packet);
+static void mk_dns_buff(struct query_state *qry, u_char *packet,
+ size_t packetlen) ;
int ip_addr_cmp (u_int16_t af_a, void *a, u_int16_t af_b, void *b);
static void udp_dns_cb(int err, struct evutil_addrinfo *ev_res, void *arg);
static void noreply_callback(int unused UNUSED_PARAM, const short event UNUSED_PARAM, void *h);
static void free_qry_inst(struct query_state *qry);
static void ready_callback (int unused, const short event, void * arg);
-/* move the next functions from tdig.c */
u_int32_t get32b (char *p);
void ldns_write_uint16(void *dst, uint16_t data);
uint16_t ldns_read_uint16(const void *src);
unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
int* count);
-/* from tdig.c */
+int dns_namelen(unsigned char *base, size_t offset, size_t size);
void print_txt_json(unsigned char *rdata, int txt_len,struct query_state *qry);
@@ -673,14 +673,15 @@ int ip_addr_cmp (u_int16_t af_a, void *a, u_int16_t af_b, void *b)
return 1;
}
-static void mk_dns_buff(struct query_state *qry, u_char *packet)
+static void mk_dns_buff(struct query_state *qry, u_char *packet,
+ size_t packetlen)
{
struct DNS_HEADER *dns = NULL;
- u_char *qname;
+ u_char *qname, *p;
struct QUESTION *qinfo = NULL;
struct EDNS0_HEADER *e;
struct EDNS_NSID *n;
- int r;
+ int r, qnamelen;
struct buf pbuf;
char *lookup_prepend;
int probe_id;
@@ -719,6 +720,20 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet)
//point to the query portion
qname =(u_char *)&packet[sizeof(struct DNS_HEADER)];
+ /* DNS limits the name lengths to 255 in DNS encoding. Verify that the
+ * buffer is big enough. Also include space for EDNS0 and NSID */
+ qnamelen= 255;
+
+ if (packetlen <
+ sizeof(struct DNS_HEADER) +
+ qnamelen + sizeof(struct QUESTION) +
+ 1 /* dummy dns name */ + sizeof(struct EDNS0_HEADER) +
+ sizeof(struct EDNS_NSID))
+ {
+ crondlog(DIE9 "mk_dns_buff: packet size too small, got %d",
+ packetlen);
+ }
+
// should it be limited to clas C_IN ?
if(qry->opt_prepend_probe_id ) {
probe_id = get_probe_id();
@@ -731,21 +746,31 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet)
"%d.%lu.%s", probe_id, qry->xmit_time,
qry->lookupname);
- ChangetoDnsNameFormat(qname, lookup_prepend); // fill the query portion.
+ qnamelen= ChangetoDnsNameFormat(qname, qnamelen,
+ lookup_prepend); // fill the query portion.
free(lookup_prepend);
}
else {
- ChangetoDnsNameFormat(qname, qry->lookupname); // fill the query portion.
+ qnamelen= ChangetoDnsNameFormat(qname, qnamelen,
+ qry->lookupname); // fill the query portion.
}
- qinfo =(struct QUESTION*)&packet[sizeof(struct DNS_HEADER) + (strlen((const char*)qname) + 1)];
+ if (qnamelen == -1)
+ return; /* Do we need to tell anybody? */
+
+ qinfo =(struct QUESTION*)&packet[sizeof(struct DNS_HEADER) + qnamelen];
qinfo->qtype = htons(qry->qtype);
qinfo->qclass = htons(qry->qclass);
- qry->pktsize = (strlen((const char*)qname) + 1) + sizeof(struct DNS_HEADER) + sizeof(struct QUESTION) ;
+ qry->pktsize = (sizeof(struct DNS_HEADER) + qnamelen +
+ sizeof(struct QUESTION)) ;
if(qry->opt_nsid || qry->opt_dnssec || (qry->opt_edns0 > 512)) {
- e=(struct EDNS0_HEADER*)&packet[ qry->pktsize + 1 ];
+ p= &packet[qry->pktsize];
+ *p= 0; /* encoding of '.' */
+ qry->pktsize++;
+
+ e=(struct EDNS0_HEADER*)&packet[ qry->pktsize ];
e->otype = htons(ns_t_opt);
e->_edns_udp_size = htons(qry->opt_edns0);
if(qry->opt_dnssec) {
@@ -754,6 +779,7 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet)
else {
e->Z = 0x0;
}
+ e->_edns_rdlen = htons(0);
crondlog(LVL5 "opt header in hex | %02X %02X %02X %02X %02X %02X %02X %02X %02X | %02X",
packet[qry->pktsize],
packet[qry->pktsize + 1],
@@ -767,15 +793,16 @@ static void mk_dns_buff(struct query_state *qry, u_char *packet)
packet[qry->pktsize + 9]);
qry->pktsize += sizeof(struct EDNS0_HEADER) ;
+ dns->add_count = htons(1);
if(qry->opt_nsid ) {
- dns->add_count = htons(1);
- n=(struct EDNS_NSID*)&packet[ qry->pktsize + 1 ];
- n->len = htons(4);
+ n=(struct EDNS_NSID*)&packet[ qry->pktsize ];
+ e->_edns_rdlen = htons(sizeof(struct EDNS_NSID));
n->otype = htons(3);
+ n->olength = htons(0);
+ qry->pktsize += sizeof(struct EDNS_NSID);
}
- qry->pktsize += sizeof(struct EDNS_NSID) + 1;
- dns->add_count = htons(1);
+
/* Transmit the request over the network */
}
buf_init(&pbuf, -1);
@@ -821,7 +848,7 @@ static void tdig_send_query_callback(int unused UNUSED_PARAM, const short event
//AA delete qry->outbuff = outbuff;
qry->xmit_time= time(NULL);
clock_gettime(CLOCK_MONOTONIC_RAW, &qry->xmit_time_ts);
- mk_dns_buff(qry, outbuff);
+ mk_dns_buff(qry, outbuff, MAX_DNS_OUT_BUF_SIZE);
do {
if (qry->udp_fd != -1)
{
@@ -1091,9 +1118,9 @@ static void tcp_connected(struct tu_env *env, struct bufferevent *bev)
getsockname(bufferevent_getfd(bev), &qry->loc_sin6, &qry->loc_socklen);
qry->bev_tcp = bev;
- outbuff = xzalloc(MAX_DNS_BUF_SIZE);
+ outbuff = xzalloc(MAX_DNS_OUT_BUF_SIZE);
bzero(outbuff, MAX_DNS_OUT_BUF_SIZE);
- mk_dns_buff(qry, outbuff);
+ mk_dns_buff(qry, outbuff, MAX_DNS_OUT_BUF_SIZE);
payload_len = (uint16_t) qry->pktsize;
wire = xzalloc (payload_len + 4);
ldns_write_uint16(wire, qry->pktsize);
@@ -1153,6 +1180,7 @@ static void tcp_readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr)
if (qry->response_out)
fwrite(b2, 2, 1, qry->resp_file);
qry->wire_size = ldns_read_uint16(b2);
+qry->wire_size= sizeof(struct DNS_HEADER);
buf_init(&qry->packet, -1);
}
else {
@@ -1161,6 +1189,18 @@ static void tcp_readcb(struct bufferevent *bev UNUSED_PARAM, void *ptr)
buf_add(&qry->err, line, strlen(line));
}
}
+
+ /* We need at least a header */
+ if (qry->wire_size < sizeof(struct DNS_HEADER))
+ {
+ snprintf(line, DEFAULT_LINE_LENGTH, "%s \"TCPREADSIZE\" : "
+ " \"reply too small, got %zu\""
+ , qry->err.size ? ", " : ""
+ , (size_t)qry->wire_size);
+ buf_add(&qry->err, line, strlen(line));
+ printReply (qry, 0, NULL);
+ return;
+ }
for (;;) {
if (qry->response_in)
n= fread(line, 1, 1, qry->resp_file);
@@ -1976,8 +2016,9 @@ void tdig_start (void *arg)
if(qry->resolv_max ) {
free(qry->server_name);
qry->server_name = NULL;
- qry->server_name = qry->nslist[qry->resolv_i];
- qry->nslist[qry->resolv_i]= NULL;
+ qry->server_name =
+ strdup(qry->nslist
+ [qry->resolv_i]);
}
else {
crondlog(LVL5 "AAA RESOLV QUERY FREE %s resolv_max is zero %d i %d", qry->server_name, qry->resolv_max, qry->resolv_i);
@@ -2179,23 +2220,68 @@ static void tdig_stats(int unusg_statsed UNUSED_PARAM, const short event UNUSED_
}
-static void ChangetoDnsNameFormat(u_char * dns, char* qry)
+/* Convert a string into DNS format. This is for a query so no compression.
+ * DNS format is a length byte followed by the contents of a label. We
+ * can assume that length of the DNS format is one larger than the original
+ * string because of the dots (except for just '.' where the length is the
+ * same).
+ */
+static int ChangetoDnsNameFormat(u_char *dns, size_t maxlen, char* qry)
{
- int lock = 0, i;
+ size_t qrylen, labellen;
+ char *src, *e;
+ u_char *dst;
+
+ qrylen= strlen(qry);
+
+ if (qrylen+1 > maxlen)
+ {
+ // printf("ChangetoDnsNameFormat: name too long\n");
+ return -1; /* Doesn't fit */
+ }
+
+ if (strcmp(qry, ".") == 0)
+ {
+ /* This doesn't fit in our regular schedule */
+ dns[0]= 0;
+ return 1;
+ }
- for(i = 0 ; i < (int)strlen((char*)qry) ; i++)
+ src= qry;
+ dst= dns;
+ for (; src[0] != '\0' && dst < dns+maxlen;)
{
- //printf ("%c", qry[i] );
- if(qry[i]=='.')
+ e= strchr(src, '.');
+ if (e == NULL)
{
- *dns++=i-lock;
- for(;lock<i;lock++) {
- *dns++=qry[lock];
- }
- lock++; //or lock=i+1;
+ // printf("ChangetoDnsNameFormat: no trailing dot\n");
+ return -1; /* qry does not end in a '.' */
+ }
+
+ labellen= e-src;
+ if (labellen > 63)
+ {
+ // printf("ChangetoDnsNameFormat: label too long\n");
+ return -1; /* Can't do more than 63 */
+ }
+ if (labellen == 0)
+ {
+ // printf("ChangetoDnsNameFormat: empty label\n");
+ return -1; /* Take care of lonely '.' earlier */
}
+
+ *dst= labellen;
+ dst++;
+ memcpy(dst, src, labellen);
+ src= e+1;
+ dst += labellen;
}
- *dns++=0;
+
+ /* End, at a trailing null label */
+ *dst= 0;
+ dst++;
+
+ return dst-dns;
}
@@ -2254,6 +2340,10 @@ static void free_qry_inst(struct query_state *qry)
free (qry->server_name);
qry->server_name = NULL;
}
+ if (qry->nslist[qry->resolv_i] == NULL)
+ {
+ crondlog(DIE9 "free_qry_inst: qry %p, no resolver at index %d, max %d", qry, qry->resolv_i, qry->resolv_max);
+ }
qry->server_name = strdup(qry->nslist[qry->resolv_i]);
qry->qst = STATUS_NEXT_QUERY;
evtimer_add(&qry->next_qry_timer, &asap);
@@ -2425,7 +2515,6 @@ void printErrorQuick (struct query_state *qry)
void printReply(struct query_state *qry, int wire_size, unsigned char *result)
{
int i, stop=0;
- unsigned char *qname, *reader;
struct DNS_HEADER *dnsR = NULL;
struct RES_RECORD answers[20]; //the replies from the DNS server
void *ptr = NULL;
@@ -2434,8 +2523,10 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result)
u_int32_t serial;
int iMax ;
int flagAnswer = 0;
- int data_len, offset;
+ int data_len, len;
int write_out = FALSE;
+ unsigned offset;
+ unsigned char *name1= NULL, *name2= NULL;
int fw = get_atlas_fw_version();
int lts = get_timesync();
@@ -2526,19 +2617,26 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result)
if(result)
{
- dnsR = (struct DNS_HEADER*) result;
-
- //point to the query portion
- qname =(unsigned char*)&result[sizeof(struct DNS_HEADER)];
-
- //move ahead of the dns header and the query field
- reader = &result[sizeof(struct DNS_HEADER) + (strlen((const char*)qname)+1) + sizeof(struct QUESTION)];
-
snprintf(line, DEFAULT_LINE_LENGTH, ",\"result\" : { \"rt\" : %.3f,", qry->triptime);
buf_add(&qry->result,line, strlen(line));
JD (size, wire_size);
+
+ if(qry->opt_abuf) {
+ snprintf(line, DEFAULT_LINE_LENGTH, "\"abuf\" : \"");
+ buf_add(&qry->result,line, strlen(line));
+ buf_add_b64(&qry->result, result, wire_size, 0);
+ AS("\"");
+ }
+
+ if (wire_size < sizeof(struct DNS_HEADER))
+ goto truncated;
+
+ dnsR = (struct DNS_HEADER*) result;
+
+ buf_add(&qry->result, ",", 1);
JU (ID, ntohs(dnsR->id));
+
/*
fprintf (fh, " , \"RCODE\" : %d", dnsR->rcode);
fprintf (fh, " , \"AA\" : %d", dnsR->aa);
@@ -2549,12 +2647,17 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result)
JU (NSCOUNT, ntohs(dnsR->ns_count));
JU_NC (ARCOUNT, ntohs(dnsR->add_count));
- if(qry->opt_abuf) {
- snprintf(line, DEFAULT_LINE_LENGTH, ",\"abuf\" : \"");
- buf_add(&qry->result,line, strlen(line));
- buf_add_b64(&qry->result, result, wire_size, 0);
- AS("\"");
- }
+ /* Start just after header */
+ offset= sizeof(struct DNS_HEADER);
+
+ len= dns_namelen(result, offset, wire_size);
+ if (len == -1)
+ goto truncated;
+
+ offset += len + sizeof(struct QUESTION);
+
+ if (offset > wire_size)
+ goto truncated;
stop=0;
iMax = 0;
@@ -2568,24 +2671,31 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result)
for(i=0;i<iMax;i++)
{
answers[i].name=ReadName(result,wire_size,
- reader-result,&stop);
- reader = reader + stop;
+ offset,&stop);
+ if (stop == -1)
+ goto truncated;
+ offset += stop;
- if (reader + sizeof(answers[i].resource) >
- result + wire_size)
+ if (offset + sizeof(struct R_DATA) >
+ wire_size)
{
/* Report error? */
- break;
+ goto truncated;
}
- answers[i].resource = (struct R_DATA*)(reader);
- reader = reader + sizeof(struct R_DATA);
+ answers[i].resource =
+ (struct R_DATA*)(result+offset);
+ offset += sizeof(struct R_DATA);
answers[i].rdata = NULL;
if(ntohs(answers[i].resource->type)==T_TXT) //txt
{
data_len = ntohs(answers[i].resource->data_len);
+
+ if (offset+data_len > wire_size)
+ goto truncated;
+
if(flagAnswer == 0) {
AS(",\"answers\" : [ {");
flagAnswer++;
@@ -2596,17 +2706,37 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result)
flagAnswer++;
JS (TYPE, "TXT");
JS (NAME, answers[i].name);
- offset= reader-result;
- if (offset+data_len > wire_size)
- data_len= wire_size-offset;
- print_txt_json(reader,
+ print_txt_json(result+offset,
data_len, qry);
- reader = reader + ntohs(answers[i].resource->data_len);
+ offset += data_len;
AS("}");
}
else if (ntohs(answers[i].resource->type)== T_SOA)
{
+ name1= name2= NULL;
+ name1 = ReadName(
+ result,wire_size,
+ offset,&stop);
+ if (stop == -1)
+ goto truncated;
+ offset += stop;
+ name2 = ReadName(
+ result,wire_size,
+ offset,&stop);
+ if (stop == -1)
+ {
+ free(name1); name1= NULL;
+ goto truncated;
+ }
+ offset += stop;
+ if (offset+5*4 > wire_size)
+ {
+ free(name1); name1= NULL;
+ free(name2); name2= NULL;
+ goto truncated;
+ }
+
if(flagAnswer == 0) {
AS(",\"answers\" : [ { ");
}
@@ -2618,26 +2748,27 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result)
JS(TYPE, "SOA");
JSDOT(NAME, answers[i].name);
JU(TTL, ntohl(answers[i].resource->ttl));
- answers[i].rdata = ReadName(
- result,wire_size,
- reader-result,&stop);
- JSDOT( MNAME, answers[i].rdata);
- reader = reader + stop;
- free(answers[i].rdata);
- answers[i].rdata = ReadName(
- result,wire_size,
- reader-result,&stop);
- JSDOT( RNAME, answers[i].rdata);
- reader = reader + stop;
- serial = get32b((char *)reader);
+ JSDOT( MNAME, name1);
+ free(name1); name1= NULL;
+ JSDOT( RNAME, name2);
+ free(name2); name2= NULL;
+
+ serial = get32b(result+offset);
JU_NC(SERIAL, serial);
- reader = reader + 4;
- reader = reader + 16; // skip REFRESH, RETRY, EXIPIRE, and MINIMUM
+ offset += 4;
+
+ offset += 4*4; // skip REFRESH, RETRY, EXIPIRE, and MINIMUM
AS(" } ");
}
else
{
- reader = reader + ntohs(answers[i].resource->data_len);
+ data_len = ntohs(answers[i].
+ resource->data_len);
+
+ if (offset+data_len > wire_size)
+ goto truncated;
+
+ offset += data_len;
}
// free mem
@@ -2653,6 +2784,7 @@ void printReply(struct query_state *qry, int wire_size, unsigned char *result)
free(answers[i].name);
}
+truncated:
AS (" }"); //result {
}
if(qry->err.size)
@@ -2729,7 +2861,8 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
snprintf((char *)name, sizeof(name),
"format-error at %lu: value 0x%x",
offset, len);
- //abort();
+ *count= -1;
+ free(name); name= NULL;
return name;
}
@@ -2739,7 +2872,8 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
snprintf((char *)name, sizeof(name),
"offset-error at %lu: offset %lu",
offset, noffset);
- //abort();
+ *count= -1;
+ free(name); name= NULL;
return name;
}
@@ -2749,7 +2883,8 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
snprintf((char *)name, sizeof(name),
"too many redirects at %lu",
offset);
- //abort();
+ *count= -1;
+ free(name); name= NULL;
return name;
}
@@ -2770,7 +2905,8 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
snprintf((char *)name, sizeof(name),
"buf-bounds-error at %lu: len %d",
offset, len);
- //abort();
+ *count= -1;
+ free(name); name= NULL;
return name;
}
@@ -2779,7 +2915,8 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
snprintf((char *)name, sizeof(name),
"name-length-error at %lu: len %d",
offset, p+len+1);
- //abort();
+ *count= -1;
+ free(name); name= NULL;
return name;
}
memcpy(name+p, base+offset+1, len);
@@ -2806,6 +2943,42 @@ unsigned char* ReadName(unsigned char *base, size_t size, size_t offset,
return name;
}
+int dns_namelen(unsigned char *base, size_t offset, size_t size)
+{
+ size_t start_offset;
+ unsigned int len;
+
+ start_offset= offset;
+
+ //figure out the length of a name in 3www6google3com format
+ while(offset < size)
+ {
+ len= base[offset];
+ if (len & 0xc0)
+ {
+ if ((len & 0xc0) != 0xc0)
+ {
+ /* Bad format */
+ return -1;
+ }
+
+ offset++;
+ break;
+ }
+ if (offset+len+1 > size)
+ {
+ return -1;
+ }
+
+ offset += len+1;
+
+ if (len == 0)
+ break;
+ }
+
+ return offset-start_offset;
+}
+
/* get 4 bytes from memory
* eg. used to extract serial number from soa packet
*/
diff --git a/eperd/ping.c b/eperd/ping.c
index 583d512..a479312 100644
--- a/eperd/ping.c
+++ b/eperd/ping.c
@@ -87,7 +87,7 @@ struct pingbase
void (*done)(void *state); /* Called when a ping is done */
- u_char packet [MAX_DATA_SIZE];
+ u_char packet[MAX_DATA_SIZE];
};
struct pingstate
@@ -720,7 +720,6 @@ static void ready_callback4 (int __attribute((unused)) unused,
/* Pointer to relevant portions of the packet (IP, ICMP and user
* data) */
ip = (struct ip *) base->packet;
- data = (struct evdata *) (base->packet + IPHDR + ICMP_MINLEN);
/* Time the packet has been received */
clock_gettime(CLOCK_MONOTONIC_RAW, &now);
@@ -791,7 +790,8 @@ static void ready_callback4 (int __attribute((unused)) unused,
hlen = ip->ip_hl * 4;
/* Check the IP header */
- if (nrecv < hlen + ICMP_MINLEN || ip->ip_hl < 5)
+ if (nrecv < hlen + ICMP_MINLEN + sizeof (struct evdata) ||
+ ip->ip_hl < 5)
{
/* One more too short packet */
goto done;
@@ -811,8 +811,15 @@ static void ready_callback4 (int __attribute((unused)) unused,
}
/* Check the ICMP payload for legal values of the 'index' portion */
+ data = (struct evdata *) (base->packet + hlen + ICMP_MINLEN);
if (data->index >= base->tabsiz || base->table[data->index] == NULL)
+ {
+#if 0
+ printf("ready_callback4: bad index: got %d\n",
+ data->index);
+#endif
goto done;
+ }
/* Get the pointer to the host descriptor in our internal table */
if (state != base->table[data->index])
@@ -899,6 +906,7 @@ static void ready_callback6 (int __attribute((unused)) unused,
struct pingstate *state;
int nrecv, isDup;
+ size_t icmp_len;
struct sockaddr_in6 remote; /* responding internet address */
struct icmp6_hdr *icmp;
@@ -918,8 +926,8 @@ static void ready_callback6 (int __attribute((unused)) unused,
/* Pointer to relevant portions of the packet (IP, ICMP and user
* data) */
icmp = (struct icmp6_hdr *) base->packet;
- data = (struct evdata *) (base->packet +
- offsetof(struct icmp6_hdr, icmp6_data16[2]));
+ icmp_len= offsetof(struct icmp6_hdr, icmp6_data16[2]);
+ data = (struct evdata *) (base->packet + icmp_len);
/* Time the packet has been received */
clock_gettime(CLOCK_MONOTONIC_RAW, &now);
@@ -995,6 +1003,12 @@ static void ready_callback6 (int __attribute((unused)) unused,
fwrite(&remote, sizeof(remote), 1, state->resp_file_out);
}
+ if (nrecv < icmp_len+sizeof(struct evdata))
+ {
+ // printf("ready_callback6: short packet\n");
+ goto done;
+ }
+
/* Check the ICMP header to drop unexpected packets due to
* unrecognized id
*/
diff --git a/eperd/sslgetcert.c b/eperd/sslgetcert.c
index 6660b40..cba0f42 100644
--- a/eperd/sslgetcert.c
+++ b/eperd/sslgetcert.c
@@ -410,6 +410,11 @@ static int msgbuf_read(struct state *state, struct msgbuf *msgbuf, int *typep,
*majorp= p[1];
*minorp= p[2];
len= (p[3] << 8) + p[4];
+ /* Note that buf_read may reallocate msgbuf->inbuf->buf,
+ * which invalidates p. For this reason, after buf_read
+ * either return to the caller, or use 'continue' to
+ * restart at the top of the loop.
+ */
if (msgbuf->inbuf->size - msgbuf->inbuf->offset < 5 + len)
{
r= buf_read(state, msgbuf->inbuf);
@@ -1264,6 +1269,13 @@ static int eat_certificate(struct state *state)
return -1;
}
len= (p[1] << 16) + (p[2] << 8) + p[3];
+
+ /* Note that msgbuf_read may cause the buffer
+ * (msgbuf->buffer.buf) to be reallocated. This will make
+ * p a wild pointer. To counter that, after msgbuf_read,
+ * either return an error to the caller or use 'continue'
+ * to restart at the top of the loop.
+ */
if (msgbuf->buffer.size - msgbuf->buffer.offset < 4+len)
{
r= msgbuf_read(state, msgbuf, &type,
diff --git a/eperd/traceroute.c b/eperd/traceroute.c
index b335a9d..e29f174 100644
--- a/eperd/traceroute.c
+++ b/eperd/traceroute.c
@@ -74,7 +74,10 @@ struct trtbase
*/
void (*done)(void *state);
- u_char packet[MAX_DATA_SIZE];
+ /* Leave some space for headers. The various traceroute variations
+ * have to check that it fits.
+ */
+ u_char packet[MAX_DATA_SIZE+128];
};
struct trtstate
@@ -602,6 +605,12 @@ static void send_pkt(struct trtstate *state)
tcphdr->doff= len / 4;
tcphdr->syn= 1;
+ if (len+state->curpacksize > sizeof(base->packet))
+ {
+ crondlog(
+ DIE9 "base->packet too small, need at least %d",
+ len+state->curpacksize);
+ }
if (state->curpacksize > 0)
{
memset(&base->packet[len], '\0',
@@ -709,6 +718,14 @@ static void send_pkt(struct trtstate *state)
if (state->curpacksize < len)
state->curpacksize= len;
+ if (ICMP6_HDR+state->curpacksize >
+ sizeof(base->packet))
+ {
+ crondlog(
+ DIE9 "base->packet too small, need at least %d",
+ ICMP6_HDR+state->curpacksize);
+ }
+
if (state->curpacksize > len)
{
memset(&base->packet[ICMP6_HDR+len], '\0',
@@ -981,6 +998,12 @@ static void send_pkt(struct trtstate *state)
tcphdr->doff= len / 4;
tcphdr->syn= 1;
+ if (len+state->curpacksize > sizeof(base->packet))
+ {
+ crondlog(
+ DIE9 "base->packet too small, need at least %d",
+ len+state->curpacksize);
+ }
if (state->curpacksize > 0)
{
memset(&base->packet[len], '\0',
@@ -1094,14 +1117,26 @@ static void send_pkt(struct trtstate *state)
len= offsetof(struct icmp, icmp_data[2]);
- if (state->curpacksize+ICMP_MINLEN < len)
+ /* currpacksize is the amount of data after the
+ * ICMP header. len is the minimal amount of data
+ * including the ICMP header. Later len becomes
+ * the packet size including ICMP header.
+ */
+ if (ICMP_MINLEN+state->curpacksize < len)
state->curpacksize= len-ICMP_MINLEN;
- if (state->curpacksize+ICMP_MINLEN > len)
+ if (ICMP_MINLEN+state->curpacksize >
+ sizeof(base->packet))
+ {
+ crondlog(
+ DIE9 "base->packet too small, need at least %d",
+ ICMP_MINLEN+state->curpacksize);
+ }
+ if (ICMP_MINLEN+state->curpacksize > len)
{
memset(&base->packet[len], '\0',
- state->curpacksize-ICMP_MINLEN-len);
+ ICMP_MINLEN+state->curpacksize-len);
strcpy((char *)&base->packet[len], id);
- len= state->curpacksize+ICMP_MINLEN;
+ len= ICMP_MINLEN+state->curpacksize;
}
if (state->parismod)
@@ -2961,7 +2996,7 @@ static void ready_callback6(int __attribute((unused)) unused,
ssize_t nrecv;
int ind, rcvdttl, late, isDup, nxt, icmp_prefixlen, offset;
unsigned nextmtu, seq, optlen, hbhoptsize, dstoptsize;
- size_t ehdrsiz, v6info_siz, siz;
+ size_t v6info_siz, siz;
struct trtbase *base;
struct trtstate *state;
struct ip6_hdr *eip;
@@ -3136,7 +3171,8 @@ static void ready_callback6(int __attribute((unused)) unused,
return;
}
- /* Make sure we have TCP, UDP, ICMP or a fragment header */
+ /* Make sure we have TCP, UDP, ICMP, a fragment header or
+ * an options header */
if (eip->ip6_nxt == IPPROTO_FRAGMENT ||
eip->ip6_nxt == IPPROTO_HOPOPTS ||
eip->ip6_nxt == IPPROTO_DSTOPTS ||
@@ -3144,7 +3180,6 @@ static void ready_callback6(int __attribute((unused)) unused,
eip->ip6_nxt == IPPROTO_UDP ||
eip->ip6_nxt == IPPROTO_ICMPV6)
{
- ehdrsiz= 0;
frag= NULL;
nxt= eip->ip6_nxt;
ptr= &eip[1];
@@ -3153,12 +3188,12 @@ static void ready_callback6(int __attribute((unused)) unused,
/* Make sure the options header is completely
* there.
*/
- if (nrecv < sizeof(*icmp) + sizeof(*eip)
- + sizeof(*opthdr))
+ offset= (u_char *)ptr - base->packet;
+ if (offset + sizeof(*opthdr) > nrecv)
{
#if 0
printf(
- "ready_callback6: too short %d (icmp+ip+opt)\n",
+ "ready_callback6: too short %d (HOPOPTS)\n",
(int)nrecv);
#endif
return;
@@ -3166,13 +3201,11 @@ static void ready_callback6(int __attribute((unused)) unused,
opthdr= (struct ip6_ext *)ptr;
hbhoptsize= 8*opthdr->ip6e_len;
optlen= hbhoptsize+8;
- if (nrecv < sizeof(*icmp) + sizeof(*eip) +
- optlen)
+ if (offset + optlen > nrecv)
{
/* Does not contain the full header */
return;
}
- ehdrsiz += optlen;
nxt= opthdr->ip6e_nxt;
ptr= ((char *)opthdr)+optlen;
}
@@ -3181,12 +3214,12 @@ static void ready_callback6(int __attribute((unused)) unused,
/* Make sure the fragment header is completely
* there.
*/
- if (nrecv < sizeof(*icmp) + sizeof(*eip)
- + sizeof(*frag))
+ offset= (u_char *)ptr - base->packet;
+ if (offset + sizeof(*frag) > nrecv)
{
#if 0
printf(
- "ready_callback6: too short %d (icmp+ip+frag)\n",
+ "ready_callback6: too short %d (FRAGMENT)\n",
(int)nrecv);
#endif
return;
@@ -3199,7 +3232,6 @@ static void ready_callback6(int __attribute((unused)) unused,
*/
return;
}
- ehdrsiz += sizeof(*frag);
nxt= frag->ip6f_nxt;
ptr= &frag[1];
}
@@ -3208,12 +3240,12 @@ static void ready_callback6(int __attribute((unused)) unused,
/* Make sure the options header is completely
* there.
*/
- if (nrecv < sizeof(*icmp) + sizeof(*eip)
- + sizeof(*opthdr))
+ offset= (u_char *)ptr - base->packet;
+ if (offset + sizeof(*opthdr) > nrecv)
{
#if 0
printf(
- "ready_callback6: too short %d (icmp+ip+opt)\n",
+ "ready_callback6: too short %d (DSTOPTS)\n",
(int)nrecv);
#endif
return;
@@ -3221,13 +3253,16 @@ static void ready_callback6(int __attribute((unused)) unused,
opthdr= (struct ip6_ext *)ptr;
dstoptsize= 8*opthdr->ip6e_len;
optlen= dstoptsize+8;
- if (nrecv < sizeof(*icmp) + sizeof(*eip) +
- optlen)
+ if (offset + optlen > nrecv)
{
/* Does not contain the full header */
+#if 0
+ printf(
+ "ready_callback6: too short %d (full DSTOPTS)\n",
+ (int)nrecv);
+#endif
return;
}
- ehdrsiz += optlen;
nxt= opthdr->ip6e_nxt;
ptr= ((char *)opthdr)+optlen;
}
@@ -3235,19 +3270,19 @@ static void ready_callback6(int __attribute((unused)) unused,
v6info_siz= sizeof(*v6info);
if (nxt == IPPROTO_TCP)
{
- ehdrsiz += sizeof(*etcp);
+ siz= sizeof(*etcp);
v6info_siz= 0;
}
else if (nxt == IPPROTO_UDP)
- ehdrsiz += sizeof(*eudp);
+ siz= sizeof(*eudp);
else
- ehdrsiz += sizeof(*eicmp);
+ siz= sizeof(*eicmp);
/* Now check if there is also a header in the
* packet.
*/
- if (nrecv < sizeof(*icmp) + sizeof(*eip)
- + ehdrsiz + v6info_siz)
+ offset= (u_char *)ptr - base->packet;
+ if (offset + siz + v6info_siz > nrecv)
{
#if 0
printf(
@@ -3885,8 +3920,11 @@ for (i= 0; argv[i] != NULL; i++)
*/
do_tcp= !!(opt & OPT_T);
do_udp= !(do_icmp || do_tcp);
- if (maxpacksize > sizeof(trt_base->packet))
- maxpacksize= sizeof(trt_base->packet);
+ if (maxpacksize > MAX_DATA_SIZE)
+ {
+ crondlog(LVL8 "max. packet size too big");
+ return NULL;
+ }
if (response_in)
{
diff --git a/include/libbb.h b/include/libbb.h
index 7325ede..96c9bab 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -309,6 +309,7 @@ extern char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC;
#define ATLAS_DATA_OUT ATLAS_HOME "/data/out"
#define ATLAS_DATA_OOQ_OUT ATLAS_HOME "/data/ooq.out"
#define ATLAS_DATA_NEW ATLAS_HOME "/data/new"
+#define ATLAS_DATA_STORAGE ATLAS_HOME "/data/storage"
#define ATLAS_TIMESYNC_FILE ATLAS_DATA_NEW "/timesync.vol"
#define ATLAS_FUZZING ATLAS_HOME "/data"
diff --git a/libbb/atlas_check_addr.c b/libbb/atlas_check_addr.c
index a3a69f3..87245aa 100644
--- a/libbb/atlas_check_addr.c
+++ b/libbb/atlas_check_addr.c
@@ -30,6 +30,8 @@ static bad_ipv6[] =
{
{ { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001 },
128 }, /* ::1 loopback */
+ { { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0x0000, 0x0000 },
+ 96 }, /* ::ffff:0:0/96 IPv4-mapped */
{ { 0xE000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
3 }, /* e000::/3 ULA, link local, multicast */
};
diff --git a/networking/httppost.c b/networking/httppost.c
index b6e01da..edc88a4 100644
--- a/networking/httppost.c
+++ b/networking/httppost.c
@@ -19,6 +19,7 @@
#define SAFE_PREFIX_DATA_OUT ATLAS_DATA_OUT
#define SAFE_PREFIX_DATA_OOQ_OUT ATLAS_DATA_OOQ_OUT
#define SAFE_PREFIX_DATA_NEW ATLAS_DATA_NEW
+#define SAFE_PREFIX_DATA_STORAGE ATLAS_DATA_STORAGE
#define SAFE_PREFIX_STATUS ATLAS_STATUS
/* Maximum number of files to post in one go with post-dir */
@@ -372,7 +373,10 @@ int httppost_main(int argc, char *argv[])
{
fprintf(stderr, "posting file '%s'\n", p);
if (!validate_filename(p, SAFE_PREFIX_DATA_OUT) &&
- !validate_filename(p, SAFE_PREFIX_DATA_OOQ_OUT))
+ !validate_filename(p,
+ SAFE_PREFIX_DATA_OOQ_OUT) &&
+ !validate_filename(p,
+ SAFE_PREFIX_DATA_STORAGE))
{
report("protected file (post dir) '%s'", p);
goto err;