Skip to content

Commit 050c4cf

Browse files
authored
Require the SQL used by ODBCAppender to be a single statement (#564)
* Add web-site nudge to protect the configuration file
1 parent 0a21e4d commit 050c4cf

File tree

4 files changed

+37
-4
lines changed

4 files changed

+37
-4
lines changed

src/main/cpp/odbcappender.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ void ODBCAppender::append(const spi::LoggingEventPtr& event, LOG4CXX_NS::helpers
267267
#endif
268268
}
269269

270+
#if LOG4CXX_ABI_VERSION <= 15
270271
LogString ODBCAppender::getLogStatement(const spi::LoggingEventPtr& event, LOG4CXX_NS::helpers::Pool& p) const
271272
{
272273
return LogString();
@@ -275,6 +276,7 @@ LogString ODBCAppender::getLogStatement(const spi::LoggingEventPtr& event, LOG4C
275276
void ODBCAppender::execute(const LogString& sql, LOG4CXX_NS::helpers::Pool& p)
276277
{
277278
}
279+
#endif
278280

279281
/* The default behavior holds a single connection open until the appender
280282
is closed (typically when garbage collected).*/
@@ -613,6 +615,28 @@ void ODBCAppender::flushBuffer(Pool& p)
613615

614616
void ODBCAppender::setSql(const LogString& s)
615617
{
618+
const logchar doubleQuote{ 0x22 };
619+
const logchar singleQuote{ 0x27 };
620+
const logchar semiColan{ 0x3b };
621+
// A basic check which disallows multiple SQL statements - for defense-in-depth security.
622+
// Allow a semicolan in a quoted context or as the last character.
623+
logchar currentQuote{ 0 };
624+
int charCount{ 0 };
625+
for (auto ch : s)
626+
{
627+
++charCount;
628+
if (currentQuote == ch)
629+
currentQuote = 0;
630+
else if (currentQuote == 0)
631+
{
632+
if (doubleQuote == ch || singleQuote == ch)
633+
currentQuote = ch;
634+
else if (semiColan == ch && s.size() != charCount)
635+
throw IllegalArgumentException(LOG4CXX_STR("SQL statement cannot contain a ';'"));
636+
}
637+
}
638+
if (0 != currentQuote)
639+
throw IllegalArgumentException(LogString(LOG4CXX_STR("Unmatched ")) + currentQuote + LOG4CXX_STR(" in SQL statement"));
616640
_priv->sqlStatement = s;
617641
}
618642

src/main/include/log4cxx/db/odbcappender.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ class LOG4CXX_EXPORT ODBCAppender : public AppenderSkeleton
187187
void append(const spi::LoggingEventPtr& event, helpers::Pool&) override;
188188

189189
protected:
190+
#if LOG4CXX_ABI_VERSION <= 15
190191
/**
191192
* To be removed.
192193
*/
@@ -199,7 +200,7 @@ class LOG4CXX_EXPORT ODBCAppender : public AppenderSkeleton
199200
* */
200201
virtual void execute(const LogString& sql,
201202
LOG4CXX_NS::helpers::Pool& p) /*throw(SQLException)*/;
202-
203+
#endif
203204
/**
204205
* Override this to return the connection to a pool, or to clean up the
205206
* resource.

src/site/markdown/configuration-samples.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ specify the instantiated appender/layout/filter classes and
2727
the properties of those class instances
2828
without recompiling and rebuilding.
2929

30+
The configuration file must be protected from modification by untrusted parties.
31+
Use restrictive file system permissions to ensure
32+
untrusted parties do not have write access.
33+
Do not load the configuration file from an untrusted location.
34+
3035
As Log4cxx was designed to be extendable,
3136
property names and values are not constrained by the core library.
3237
The configuration file parsers,

src/test/cpp/db/odbcappendertestcase.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ class ODBCAppenderTestCase : public AppenderSkeletonTestCase
3939
//
4040
LOGUNIT_TEST(testDefaultThreshold);
4141
LOGUNIT_TEST(testSetOptionThreshold);
42-
//LOGUNIT_TEST(testConnectUsingDSN);
42+
//#define DataSourceName_Log4cxxTest_Is_Valid
43+
#ifdef DataSourceName_Log4cxxTest_Is_Valid
44+
LOGUNIT_TEST(testConnectUsingDSN);
45+
#endif
4346
LOGUNIT_TEST_SUITE_END();
4447

4548

@@ -72,7 +75,7 @@ class ODBCAppenderTestCase : public AppenderSkeletonTestCase
7275
//
7376
// CREATE TABLE [dbo].[UnitTestLog](
7477
// [Item] [bigint] IDENTITY(1,1) NOT NULL, /* auto incremented */
75-
// [Thread] [nchar](20) NULL
78+
// [Thread] [nchar](20) NULL,
7679
// [LogTime] [datetime] NOT NULL,
7780
// [LogName] [nchar](50) NULL,
7881
// [LogLevel] [nchar](10) NULL,
@@ -90,7 +93,7 @@ class ODBCAppenderTestCase : public AppenderSkeletonTestCase
9093
for (int i = 0; i < 100; ++i)
9194
{
9295
LOG4CXX_INFO(odbc, "Message '" << i << "'");
93-
apr_sleep(30000);
96+
apr_sleep(30000); // 30 milliseconds
9497
}
9598
LOG4CXX_INFO(odbc, "Last message");
9699
}

0 commit comments

Comments
 (0)