[TACACS+]: Extract tacacs support functions into library and fix memory leak issue. (#8659) (#15703)
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. ##### Work item tracking - Microsoft ADO **(number only)**: 24433713 #### 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. #### Tested branch (Please provide the tested image version) 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. - [ ] SONiC.202012-15703.306864-1ef589c19 #### 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:
parent
ff9a1d5a11
commit
f75794abdc
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,20 +1,20 @@
|
||||
From 4ef102dfa137c2c6e3dd63c2d16f2966b6f5add8 Mon Sep 17 00:00:00 2001
|
||||
From ed8b0366d3dbe137752fbb37a4b9fd1d46402d5b Mon Sep 17 00:00:00 2001
|
||||
From: Renuka Manavalan <remanava@microsoft.com>
|
||||
Date: Fri, 18 Feb 2022 22:07:24 +0000
|
||||
Date: Fri, 18 Feb 2022 22:27:39 +0000
|
||||
Subject: [PATCH] handle bad password set by sshd
|
||||
|
||||
---
|
||||
pam_tacplus.c | 11 +++++++++--
|
||||
support.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
support.c | 39 ++++++++++++++++++++++++++++++++++++++-
|
||||
support.h | 1 +
|
||||
tacc.c | 4 ++--
|
||||
4 files changed, 49 insertions(+), 4 deletions(-)
|
||||
4 files changed, 50 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/pam_tacplus.c b/pam_tacplus.c
|
||||
index ec8ea27..2421874 100644
|
||||
index d57657a..38b6ee3 100644
|
||||
--- a/pam_tacplus.c
|
||||
+++ b/pam_tacplus.c
|
||||
@@ -251,6 +251,13 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
|
||||
@@ -248,6 +248,13 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
|
||||
return PAM_CRED_INSUFFICIENT;
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ index ec8ea27..2421874 100644
|
||||
retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
_pam_log(LOG_ERR, "unable to set password");
|
||||
@@ -483,7 +490,7 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
|
||||
@@ -481,7 +488,7 @@ int pam_sm_authenticate (pam_handle_t * pamh, int flags,
|
||||
syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status);
|
||||
|
||||
if (NULL != pass) {
|
||||
@ -37,20 +37,20 @@ index ec8ea27..2421874 100644
|
||||
free(pass);
|
||||
pass = NULL;
|
||||
}
|
||||
@@ -979,7 +986,7 @@ finish:
|
||||
@@ -978,7 +985,7 @@ finish:
|
||||
syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status);
|
||||
|
||||
if (NULL != pass) {
|
||||
- bzero(pass, strlen(pass));
|
||||
+ memset(pass, 0, strlen (pass));
|
||||
+ memset(pass, 0, strlen(pass));
|
||||
free(pass);
|
||||
pass = NULL;
|
||||
}
|
||||
diff --git a/support.c b/support.c
|
||||
index 3e55e2f..09d09bf 100644
|
||||
index f056ec4..81f3466 100644
|
||||
--- a/support.c
|
||||
+++ b/support.c
|
||||
@@ -108,6 +108,43 @@ int converse(pam_handle_t * pamh, int nargs, const struct pam_message *message,
|
||||
@@ -117,6 +117,43 @@ int converse(pam_handle_t * pamh, int nargs, const struct pam_message *message,
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -94,11 +94,18 @@ index 3e55e2f..09d09bf 100644
|
||||
/* stolen from pam_stress */
|
||||
int tacacs_get_password (pam_handle_t * pamh, int flags
|
||||
,int ctrl, char **password) {
|
||||
@@ -459,4 +496,4 @@ int _pam_parse (int argc, const char **argv) {
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
-} /* _pam_parse */
|
||||
\ No newline at end of file
|
||||
+} /* _pam_parse */
|
||||
diff --git a/support.h b/support.h
|
||||
index 09b8a85..cb04a4f 100644
|
||||
index 20553da..1989530 100644
|
||||
--- a/support.h
|
||||
+++ b/support.h
|
||||
@@ -42,6 +42,7 @@ extern struct addrinfo *tac_source_addr;
|
||||
@@ -59,6 +59,7 @@ extern struct addrinfo *tac_source_addr;
|
||||
int _pam_parse (int, const char **);
|
||||
unsigned long _resolve_name (char *);
|
||||
unsigned long _getserveraddr (char *serv);
|
||||
@ -130,4 +137,3 @@ index fcc7d8c..bf0f2a3 100644
|
||||
if (do_account) {
|
||||
--
|
||||
2.17.1
|
||||
|
@ -20,7 +20,10 @@ $(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-handle-bad-password-set-by-sshd.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
|
||||
git apply ../0010-handle-bad-password-set-by-sshd.patch
|
||||
|
||||
dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) --admindir $(SONIC_DPKG_ADMINDIR)
|
||||
popd
|
||||
|
Loading…
Reference in New Issue
Block a user