diff --git a/src/tacacs/pam/0006-Add-support-for-source-ip-address.patch b/src/tacacs/pam/0006-Add-support-for-source-ip-address.patch index 280cfeee28f..8230b34e0d1 100644 --- a/src/tacacs/pam/0006-Add-support-for-source-ip-address.patch +++ b/src/tacacs/pam/0006-Add-support-for-source-ip-address.patch @@ -1,16 +1,16 @@ -From 9c26e734cf9e5cec950dc8b8f474f89d87833bcd Mon Sep 17 00:00:00 2001 +From 49526a27e90647ed4e48c1d1d88e0c75a1ce221b Mon Sep 17 00:00:00 2001 From: Venkatesan Mahalingam -Date: Wed, 1 Jul 2020 18:57:28 -0700 -Subject: [PATCH] Add support to specify source address for TACACS+ +Date: Thu, 2 Jul 2020 09:57:28 +0800 +Subject: [PATCH 1/4] Add support to specify source address for TACACS+ --- pam_tacplus.c | 8 ++++---- - support.c | 31 +++++++++++++++++++++++++++++++ + support.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++-- support.h | 1 + - 3 files changed, 36 insertions(+), 4 deletions(-) + 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/pam_tacplus.c b/pam_tacplus.c -index 38e2a70..ec8ea27 100644 +index 7544b2e..9fc6be7 100644 --- a/pam_tacplus.c +++ b/pam_tacplus.c @@ -177,7 +177,7 @@ int _pam_account(pam_handle_t *pamh, int argc, const char **argv, @@ -50,7 +50,7 @@ index 38e2a70..ec8ea27 100644 _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i); continue; diff --git a/support.c b/support.c -index 7c00618..3e55e2f 100644 +index 8f42a0c..164df62 100644 --- a/support.c +++ b/support.c @@ -37,6 +37,8 @@ char tac_service[64]; @@ -62,31 +62,76 @@ index 7c00618..3e55e2f 100644 void _pam_log(int err, const char *format,...) { char msg[256]; -@@ -183,6 +185,12 @@ int _pam_parse (int argc, const char **argv) { +@@ -171,6 +173,44 @@ int tacacs_get_password (pam_handle_t * pamh, int flags + return PAM_SUCCESS; + } + ++/* set source ip address for the outgoing tacacs packets */ ++void set_source_ip(const char *tac_source_ip) { ++ /* ++ addrinfo created by getaddrinfo must be released with freeaddrinfo. ++ so source ip address will be stored in following static variables. ++ */ ++ static struct addrinfo tac_source_address; ++ static struct sockaddr tac_source_sock_addr; ++ static struct sockaddr_in6 tac_source_sock6_addr; ++ ++ struct addrinfo hints, *source_address; ++ int rv; ++ ++ /* set the source ip address for the tacacs packets */ ++ memset(&hints, 0, sizeof(hints)); ++ hints.ai_family = AF_UNSPEC; ++ hints.ai_socktype = SOCK_STREAM; ++ if ((rv = getaddrinfo(tac_source_ip, NULL, &hints, ++ &source_address)) != 0) { ++ _pam_log(LOG_ERR, "error setting the source ip information"); ++ } else { ++ tac_source_addr = &tac_source_address; ++ memcpy(tac_source_addr, source_address, sizeof(struct addrinfo)); ++ ++ if (source_address->ai_family == AF_INET6) { ++ tac_source_addr->ai_addr = (struct sockaddr *)&(tac_source_sock6_addr); ++ memcpy(tac_source_addr->ai_addr, source_address->ai_addr, sizeof(struct sockaddr_in6)); ++ } ++ else { ++ tac_source_addr->ai_addr = &(tac_source_sock_addr); ++ memcpy(tac_source_addr->ai_addr, source_address->ai_addr, sizeof(struct sockaddr)); ++ } ++ ++ freeaddrinfo(source_address); ++ _pam_log(LOG_DEBUG, "source ip is set"); ++ } ++} ++ + int _pam_parse (int argc, const char **argv) { + int ctrl = 0; + const char *current_secret = NULL; +@@ -183,6 +223,12 @@ int _pam_parse (int argc, const char **argv) { tac_protocol[0] = 0; tac_prompt[0] = 0; tac_login[0] = 0; + tac_source_ip[0] = 0; + + if (tac_source_addr != NULL) { -+ freeaddrinfo(tac_source_addr); ++ /* reset source address */ + tac_source_addr = NULL; + } for (ctrl = 0; argc-- > 0; ++argv) { if (!strcmp (*argv, "debug")) { /* all */ -@@ -274,6 +282,10 @@ int _pam_parse (int argc, const char **argv) { +@@ -274,6 +320,10 @@ int _pam_parse (int argc, const char **argv) { } } else if(!strncmp(*argv, "vrf=", 4)) { __vrfname = strdup(*argv + 4); + } else if (!strncmp (*argv, "source_ip=", strlen("source_ip="))) { + /* source ip for the packets */ + strncpy (tac_source_ip, *argv + strlen("source_ip="), sizeof(tac_source_ip)); -+ set_source_ip (tac_source_ip, &tac_source_addr); ++ set_source_ip(tac_source_ip); } else { _pam_log (LOG_WARNING, "unrecognized option: %s", *argv); } -@@ -292,8 +304,27 @@ int _pam_parse (int argc, const char **argv) { +@@ -292,8 +342,8 @@ int _pam_parse (int argc, const char **argv) { _pam_log(LOG_DEBUG, "tac_protocol='%s'", tac_protocol); _pam_log(LOG_DEBUG, "tac_prompt='%s'", tac_prompt); _pam_log(LOG_DEBUG, "tac_login='%s'", tac_login); @@ -94,28 +139,12 @@ index 7c00618..3e55e2f 100644 } return ctrl; - } /* _pam_parse */ - -+/* set source ip address for the outgoing tacacs packets */ -+void set_source_ip(const char *tac_source_ip, -+ struct addrinfo **source_address) { -+ -+ struct addrinfo hints; -+ int rv; -+ -+ /* set the source ip address for the tacacs packets */ -+ memset(&hints, 0, sizeof(hints)); -+ hints.ai_family = AF_UNSPEC; -+ hints.ai_socktype = SOCK_STREAM; -+ if ((rv = getaddrinfo(tac_source_ip, NULL, &hints, -+ source_address)) != 0) { -+ _pam_log(LOG_ERR, "error setting the source ip information"); -+ } else { -+ _pam_log(LOG_DEBUG, "source ip is set"); -+ } -+} +-} /* _pam_parse */ +- ++} /* _pam_parse */ +\ No newline at end of file diff --git a/support.h b/support.h -index 9cbd040..09b8a85 100644 +index 9cbd040..b1faf43 100644 --- a/support.h +++ b/support.h @@ -37,6 +37,7 @@ extern int tac_srv_no; @@ -127,5 +156,5 @@ index 9cbd040..09b8a85 100644 int _pam_parse (int, const char **); unsigned long _resolve_name (char *); -- -2.7.4 +2.17.1.windows.2 diff --git a/src/tacacs/pam/0007-Fix-memory-leak-when-parse-configuration.patch b/src/tacacs/pam/0007-Fix-memory-leak-when-parse-configuration.patch new file mode 100644 index 00000000000..f79521d9028 --- /dev/null +++ b/src/tacacs/pam/0007-Fix-memory-leak-when-parse-configuration.patch @@ -0,0 +1,124 @@ +From 99eeeccd14c905b7ad77210343bb07334eb0e8d1 Mon Sep 17 00:00:00 2001 +From: liuh-80 <58683130+liuh-80@users.noreply.github.com> +Date: Tue, 12 Oct 2021 10:05:28 +0800 +Subject: [PATCH 2/4] Fix memory leak when parse configuration. +The fix code in this patch are copy from upstream project: https://github.com/kravietz/pam_tacplus/blob/master/support.c + +--- + pam_tacplus.c | 6 ++++-- + support.c | 37 +++++++++++++++++++++++++++++++++---- + support.h | 2 +- + 3 files changed, 38 insertions(+), 7 deletions(-) + +diff --git a/pam_tacplus.c b/pam_tacplus.c +index 9fc6be7..d062359 100644 +--- a/pam_tacplus.c ++++ b/pam_tacplus.c +@@ -323,7 +323,8 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags, + status = PAM_SUCCESS; + communicating = 0; + active_server.addr = tac_srv[srv_i].addr; +- active_server.key = tac_srv[srv_i].key; ++ /* copy secret to key */ ++ snprintf(active_server.key, sizeof(active_server.key), "%s", tac_srv[srv_i].key); + + if (ctrl & PAM_TAC_DEBUG) + syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i); +@@ -820,7 +821,8 @@ int pam_sm_chauthtok(pam_handle_t * pamh, int flags, + communicating = 0; + + active_server.addr = tac_srv[srv_i].addr; +- active_server.key = tac_srv[srv_i].key; ++ /* copy secret to key */ ++ snprintf(active_server.key, sizeof(active_server.key), "%s", tac_srv[srv_i].key); + + if (ctrl & PAM_TAC_DEBUG) + syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i); +diff --git a/support.c b/support.c +index 164df62..e22fa31 100644 +--- a/support.c ++++ b/support.c +@@ -30,7 +30,12 @@ + #include + #include + ++/* tacacs server information */ + tacplus_server_t tac_srv[TAC_PLUS_MAXSERVERS]; ++struct addrinfo tac_srv_addr[TAC_PLUS_MAXSERVERS]; ++struct sockaddr tac_sock_addr[TAC_PLUS_MAXSERVERS]; ++struct sockaddr_in6 tac_sock6_addr[TAC_PLUS_MAXSERVERS]; ++ + int tac_srv_no = 0; + + char tac_service[64]; +@@ -173,6 +178,26 @@ int tacacs_get_password (pam_handle_t * pamh, int flags + return PAM_SUCCESS; + } + ++/* ++ * Set tacacs server addrinfo. ++ */ ++void set_tacacs_server_addr(int tac_srv_no, struct addrinfo* server) { ++ tac_srv[tac_srv_no].addr = &(tac_srv_addr[tac_srv_no]); ++ memcpy(tac_srv[tac_srv_no].addr, server, sizeof(struct addrinfo)); ++ ++ if (server->ai_family == AF_INET6) { ++ tac_srv[tac_srv_no].addr->ai_addr = (struct sockaddr *)&(tac_sock6_addr[tac_srv_no]); ++ memcpy(tac_srv[tac_srv_no].addr->ai_addr, server->ai_addr, sizeof(struct sockaddr_in6)); ++ } ++ else { ++ tac_srv[tac_srv_no].addr->ai_addr = &(tac_sock_addr[tac_srv_no]); ++ memcpy(tac_srv[tac_srv_no].addr->ai_addr, server->ai_addr, sizeof(struct sockaddr)); ++ } ++ ++ tac_srv[tac_srv_no].addr->ai_canonname = NULL; ++ tac_srv[tac_srv_no].addr->ai_next = NULL; ++} ++ + /* set source ip address for the outgoing tacacs packets */ + void set_source_ip(const char *tac_source_ip) { + /* +@@ -284,8 +309,11 @@ int _pam_parse (int argc, const char **argv) { + } + if ((rv = getaddrinfo(server_name, (port == NULL) ? "49" : port, &hints, &servers)) == 0) { + for(server = servers; server != NULL && tac_srv_no < TAC_PLUS_MAXSERVERS; server = server->ai_next) { +- tac_srv[tac_srv_no].addr = server; +- tac_srv[tac_srv_no].key = current_secret; ++ /* set server address with allocate memory */ ++ set_tacacs_server_addr(tac_srv_no, server); ++ ++ /* copy secret to key */ ++ snprintf(tac_srv[tac_srv_no].key, sizeof(tac_srv[tac_srv_no].key), "%s", current_secret); + tac_srv_no++; + } + } else { +@@ -304,10 +332,11 @@ int _pam_parse (int argc, const char **argv) { + + /* if 'secret=' was given after a 'server=' parameter, fill in the current secret */ + for(i = tac_srv_no-1; i >= 0; i--) { +- if (tac_srv[i].key != NULL) ++ if (tac_srv[i].key[0] != 0) + break; + +- tac_srv[i].key = current_secret; ++ /* copy secret to key */ ++ snprintf(tac_srv[i].key, sizeof(tac_srv[i].key), "%s", current_secret); + } + } else if (!strncmp (*argv, "timeout=", 8)) { + /* FIXME atoi() doesn't handle invalid numeric strings well */ +diff --git a/support.h b/support.h +index b1faf43..6bcb07f 100644 +--- a/support.h ++++ b/support.h +@@ -28,7 +28,7 @@ + + typedef struct { + struct addrinfo *addr; +- const char *key; ++ char key[256]; + } tacplus_server_t; + + extern tacplus_server_t tac_srv[TAC_PLUS_MAXSERVERS]; +-- +2.17.1.windows.2 + diff --git a/src/tacacs/pam/0008-Extract-tacacs-support-functions-into-library.patch b/src/tacacs/pam/0008-Extract-tacacs-support-functions-into-library.patch new file mode 100644 index 00000000000..139c49564c0 --- /dev/null +++ b/src/tacacs/pam/0008-Extract-tacacs-support-functions-into-library.patch @@ -0,0 +1,446 @@ +From d820001f60e0a9f5e5df83b1edb229be5212e0b5 Mon Sep 17 00:00:00 2001 +From: liuh-80 <58683130+liuh-80@users.noreply.github.com> +Date: Tue, 12 Oct 2021 10:09:10 +0800 +Subject: [PATCH 3/4] Extract tacacs support functions into library. + +--- + Makefile.am | 16 ++- + configure.ac | 3 +- + libtacsupport.pc.in | 11 ++ + pam_tacplus.c | 3 - + pam_tacplus.h | 6 -- + support.c | 255 ++++++++++++++++++++++++++------------------ + support.h | 14 +++ + 7 files changed, 194 insertions(+), 114 deletions(-) + create mode 100644 libtacsupport.pc.in + +diff --git a/Makefile.am b/Makefile.am +index c90c582..2ac9ea0 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -20,7 +20,7 @@ libtac/include/tacplus.h \ + libtac/include/libtac.h \ + libtac/include/cdefs.h + +-lib_LTLIBRARIES = libtac.la ++lib_LTLIBRARIES = libtac.la libtacsupport.la + libtac_la_SOURCES = \ + libtac/lib/acct_r.c \ + libtac/lib/acct_s.c \ +@@ -48,6 +48,16 @@ $(libtac_include_HEADERS) + libtac_la_CFLAGS = $(AM_CFLAGS) -I $(top_srcdir)/libtac/include + libtac_la_LDFLAGS = -version-info 2:0:0 -shared + ++libtacsupport_includedir = $(includedir)/libtac ++libtacsupport_include_HEADERS = \ ++support.h ++ ++libtacsupport_la_SOURCES = \ ++support.c \ ++$(libtacsupport_include_HEADERS) ++libtacsupport_la_CFLAGS = $(AM_CFLAGS) -I $(top_srcdir) -I $(top_srcdir)/libtac/include ++libtacsupport_la_LDFLAGS = -version-info 2:0:0 -shared ++ + moduledir = @pamdir@ + module_LTLIBRARIES = pam_tacplus.la + pam_tacplus_la_SOURCES = pam_tacplus.h \ +@@ -58,7 +68,7 @@ pam_tacplus_la_CFLAGS = $(AM_CFLAGS) -I $(top_srcdir)/libtac/include + pam_tacplus_la_LDFLAGS = -module -avoid-version + pam_tacplus_la_LIBADD = libtac.la + +-EXTRA_DIST = pam_tacplus.spec libtac.pc.in ++EXTRA_DIST = pam_tacplus.spec libtac.pc.in libtacsupport.pc.in + if DOC + dist_doc_DATA = sample.pam README.md AUTHORS ChangeLog + endif +@@ -68,5 +78,5 @@ MAINTAINERCLEANFILES = Makefile.in config.h.in configure aclocal.m4 \ + config/install-sh config/ltmain.sh config/missing + + pkgconfigdir = $(libdir)/pkgconfig +-pkgconfig_DATA = libtac.pc ++pkgconfig_DATA = libtac.pc libtacsupport.pc + +diff --git a/configure.ac b/configure.ac +index f67e2ba..0f917a8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -95,6 +95,7 @@ AM_CONDITIONAL(DOC, test "x$enable_doc" != "xno") + dnl -------------------------------------------------------------------- + dnl Generate made files + AC_CONFIG_FILES([Makefile +- libtac.pc ++ libtac.pc ++ libtacsupport.pc + pam_tacplus.spec]) + AC_OUTPUT +diff --git a/libtacsupport.pc.in b/libtacsupport.pc.in +new file mode 100644 +index 0000000..1f12fe0 +--- /dev/null ++++ b/libtacsupport.pc.in +@@ -0,0 +1,11 @@ ++prefix=@prefix@ ++exec_prefix=@exec_prefix@ ++libdir=@libdir@ ++includedir=@includedir@/libtac ++ ++Name: libtacsupport ++Description: TACACS+ support lib implementation ++URL: https://github.com/jeroennijhof/pam_tacplus ++Version: @VERSION@ ++Libs: -L${libdir} -ltacsupport ++Cflags: -I${includedir} +diff --git a/pam_tacplus.c b/pam_tacplus.c +index d062359..2a484f0 100644 +--- a/pam_tacplus.c ++++ b/pam_tacplus.c +@@ -53,9 +53,6 @@ static tacplus_server_t active_server; + /* accounting task identifier */ + static short int task_id = 0; + +-extern char *__vrfname; +- +- + /* Helper functions */ + int _pam_send_account(int tac_fd, int type, const char *user, char *tty, + char *r_addr, char *cmd) { +diff --git a/pam_tacplus.h b/pam_tacplus.h +index bc71b54..e7b30f7 100644 +--- a/pam_tacplus.h ++++ b/pam_tacplus.h +@@ -31,12 +31,6 @@ + #include + #include + +-/* pam_tacplus command line options */ +-#define PAM_TAC_DEBUG 0x01 +-#define PAM_TAC_ACCT 0x02 /* account on all specified servers */ +-#define PAM_TAC_USE_FIRST_PASS 0x04 +-#define PAM_TAC_TRY_FIRST_PASS 0x08 +- + /* pam_tacplus major, minor and patchlevel version numbers */ + #define PAM_TAC_VMAJ 1 + #define PAM_TAC_VMIN 3 +diff --git a/support.c b/support.c +index e22fa31..5b6e1fa 100644 +--- a/support.c ++++ b/support.c +@@ -29,6 +29,7 @@ + + #include + #include ++#include /* isspace() */ + + /* tacacs server information */ + tacplus_server_t tac_srv[TAC_PLUS_MAXSERVERS]; +@@ -236,9 +237,160 @@ void set_source_ip(const char *tac_source_ip) { + } + } + ++/* ++ * Parse one arguments. ++ * Use this method for both: ++ * 1. command line parameter ++ * 2. config file ++ */ ++int _pam_parse_arg (const char *arg, char* current_secret, uint current_secret_buffer_size) { ++ int ctrl = 0; ++ ++ if (!strcmp (arg, "debug")) { /* all */ ++ ctrl |= PAM_TAC_DEBUG; ++ } else if (!strcmp (arg, "use_first_pass")) { ++ ctrl |= PAM_TAC_USE_FIRST_PASS; ++ } else if (!strcmp (arg, "try_first_pass")) { ++ ctrl |= PAM_TAC_TRY_FIRST_PASS; ++ } else if (!strncmp (arg, "service=", 8)) { /* author & acct */ ++ xstrcpy (tac_service, arg + 8, sizeof(tac_service)); ++ } else if (!strncmp (arg, "protocol=", 9)) { /* author & acct */ ++ xstrcpy (tac_protocol, arg + 9, sizeof(tac_protocol)); ++ } else if (!strncmp (arg, "prompt=", 7)) { /* authentication */ ++ xstrcpy (tac_prompt, arg + 7, sizeof(tac_prompt)); ++ /* Replace _ with space */ ++ int chr; ++ for (chr = 0; chr < strlen(tac_prompt); chr++) { ++ if (tac_prompt[chr] == '_') { ++ tac_prompt[chr] = ' '; ++ } ++ } ++ } else if (!strncmp (arg, "login=", 6)) { ++ xstrcpy (tac_login, arg + 6, sizeof(tac_login)); ++ } else if (!strcmp (arg, "acct_all")) { ++ ctrl |= PAM_TAC_ACCT; ++ } else if (!strncmp (arg, "server=", 7)) { /* authen & acct */ ++ if(tac_srv_no < TAC_PLUS_MAXSERVERS) { ++ struct addrinfo hints, *servers, *server; ++ int rv; ++ char *close_bracket, *server_name, *port, server_buf[256]; ++ ++ memset(&hints, 0, sizeof hints); ++ hints.ai_family = AF_UNSPEC; /* use IPv4 or IPv6, whichever */ ++ hints.ai_socktype = SOCK_STREAM; ++ ++ if (strlen(arg + 7) >= sizeof(server_buf)) { ++ _pam_log(LOG_ERR, "server address too long, sorry"); ++ return ctrl; ++ } ++ strcpy(server_buf, arg + 7); ++ ++ if (*server_buf == '[' && (close_bracket = strchr(server_buf, ']')) != NULL) { /* Check for URI syntax */ ++ server_name = server_buf + 1; ++ port = strrchr(close_bracket, ':'); ++ *close_bracket = '\0'; ++ } else { /* Fall back to traditional syntax */ ++ server_name = server_buf; ++ port = strrchr(server_buf, ':'); ++ } ++ if (port != NULL) { ++ *port = '\0'; ++ port++; ++ } ++ if ((rv = getaddrinfo(server_name, (port == NULL) ? "49" : port, &hints, &servers)) == 0) { ++ for(server = servers; server != NULL && tac_srv_no < TAC_PLUS_MAXSERVERS; server = server->ai_next) { ++ /* set server address with allocate memory */ ++ set_tacacs_server_addr(tac_srv_no, server); ++ ++ /* copy secret to key */ ++ snprintf(tac_srv[tac_srv_no].key, sizeof(tac_srv[tac_srv_no].key), "%s", current_secret); ++ tac_srv_no++; ++ } ++ ++ /* release servers memory */ ++ freeaddrinfo(servers); ++ } else { ++ _pam_log (LOG_ERR, ++ "skip invalid server: %s (getaddrinfo: %s)", ++ server_name, gai_strerror(rv)); ++ } ++ } else { ++ _pam_log(LOG_ERR, "maximum number of servers (%d) exceeded, skipping", ++ TAC_PLUS_MAXSERVERS); ++ } ++ } else if (!strncmp (arg, "secret=", 7)) { ++ int i; ++ ++ /* points right into arg (which is const) */ ++ snprintf(current_secret, current_secret_buffer_size, "%s", arg + 7); ++ ++ /* if 'secret=' was given after a 'server=' parameter, fill in the current secret */ ++ for(i = tac_srv_no-1; i >= 0; i--) { ++ if (tac_srv[i].key[0] != 0) ++ break; ++ ++ /* copy secret to key */ ++ snprintf(tac_srv[i].key, sizeof(tac_srv[i].key), "%s", current_secret); ++ } ++ } else if (!strncmp (arg, "timeout=", 8)) { ++ /* FIXME atoi() doesn't handle invalid numeric strings well */ ++ tac_timeout = atoi(arg + 8); ++ ++ if (tac_timeout < 0) { ++ tac_timeout = 0; ++ } else { ++ tac_readtimeout_enable = 1; ++ } ++ } else if(!strncmp(arg, "vrf=", 4)) { ++ __vrfname = strdup(arg + 4); ++ } else if (!strncmp (arg, "source_ip=", strlen("source_ip="))) { ++ /* source ip for the packets */ ++ strncpy (tac_source_ip, arg + strlen("source_ip="), sizeof(tac_source_ip)); ++ set_source_ip (tac_source_ip); ++ } else { ++ _pam_log (LOG_WARNING, "unrecognized option: %s", arg); ++ } ++ ++ return ctrl; ++} /* _pam_parse_arg */ ++ ++ ++/* ++ * Parse config file. ++ */ ++int parse_config_file(const char *file) { ++ FILE *config_file; ++ char line_buffer[256]; ++ int ctrl = 0; ++ ++ config_file = fopen(file, "r"); ++ if(config_file == NULL) { ++ _pam_log(LOG_ERR, "Failed to open config file %s: %m", file); ++ return 0; ++ } ++ ++ if (tac_source_addr != NULL) { ++ /* reset source address */ ++ tac_source_addr = NULL; ++ } ++ ++ char current_secret[256]; ++ memset(current_secret, 0, sizeof(current_secret)); ++ while (fgets(line_buffer, sizeof line_buffer, config_file)) { ++ if(*line_buffer == '#' || isspace(*line_buffer)) ++ continue; /* skip comments and blank line. */ ++ strtok(line_buffer, " \t\n\r\f"); ++ ctrl |= _pam_parse_arg(line_buffer, current_secret, sizeof(current_secret)); ++ } ++ ++ fclose(config_file); ++ return ctrl; ++} ++ + int _pam_parse (int argc, const char **argv) { + int ctrl = 0; +- const char *current_secret = NULL; ++ char current_secret[256]; ++ memset(current_secret, 0, sizeof(current_secret)); + + /* otherwise the list will grow with each call */ + memset(tac_srv, 0, sizeof(tacplus_server_t) * TAC_PLUS_MAXSERVERS); +@@ -256,106 +408,7 @@ int _pam_parse (int argc, const char **argv) { + } + + for (ctrl = 0; argc-- > 0; ++argv) { +- if (!strcmp (*argv, "debug")) { /* all */ +- ctrl |= PAM_TAC_DEBUG; +- } else if (!strcmp (*argv, "use_first_pass")) { +- ctrl |= PAM_TAC_USE_FIRST_PASS; +- } else if (!strcmp (*argv, "try_first_pass")) { +- ctrl |= PAM_TAC_TRY_FIRST_PASS; +- } else if (!strncmp (*argv, "service=", 8)) { /* author & acct */ +- xstrcpy (tac_service, *argv + 8, sizeof(tac_service)); +- } else if (!strncmp (*argv, "protocol=", 9)) { /* author & acct */ +- xstrcpy (tac_protocol, *argv + 9, sizeof(tac_protocol)); +- } else if (!strncmp (*argv, "prompt=", 7)) { /* authentication */ +- xstrcpy (tac_prompt, *argv + 7, sizeof(tac_prompt)); +- /* Replace _ with space */ +- int chr; +- for (chr = 0; chr < strlen(tac_prompt); chr++) { +- if (tac_prompt[chr] == '_') { +- tac_prompt[chr] = ' '; +- } +- } +- } else if (!strncmp (*argv, "login=", 6)) { +- xstrcpy (tac_login, *argv + 6, sizeof(tac_login)); +- } else if (!strcmp (*argv, "acct_all")) { +- ctrl |= PAM_TAC_ACCT; +- } else if (!strncmp (*argv, "server=", 7)) { /* authen & acct */ +- if(tac_srv_no < TAC_PLUS_MAXSERVERS) { +- struct addrinfo hints, *servers, *server; +- int rv; +- char *close_bracket, *server_name, *port, server_buf[256]; +- +- memset(&hints, 0, sizeof hints); +- hints.ai_family = AF_UNSPEC; /* use IPv4 or IPv6, whichever */ +- hints.ai_socktype = SOCK_STREAM; +- +- if (strlen(*argv + 7) >= sizeof(server_buf)) { +- _pam_log(LOG_ERR, "server address too long, sorry"); +- continue; +- } +- strcpy(server_buf, *argv + 7); +- +- if (*server_buf == '[' && (close_bracket = strchr(server_buf, ']')) != NULL) { /* Check for URI syntax */ +- server_name = server_buf + 1; +- port = strrchr(close_bracket, ':'); +- *close_bracket = '\0'; +- } else { /* Fall back to traditional syntax */ +- server_name = server_buf; +- port = strrchr(server_buf, ':'); +- } +- if (port != NULL) { +- *port = '\0'; +- port++; +- } +- if ((rv = getaddrinfo(server_name, (port == NULL) ? "49" : port, &hints, &servers)) == 0) { +- for(server = servers; server != NULL && tac_srv_no < TAC_PLUS_MAXSERVERS; server = server->ai_next) { +- /* set server address with allocate memory */ +- set_tacacs_server_addr(tac_srv_no, server); +- +- /* copy secret to key */ +- snprintf(tac_srv[tac_srv_no].key, sizeof(tac_srv[tac_srv_no].key), "%s", current_secret); +- tac_srv_no++; +- } +- } else { +- _pam_log (LOG_ERR, +- "skip invalid server: %s (getaddrinfo: %s)", +- server_name, gai_strerror(rv)); +- } +- } else { +- _pam_log(LOG_ERR, "maximum number of servers (%d) exceeded, skipping", +- TAC_PLUS_MAXSERVERS); +- } +- } else if (!strncmp (*argv, "secret=", 7)) { +- int i; +- +- current_secret = *argv + 7; /* points right into argv (which is const) */ +- +- /* if 'secret=' was given after a 'server=' parameter, fill in the current secret */ +- for(i = tac_srv_no-1; i >= 0; i--) { +- if (tac_srv[i].key[0] != 0) +- break; +- +- /* copy secret to key */ +- snprintf(tac_srv[i].key, sizeof(tac_srv[i].key), "%s", current_secret); +- } +- } else if (!strncmp (*argv, "timeout=", 8)) { +- /* FIXME atoi() doesn't handle invalid numeric strings well */ +- tac_timeout = atoi(*argv + 8); +- +- if (tac_timeout < 0) { +- tac_timeout = 0; +- } else { +- tac_readtimeout_enable = 1; +- } +- } else if(!strncmp(*argv, "vrf=", 4)) { +- __vrfname = strdup(*argv + 4); +- } else if (!strncmp (*argv, "source_ip=", strlen("source_ip="))) { +- /* source ip for the packets */ +- strncpy (tac_source_ip, *argv + strlen("source_ip="), sizeof(tac_source_ip)); +- set_source_ip(tac_source_ip); +- } else { +- _pam_log (LOG_WARNING, "unrecognized option: %s", *argv); +- } ++ ctrl |= _pam_parse_arg(*argv, current_secret, sizeof(current_secret)); + } + + if (ctrl & PAM_TAC_DEBUG) { +diff --git a/support.h b/support.h +index 6bcb07f..569172e 100644 +--- a/support.h ++++ b/support.h +@@ -26,6 +26,14 @@ + + #include + ++/* pam_tacplus command line options */ ++#define PAM_TAC_DEBUG 0x01 ++#define PAM_TAC_ACCT 0x02 ++ ++/* account on all specified servers */ ++#define PAM_TAC_USE_FIRST_PASS 0x04 ++#define PAM_TAC_TRY_FIRST_PASS 0x08 ++ + typedef struct { + struct addrinfo *addr; + char key[256]; +@@ -33,6 +41,7 @@ typedef struct { + + extern tacplus_server_t tac_srv[TAC_PLUS_MAXSERVERS]; + extern int tac_srv_no; ++extern char *__vrfname; + + extern char tac_service[64]; + extern char tac_protocol[64]; +@@ -50,5 +59,10 @@ char *_pam_get_user(pam_handle_t *); + char *_pam_get_terminal(pam_handle_t *); + char *_pam_get_rhost(pam_handle_t *); + ++/* ++ * Parse config file. ++ */ ++int parse_config_file(const char *file); ++ + #endif /* PAM_TACPLUS_SUPPORT_H */ + +-- +2.17.1.windows.2 + diff --git a/src/tacacs/pam/0009-Add-setting-flag-for-authorization-and-accounting.patch b/src/tacacs/pam/0009-Add-setting-flag-for-authorization-and-accounting.patch new file mode 100644 index 00000000000..824db59f5ba --- /dev/null +++ b/src/tacacs/pam/0009-Add-setting-flag-for-authorization-and-accounting.patch @@ -0,0 +1,51 @@ +From 8ffcdaf2154943c9034a32876571face842b805c Mon Sep 17 00:00:00 2001 +From: liuh-80 <58683130+liuh-80@users.noreply.github.com> +Date: Tue, 12 Oct 2021 10:10:03 +0800 +Subject: [PATCH 4/4] Add setting flag for authorization and accounting. + +--- + support.c | 8 ++++++++ + support.h | 8 ++++++++ + 2 files changed, 16 insertions(+) + +diff --git a/support.c b/support.c +index 5b6e1fa..788ae22 100644 +--- a/support.c ++++ b/support.c +@@ -347,6 +347,14 @@ int _pam_parse_arg (const char *arg, char* current_secret, uint current_secret_b + /* source ip for the packets */ + strncpy (tac_source_ip, arg + strlen("source_ip="), sizeof(tac_source_ip)); + set_source_ip (tac_source_ip); ++ } else if (!strcmp (arg, "local_accounting")) { ++ ctrl |= ACCOUNTING_FLAG_LOCAL; ++ } else if (!strcmp (arg, "tacacs_accounting")) { ++ ctrl |= ACCOUNTING_FLAG_TACACS; ++ } else if (!strcmp (arg, "local_authorization")) { ++ ctrl |= AUTHORIZATION_FLAG_LOCAL; ++ } else if (!strcmp (arg, "tacacs_authorization")) { ++ ctrl |= AUTHORIZATION_FLAG_TACACS; + } else { + _pam_log (LOG_WARNING, "unrecognized option: %s", arg); + } +diff --git a/support.h b/support.h +index 569172e..2b556a7 100644 +--- a/support.h ++++ b/support.h +@@ -34,6 +34,14 @@ + #define PAM_TAC_USE_FIRST_PASS 0x04 + #define PAM_TAC_TRY_FIRST_PASS 0x08 + ++/* accounting setting flag */ ++#define ACCOUNTING_FLAG_LOCAL 0x10 ++#define ACCOUNTING_FLAG_TACACS 0x20 ++ ++/* authorization setting flag */ ++#define AUTHORIZATION_FLAG_LOCAL 0x40 ++#define AUTHORIZATION_FLAG_TACACS 0x80 ++ + typedef struct { + struct addrinfo *addr; + char key[256]; +-- +2.17.1.windows.2 + diff --git a/src/tacacs/pam/Makefile b/src/tacacs/pam/Makefile index 503bdcb864f..cc3a8fcbca4 100644 --- a/src/tacacs/pam/Makefile +++ b/src/tacacs/pam/Makefile @@ -20,6 +20,9 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : git apply ../0004-management-vrf-support.patch git apply ../0005-pam-Modify-parsing-of-IP-address-and-port-number-to-.patch git apply ../0006-Add-support-for-source-ip-address.patch + git apply ../0007-Fix-memory-leak-when-parse-configuration.patch + git apply ../0008-Extract-tacacs-support-functions-into-library.patch + git apply ../0009-Add-setting-flag-for-authorization-and-accounting.patch dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) --admindir $(SONIC_DPKG_ADMINDIR) popd