Support SSL for mysql connections (#1965)

* Fix install location for config files when building to alternate directory.

With the previous code, we ended up with a directory structure like the following:

$ find /etc/zm/conf.d/
/etc/zm/conf.d/
/etc/zm/conf.d/01-system-paths.conf
/etc/zm/conf.d/conf.d
/etc/zm/conf.d/conf.d/README
/etc/zm/conf.d/conf.d/02-multiserver.conf

* Omitted README file that should have appeared in /etc/zm/conf.d

* Fix location for configs when building to alternate directory.

* Fix works, but this should go on a branch instead.

* Fix works, but this should go on a branch instead.

* Fix location for configs when building to alternate directory.

With the previous code, we ended up with a directory structure like the following:

$ find /etc/zm/conf.d/
/etc/zm/conf.d/
/etc/zm/conf.d/01-system-paths.conf
/etc/zm/conf.d/conf.d
/etc/zm/conf.d/conf.d/README
/etc/zm/conf.d/conf.d/02-multiserver.conf

* Remove double quotes. This is a list of paths.

* Allow SSL database connection to be secured with SSL.

* Fix incorrect variable name

* Fix PHP syntax errors

* SSL connection parameters must also be passed in API.

* Revert fixes to build files; they should not be in this branch.
This commit is contained in:
ralimi 2017-08-14 07:30:42 -07:00 committed by Isaac Connor
parent c353d5d17b
commit ecb7df0e8b
12 changed files with 72 additions and 4 deletions

View File

@ -45,6 +45,9 @@ Possible configuration options:
ZM_DB_NAME Name of ZoneMinder database, default: zm ZM_DB_NAME Name of ZoneMinder database, default: zm
ZM_DB_USER Name of ZoneMinder database user, default: zmuser ZM_DB_USER Name of ZoneMinder database user, default: zmuser
ZM_DB_PASS Password of ZoneMinder database user, default: zmpass ZM_DB_PASS Password of ZoneMinder database user, default: zmpass
ZM_DB_SSL_CA_CERT Path to SSL CA certificate, default: empty; SSL not enabled
ZM_DB_SSL_CLIENT_KEY Path to SSL client key, default: empty; SSL not enabled
ZM_DB_SSL_CLIENT_CERT Path to SSL client certificate, default: empty; SSL not enabled
ZM_WEB_USER The user apache or the local web server runs on. Leave empty for automatic detection. If that fails, you can use this variable to force ZM_WEB_USER The user apache or the local web server runs on. Leave empty for automatic detection. If that fails, you can use this variable to force
ZM_WEB_GROUP The group apache or the local web server runs on, Leave empty to be the same as the web user ZM_WEB_GROUP The group apache or the local web server runs on, Leave empty to be the same as the web user
ZM_DIR_EVENTS Location where events are recorded to, default: ZM_CONTENTDIR/events ZM_DIR_EVENTS Location where events are recorded to, default: ZM_CONTENTDIR/events

View File

@ -55,6 +55,9 @@ echo "Database host : $ZM_DB_HOST"
echo "Database name : $ZM_DB_NAME" echo "Database name : $ZM_DB_NAME"
echo "Database user : $ZM_DB_USER" echo "Database user : $ZM_DB_USER"
echo "Database password : Not shown" echo "Database password : Not shown"
echo "Database SSL CA Cert : $ZM_DB_SSL_CA_CERT"
echo "Database SSL Client Key : $ZM_DB_SSL_CLIENT_KEY"
echo "Database SSL Client Cert : $ZM_DB_SSL_CLIENT_CERT"
CMPATH="CACHE PATH \"Imported by cmakecacheimport.sh\" FORCE" CMPATH="CACHE PATH \"Imported by cmakecacheimport.sh\" FORCE"
@ -72,6 +75,9 @@ echo "set(ZM_DB_HOST \"$ZM_DB_HOST\" $CMSTRING)">>zm_conf.cmake
echo "set(ZM_DB_NAME \"$ZM_DB_NAME\" $CMSTRING)">>zm_conf.cmake echo "set(ZM_DB_NAME \"$ZM_DB_NAME\" $CMSTRING)">>zm_conf.cmake
echo "set(ZM_DB_USER \"$ZM_DB_USER\" $CMSTRING)">>zm_conf.cmake echo "set(ZM_DB_USER \"$ZM_DB_USER\" $CMSTRING)">>zm_conf.cmake
echo "set(ZM_DB_PASS \"$ZM_DB_PASS\" $CMSTRING)">>zm_conf.cmake echo "set(ZM_DB_PASS \"$ZM_DB_PASS\" $CMSTRING)">>zm_conf.cmake
echo "set(ZM_DB_SSL_CA_CERT \"$ZM_DB_SSL_CA_CERT\" $CMSTRING)">>zm_conf.cmake
echo "set(ZM_DB_SSL_CLIENT_KEY \"$ZM_DB_SSL_CLIENT_KEY\" $CMSTRING)">>zm_conf.cmake
echo "set(ZM_DB_SSL_CLIENT_CERT \"$ZM_DB_SSL_CLIENT_CERT\" $CMSTRING)">>zm_conf.cmake
echo "" echo ""
echo "Wrote zm_conf.cmake" echo "Wrote zm_conf.cmake"

View File

@ -101,8 +101,17 @@ BEGIN {
} else { } else {
$socket = ";host=".$Config{ZM_DB_HOST}; $socket = ";host=".$Config{ZM_DB_HOST};
} }
my $sslOptions = "";
if ( $Config{ZM_DB_SSL_CA_CERT} ) {
$sslOptions = ';'.join(';',
"mysql_ssl=1",
"mysql_ssl_ca_file=".$Config{ZM_DB_SSL_CA_CERT},
"mysql_ssl_client_key=".$Config{ZM_DB_SSL_CLIENT_KEY},
"mysql_ssl_client_cert=".$Config{ZM_DB_SSL_CLIENT_CERT}
);
}
my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} my $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
.$socket .$socket.$sslOptions
, $Config{ZM_DB_USER} , $Config{ZM_DB_USER}
, $Config{ZM_DB_PASS} , $Config{ZM_DB_PASS}
) or croak( "Can't connect to db" ); ) or croak( "Can't connect to db" );

View File

@ -90,8 +90,19 @@ sub zmDbConnect {
} else { } else {
$socket = ";host=".$Config{ZM_DB_HOST}; $socket = ";host=".$Config{ZM_DB_HOST};
} }
my $sslOptions = "";
if ( $Config{ZM_DB_SSL_CA_CERT} ) {
$sslOptions = ';'.join(';',
"mysql_ssl=1",
"mysql_ssl_ca_file=".$Config{ZM_DB_SSL_CA_CERT},
"mysql_ssl_client_key=".$Config{ZM_DB_SSL_CLIENT_KEY},
"mysql_ssl_client_cert=".$Config{ZM_DB_SSL_CLIENT_CERT}
);
}
$dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} $dbh = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
.$socket . ($options?';'.join(';', map { $_.'='.$$options{$_} } keys %{$options} ) : '' ) .$socket . $sslOptions . ($options?';'.join(';', map { $_.'='.$$options{$_} } keys %{$options} ) : '' )
, $Config{ZM_DB_USER} , $Config{ZM_DB_USER}
, $Config{ZM_DB_PASS} , $Config{ZM_DB_PASS}
); );

View File

@ -434,8 +434,17 @@ sub databaseLevel {
} else { } else {
$socket = ";host=".$Config{ZM_DB_HOST}; $socket = ";host=".$Config{ZM_DB_HOST};
} }
my $sslOptions = "";
if ( $Config{ZM_DB_SSL_CA_CERT} ) {
$sslOptions = ';'.join(';',
"mysql_ssl=1",
"mysql_ssl_ca_file=".$Config{ZM_DB_SSL_CA_CERT},
"mysql_ssl_client_key=".$Config{ZM_DB_SSL_CLIENT_KEY},
"mysql_ssl_client_cert=".$Config{ZM_DB_SSL_CLIENT_CERT}
);
}
$this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME} $this->{dbh} = DBI->connect( "DBI:mysql:database=".$Config{ZM_DB_NAME}
.$socket .$socket.$sslOptions
, $Config{ZM_DB_USER} , $Config{ZM_DB_USER}
, $Config{ZM_DB_PASS} , $Config{ZM_DB_PASS}
); );

View File

@ -150,6 +150,12 @@ void process_configfile( char* configFile) {
staticConfig.DB_USER = std::string(val_ptr); staticConfig.DB_USER = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_DB_PASS" ) == 0 ) else if ( strcasecmp( name_ptr, "ZM_DB_PASS" ) == 0 )
staticConfig.DB_PASS = std::string(val_ptr); staticConfig.DB_PASS = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_DB_SSL_CA_CERT" ) == 0 )
staticConfig.DB_SSL_CA_CERT = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_DB_SSL_CLIENT_KEY" ) == 0 )
staticConfig.DB_SSL_CLIENT_KEY = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_DB_SSL_CLIENT_CERT" ) == 0 )
staticConfig.DB_SSL_CLIENT_CERT = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_PATH_WEB" ) == 0 ) else if ( strcasecmp( name_ptr, "ZM_PATH_WEB" ) == 0 )
staticConfig.PATH_WEB = std::string(val_ptr); staticConfig.PATH_WEB = std::string(val_ptr);
else if ( strcasecmp( name_ptr, "ZM_SERVER_HOST" ) == 0 ) else if ( strcasecmp( name_ptr, "ZM_SERVER_HOST" ) == 0 )

View File

@ -67,6 +67,9 @@ struct StaticConfig
std::string DB_NAME; std::string DB_NAME;
std::string DB_USER; std::string DB_USER;
std::string DB_PASS; std::string DB_PASS;
std::string DB_SSL_CA_CERT;
std::string DB_SSL_CLIENT_KEY;
std::string DB_SSL_CLIENT_CERT;
std::string PATH_WEB; std::string PATH_WEB;
std::string SERVER_NAME; std::string SERVER_NAME;
unsigned int SERVER_ID; unsigned int SERVER_ID;

View File

@ -37,6 +37,8 @@ void zmDbConnect()
my_bool reconnect = 1; my_bool reconnect = 1;
if ( mysql_options( &dbconn, MYSQL_OPT_RECONNECT, &reconnect ) ) if ( mysql_options( &dbconn, MYSQL_OPT_RECONNECT, &reconnect ) )
Fatal( "Can't set database auto reconnect option: %s", mysql_error( &dbconn ) ); Fatal( "Can't set database auto reconnect option: %s", mysql_error( &dbconn ) );
if ( !staticConfig.DB_SSL_CA_CERT.empty() )
mysql_ssl_set( &dbconn, staticConfig.DB_SSL_CLIENT_KEY.c_str(), staticConfig.DB_SSL_CLIENT_CERT.c_str(), staticConfig.DB_SSL_CA_CERT.c_str(), NULL, NULL );
std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":" ); std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":" );
if ( colonIndex == std::string::npos ) if ( colonIndex == std::string::npos )
{ {

View File

@ -341,6 +341,8 @@ Logger::Level Logger::databaseLevel( Logger::Level databaseLevel ) {
my_bool reconnect = 1; my_bool reconnect = 1;
if ( mysql_options( &mDbConnection, MYSQL_OPT_RECONNECT, &reconnect ) ) if ( mysql_options( &mDbConnection, MYSQL_OPT_RECONNECT, &reconnect ) )
Fatal( "Can't set database auto reconnect option: %s", mysql_error( &mDbConnection ) ); Fatal( "Can't set database auto reconnect option: %s", mysql_error( &mDbConnection ) );
if ( !staticConfig.DB_SSL_CA_CERT.empty() )
mysql_ssl_set( &mDbConnection, staticConfig.DB_SSL_CLIENT_KEY.c_str(), staticConfig.DB_SSL_CLIENT_CERT.c_str(), staticConfig.DB_SSL_CA_CERT.c_str(), NULL, NULL );
std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":" ); std::string::size_type colonIndex = staticConfig.DB_HOST.find( ":" );
if ( colonIndex == std::string::npos ) { if ( colonIndex == std::string::npos ) {
if ( !mysql_real_connect( &mDbConnection, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, NULL, 0 ) ) { if ( !mysql_real_connect( &mDbConnection, staticConfig.DB_HOST.c_str(), staticConfig.DB_USER.c_str(), staticConfig.DB_PASS.c_str(), NULL, 0, NULL, 0 ) ) {

View File

@ -70,6 +70,9 @@ class DATABASE_CONFIG {
'login' => ZM_DB_USER, 'login' => ZM_DB_USER,
'password' => ZM_DB_PASS, 'password' => ZM_DB_PASS,
'database' => ZM_DB_NAME, 'database' => ZM_DB_NAME,
'ssl_ca' => ZM_DB_SSL_CA_CERT,
'ssl_key' => ZM_DB_SSL_CLIENT_KEY,
'ssl_cert' => ZM_DB_SSL_CLIENT_CERT,
'prefix' => '', 'prefix' => '',
'encoding' => 'utf8', 'encoding' => 'utf8',
); );

View File

@ -42,7 +42,12 @@ function dbConnect() {
} }
try { try {
$dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS ); $dbOptions = array(
PDO::MYSQL_ATTR_SSL_CA => ZM_DB_SSL_CA_CERT,
PDO::MYSQL_ATTR_SSL_KEY => ZM_DB_SSL_CLIENT_KEY,
PDO::MYSQL_ATTR_SSL_CERT => ZM_DB_SSL_CLIENT_CERT,
);
$dbConn = new PDO( ZM_DB_TYPE . $socket . ';dbname='.ZM_DB_NAME, ZM_DB_USER, ZM_DB_PASS, $dbOptions );
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $ex ) { } catch(PDOException $ex ) {

View File

@ -49,6 +49,15 @@ ZM_DB_USER=@ZM_DB_USER@
# ZoneMinder database password # ZoneMinder database password
ZM_DB_PASS=@ZM_DB_PASS@ ZM_DB_PASS=@ZM_DB_PASS@
# SSL CA certificate for ZoneMinder database
ZM_DB_SSL_CA_CERT=@ZM_DB_SSL_CA_CERT@
# SSL client key for ZoneMinder database
ZM_DB_SSL_CLIENT_KEY=@ZM_DB_SSL_CLIENT_KEY@
# SSL client cert for ZoneMinder database
ZM_DB_SSL_CLIENT_CERT=@ZM_DB_SSL_CLIENT_CERT@
# Do NOT set ZM_SERVER_HOST if you are not using Multi-Server # Do NOT set ZM_SERVER_HOST if you are not using Multi-Server
# You have been warned # You have been warned
# #