Blame SOURCES/0037-p11_child-add-wait_for_card-option.patch

71e593
From 8070497ccd404438712711f1317e800df0c774e3 Mon Sep 17 00:00:00 2001
71e593
From: Sumit Bose <sbose@redhat.com>
71e593
Date: Fri, 14 Sep 2018 12:47:00 +0200
71e593
Subject: [PATCH 37/47] p11_child: add --wait_for_card option
71e593
71e593
The --wait_for_card option will let the p11_child wait until a
71e593
Smartcard/token is available in a slot with the removable flag.
71e593
71e593
Related to  https://pagure.io/SSSD/sssd/issue/3650
71e593
71e593
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
71e593
(cherry picked from commit 42f69e26e5b858dd03492cc2a148d02c2ccc2161)
71e593
---
71e593
 src/p11_child/p11_child.h         |   5 +-
71e593
 src/p11_child/p11_child_common.c  |  12 +++-
71e593
 src/p11_child/p11_child_nss.c     | 105 +++++++++++++++++++--------
71e593
 src/p11_child/p11_child_openssl.c | 146 +++++++++++++++++++++++++++++---------
71e593
 4 files changed, 201 insertions(+), 67 deletions(-)
71e593
71e593
diff --git a/src/p11_child/p11_child.h b/src/p11_child/p11_child.h
71e593
index 1e9fc3d1c9d0a05f50080f1ef37771448deb162f..dd8fdeafbf947aad930e61ae694bc99df6d8212a 100644
71e593
--- a/src/p11_child/p11_child.h
71e593
+++ b/src/p11_child/p11_child.h
71e593
@@ -25,6 +25,9 @@
71e593
 #ifndef __P11_CHILD_H__
71e593
 #define __P11_CHILD_H__
71e593
 
71e593
+/* Time to wait during a C_Finalize C_Initialize cycle to discover
71e593
+ * new slots. */
71e593
+#define PKCS11_FINIALIZE_INITIALIZE_WAIT_TIME 3
71e593
 struct p11_ctx;
71e593
 
71e593
 enum op_mode {
71e593
@@ -41,7 +44,7 @@ enum pin_mode {
71e593
 };
71e593
 
71e593
 errno_t init_p11_ctx(TALLOC_CTX *mem_ctx, const char *nss_db,
71e593
-                     struct p11_ctx **p11_ctx);
71e593
+                     bool wait_for_card, struct p11_ctx **p11_ctx);
71e593
 
71e593
 errno_t init_verification(struct p11_ctx *p11_ctx,
71e593
                           struct cert_verify_opts *cert_verify_opts);
71e593
diff --git a/src/p11_child/p11_child_common.c b/src/p11_child/p11_child_common.c
71e593
index 125430d13d0807bc30018b49715367cabb028696..bc5f6b09b191f0ea853f45d8a78bc6e4a69c3da7 100644
71e593
--- a/src/p11_child/p11_child_common.c
71e593
+++ b/src/p11_child/p11_child_common.c
71e593
@@ -57,6 +57,7 @@ static const char *op_mode_str(enum op_mode mode)
71e593
 
71e593
 static int do_work(TALLOC_CTX *mem_ctx, enum op_mode mode, const char *ca_db,
71e593
                    struct cert_verify_opts *cert_verify_opts,
71e593
+                   bool wait_for_card,
71e593
                    const char *cert_b64, const char *pin,
71e593
                    const char *module_name, const char *token_name,
71e593
                    const char *key_id, char **multi)
71e593
@@ -64,7 +65,7 @@ static int do_work(TALLOC_CTX *mem_ctx, enum op_mode mode, const char *ca_db,
71e593
     int ret;
71e593
     struct p11_ctx *p11_ctx;
71e593
 
71e593
-    ret = init_p11_ctx(mem_ctx, ca_db, &p11_ctx);
71e593
+    ret = init_p11_ctx(mem_ctx, ca_db, wait_for_card, &p11_ctx);
71e593
     if (ret != EOK) {
71e593
         DEBUG(SSSDBG_OP_FAILURE, "init_p11_ctx failed.\n");
71e593
         return ret;
71e593
@@ -157,6 +158,7 @@ int main(int argc, const char *argv[])
71e593
     char *token_name = NULL;
71e593
     char *key_id = NULL;
71e593
     char *cert_b64 = NULL;
71e593
+    bool wait_for_card = false;
71e593
 
71e593
     struct poptOption long_options[] = {
71e593
         POPT_AUTOHELP
71e593
@@ -174,6 +176,7 @@ int main(int argc, const char *argv[])
71e593
         SSSD_LOGGER_OPTS
71e593
         {"auth", 0, POPT_ARG_NONE, NULL, 'a', _("Run in auth mode"), NULL},
71e593
         {"pre", 0, POPT_ARG_NONE, NULL, 'p', _("Run in pre-auth mode"), NULL},
71e593
+        {"wait_for_card", 0, POPT_ARG_NONE, NULL, 'w', _("Wait until card is available"), NULL},
71e593
         {"verification", 0, POPT_ARG_NONE, NULL, 'v', _("Run in verification mode"),
71e593
          NULL},
71e593
         {"pin", 0, POPT_ARG_NONE, NULL, 'i', _("Expect PIN on stdin"), NULL},
71e593
@@ -258,6 +261,9 @@ int main(int argc, const char *argv[])
71e593
             }
71e593
             pin_mode = PIN_KEYPAD;
71e593
             break;
71e593
+        case 'w':
71e593
+            wait_for_card = true;
71e593
+            break;
71e593
         default:
71e593
             fprintf(stderr, "\nInvalid option %s: %s\n\n",
71e593
                   poptBadOption(pc, 0), poptStrerror(opt));
71e593
@@ -360,8 +366,8 @@ int main(int argc, const char *argv[])
71e593
         }
71e593
     }
71e593
 
71e593
-    ret = do_work(main_ctx, mode, nss_db, cert_verify_opts, cert_b64,
71e593
-                 pin, module_name, token_name, key_id, &multi);
71e593
+    ret = do_work(main_ctx, mode, nss_db, cert_verify_opts, wait_for_card,
71e593
+                  cert_b64, pin, module_name, token_name, key_id, &multi);
71e593
     if (ret != 0) {
71e593
         DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n");
71e593
         goto fail;
71e593
diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c
71e593
index d6a0b804a23a02389d1f764488cda6924dc0b41e..b2777d1d245d4942263ebf0610eef5cf6a528bd1 100644
71e593
--- a/src/p11_child/p11_child_nss.c
71e593
+++ b/src/p11_child/p11_child_nss.c
71e593
@@ -51,6 +51,7 @@ struct p11_ctx {
71e593
     CERTCertDBHandle *handle;
71e593
     struct cert_verify_opts *cert_verify_opts;
71e593
     const char *nss_db;
71e593
+    bool wait_for_card;
71e593
 };
71e593
 
71e593
 #define EXP_USAGES (  certificateUsageSSLClient \
71e593
@@ -141,6 +142,19 @@ static int talloc_free_handle(struct p11_ctx *p11_ctx)
71e593
     return 0;
71e593
 }
71e593
 
71e593
+static NSSInitContext *get_nss_ctx(const char *nss_db)
71e593
+{
71e593
+    uint32_t flags = NSS_INIT_READONLY
71e593
+                                   | NSS_INIT_FORCEOPEN
71e593
+                                   | NSS_INIT_NOROOTINIT
71e593
+                                   | NSS_INIT_OPTIMIZESPACE
71e593
+                                   | NSS_INIT_PK11RELOAD;
71e593
+    NSSInitParameters parameters = { 0 };
71e593
+    parameters.length =  sizeof (parameters);
71e593
+
71e593
+    return NSS_InitContext(nss_db, "", "", SECMOD_DB, &parameters, flags);
71e593
+}
71e593
+
71e593
 errno_t init_verification(struct p11_ctx *p11_ctx,
71e593
                           struct cert_verify_opts *cert_verify_opts)
71e593
 {
71e593
@@ -256,14 +270,15 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
71e593
     SECItem signed_random_value = {0};
71e593
     SECKEYPublicKey *pub_key;
71e593
     CERTCertificate *found_cert = NULL;
71e593
-    PK11SlotList *list = NULL;
71e593
-    PK11SlotListElement *le;
71e593
     const char *label;
71e593
     char *key_id_str = NULL;
71e593
     CERTCertList *valid_certs = NULL;
71e593
     char *cert_b64 = NULL;
71e593
     char *multi = NULL;
71e593
     PRCList *node;
71e593
+    CK_SLOT_INFO slInfo;
71e593
+    PK11TokenStatus token_status;
71e593
+    size_t s;
71e593
 
71e593
     PK11_SetPasswordFunc(password_passthrough);
71e593
 
71e593
@@ -297,28 +312,50 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
71e593
                                 mod_list_item->module->dllName);
71e593
     }
71e593
 
71e593
-    list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE,
71e593
-                             NULL);
71e593
-    if (list == NULL) {
71e593
-        DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n");
71e593
-        ret = EIO;
71e593
-        goto done;
71e593
-    }
71e593
+    for (;;)  {
71e593
+        mod_list = SECMOD_GetDefaultModuleList();
71e593
+        for (mod_list_item = mod_list; mod_list_item != NULL;
71e593
+                                       mod_list_item = mod_list_item->next) {
71e593
+            for (s = 0; s < mod_list_item->module->slotCount; s++) {
71e593
+                slInfo.flags = 0;
71e593
+                rv = PK11_GetSlotInfo(mod_list_item->module->slots[s], &slInfo);
71e593
+                DEBUG(SSSDBG_TRACE_ALL,
71e593
+                      "Description [%s] Manufacturer [%s] flags [%lu] "
71e593
+                      "removable [%s] token present [%s].\n",
71e593
+                      slInfo.slotDescription, slInfo.manufacturerID,
71e593
+                      slInfo.flags,
71e593
+                      (slInfo.flags & CKF_REMOVABLE_DEVICE) ? "true": "false",
71e593
+                      (slInfo.flags & CKF_TOKEN_PRESENT) ? "true": "false");
71e593
 
71e593
-    for (le = list->head; le; le = le->next) {
71e593
-        CK_SLOT_INFO slInfo;
71e593
+                if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) {
71e593
+                    slot = PK11_ReferenceSlot(mod_list_item->module->slots[s]);
71e593
+                    break;
71e593
+                }
71e593
+            }
71e593
+        }
71e593
 
71e593
-        slInfo.flags = 0;
71e593
-        rv = PK11_GetSlotInfo(le->slot, &slInfo);
71e593
-        DEBUG(SSSDBG_TRACE_ALL,
71e593
-              "Description [%s] Manufacturer [%s] flags [%lu].\n",
71e593
-              slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags);
71e593
-        if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) {
71e593
-            slot = PK11_ReferenceSlot(le->slot);
71e593
+        /* When e.g. using Yubikeys the slot isn't present until the device is
71e593
+         * inserted, so we should wait for a slot as well. */
71e593
+        if (p11_ctx->wait_for_card && slot == NULL) {
71e593
+            rv = NSS_ShutdownContext(p11_ctx->nss_ctx);
71e593
+            if (rv != SECSuccess) {
71e593
+                DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d][%s].\n",
71e593
+                      PR_GetError(), PORT_ErrorToString(PR_GetError()));
71e593
+            }
71e593
+
71e593
+            sleep(PKCS11_FINIALIZE_INITIALIZE_WAIT_TIME);
71e593
+
71e593
+            p11_ctx->nss_ctx = get_nss_ctx(p11_ctx->nss_db);
71e593
+            if (p11_ctx->nss_ctx == NULL) {
71e593
+                DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d][%s].\n",
71e593
+                      PR_GetError(), PORT_ErrorToString(PR_GetError()));
71e593
+                return EIO;
71e593
+            }
71e593
+        } else {
71e593
             break;
71e593
         }
71e593
     }
71e593
-    PK11_FreeSlotList(list);
71e593
+
71e593
     if (slot == NULL) {
71e593
         DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n");
71e593
         ret = EIO;
71e593
@@ -332,6 +369,22 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
71e593
     module = PK11_GetModule(slot);
71e593
     module_name = module->dllName == NULL ? "NSS-Internal" : module->dllName;
71e593
 
71e593
+    if (!(slInfo.flags & CKF_TOKEN_PRESENT)) {
71e593
+        DEBUG(SSSDBG_TRACE_ALL, "Token not present.\n");
71e593
+        if (p11_ctx->wait_for_card) {
71e593
+            token_status = PK11_WaitForTokenEvent(slot, PK11TokenPresentEvent,
71e593
+                                                 PR_INTERVAL_NO_TIMEOUT, 0, 0);
71e593
+            if (token_status != PK11TokenPresent) {
71e593
+                DEBUG(SSSDBG_OP_FAILURE, "PK11_WaitForTokenEvent failed.\n");
71e593
+                ret = EIO;
71e593
+                goto done;
71e593
+            }
71e593
+        } else {
71e593
+            ret = EIO;
71e593
+            goto done;
71e593
+        }
71e593
+    }
71e593
+
71e593
     DEBUG(SSSDBG_TRACE_ALL, "Found [%s] in slot [%s][%d] of module [%d][%s].\n",
71e593
           token_name, slot_name, (int) slot_id, (int) module_id, module_name);
71e593
 
71e593
@@ -651,26 +704,18 @@ static int talloc_nss_shutdown(struct p11_ctx *p11_ctx)
71e593
 }
71e593
 
71e593
 errno_t init_p11_ctx(TALLOC_CTX *mem_ctx, const char *nss_db,
71e593
-                     struct p11_ctx **p11_ctx)
71e593
+                     bool wait_for_card, struct p11_ctx **p11_ctx)
71e593
 {
71e593
     struct p11_ctx *ctx;
71e593
-    uint32_t flags = NSS_INIT_READONLY
71e593
-                                   | NSS_INIT_FORCEOPEN
71e593
-                                   | NSS_INIT_NOROOTINIT
71e593
-                                   | NSS_INIT_OPTIMIZESPACE
71e593
-                                   | NSS_INIT_PK11RELOAD;
71e593
-    NSSInitParameters parameters = { 0 };
71e593
-    parameters.length =  sizeof (parameters);
71e593
-
71e593
     ctx = talloc_zero(mem_ctx, struct p11_ctx);
71e593
     if (ctx == NULL) {
71e593
         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
71e593
         return ENOMEM;
71e593
     }
71e593
     ctx->nss_db = nss_db;
71e593
+    ctx->wait_for_card = wait_for_card;
71e593
 
71e593
-    ctx->nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, &parameters,
71e593
-                                    flags);
71e593
+    ctx->nss_ctx = get_nss_ctx(nss_db);
71e593
     if (ctx->nss_ctx == NULL) {
71e593
         DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d][%s].\n",
71e593
               PR_GetError(), PORT_ErrorToString(PR_GetError()));
71e593
diff --git a/src/p11_child/p11_child_openssl.c b/src/p11_child/p11_child_openssl.c
71e593
index bf4418f8603eac4d77d20f464e8b56fb82285f0a..d4572d99cd3a3186128b46cc4a9453d716bd7979 100644
71e593
--- a/src/p11_child/p11_child_openssl.c
71e593
+++ b/src/p11_child/p11_child_openssl.c
71e593
@@ -40,6 +40,7 @@
71e593
 struct p11_ctx {
71e593
     X509_STORE *x509_store;
71e593
     const char *ca_db;
71e593
+    bool wait_for_card;
71e593
 };
71e593
 
71e593
 static int talloc_cleanup_openssl(struct p11_ctx *p11_ctx)
71e593
@@ -48,8 +49,9 @@ static int talloc_cleanup_openssl(struct p11_ctx *p11_ctx)
71e593
 
71e593
     return 0;
71e593
 }
71e593
+
71e593
 errno_t init_p11_ctx(TALLOC_CTX *mem_ctx, const char *ca_db,
71e593
-                     struct p11_ctx **p11_ctx)
71e593
+                     bool wait_for_card, struct p11_ctx **p11_ctx)
71e593
 {
71e593
     int ret;
71e593
     struct p11_ctx *ctx;
71e593
@@ -73,6 +75,7 @@ errno_t init_p11_ctx(TALLOC_CTX *mem_ctx, const char *ca_db,
71e593
     }
71e593
 
71e593
     ctx->ca_db = ca_db;
71e593
+    ctx->wait_for_card = wait_for_card;
71e593
     talloc_set_destructor(ctx, talloc_cleanup_openssl);
71e593
 
71e593
     *p11_ctx = ctx;
71e593
@@ -547,6 +550,45 @@ done:
71e593
     return ret;
71e593
 }
71e593
 
71e593
+static errno_t wait_for_card(CK_FUNCTION_LIST *module, CK_SLOT_ID *slot_id)
71e593
+{
71e593
+    CK_FLAGS wait_flags = 0;
71e593
+    CK_RV rv;
71e593
+    CK_SLOT_INFO info;
71e593
+
71e593
+    rv = module->C_WaitForSlotEvent(wait_flags, slot_id, NULL);
71e593
+    if (rv != CKR_OK) {
71e593
+        if (rv != CKR_FUNCTION_NOT_SUPPORTED) {
71e593
+            DEBUG(SSSDBG_OP_FAILURE,
71e593
+                  "C_WaitForSlotEvent failed [%lu][%s].\n",
71e593
+                  rv, p11_kit_strerror(rv));
71e593
+            return EIO;
71e593
+        }
71e593
+
71e593
+        /* Poor man's wait */
71e593
+        do {
71e593
+            sleep(10);
71e593
+            rv = module->C_GetSlotInfo(*slot_id, &info;;
71e593
+            if (rv != CKR_OK) {
71e593
+                DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotInfo failed\n");
71e593
+                return EIO;
71e593
+            }
71e593
+            DEBUG(SSSDBG_TRACE_ALL,
71e593
+                  "Description [%s] Manufacturer [%s] flags [%lu] "
71e593
+                  "removable [%s] token present [%s].\n",
71e593
+                  info.slotDescription, info.manufacturerID, info.flags,
71e593
+                  (info.flags & CKF_REMOVABLE_DEVICE) ? "true": "false",
71e593
+                  (info.flags & CKF_TOKEN_PRESENT) ? "true": "false");
71e593
+            if ((info.flags & CKF_REMOVABLE_DEVICE)
71e593
+                    && (info.flags & CKF_TOKEN_PRESENT)) {
71e593
+                break;
71e593
+            }
71e593
+        } while (true);
71e593
+    }
71e593
+
71e593
+    return EOK;
71e593
+}
71e593
+
71e593
 #define MAX_SLOTS 64
71e593
 
71e593
 errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
71e593
@@ -588,39 +630,62 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
71e593
         return EIO;
71e593
     }
71e593
 
71e593
-    DEBUG(SSSDBG_TRACE_ALL, "Module List:\n");
71e593
-    for (c = 0; modules[c] != NULL; c++) {
71e593
-        mod_name = p11_kit_module_get_name(modules[c]);
71e593
-        mod_file_name = p11_kit_module_get_filename(modules[c]);
71e593
-        DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n", mod_name);
71e593
-        DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n", mod_file_name);
71e593
-        free(mod_name);
71e593
-        free(mod_file_name);
71e593
+    for (;;) {
71e593
+        DEBUG(SSSDBG_TRACE_ALL, "Module List:\n");
71e593
+        for (c = 0; modules[c] != NULL; c++) {
71e593
+            mod_name = p11_kit_module_get_name(modules[c]);
71e593
+            mod_file_name = p11_kit_module_get_filename(modules[c]);
71e593
+            DEBUG(SSSDBG_TRACE_ALL, "common name: [%s].\n", mod_name);
71e593
+            DEBUG(SSSDBG_TRACE_ALL, "dll name: [%s].\n", mod_file_name);
71e593
+            free(mod_name);
71e593
+            free(mod_file_name);
71e593
 
71e593
-        num_slots = MAX_SLOTS;
71e593
-        rv = modules[c]->C_GetSlotList(CK_TRUE, slots, &num_slots);
71e593
-        if (rv != CKR_OK) {
71e593
-            DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotList failed.\n");
71e593
-            ret = EIO;
71e593
-            goto done;
71e593
-        }
71e593
-
71e593
-        for (s = 0; s < num_slots; s++) {
71e593
-            rv = modules[c]->C_GetSlotInfo(slots[s], &info;;
71e593
+            num_slots = MAX_SLOTS;
71e593
+            rv = modules[c]->C_GetSlotList(CK_FALSE, slots, &num_slots);
71e593
             if (rv != CKR_OK) {
71e593
-                DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotInfo failed\n");
71e593
+                DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotList failed.\n");
71e593
                 ret = EIO;
71e593
                 goto done;
71e593
             }
71e593
-            DEBUG(SSSDBG_TRACE_ALL,
71e593
-                  "Description [%s] Manufacturer [%s] flags [%lu] removable [%s].\n",
71e593
-                  info.slotDescription, info.manufacturerID, info.flags,
71e593
-                  (info.flags & CKF_REMOVABLE_DEVICE) ? "true": "false");
71e593
-            if ((info.flags & CKF_REMOVABLE_DEVICE)) {
71e593
+
71e593
+            for (s = 0; s < num_slots; s++) {
71e593
+                rv = modules[c]->C_GetSlotInfo(slots[s], &info;;
71e593
+                if (rv != CKR_OK) {
71e593
+                    DEBUG(SSSDBG_OP_FAILURE, "C_GetSlotInfo failed\n");
71e593
+                    ret = EIO;
71e593
+                    goto done;
71e593
+                }
71e593
+                DEBUG(SSSDBG_TRACE_ALL,
71e593
+                      "Description [%s] Manufacturer [%s] flags [%lu] "
71e593
+                      "removable [%s] token present [%s].\n",
71e593
+                      info.slotDescription, info.manufacturerID, info.flags,
71e593
+                      (info.flags & CKF_REMOVABLE_DEVICE) ? "true": "false",
71e593
+                      (info.flags & CKF_TOKEN_PRESENT) ? "true": "false");
71e593
+                if ((info.flags & CKF_REMOVABLE_DEVICE)) {
71e593
+                    break;
71e593
+                }
71e593
+            }
71e593
+            if (s != num_slots) {
71e593
                 break;
71e593
             }
71e593
         }
71e593
-        if (s != num_slots) {
71e593
+
71e593
+        /* When e.g. using Yubikeys the slot isn't present until the device is
71e593
+         * inserted, so we should wait for a slot as well. */
71e593
+        if (p11_ctx->wait_for_card && modules[c] == NULL) {
71e593
+            p11_kit_modules_finalize_and_release(modules);
71e593
+
71e593
+            sleep(PKCS11_FINIALIZE_INITIALIZE_WAIT_TIME);
71e593
+
71e593
+            modules = p11_kit_modules_load_and_initialize(0);
71e593
+            if (modules == NULL) {
71e593
+                DEBUG(SSSDBG_OP_FAILURE,
71e593
+                      "p11_kit_modules_load_and_initialize failed.\n");
71e593
+                ret = EIO;
71e593
+                goto done;
71e593
+            }
71e593
+
71e593
+        } else {
71e593
             break;
71e593
         }
71e593
     }
71e593
@@ -631,14 +696,29 @@ errno_t do_card(TALLOC_CTX *mem_ctx, struct p11_ctx *p11_ctx,
71e593
         goto done;
71e593
     }
71e593
 
71e593
-    rv = modules[c]->C_GetTokenInfo(slots[s], &token_info);
71e593
-    if (rv != CKR_OK) {
71e593
-        DEBUG(SSSDBG_OP_FAILURE, "C_GetTokenInfo failed.\n");
71e593
-        ret = EIO;
71e593
-        goto done;
71e593
-    }
71e593
-
71e593
     slot_id = slots[s];
71e593
+
71e593
+    if (!(info.flags & CKF_TOKEN_PRESENT)) {
71e593
+        DEBUG(SSSDBG_TRACE_ALL, "Token not present.\n");
71e593
+        if (p11_ctx->wait_for_card) {
71e593
+            ret = wait_for_card(modules[c], &slot_id);
71e593
+            if (ret != EOK) {
71e593
+                DEBUG(SSSDBG_OP_FAILURE, "wait_for_card failed.\n");
71e593
+                goto done;
71e593
+            }
71e593
+        } else {
71e593
+            ret = EIO;
71e593
+            goto done;
71e593
+        }
71e593
+    }
71e593
+
71e593
+    rv = modules[c]->C_GetTokenInfo(slot_id, &token_info);
71e593
+    if (rv != CKR_OK) {
71e593
+        DEBUG(SSSDBG_OP_FAILURE, "C_GetTokenInfo failed.\n");
71e593
+        ret = EIO;
71e593
+        goto done;
71e593
+    }
71e593
+
71e593
     module_id = c;
71e593
     slot_name = p11_kit_space_strdup(info.slotDescription,
71e593
                                      sizeof(info.slotDescription));
71e593
-- 
71e593
2.14.4
71e593