Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,17 @@ include pyext/Makefile.am
include sonic-db-cli/Makefile.am
include tests/Makefile.am

# This will set redis_acl to an empty value if not already set
redis_acl ?=

# If redis_acl is set, append -D$(redis_acl) to DBGFLAGS
ifneq ($(strip $(redis_acl)),)
ifeq ($(redis_acl),y)
REDIS_ACL_G=1
else ifeq ($(redis_acl),n)
REDIS_ACL_G=0
endif
AM_CPPFLAGS += -DREDIS_ACL_G
endif

ACLOCAL_AMFLAGS = -I m4
2 changes: 1 addition & 1 deletion common/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ common_libswsscommon_la_SOURCES = \

common_libswsscommon_la_CXXFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CFLAGS) $(CODE_COVERAGE_CXXFLAGS)
common_libswsscommon_la_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(LIBNL_CPPFLAGS) $(CODE_COVERAGE_CPPFLAGS)
common_libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization -luuid
common_libswsscommon_la_LIBADD = -lpthread $(LIBNL_LIBS) $(CODE_COVERAGE_LIBS) -lzmq -lboost_serialization -luuid -ldl -lssl -lcrypto -lhiredis_ssl
common_libswsscommon_la_LDFLAGS = -Wl,-z,now $(LDFLAGS)

if YANGMODS
Expand Down
151 changes: 149 additions & 2 deletions common/dbconnector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,113 @@
#include "common/redispipeline.h"
#include "common/pubsub.h"

#include <iostream>
#include <string>
#include <grp.h>
#include <cstring>

using json = nlohmann::json;
using namespace std;
using namespace swss;
#define SUDO_GID 27

// This is a macro to check if the REDIS_ACL_G is defined, which meaning that the feature Redis ACL is enabled.
#ifdef REDIS_ACL_G

bool isUserInSudoGroup() {
int ngroups = getgroups(0, nullptr); // Get the number of supplementary groups
bool group_sudo_exists = false;
gid_t groupToFind = SUDO_GID;

if (ngroups < 0) {
SWSS_LOG_ERROR("no ngroups exits");
return false;
}

std::vector<gid_t> groups(ngroups);
if (getgroups(ngroups, groups.data()) < 0) {
SWSS_LOG_ERROR("no ngroups exits");
return false;
}

for (const auto& group : groups) {
if (group == groupToFind) {
group_sudo_exists = true;
break;

}
}
return group_sudo_exists;
}

bool isRootUser() {
uid_t uid = getuid(); // Get the user ID of the current user

return (uid == 0);
}

bool is_admin_user() {
bool is_admin_user = false;

if (isRootUser()) {
is_admin_user = true;
} else if (isUserInSudoGroup()) {
is_admin_user = true;
}

return is_admin_user;
}


// Function to write content to a file
void writeFile(const std::string& filename, const std::string& content) {
std::ofstream outputFile(filename, std::ios_base::app);

if (!outputFile.is_open()) {
std::cerr << "Failed to open the file for writing." << std::endl;
return;
}

outputFile << content;
outputFile.close();

}

// Function to read the entire content of a file and return as a string
std::string readFileContent_pw(const std::string& filename) {
std::ifstream inputFile(filename);
std::string content;

if (!inputFile.is_open()) {
std::cerr << "Failed to open the file." << std::endl;
return content;
}

content.assign((std::istreambuf_iterator<char>(inputFile)), std::istreambuf_iterator<char>());

inputFile.close();

// Check if the string ends with '\n' and remove it.
if (!content.empty() && content.back() == '\n') {
content.pop_back();
}

return content;
}

std::string get_auth_cmd() {
std::string command = "";
if (is_admin_user()){
std::string shadow_redis_admin = readFileContent_pw("/etc/shadow_redis_dir/shadow_redis_admin");
command = std::string("auth admin ") + shadow_redis_admin;
}else{
std::string shadow_redis_monitor = readFileContent_pw("/etc/shadow_redis_dir/shadow_redis_monitor");
command = std::string("auth monitor ") + shadow_redis_monitor;
}
return command;
}

#endif

void SonicDBConfig::parseDatabaseConfig(const string &file,
std::map<std::string, RedisInstInfo> &inst_entry,
Expand Down Expand Up @@ -541,11 +644,11 @@ RedisContext::RedisContext(const RedisContext &other)
const char *unixPath = octx->unix_sock.path;
if (unixPath)
{
initContext(unixPath, octx->timeout);
initContext(unixPath, octx->connect_timeout);
}
else
{
initContext(octx->tcp.host, octx->tcp.port, octx->timeout);
initContext(octx->tcp.host, octx->tcp.port, octx->connect_timeout);
}
}

Expand All @@ -563,6 +666,43 @@ void RedisContext::initContext(const char *host, int port, const timeval *tv)
if (m_conn->err)
throw system_error(make_error_code(errc::address_not_available),
"Unable to connect to redis - " + std::string(m_conn->errstr) + "(" + std::to_string(m_conn->err) + ")");

#ifdef REDIS_ACL_G
// Redis SSL configuration
redisSSLContext *ssl;
redisSSLContextError ssl_error = REDIS_SSL_CTX_NONE;
const char *ca = "/etc/shadow_redis_dir/certs_redis/ca.crt";
redisInitOpenSSL();

redisSSLOptions options = {
.cacert_filename = ca,
.capath = NULL,
.cert_filename = NULL,
.private_key_filename = NULL,
.server_name = NULL,
.verify_mode = REDIS_SSL_VERIFY_NONE,
};


ssl = redisCreateSSLContextWithOptions(&options, &ssl_error);
if (!ssl || ssl_error != REDIS_SSL_CTX_NONE) {
SWSS_LOG_ERROR("SSL Context error: %s\n", redisSSLContextGetError(ssl_error));
exit(1);
}

// start ssl connection
if (redisInitiateSSLWithContext(m_conn, ssl) != REDIS_OK) {
SWSS_LOG_ERROR("Couldn't initialize SSL!\n");
redisFree(m_conn);
exit(1);
}


// Redis Authentication
std::string command = "";
command = get_auth_cmd();
RedisReply r1(this, command, REDIS_REPLY_STATUS);
#endif
}

void RedisContext::initContext(const char *path, const timeval *tv)
Expand All @@ -579,6 +719,13 @@ void RedisContext::initContext(const char *path, const timeval *tv)
if (m_conn->err)
throw system_error(make_error_code(errc::address_not_available),
"Unable to connect to redis (unix-socket) - " + std::string(m_conn->errstr) + "(" + std::to_string(m_conn->err) + ")");

#ifdef REDIS_ACL_G
// Redis Authentication
std::string command = "";
command = get_auth_cmd();
RedisReply r1(this, command, REDIS_REPLY_STATUS);
#endif
}

redisContext *RedisContext::getContext() const
Expand Down
1 change: 1 addition & 0 deletions common/dbconnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <boost/algorithm/string.hpp>

#include <hiredis/hiredis.h>
#include <hiredis/hiredis_ssl.h>
#include "rediscommand.h"
#include "redisreply.h"
#define EMPTY_NAMESPACE std::string()
Expand Down
5 changes: 3 additions & 2 deletions common/rediscommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ void RedisCommand::formatArgv(int argc, const char **argv, const size_t *argvlen
}
len = 0;

int ret = redisFormatCommandArgv(&temp, argc, argv, argvlen);
if (ret == -1) {
long long ret = redisFormatCommandArgv(&temp, argc, argv, argvlen);
if (len == -1) {
throw std::bad_alloc();
}
len = ret;
Expand Down Expand Up @@ -148,6 +148,7 @@ size_t RedisCommand::length() const
{
if (len <= 0)
return 0;
// TODO review this casting
return static_cast<size_t>(len);
}

Expand Down
2 changes: 1 addition & 1 deletion common/rediscommand.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class RedisCommand {

private:
char *temp;
int len;
long long len;
};

template<typename InputIterator>
Expand Down
Loading