Skip to content

Commit

Permalink
Correct escaping when writing text arrays.
Browse files Browse the repository at this point in the history
  • Loading branch information
0xxon committed Jan 24, 2017
1 parent 16067ca commit cbacc59
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 24 deletions.
44 changes: 25 additions & 19 deletions src/PostgresWriter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <string>
#include <errno.h>
#include <vector>
#include <regex>

#include "bro-config.h"

Expand Down Expand Up @@ -256,12 +257,15 @@ bool PostgreSQL::DoHeartbeat(double network_time, double current_time)
return true;
}

std::tuple<bool, string> PostgreSQL::CreateParams(const Value* val)
std::tuple<bool, string, int> PostgreSQL::CreateParams(const Value* val)
{
static std::regex curly_re("\\{|\"");

if ( ! val->present )
return std::make_tuple(false, string());
return std::make_tuple(false, string(), 0);

string retval;
int retlength = 0;

switch ( val->type ) {

Expand Down Expand Up @@ -301,7 +305,7 @@ std::tuple<bool, string> PostgreSQL::CreateParams(const Value* val)
case TYPE_FILE:
case TYPE_FUNC:
if ( ! val->val.string_val.length || val->val.string_val.length == 0 )
return std::make_tuple(false, string());
return std::make_tuple(false, string(), 0);

retval = string(val->val.string_val.data, val->val.string_val.length);
break;
Expand All @@ -313,6 +317,7 @@ std::tuple<bool, string> PostgreSQL::CreateParams(const Value* val)
Value** vals;

string out("{");
retlength = 1;

if ( val->type == TYPE_TABLE )
{
Expand All @@ -326,7 +331,7 @@ std::tuple<bool, string> PostgreSQL::CreateParams(const Value* val)
}

if ( ! size )
return std::make_tuple(false, string());
return std::make_tuple(false, string(), 0);

for ( int i = 0; i < size; ++i )
{
Expand All @@ -349,61 +354,62 @@ std::tuple<bool, string> PostgreSQL::CreateParams(const Value* val)
out += resstr;
else
{
char* escaped = PQescapeLiteral(conn, resstr.c_str(), resstr.size());
if ( escaped == nullptr )
{
Error(Fmt("Error while escaping '%s'", resstr.c_str()));
return std::make_tuple(false, string());
}
else
{
out += escaped;
PQfreemem(escaped);
}
string escaped = std::regex_replace(resstr, curly_re, "\\$&");
out += "\"" + escaped + "\"";
retlength += 2+escaped.length();
}
}

out += "}";
retlength += 1;
retval = out;
break;
}

default:
Error(Fmt("unsupported field format %d", val->type ));
return std::make_tuple(false, string());
return std::make_tuple(false, string(), 0);
}

return std::make_tuple(true, retval);
if ( retlength == 0 )
retlength = retval.length();

return std::make_tuple(true, retval, retlength);
}

bool PostgreSQL::DoWrite(int num_fields, const Field* const* fields, Value** vals)
{
vector<std::tuple<bool, string>> params; // vector in which we compile the string representation of characters
vector<std::tuple<bool, string, int>> params; // vector in which we compile the string representation of characters

for ( int i = 0; i < num_fields; ++i )
params.push_back(CreateParams(vals[i]));

vector<const char*> params_char; // vector in which we compile the character pointers that we
// then pass to PQexecParams. These do not have to be cleaned up because the srings will be
// cleaned up automatically.
vector<int> params_length; // vector in which we compile the lengths of the parameters that we
// then pass to PQexecParams

for ( auto &i: params )
{
if ( std::get<0>(i) == false)
params_char.push_back(nullptr); // null pointer is accepted to signify NULL in parameters
else
params_char.push_back(std::get<1>(i).c_str());

params_length.push_back(std::get<2>(i));
}

assert( params_char.size() == num_fields );
assert( params_length.size() == num_fields );

// & of vector is legal - according to current STL standard, vector has to be saved in consecutive memory.
PGresult *res = PQexecParams(conn,
insert.c_str(),
params_char.size(),
NULL,
&params_char[0],
NULL,
&params_length[0],
NULL,
0);

Expand Down
2 changes: 1 addition & 1 deletion src/PostgresWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class PostgreSQL : public WriterBackend {
string LookupParam(const WriterInfo& info, const string name) const;
// note - EscapeIdentifier is replicated in reader
string EscapeIdentifier(const char* identifier);
std::tuple<bool, string> CreateParams(const threading::Value* val);
std::tuple<bool, string, int> CreateParams(const threading::Value* val);
string GetTableType(int, int);
bool CreateInsert(int num_fields, const threading::Field* const* fields);

Expand Down
13 changes: 11 additions & 2 deletions tests/Baseline/postgres.write-basic/ssh.out
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
id|b|i|e|c|p|sn|a|d|t|iv|s|sc|ss|se|vc|ve|f
1|t|-42|SSH::LOG|21|123|10.0.0.0/24|1.2.3.4|3.14|1469746520.97267|100|hurz|{2,4,1,3}|{'BB','AA','CC'}||{10,20,30}||SSHTest::foo
1|t|-42|SSH::LOG|21|123|10.0.0.0/24|1.2.3.4|3.14|1485285824.55032|100|hurz|{2,4,1,3}|{BB,AA,CC}||{10,20,30}||SSHTest::foo
{
if (0 < SSHTest::i)
return (Foo);
else
return (Bar);

}
(1 row)
2|t|-42|SSH::LOG|21|123|10.0.0.0/24|1.2.3.4|3.14|1485285824.55032|100|hurz|{2,4,1,3}|{"{\"\"hello","a b
cd~e","{{{{{}'","\""}||{10,20,30}||SSHTest::foo
{
if (0 < SSHTest::i)
return (Foo);
else
return (Bar);

}
(2 rows)
Expand Down
2 changes: 1 addition & 1 deletion tests/Baseline/postgres.write-bytea/ssh.out
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
id|b|i|e|c|p|sn|a|d|t|iv|s|sc|ss|se|vc|ve|f
1|t|-42|\x5353483a3a4c4f47|21|123|10.0.0.0/24|1.2.3.4|3.14|1483728223.83267|100|\x6875727a|{2,4,1,3}|{"\\x27424227","\\x27414127","\\x27434327"}||{10,20,30}||\x535348546573743a3a666f6f0a7b200a6966202830203c20535348546573743a3a6929200a0972657475726e2028466f6f293b0a656c73650a0972657475726e2028426172293b0a0a7d
1|t|-42|\x5353483a3a4c4f47|21|123|10.0.0.0/24|1.2.3.4|3.14|1485286025.31206|100|\x6875727a|{2,4,1,3}|{"\\x4242","\\x4141","\\x4343"}||{10,20,30}||\x535348546573743a3a666f6f0a7b200a6966202830203c20535348546573743a3a6929200a0972657475726e2028466f6f293b0a656c73650a0972657475726e2028426172293b0a0a7d
(1 row)
2 changes: 1 addition & 1 deletion tests/Baseline/postgres.write-error/ssh.out
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
id|b|i|e|c|p|sn|a|d|t|iv|s|sc|ss|se|vc|ve|f
1|t|-42|SSH::LOG|21|123|10.0.0.0/24|1.2.3.4|3.14|1483728583.31779|100|h|{2,4,1,3}|{'BB','AA','CC'}||{10,20,30}||SSHTest::foo
1|t|-42|SSH::LOG|21|123|10.0.0.0/24|1.2.3.4|3.14|1485286076.88712|100|h|{2,4,1,3}|{BB,AA,CC}||{10,20,30}||SSHTest::foo
{
if (0 < SSHTest::i)
return (Foo);
Expand Down
20 changes: 20 additions & 0 deletions tests/postgres/write-basic.bro
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,25 @@ event bro_init()
$ve=empty_vector,
$f=foo
]);

Log::write(SSHTest::LOG, [
$b=T,
$i=-42,
$e=SSH::LOG,
$c=21,
$p=123/tcp,
$sn=10.0.0.1/24,
$a=1.2.3.4,
$d=3.14,
$t=network_time(),
$iv=100secs,
$s="hurz",
$sc=set(1,2,3,4),
$ss=set("\"", "{{{{{}'", "{\"\"\\hello", "a\tb\nc\rd\x01\x02\x03\x7Ee"),
$se=empty_set,
$vc=vector(10, 20, 30),
$ve=empty_vector,
$f=foo
]);
}

0 comments on commit cbacc59

Please sign in to comment.