[TACACS+]: Extract tacacs support functions into library and fix memory leak issue. (#8659)

This pull request extract tacacs support functions into library to share TACACS config file parse code with other project. Also fix memory leak issue in parse config code.

Why I did it
    To support TACACS per command authorization, we need reuse the TACACS config file parse code in bash plugin project.

How I did it
    Add libtacsupport.pc.in to extract tacacs support functions into library.
    Fix memory leak issue in TACACS config parse code by convert the dynamic memory allocation memory to static memory allocation.

How to verify it
    Pass all current UT.
    Check shared library generated manually.

Which release branch to backport (provide reason below if selected)
    N/A

Description for the changelog
    Extract tacacs support functions into library, this will share TACACS config file parse code with other project.
    Also fix memory leak issue in parse config code.
This commit is contained in:
liuh-80 2021-10-14 10:04:58 +08:00 committed by GitHub
parent 4654f72f1c
commit a4ac69e4f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 699 additions and 46 deletions

View File

@ -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 <venkatesan_mahalinga@dell.com>
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,45 +62,21 @@ 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) {
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);
+ 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) {
}
} 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);
} else {
_pam_log (LOG_WARNING, "unrecognized option: %s", *argv);
}
@@ -292,8 +304,27 @@ 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);
+ _pam_log(LOG_DEBUG, "tac_source_ip='%s'", tac_source_ip);
}
return ctrl;
} /* _pam_parse */
@@ -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,
+ struct addrinfo **source_address) {
+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;
+ struct addrinfo hints, *source_address;
+ int rv;
+
+ /* set the source ip address for the tacacs packets */
@ -108,14 +84,67 @@ index 7c00618..3e55e2f 100644
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ if ((rv = getaddrinfo(tac_source_ip, NULL, &hints,
+ source_address)) != 0) {
+ &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) {
+ /* reset source address */
+ tac_source_addr = NULL;
+ }
for (ctrl = 0; argc-- > 0; ++argv) {
if (!strcmp (*argv, "debug")) { /* all */
@@ -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);
} else {
_pam_log (LOG_WARNING, "unrecognized option: %s", *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);
+ _pam_log(LOG_DEBUG, "tac_source_ip='%s'", tac_source_ip);
}
return ctrl;
-} /* _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

View File

@ -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 <stdlib.h>
#include <string.h>
+/* 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

View File

@ -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 <security/pam_appl.h>
#include <security/pam_modules.h>
-/* 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 <stdlib.h>
#include <string.h>
+#include <ctype.h> /* 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 <security/pam_modules.h>
+/* 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

View File

@ -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

View File

@ -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