From f3bb382f934f7229c09a6fd1618370c369fddd66 Mon Sep 17 00:00:00 2001 From: Kwan Kim Date: Fri, 21 Feb 2020 15:03:53 -0800 Subject: [PATCH] SNC-3888: mask the password/key in cli command history --- .../clish/plugin/mgmt_clish_utils.c | 177 ++++++++++++++++++ .../clish/plugin/mgmt_clish_utils.h | 59 ++++++ .../klish-2.1.4/clish/plugin/module.am.diff | 5 + .../klish-2.1.4/tinyrl/history/history.c.diff | 28 +++ 4 files changed, 269 insertions(+) create mode 100644 src/CLI/klish/patches/klish-2.1.4/clish/plugin/mgmt_clish_utils.c create mode 100644 src/CLI/klish/patches/klish-2.1.4/clish/plugin/mgmt_clish_utils.h create mode 100644 src/CLI/klish/patches/klish-2.1.4/clish/plugin/module.am.diff create mode 100644 src/CLI/klish/patches/klish-2.1.4/tinyrl/history/history.c.diff diff --git a/src/CLI/klish/patches/klish-2.1.4/clish/plugin/mgmt_clish_utils.c b/src/CLI/klish/patches/klish-2.1.4/clish/plugin/mgmt_clish_utils.c new file mode 100644 index 0000000000..93bb3be38d --- /dev/null +++ b/src/CLI/klish/patches/klish-2.1.4/clish/plugin/mgmt_clish_utils.c @@ -0,0 +1,177 @@ +/* + * filename: mgmt_clish_utils.c + * (c) Copyright 2020 Dell EMC All Rights Reserved. + */ + +#include "clish/shell/private.h" +#include "lub/string.h" +#include "lub/dump.h" +#include +#include +#include +#include +#include +#include + +#include "string.h" +#include "stdlib.h" +#include "signal.h" + +int interruptRecvd = 0; + +/* Ctrl-C information is shared from C context to python context + * via pipe. C context writes dummy data in pipe and python context + * reads from the pipe. + */ +int ctrlc_rd_fd = 0, ctrlc_wr_fd = 0; + +/*-------------------------------------------------------- */ +void clish_interrupt_handler(int signum) +{ + interruptRecvd = 1; + /* Write some data in Ctrl-C pipe to exit render gracefully */ + write(ctrlc_wr_fd, "q", 1); +} + +bool_t is_ctrlc_pressed(void) +{ + bool_t result = BOOL_FALSE; + + if(interruptRecvd) + result = BOOL_TRUE; + + return result; +} + +void flush_ctrlc_pipe(void) +{ + fd_set fds; + char tmp_buf[100] = {0}; + struct timeval timeout = {0}; // Timeout 0 is polling + ssize_t size = 0; + int ret = 0; + + // Reset interrupt recieved flag + interruptRecvd = 0; + // Flush pipe contents + while(BOOL_TRUE) { + FD_ZERO (&fds); + FD_SET(ctrlc_rd_fd, &fds); + ret = select(ctrlc_rd_fd + 1, &fds, NULL, NULL, &timeout); + if(ret == 0) break; // If returned fds count is 0, pipe is empty. + if(FD_ISSET(ctrlc_rd_fd, &fds) == 0) + continue; + size = read(ctrlc_rd_fd, tmp_buf, 100); + if (size == -1) { + if (errno == EINTR) // We may have got signal. Just go back + continue; + } + } +} + + +/* + * + */ +static char *obscure_string= "*****"; + +#define MAX_KEYWORDS 4 +/* Entries with only 0 as encryption identifier may not strictly have one - used as placeholder */ +static const char * keywords[2*MAX_KEYWORDS] = { + "password", "079", + "key", "079", + "auth-password", "079", + "priv-password", "079" +}; + +/* URL patterns contain: prefix string + ASSUMPTION: should contain phrase as per pattern: :@ + */ +#define COLON_DELIM 0x3A +#define ATSIGN_DELIM 0x40 +#define MAX_URL_PATTERN 6 +static char *url_pattern[MAX_URL_PATTERN] = {"scp://", + "ftp://", "sftp://", "http://", "https://", "tftp://"}; + + +void mask_password(const char *line, char **masked_line) +{ + int pos = 0, index, length; + bool_t match; + char *word = NULL, *ctxt = NULL, *url=NULL, *passwd= NULL, *remainder= NULL, *line_tmp = NULL; + + if(*masked_line){ + lub_string_free(*masked_line); + } + + lub_string_cat(&line_tmp, line); + word = strtok_r(line_tmp, " ", &ctxt); + /* tokenize string - space delimited */ + while(word) { + if(pos != 0) { + lub_string_cat(masked_line, " "); + } + match= BOOL_FALSE; + + for (index=0; index password role } + * radius-server key + * tacacs-server key + * snmp-server user [encrypted] auth [md5|sha] auth-password priv [aes-128 | + * des] priv-password +* +* @param [in] command line : CLI command string +* @param [out] masked line : CLI command string with masked password/key +* +*/ + +void mask_password(const char *line, char **masked_line); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/CLI/klish/patches/klish-2.1.4/clish/plugin/module.am.diff b/src/CLI/klish/patches/klish-2.1.4/clish/plugin/module.am.diff new file mode 100644 index 0000000000..1e154e6ed6 --- /dev/null +++ b/src/CLI/klish/patches/klish-2.1.4/clish/plugin/module.am.diff @@ -0,0 +1,5 @@ +5c5,6 +< clish/plugin/private.h +--- +> clish/plugin/private.h \ +> clish/plugin/mgmt_clish_utils.c diff --git a/src/CLI/klish/patches/klish-2.1.4/tinyrl/history/history.c.diff b/src/CLI/klish/patches/klish-2.1.4/tinyrl/history/history.c.diff new file mode 100644 index 0000000000..6c0c3f7803 --- /dev/null +++ b/src/CLI/klish/patches/klish-2.1.4/tinyrl/history/history.c.diff @@ -0,0 +1,28 @@ +14a15 +> #include "clish/plugin/mgmt_clish_utils.h" +138,146c139,140 +< for (i = 0; i < this->length; i++) { +< tinyrl_history_entry_t *entry = this->entries[i]; +< if (0 == strcmp(line, tinyrl_history_entry__get_line(entry))) { +< free_entries(this, i, i); +< remove_entries(this, i, i); +< result = BOOL_TRUE; +< break; +< } +< } +--- +> /* We don't want to remove duplicates from the history, +> hence returning false immediately*/ +203a198,199 +> char *masked_line = NULL; +> mask_password(line, &masked_line); +205c201 +< add_n_replace(this, line); +--- +> add_n_replace(this, (const char*)masked_line); +207c203 +< add_n_grow(this, line); +--- +> add_n_grow(this, (const char*)masked_line); +208a205 +> if(masked_line) free(masked_line);