Skip to content
Open
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
4 changes: 4 additions & 0 deletions build_debian.sh
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,10 @@ set /files/etc/ssh/sshd_config/#comment[following-sibling::*[1][self::AllowAgent
save
quit
EOF
# Allow TACACS+ authorization to receive a client-supplied trace ID.
if ! sudo grep -Eq '^[[:space:]]*AcceptEnv[[:space:]]+([^#[:space:]]+[[:space:]]+)*SSH_CLIENT_TRACEID([[:space:]]|$)' "$FILESYSTEM_ROOT/etc/ssh/sshd_config"; then
echo "AcceptEnv SSH_CLIENT_TRACEID" | sudo tee -a "$FILESYSTEM_ROOT/etc/ssh/sshd_config" > /dev/null
fi
Comment thread
Rod-Persky marked this conversation as resolved.
# Configure sshd to listen for v4 and v6 connections
sudo sed -i 's/^#ListenAddress 0.0.0.0/ListenAddress 0.0.0.0/' $FILESYSTEM_ROOT/etc/ssh/sshd_config
sudo sed -i 's/^#ListenAddress ::/ListenAddress ::/' $FILESYSTEM_ROOT/etc/ssh/sshd_config
Expand Down
5 changes: 5 additions & 0 deletions files/image_config/bash/bash.bashrc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
# If not running interactively, don't do anything
[ -z "$PS1" ] && return

# Best-effort guard for the SSH-supplied TACACS+ trace ID in this shell.
if [ -n "${SSH_CLIENT_TRACEID+x}" ]; then
readonly SSH_CLIENT_TRACEID
fi

# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"auth_type": "chap",
"timeout": 5,
"passkey": "dellsonic",
"src_intf": "Ethernet0"
"src_intf": "Ethernet0",
"traceid_authorization": true
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/sonic-yang-models/yang-models/sonic-system-tacacs.yang
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ module sonic-system-tacacs {
}
description "Source interface whose IP address is used for outgoing TACACS+ packets.";
}

leaf traceid_authorization {
type boolean;
default true;
description "Enable adding validated SSH TraceId values to TACACS+ command authorization requests.";
}
Comment thread
Rod-Persky marked this conversation as resolved.
}
}
}
Expand Down
64 changes: 64 additions & 0 deletions src/tacacs/bash_tacplus/bash_tacplus.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@
/* Remote IP address size */
#define REMOTE_ADDRESS_SIZE 64

/* TACACS+ attributes are encoded as key=value strings with a 255 byte limit. */
#define TACACS_ATTR_MAX_SIZE 255
#define TRACE_ID_ENV_VARIABLE "SSH_CLIENT_TRACEID"
#define TRACE_ID_ATTR_NAME "traceid"
#define TRACE_ID_ATTR_PREFIX_SIZE (sizeof(TRACE_ID_ATTR_NAME "=") - 1)
#define TRACE_ID_VALUE_SIZE (TACACS_ATTR_MAX_SIZE - TRACE_ID_ATTR_PREFIX_SIZE + 1)

/* Return value for is_local_user method */
#define IS_LOCAL_USER 0
#define IS_REMOTE_USER 1
Expand Down Expand Up @@ -110,6 +117,54 @@ void output_debug(const char *format, ...)
syslog(LOG_DEBUG, TACACS_LOG_FORMAT, logBuffer);
}

/*
* Check whether a TraceId character is safe to send as a TACACS+ attribute.
*/
static int is_valid_trace_id_char(char value)
{
return (value >= 'A' && value <= 'Z') ||
(value >= 'a' && value <= 'z') ||
(value >= '0' && value <= '9') ||
value == '.' || value == '_' || value == ':' ||
value == '-' || value == '|';
Comment thread
Rod-Persky marked this conversation as resolved.
}

/*
* Get SSH supplied trace ID for TACACS+ authorization.
*/
static int get_trace_id(char *dst, size_t size)
{
const char *trace_id;
const char *trace_id_end;
size_t trace_id_len, i;

if (size == 0) {
return 0;
}

trace_id = getenv(TRACE_ID_ENV_VARIABLE);
if (trace_id == NULL || trace_id[0] == '\0') {
return 0;
}

trace_id_end = memchr(trace_id, '\0', size);
if (trace_id_end == NULL) {
output_debug("%s ignored: value exceeds TACACS+ attribute size limit\n", TRACE_ID_ENV_VARIABLE);
return 0;
}

trace_id_len = trace_id_end - trace_id;

for (i = 0; i < trace_id_len; i++) {
if (!is_valid_trace_id_char(trace_id[i])) {
output_debug("%s ignored: invalid character at offset %zu\n", TRACE_ID_ENV_VARIABLE, i);
return 0;
}
}

snprintf(dst, size, "%s", trace_id);
return 1;
}

/*
* Send authorization message.
Expand All @@ -130,6 +185,7 @@ int send_authorization_message(
int retval;
struct areply re;
int i;
char trace_id[TRACE_ID_VALUE_SIZE];

attr=(struct tac_attrib *)xcalloc(1, sizeof(struct tac_attrib));

Expand All @@ -138,6 +194,10 @@ int send_authorization_message(
tac_add_attrib(&attr, "protocol", "ssh");
tac_add_attrib(&attr, "service", "shell");

if ((tacacs_ctrl & TRACE_ID_AUTHORIZATION_FLAG) && get_trace_id(trace_id, sizeof(trace_id))) {
tac_add_attrib(&attr, TRACE_ID_ATTR_NAME, trace_id);
}

tac_add_attrib(&attr, "cmd", (char*)cmd);

for(i=1; i<argc; i++) {
Expand Down Expand Up @@ -347,6 +407,10 @@ void load_tacacs_config()
output_debug("Local per-command authorization enabled.\n");
}

if (tacacs_ctrl & TRACE_ID_AUTHORIZATION_FLAG) {
output_debug("TACACS+ TraceId authorization attribute enabled.\n");
}

if (tacacs_ctrl & PAM_TAC_DEBUG) {
output_debug("TACACS+ debug enabled.\n");
}
Expand Down
19 changes: 19 additions & 0 deletions src/tacacs/bash_tacplus/unittest/mock_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#include "mock_helper.h"

#define TRACE_ID_ATTR_NAME "traceid"

// define BASH_PLUGIN_UT_DEBUG to output UT debug message.
#if defined (BASH_PLUGIN_UT_DEBUG)
#define debug_printf printf
Expand All @@ -24,6 +26,10 @@
/* Mock syslog buffer */
char mock_syslog_message_buffer[1024];

/* Mock TraceId TACACS+ attribute state */
char mock_tac_trace_id_attr_value[256];
int mock_tac_trace_id_attr_count;

/* define test scenarios for mock functions return different value by scenario. */
int test_scenario;

Expand Down Expand Up @@ -101,6 +107,13 @@ int get_memory_allocate_count()
return memory_allocate_count;
}

/* Reset mocked TACACS+ attribute state */
void reset_mock_tac_attrs()
{
memset(mock_tac_trace_id_attr_value, 0, sizeof(mock_tac_trace_id_attr_value));
mock_tac_trace_id_attr_count = 0;
}

/* Mock xcalloc method */
void *xcalloc(size_t count, size_t size)
{
Expand All @@ -112,6 +125,12 @@ void *xcalloc(size_t count, size_t size)
/* Mock tac_free_attrib method */
void tac_add_attrib(struct tac_attrib **attr, char *attrname, char *attrvalue)
{
if (strcmp(attrname, TRACE_ID_ATTR_NAME) == 0)
{
mock_tac_trace_id_attr_count++;
snprintf(mock_tac_trace_id_attr_value, sizeof(mock_tac_trace_id_attr_value), "%s", attrvalue);
}
Comment thread
Rod-Persky marked this conversation as resolved.

debug_printf("MOCK: tac_add_attrib add attribute: %s, value: %s\n", attrname, attrvalue);
}

Expand Down
7 changes: 7 additions & 0 deletions src/tacacs/bash_tacplus/unittest/mock_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
/* Mock syslog buffer */
extern char mock_syslog_message_buffer[1024];

/* Mock TraceId TACACS+ attribute state */
extern char mock_tac_trace_id_attr_value[256];
extern int mock_tac_trace_id_attr_count;

#define TEST_SCEANRIO_CONNECTION_ALL_FAILED 1
#define TEST_SCEANRIO_CONNECTION_SEND_FAILED_RESULT 2
#define TEST_SCEANRIO_CONNECTION_SEND_SUCCESS_READ_FAILED 3
Expand All @@ -47,5 +51,8 @@ void set_memory_allocate_count(int count);
/* Get memory allocate count for test*/
int get_memory_allocate_count();

/* Reset mocked TACACS+ attribute state */
void reset_mock_tac_attrs();


#endif /* _MOCK_HELPER_H_ */
Loading
Loading