dpward / rpms / sssd

Forked from rpms/sssd 3 years ago
Clone

Blame SOURCES/0196-sssd_client-add-mutex-protected-call-to-the-PAC-resp.patch

60d7aa
From daa59b79602cfeff81223a7461e18f513178c9d4 Mon Sep 17 00:00:00 2001
60d7aa
From: Sumit Bose <sbose@redhat.com>
60d7aa
Date: Mon, 18 Sep 2017 15:00:53 +0200
60d7aa
Subject: [PATCH 196/196] sssd_client: add mutex protected call to the PAC
60d7aa
 responder
60d7aa
MIME-Version: 1.0
60d7aa
Content-Type: text/plain; charset=UTF-8
60d7aa
Content-Transfer-Encoding: 8bit
60d7aa
60d7aa
SSSD's plugin for MIT Kerberos to send the PAC to the PAC responder
60d7aa
currently uses sss_pac_make_request() which does not protect the
60d7aa
communication with the PAC responder with a mutex as e.g. the NSS and
60d7aa
PAM clients.
60d7aa
60d7aa
If an application using threads loads this plugin via libkrb5 in
60d7aa
different threads and is heavily processing Kerberos tickets with PACs
60d7aa
chances are that two threads try to communicate with SSSD at once. In
60d7aa
this case one of the threads will miss a reply and will wait for it
60d7aa
until the default client timeout of 300s is passed.
60d7aa
60d7aa
This patch adds a call which uses a mutex to protect the communication
60d7aa
which will avoid the 300s delay mentioned above.
60d7aa
60d7aa
Resolves:
60d7aa
https://pagure.io/SSSD/sssd/issue/3518
60d7aa
60d7aa
Reviewed-by: Lukáš Slebodník <lslebodn@redhat.com>
60d7aa
Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
60d7aa
(cherry picked from commit 1f331476e7d33bb03cc35a2a9064ee1cc5bed6cf)
60d7aa
---
60d7aa
 Makefile.am                               |  16 ++++
60d7aa
 src/sss_client/common.c                   |  30 +++++++
60d7aa
 src/sss_client/sss_cli.h                  |   7 ++
60d7aa
 src/sss_client/sss_pac_responder_client.c | 137 ++++++++++++++++++++++++++++++
60d7aa
 src/sss_client/sssd_pac.c                 |   4 +-
60d7aa
 src/tests/intg/Makefile.am                |   1 +
60d7aa
 src/tests/intg/test_pac_responder.py      | 120 ++++++++++++++++++++++++++
60d7aa
 7 files changed, 313 insertions(+), 2 deletions(-)
60d7aa
 create mode 100644 src/sss_client/sss_pac_responder_client.c
60d7aa
 create mode 100644 src/tests/intg/test_pac_responder.py
60d7aa
60d7aa
diff --git a/Makefile.am b/Makefile.am
60d7aa
index 907c3256a154ebe2aae5a1667744e1dfbe8abaae..cdd517d50679b876814303fb7d6c63d49bcd8d38 100644
60d7aa
--- a/Makefile.am
60d7aa
+++ b/Makefile.am
60d7aa
@@ -3501,6 +3501,9 @@ endif
60d7aa
 if BUILD_WITH_LIBCURL
60d7aa
 noinst_PROGRAMS += tcurl-test-tool
60d7aa
 endif
60d7aa
+if BUILD_PAC_RESPONDER
60d7aa
+    noinst_PROGRAMS += sssd_pac_test_client
60d7aa
+endif
60d7aa
 
60d7aa
 if BUILD_AUTOFS
60d7aa
 autofs_test_client_SOURCES = \
60d7aa
@@ -4210,6 +4213,19 @@ sssd_pac_plugin_la_LDFLAGS = \
60d7aa
     -avoid-version \
60d7aa
     -module
60d7aa
 
60d7aa
+sssd_pac_test_client_SOURCES = \
60d7aa
+    src/sss_client/sss_pac_responder_client.c \
60d7aa
+    src/sss_client/common.c \
60d7aa
+    src/util/strtonum.c \
60d7aa
+    $(NULL)
60d7aa
+sssd_pac_test_client_CFLAGS = \
60d7aa
+    $(AM_CFLAGS) \
60d7aa
+    $(NULL)
60d7aa
+sssd_pac_test_client_LDADD = \
60d7aa
+    $(CLIENT_LIBS) \
60d7aa
+    -lpthread \
60d7aa
+    $(NULL)
60d7aa
+
60d7aa
 # python[23] bindings
60d7aa
 pysss_la_SOURCES = \
60d7aa
     $(SSSD_TOOLS_OBJ) \
60d7aa
diff --git a/src/sss_client/common.c b/src/sss_client/common.c
60d7aa
index b7a5ed760ca379acdfd8f1d2bf95cee1aa271fd8..b527c046e2e3369934b4f9ea7efc1b52eb8c57ea 100644
60d7aa
--- a/src/sss_client/common.c
60d7aa
+++ b/src/sss_client/common.c
60d7aa
@@ -821,6 +821,22 @@ int sss_pac_make_request(enum sss_cli_command cmd,
60d7aa
     }
60d7aa
 }
60d7aa
 
60d7aa
+int sss_pac_make_request_with_lock(enum sss_cli_command cmd,
60d7aa
+                                   struct sss_cli_req_data *rd,
60d7aa
+                                   uint8_t **repbuf, size_t *replen,
60d7aa
+                                   int *errnop)
60d7aa
+{
60d7aa
+    int ret;
60d7aa
+
60d7aa
+    sss_pac_lock();
60d7aa
+
60d7aa
+    ret = sss_pac_make_request(cmd, rd, repbuf, replen, errnop);
60d7aa
+
60d7aa
+    sss_pac_unlock();
60d7aa
+
60d7aa
+    return ret;
60d7aa
+}
60d7aa
+
60d7aa
 errno_t check_server_cred(int sockfd)
60d7aa
 {
60d7aa
 #ifdef HAVE_UCRED
60d7aa
@@ -1079,6 +1095,8 @@ static struct sss_mutex sss_pam_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
60d7aa
 
60d7aa
 static struct sss_mutex sss_nss_mc_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
60d7aa
 
60d7aa
+static struct sss_mutex sss_pac_mtx = { .mtx  = PTHREAD_MUTEX_INITIALIZER };
60d7aa
+
60d7aa
 static void sss_mt_lock(struct sss_mutex *m)
60d7aa
 {
60d7aa
     pthread_mutex_lock(&m->mtx);
60d7aa
@@ -1121,6 +1139,16 @@ void sss_nss_mc_unlock(void)
60d7aa
     sss_mt_unlock(&sss_nss_mc_mtx);
60d7aa
 }
60d7aa
 
60d7aa
+/* PAC mutex wrappers */
60d7aa
+void sss_pac_lock(void)
60d7aa
+{
60d7aa
+    sss_mt_lock(&sss_pac_mtx);
60d7aa
+}
60d7aa
+void sss_pac_unlock(void)
60d7aa
+{
60d7aa
+    sss_mt_unlock(&sss_pac_mtx);
60d7aa
+}
60d7aa
+
60d7aa
 #else
60d7aa
 
60d7aa
 /* sorry no mutexes available */
60d7aa
@@ -1130,6 +1158,8 @@ void sss_pam_lock(void) { return; }
60d7aa
 void sss_pam_unlock(void) { return; }
60d7aa
 void sss_nss_mc_lock(void) { return; }
60d7aa
 void sss_nss_mc_unlock(void) { return; }
60d7aa
+void sss_pac_lock(void) { return; }
60d7aa
+void sss_pac_unlock(void) { return; }
60d7aa
 #endif
60d7aa
 
60d7aa
 
60d7aa
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
60d7aa
index d4198407f2f86c6594aee6a2a43775e429692df0..337fe9803d2df3167cd2da77107dbd077f35a51b 100644
60d7aa
--- a/src/sss_client/sss_cli.h
60d7aa
+++ b/src/sss_client/sss_cli.h
60d7aa
@@ -585,6 +585,11 @@ int sss_pac_make_request(enum sss_cli_command cmd,
60d7aa
                          uint8_t **repbuf, size_t *replen,
60d7aa
                          int *errnop);
60d7aa
 
60d7aa
+int sss_pac_make_request_with_lock(enum sss_cli_command cmd,
60d7aa
+                                   struct sss_cli_req_data *rd,
60d7aa
+                                   uint8_t **repbuf, size_t *replen,
60d7aa
+                                   int *errnop);
60d7aa
+
60d7aa
 int sss_sudo_make_request(enum sss_cli_command cmd,
60d7aa
                           struct sss_cli_req_data *rd,
60d7aa
                           uint8_t **repbuf, size_t *replen,
60d7aa
@@ -634,6 +639,8 @@ void sss_pam_lock(void);
60d7aa
 void sss_pam_unlock(void);
60d7aa
 void sss_nss_mc_lock(void);
60d7aa
 void sss_nss_mc_unlock(void);
60d7aa
+void sss_pac_lock(void);
60d7aa
+void sss_pac_unlock(void);
60d7aa
 
60d7aa
 errno_t sss_readrep_copy_string(const char *in,
60d7aa
                                 size_t *offset,
60d7aa
diff --git a/src/sss_client/sss_pac_responder_client.c b/src/sss_client/sss_pac_responder_client.c
60d7aa
new file mode 100644
60d7aa
index 0000000000000000000000000000000000000000..9eb0cbea6175ee273b23d9a975529d85c02fc603
60d7aa
--- /dev/null
60d7aa
+++ b/src/sss_client/sss_pac_responder_client.c
60d7aa
@@ -0,0 +1,137 @@
60d7aa
+
60d7aa
+#include <stdio.h>
60d7aa
+#include <stdbool.h>
60d7aa
+#include <pthread.h>
60d7aa
+#include <pwd.h>
60d7aa
+#include <unistd.h>
60d7aa
+#include <sys/types.h>
60d7aa
+#include <errno.h>
60d7aa
+
60d7aa
+#include <unistd.h>
60d7aa
+#include <sys/syscall.h>
60d7aa
+
60d7aa
+#include "sss_client/sss_cli.h"
60d7aa
+
60d7aa
+const uint8_t pac[] = {
60d7aa
+0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10,
60d7aa
+0x02, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
60d7aa
+0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x68, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x0c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x78, 0x02, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xb8,
60d7aa
+0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00,
60d7aa
+0x00, 0x00, 0xc8, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x08,
60d7aa
+0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x02, 0x00, 0x30, 0xe3, 0xd6, 0x9e, 0x99, 0x2b, 0xd3, 0x01, 0xff,
60d7aa
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60d7aa
+0xff, 0x7f, 0xe2, 0xf7, 0x8a, 0xaf, 0x00, 0x0f, 0xd0, 0x01, 0xe2, 0xb7, 0xf4,
60d7aa
+0xd9, 0xc9, 0x0f, 0xd0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
60d7aa
+0x06, 0x00, 0x06, 0x00, 0x04, 0x00, 0x02, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08,
60d7aa
+0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x02, 0x00, 0x45, 0x02, 0x00, 0x00,
60d7aa
+0x50, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x1c,
60d7aa
+0x00, 0x02, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x14,
60d7aa
+0x00, 0x20, 0x00, 0x02, 0x00, 0x04, 0x00, 0x06, 0x00, 0x24, 0x00, 0x02, 0x00,
60d7aa
+0x28, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
60d7aa
+0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x02, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x74, 0x00,
60d7aa
+0x75, 0x00, 0x31, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x03, 0x00, 0x00, 0x00, 0x74, 0x00, 0x20, 0x00, 0x75, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
60d7aa
+0xfd, 0xa2, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x07,
60d7aa
+0x00, 0x00, 0x00, 0x5c, 0x04, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x56, 0x04,
60d7aa
+0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x89, 0xa6, 0x00, 0x00, 0x07, 0x00, 0x00,
60d7aa
+0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
60d7aa
+0x41, 0x00, 0x44, 0x00, 0x2d, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x56,
60d7aa
+0x00, 0x45, 0x00, 0x52, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
60d7aa
+0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x44, 0x00, 0x04, 0x00, 0x00,
60d7aa
+0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00,
60d7aa
+0xf8, 0x12, 0x13, 0xdc, 0x47, 0xf3, 0x1c, 0x76, 0x47, 0x2f, 0x2e, 0xd7, 0x02,
60d7aa
+0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x34, 0x00,
60d7aa
+0x02, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00,
60d7aa
+0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0x29, 0xc9, 0x4f, 0xd9,
60d7aa
+0xc2, 0x3c, 0xc3, 0x78, 0x36, 0x55, 0x87, 0xf8, 0x54, 0x04, 0x00, 0x00, 0x05,
60d7aa
+0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00,
60d7aa
+0x00, 0x00, 0x25, 0xe1, 0xff, 0x1c, 0xf7, 0x87, 0x6b, 0x2c, 0x25, 0xd2, 0x0c,
60d7aa
+0xe3, 0xf2, 0x03, 0x00, 0x00, 0x00, 0x2c, 0x29, 0x89, 0x65, 0x2d, 0xd3, 0x01,
60d7aa
+0x06, 0x00, 0x74, 0x00, 0x75, 0x00, 0x31, 0x00, 0x20, 0x00, 0x10, 0x00, 0x10,
60d7aa
+0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00,
60d7aa
+0x75, 0x00, 0x31, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x40,
60d7aa
+0x00, 0x61, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x64, 0x00, 0x65, 0x00, 0x76, 0x00,
60d7aa
+0x65, 0x00, 0x6c, 0x00, 0x41, 0x00, 0x44, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x45,
60d7aa
+0x00, 0x56, 0x00, 0x45, 0x00, 0x4c, 0x00, 0x10, 0x00, 0x00, 0x00, 0x76, 0x8e,
60d7aa
+0x25, 0x32, 0x7c, 0x85, 0x00, 0x32, 0xac, 0x8f, 0x02, 0x2c, 0x10, 0x00, 0x00,
60d7aa
+0x00, 0x6b, 0xe8, 0x51, 0x03, 0x30, 0xed, 0xca, 0x7d, 0xe2, 0x12, 0xa5, 0xde};
60d7aa
+
60d7aa
+enum nss_status _nss_sss_getpwuid_r(uid_t uid, struct passwd *result,
60d7aa
+                                    char *buffer, size_t buflen, int *errnop);
60d7aa
+static void *pac_client(void *arg)
60d7aa
+{
60d7aa
+    struct sss_cli_req_data sss_data = { sizeof(pac), pac };
60d7aa
+    int errnop = -1;
60d7aa
+    int ret;
60d7aa
+    size_t c;
60d7aa
+
60d7aa
+    fprintf(stderr, "[%ld][%d][%ld][%s] started\n", time(NULL), getpid(),
60d7aa
+                                                    syscall(SYS_gettid),
60d7aa
+                                                    (char *) arg);
60d7aa
+    for (c = 0; c < 1000; c++) {
60d7aa
+        /* sss_pac_make_request() does not protect the client's file
60d7aa
+         * descriptor to the PAC responder. With this one thread will miss a
60d7aa
+         * reply for a SSS_GET_VERSION request and will wait until
60d7aa
+         * SSS_CLI_SOCKET_TIMEOUT is passed.
60d7aa
+
60d7aa
+        ret = sss_pac_make_request(SSS_PAC_ADD_PAC_USER, &sss_data,
60d7aa
+                                   NULL, NULL, &errnop);
60d7aa
+         */
60d7aa
+        ret = sss_pac_make_request_with_lock(SSS_PAC_ADD_PAC_USER, &sss_data,
60d7aa
+                                             NULL, NULL, &errnop);
60d7aa
+        if (ret != NSS_STATUS_SUCCESS
60d7aa
+                && !(ret == NSS_STATUS_UNAVAIL && errnop != ECONNREFUSED)) {
60d7aa
+                /* NSS_STATUS_UNAVAIL is returned if the PAC responder rejects
60d7aa
+                 * the request which is ok becasue the client is waiting for a
60d7aa
+                 * response here as well. Only errnop == ECONNREFUSED should
60d7aa
+                 * be treated as error becasue this means that the PAC
60d7aa
+                 * responder is not running. */
60d7aa
+            fprintf(stderr, "pac: [%s][%d][%d]\n", (char *)arg, ret, errnop);
60d7aa
+            return ((void *)((uintptr_t)("X")));
60d7aa
+        }
60d7aa
+    }
60d7aa
+
60d7aa
+    fprintf(stderr, "[%ld][%s] done\n", time(NULL),(char *) arg);
60d7aa
+    return NULL;
60d7aa
+}
60d7aa
+
60d7aa
+int main(void)
60d7aa
+{
60d7aa
+    pthread_t thread1;
60d7aa
+    pthread_t thread2;
60d7aa
+    int ret;
60d7aa
+    void *t_ret;
60d7aa
+
60d7aa
+    pthread_create(&thread1, NULL, pac_client,
60d7aa
+                   ((void *)((uintptr_t)("Thread 1"))));
60d7aa
+    pthread_create(&thread2, NULL, pac_client,
60d7aa
+                   ((void *)((uintptr_t)("Thread 2"))));
60d7aa
+
60d7aa
+    ret = pthread_join(thread1, &t_ret);
60d7aa
+    if (ret != 0 || t_ret != NULL) {
60d7aa
+        fprintf(stderr, "Thread 1 failed.\n");
60d7aa
+        return EIO;
60d7aa
+    }
60d7aa
+
60d7aa
+    ret = pthread_join(thread2, &t_ret);
60d7aa
+    if (ret != 0 || t_ret != NULL) {
60d7aa
+        fprintf(stderr, "Thread 1 failed.\n");
60d7aa
+        return EIO;
60d7aa
+    }
60d7aa
+
60d7aa
+    return 0;
60d7aa
+}
60d7aa
diff --git a/src/sss_client/sssd_pac.c b/src/sss_client/sssd_pac.c
60d7aa
index 1d98e38826b36aed199b32880a7e27de905a4592..8444834a7f148787e847f5e8e21186c8701b2de7 100644
60d7aa
--- a/src/sss_client/sssd_pac.c
60d7aa
+++ b/src/sss_client/sssd_pac.c
60d7aa
@@ -169,8 +169,8 @@ static krb5_error_code sssdpac_verify(krb5_context kcontext,
60d7aa
     sss_data.len = sssdctx->data.length;
60d7aa
     sss_data.data = sssdctx->data.data;
60d7aa
 
60d7aa
-    ret = sss_pac_make_request(SSS_PAC_ADD_PAC_USER, &sss_data,
60d7aa
-                               NULL, NULL, &errnop);
60d7aa
+    ret = sss_pac_make_request_with_lock(SSS_PAC_ADD_PAC_USER, &sss_data,
60d7aa
+                                         NULL, NULL, &errnop);
60d7aa
     if (ret != 0) {
60d7aa
         /* Ignore the error */
60d7aa
     }
60d7aa
diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am
60d7aa
index 8566106e9017a8d3c9e7a3898a3a886e2966e346..0af7c62ca243822d919619f3d0ebc852a317efc4 100644
60d7aa
--- a/src/tests/intg/Makefile.am
60d7aa
+++ b/src/tests/intg/Makefile.am
60d7aa
@@ -29,6 +29,7 @@ dist_noinst_DATA = \
60d7aa
     kdc.py \
60d7aa
     krb5utils.py \
60d7aa
     test_kcm.py \
60d7aa
+    test_pac_responder.py \
60d7aa
     $(NULL)
60d7aa
 
60d7aa
 config.py: config.py.m4
60d7aa
diff --git a/src/tests/intg/test_pac_responder.py b/src/tests/intg/test_pac_responder.py
60d7aa
new file mode 100644
60d7aa
index 0000000000000000000000000000000000000000..4354a5d78da6a6627a27d0ca85c8a1d47419cedf
60d7aa
--- /dev/null
60d7aa
+++ b/src/tests/intg/test_pac_responder.py
60d7aa
@@ -0,0 +1,120 @@
60d7aa
+#
60d7aa
+# SSSD PAC responder tests
60d7aa
+#
60d7aa
+# Copyright (c) 2017 Red Hat, Inc.
60d7aa
+# Author: Sumit Bose <sbose@redhat.com>
60d7aa
+#
60d7aa
+# This is free software; you can redistribute it and/or modify it
60d7aa
+# under the terms of the GNU General Public License as published by
60d7aa
+# the Free Software Foundation; version 2 only
60d7aa
+#
60d7aa
+# This program is distributed in the hope that it will be useful, but
60d7aa
+# WITHOUT ANY WARRANTY; without even the implied warranty of
60d7aa
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
60d7aa
+# General Public License for more details.
60d7aa
+#
60d7aa
+# You should have received a copy of the GNU General Public License
60d7aa
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
60d7aa
+#
60d7aa
+import os
60d7aa
+import stat
60d7aa
+import time
60d7aa
+import config
60d7aa
+import signal
60d7aa
+import subprocess
60d7aa
+import pytest
60d7aa
+from util import unindent
60d7aa
+
60d7aa
+
60d7aa
+def stop_sssd():
60d7aa
+    with open(config.PIDFILE_PATH, "r") as pid_file:
60d7aa
+        pid = int(pid_file.read())
60d7aa
+    os.kill(pid, signal.SIGTERM)
60d7aa
+    while True:
60d7aa
+        try:
60d7aa
+            os.kill(pid, signal.SIGCONT)
60d7aa
+        except:
60d7aa
+            break
60d7aa
+        time.sleep(1)
60d7aa
+
60d7aa
+
60d7aa
+def create_conf_fixture(request, contents):
60d7aa
+    """Generate sssd.conf and add teardown for removing it"""
60d7aa
+    conf = open(config.CONF_PATH, "w")
60d7aa
+    conf.write(contents)
60d7aa
+    conf.close()
60d7aa
+    os.chmod(config.CONF_PATH, stat.S_IRUSR | stat.S_IWUSR)
60d7aa
+    request.addfinalizer(lambda: os.unlink(config.CONF_PATH))
60d7aa
+
60d7aa
+
60d7aa
+def create_sssd_fixture(request):
60d7aa
+    """Start sssd and add teardown for stopping it and removing state"""
60d7aa
+    if subprocess.call(["sssd", "-D", "-f"]) != 0:
60d7aa
+        raise Exception("sssd start failed")
60d7aa
+
60d7aa
+    def teardown():
60d7aa
+        try:
60d7aa
+            stop_sssd()
60d7aa
+        except:
60d7aa
+            pass
60d7aa
+        for path in os.listdir(config.DB_PATH):
60d7aa
+            os.unlink(config.DB_PATH + "/" + path)
60d7aa
+        for path in os.listdir(config.MCACHE_PATH):
60d7aa
+            os.unlink(config.MCACHE_PATH + "/" + path)
60d7aa
+    request.addfinalizer(teardown)
60d7aa
+
60d7aa
+
60d7aa
+@pytest.fixture
60d7aa
+def local_domain_only(request):
60d7aa
+    conf = unindent("""\
60d7aa
+        [sssd]
60d7aa
+        domains = LOCAL
60d7aa
+        services = nss, pac
60d7aa
+
60d7aa
+        [nss]
60d7aa
+        memcache_timeout = 0
60d7aa
+
60d7aa
+        [domain/LOCAL]
60d7aa
+        id_provider = local
60d7aa
+        min_id = 10000
60d7aa
+        max_id = 20000
60d7aa
+    """).format(**locals())
60d7aa
+    create_conf_fixture(request, conf)
60d7aa
+    create_sssd_fixture(request)
60d7aa
+    return None
60d7aa
+
60d7aa
+
60d7aa
+@pytest.fixture
60d7aa
+def sssd_pac_test_client(request):
60d7aa
+    path = os.path.join(config.ABS_BUILDDIR,
60d7aa
+                        "..", "..", "..", "sssd_pac_test_client")
60d7aa
+    if os.access(path, os.X_OK):
60d7aa
+        return path
60d7aa
+
60d7aa
+    return None
60d7aa
+
60d7aa
+
60d7aa
+def timeout_handler(signum, frame):
60d7aa
+    raise Exception("Timeout")
60d7aa
+
60d7aa
+
60d7aa
+def test_multithreaded_pac_client(local_domain_only, sssd_pac_test_client):
60d7aa
+    """
60d7aa
+    Test for ticket
60d7aa
+    https://pagure.io/SSSD/sssd/issue/3518
60d7aa
+    """
60d7aa
+
60d7aa
+    if not sssd_pac_test_client:
60d7aa
+        pytest.skip("The sssd_pac_test_client is not available, skipping test")
60d7aa
+
60d7aa
+    signal.signal(signal.SIGALRM, timeout_handler)
60d7aa
+    signal.alarm(10)
60d7aa
+
60d7aa
+    try:
60d7aa
+        subprocess.check_call(sssd_pac_test_client)
60d7aa
+    except:
60d7aa
+        # cancel alarm
60d7aa
+        signal.alarm(0)
60d7aa
+        raise Exception("sssd_pac_test_client failed")
60d7aa
+
60d7aa
+    signal.alarm(0)
60d7aa
-- 
60d7aa
2.13.5
60d7aa