1dedfbb334
Resolves: upstream#3588 - sssd_nss consumes more memory until restarted or machine swaps Resolves: failure in glibc tests https://sourceware.org/bugzilla/show_bug.cgi?id=22530 Resolves: upstream#3451 - When sssd is configured with id_provider proxy and auth_provider ldap, login fails if the LDAP server is not allowing anonymous binds Resolves: upstream#3285 - SSSD needs restart after incorrect clock is corrected with AD Resolves: upstream#3586 - Give a more detailed debug and system-log message if krb5_init_context() failed Resolves: rhbz#1431153 - SSSD ships a drop-in configuration snippet in /etc/systemd/system Backport few upstream features from 1.16.1
680 lines
21 KiB
Diff
680 lines
21 KiB
Diff
From 55deead9f2a98c3ba1fd5754bd38203b6c02b6a1 Mon Sep 17 00:00:00 2001
|
||
From: Sumit Bose <sbose@redhat.com>
|
||
Date: Mon, 16 Oct 2017 14:13:10 +0200
|
||
Subject: [PATCH 44/79] pam_sss: refactoring, use struct cert_auth_info
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
Similar as in the PAM responder this patch replaces the individual
|
||
certificate authentication related attributes by a struct which can be
|
||
used as a list. With the pam_sss can handle multiple SSS_PAM_CERT_INFO
|
||
message and place the data in individual list items.
|
||
|
||
If multiple certificates are returned before prompting for the PIN a
|
||
dialog to select a certificate is shown to the users. If available a GDM
|
||
PAM extension is used to let the user choose from a list. All coded
|
||
needed at runtime to check if the extension is available and handle the
|
||
data is provided by GDM as macros. This means that there are no
|
||
additional run-time requirements.
|
||
|
||
Related to https://pagure.io/SSSD/sssd/issue/3560
|
||
|
||
Reviewed-by: Fabiano Fidêncio <fidencio@redhat.com>
|
||
Tested-by: Scott Poore <spoore@redhat.com>
|
||
---
|
||
contrib/sssd.spec.in | 9 +
|
||
src/external/pam.m4 | 12 ++
|
||
src/sss_client/pam_message.h | 8 +-
|
||
src/sss_client/pam_sss.c | 439 ++++++++++++++++++++++++++++++++++---------
|
||
4 files changed, 370 insertions(+), 98 deletions(-)
|
||
|
||
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
|
||
index 4aafd1832b67161ff1c25a4e9ad689586a227a25..c716efdce05ab7b9178be66f34d09124c78071b5 100644
|
||
--- a/contrib/sssd.spec.in
|
||
+++ b/contrib/sssd.spec.in
|
||
@@ -121,6 +121,12 @@
|
||
%global with_kcm_option --without-kcm
|
||
%endif
|
||
|
||
+%if (0%{?fedora} >= 27 || (0%{?rhel} >= 7 && 0%{?rhel7_minor} > 4))
|
||
+ %global with_gdm_pam_extensions 1
|
||
+%else
|
||
+ %global with_gdm_pam_extensions 0
|
||
+%endif
|
||
+
|
||
Name: @PACKAGE_NAME@
|
||
Version: @PACKAGE_VERSION@
|
||
Release: 0@PRERELEASE_VERSION@%{?dist}
|
||
@@ -233,6 +239,9 @@ BuildRequires: libuuid-devel
|
||
BuildRequires: jansson-devel
|
||
BuildRequires: libcurl-devel
|
||
%endif
|
||
+%if (0%{?with_gdm_pam_extensions} == 1)
|
||
+BuildRequires: gdm-devel
|
||
+%endif
|
||
|
||
%description
|
||
Provides a set of daemons to manage access to remote directories and
|
||
diff --git a/src/external/pam.m4 b/src/external/pam.m4
|
||
index 4776b6ae338409f0a2729dfc4cf5962463a40dfd..0dc7f19d0df6a4588cf893ecff6e518111462433 100644
|
||
--- a/src/external/pam.m4
|
||
+++ b/src/external/pam.m4
|
||
@@ -27,3 +27,15 @@ AC_CHECK_FUNCS(pam_modutil_getlogin pam_vsyslog)
|
||
|
||
dnl restore LIBS
|
||
LIBS="$save_LIBS"
|
||
+
|
||
+PKG_CHECK_MODULES([GDM_PAM_EXTENSIONS], [gdm-pam-extensions],
|
||
+ [found_gdm_pam_extensions=yes],
|
||
+ [AC_MSG_NOTICE([gdm-pam-extensions were not found. gdm support
|
||
+for multiple certificates will not be build.
|
||
+])])
|
||
+
|
||
+AC_SUBST(GDM_PAM_EXTENSIONS_CFLAGS)
|
||
+
|
||
+AS_IF([test x"$found_gdm_pam_extensions" = xyes],
|
||
+ [AC_DEFINE_UNQUOTED(HAVE_GDM_PAM_EXTENSIONS, 1,
|
||
+ [Build with gdm-pam-extensions support])])
|
||
diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h
|
||
index f215392f6879f01a0ca12abc8807bac5fc1f1cbb..11526a80a767ff5602b194d14765ff261e8f9707 100644
|
||
--- a/src/sss_client/pam_message.h
|
||
+++ b/src/sss_client/pam_message.h
|
||
@@ -29,6 +29,8 @@
|
||
|
||
#include "sss_client/sss_cli.h"
|
||
|
||
+struct cert_auth_info;
|
||
+
|
||
struct pam_items {
|
||
const char *pam_service;
|
||
const char *pam_user;
|
||
@@ -59,11 +61,9 @@ struct pam_items {
|
||
char *first_factor;
|
||
bool password_prompting;
|
||
|
||
- char *cert_user;
|
||
- char *token_name;
|
||
- char *module_name;
|
||
- char *key_id;
|
||
bool user_name_hint;
|
||
+ struct cert_auth_info *cert_list;
|
||
+ struct cert_auth_info *selected_cert;
|
||
};
|
||
|
||
int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer);
|
||
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
|
||
index 303809b9ea05b5a8709c05ae230d5f289b57de31..c147d4b3d76443d69e27eb2da042f8eebd1ae6ab 100644
|
||
--- a/src/sss_client/pam_sss.c
|
||
+++ b/src/sss_client/pam_sss.c
|
||
@@ -36,6 +36,10 @@
|
||
#include <security/pam_modules.h>
|
||
#include <security/pam_appl.h>
|
||
|
||
+#ifdef HAVE_GDM_PAM_EXTENSIONS
|
||
+#include <gdm/gdm-pam-extensions.h>
|
||
+#endif
|
||
+
|
||
#include "sss_pam_compat.h"
|
||
#include "sss_pam_macros.h"
|
||
|
||
@@ -43,6 +47,7 @@
|
||
#include "pam_message.h"
|
||
#include "util/atomic_io.h"
|
||
#include "util/authtok-utils.h"
|
||
+#include "util/dlinklist.h"
|
||
|
||
#include <libintl.h>
|
||
#define _(STRING) dgettext (PACKAGE, STRING)
|
||
@@ -118,6 +123,40 @@ static void close_fd(pam_handle_t *pamh, void *ptr, int err)
|
||
sss_pam_close_fd();
|
||
}
|
||
|
||
+struct cert_auth_info {
|
||
+ char *cert_user;
|
||
+ char *cert;
|
||
+ char *token_name;
|
||
+ char *module_name;
|
||
+ char *key_id;
|
||
+ struct cert_auth_info *prev;
|
||
+ struct cert_auth_info *next;
|
||
+};
|
||
+
|
||
+static void free_cai(struct cert_auth_info *cai)
|
||
+{
|
||
+ if (cai != NULL) {
|
||
+ free(cai->cert_user);
|
||
+ free(cai->cert);
|
||
+ free(cai->token_name);
|
||
+ free(cai->key_id);
|
||
+ free(cai);
|
||
+ }
|
||
+}
|
||
+
|
||
+static void free_cert_list(struct cert_auth_info *list)
|
||
+{
|
||
+ struct cert_auth_info *cai;
|
||
+ struct cert_auth_info *cai_next;
|
||
+
|
||
+ if (list != NULL) {
|
||
+ DLIST_FOR_EACH_SAFE(cai, cai_next, list) {
|
||
+ DLIST_REMOVE(list, cai);
|
||
+ free_cai(cai);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
static void overwrite_and_free_authtoks(struct pam_items *pi)
|
||
{
|
||
if (pi->pam_authtok != NULL) {
|
||
@@ -158,17 +197,9 @@ static void overwrite_and_free_pam_items(struct pam_items *pi)
|
||
free(pi->otp_challenge);
|
||
pi->otp_challenge = NULL;
|
||
|
||
- free(pi->cert_user);
|
||
- pi->cert_user = NULL;
|
||
-
|
||
- free(pi->token_name);
|
||
- pi->token_name = NULL;
|
||
-
|
||
- free(pi->module_name);
|
||
- pi->module_name = NULL;
|
||
-
|
||
- free(pi->key_id);
|
||
- pi->key_id = NULL;
|
||
+ free_cert_list(pi->cert_list);
|
||
+ pi->cert_list = NULL;
|
||
+ pi->selected_cert = NULL;
|
||
}
|
||
|
||
static int null_strcmp(const char *s1, const char *s2) {
|
||
@@ -821,6 +852,90 @@ static int eval_user_info_response(pam_handle_t *pamh, size_t buflen,
|
||
return ret;
|
||
}
|
||
|
||
+static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len,
|
||
+ size_t *p, const char **cert_user)
|
||
+{
|
||
+ struct cert_auth_info *cai = NULL;
|
||
+ size_t offset;
|
||
+ int ret;
|
||
+
|
||
+ if (buf[*p + (len - 1)] != '\0') {
|
||
+ D(("cert info does not end with \\0."));
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ cai = calloc(1, sizeof(struct cert_auth_info));
|
||
+ if (cai == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ cai->cert_user = strdup((char *) &buf[*p]);
|
||
+ if (cai->cert_user == NULL) {
|
||
+ D(("strdup failed"));
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ if (cert_user != NULL) {
|
||
+ *cert_user = cai->cert_user;
|
||
+ }
|
||
+
|
||
+ offset = strlen(cai->cert_user) + 1;
|
||
+ if (offset >= len) {
|
||
+ D(("Cert message size mismatch"));
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ cai->token_name = strdup((char *) &buf[*p + offset]);
|
||
+ if (cai->token_name == NULL) {
|
||
+ D(("strdup failed"));
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ offset += strlen(cai->token_name) + 1;
|
||
+ if (offset >= len) {
|
||
+ D(("Cert message size mismatch"));
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ cai->module_name = strdup((char *) &buf[*p + offset]);
|
||
+ if (cai->module_name == NULL) {
|
||
+ D(("strdup failed"));
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ offset += strlen(cai->module_name) + 1;
|
||
+ if (offset >= len) {
|
||
+ D(("Cert message size mismatch"));
|
||
+ ret = EINVAL;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ cai->key_id = strdup((char *) &buf[*p + offset]);
|
||
+ if (cai->key_id == NULL) {
|
||
+ D(("strdup failed"));
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]",
|
||
+ cai->cert_user, cai->token_name, cai->module_name,
|
||
+ cai->key_id));
|
||
+
|
||
+ DLIST_ADD(pi->cert_list, cai);
|
||
+ ret = 0;
|
||
+
|
||
+done:
|
||
+ if (ret != 0) {
|
||
+ free_cai(cai);
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
|
||
struct pam_items *pi)
|
||
{
|
||
@@ -832,6 +947,7 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
|
||
int32_t len;
|
||
int32_t pam_status;
|
||
size_t offset;
|
||
+ const char *cert_user;
|
||
|
||
if (buflen < (2*sizeof(int32_t))) {
|
||
D(("response buffer is too small"));
|
||
@@ -988,27 +1104,21 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
|
||
break;
|
||
}
|
||
|
||
- free(pi->cert_user);
|
||
- pi->cert_user = strdup((char *) &buf[p]);
|
||
- if (pi->cert_user == NULL) {
|
||
- D(("strdup failed"));
|
||
- break;
|
||
- }
|
||
-
|
||
- if (type == SSS_PAM_CERT_INFO && *pi->cert_user == '\0') {
|
||
- D(("Invalid CERT message"));
|
||
- break;
|
||
- }
|
||
-
|
||
if (type == SSS_PAM_CERT_INFO_WITH_HINT) {
|
||
pi->user_name_hint = true;
|
||
} else {
|
||
pi->user_name_hint = false;
|
||
}
|
||
|
||
+ ret = parse_cert_info(pi, buf, len, &p, &cert_user);
|
||
+ if (ret != 0) {
|
||
+ D(("Failed to parse cert info"));
|
||
+ break;
|
||
+ }
|
||
+
|
||
if ((pi->pam_user == NULL || *(pi->pam_user) == '\0')
|
||
- && *pi->cert_user != '\0') {
|
||
- ret = pam_set_item(pamh, PAM_USER, pi->cert_user);
|
||
+ && *cert_user != '\0') {
|
||
+ ret = pam_set_item(pamh, PAM_USER, cert_user);
|
||
if (ret != PAM_SUCCESS) {
|
||
D(("Failed to set PAM_USER during "
|
||
"Smartcard authentication [%s]",
|
||
@@ -1027,59 +1137,6 @@ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,
|
||
|
||
pi->pam_user_size = strlen(pi->pam_user) + 1;
|
||
}
|
||
-
|
||
- offset = strlen(pi->cert_user) + 1;
|
||
- if (offset >= len) {
|
||
- D(("Cert message size mismatch"));
|
||
- free(pi->cert_user);
|
||
- pi->cert_user = NULL;
|
||
- break;
|
||
- }
|
||
- free(pi->token_name);
|
||
- pi->token_name = strdup((char *) &buf[p + offset]);
|
||
- if (pi->token_name == NULL) {
|
||
- D(("strdup failed"));
|
||
- free(pi->cert_user);
|
||
- pi->cert_user = NULL;
|
||
- break;
|
||
- }
|
||
-
|
||
- offset += strlen(pi->token_name) + 1;
|
||
- if (offset >= len) {
|
||
- D(("Cert message size mismatch"));
|
||
- free(pi->cert_user);
|
||
- pi->cert_user = NULL;
|
||
- free(pi->token_name);
|
||
- pi->token_name = NULL;
|
||
- break;
|
||
- }
|
||
- free(pi->module_name);
|
||
- pi->module_name = strdup((char *) &buf[p + offset]);
|
||
- if (pi->module_name == NULL) {
|
||
- D(("strdup failed"));
|
||
- break;
|
||
- }
|
||
-
|
||
- offset += strlen(pi->module_name) + 1;
|
||
- if (offset >= len) {
|
||
- D(("Cert message size mismatch"));
|
||
- free(pi->cert_user);
|
||
- pi->cert_user = NULL;
|
||
- free(pi->token_name);
|
||
- pi->token_name = NULL;
|
||
- free(pi->module_name);
|
||
- pi->module_name = NULL;
|
||
- break;
|
||
- }
|
||
- free(pi->key_id);
|
||
- pi->key_id = strdup((char *) &buf[p + offset]);
|
||
- if (pi->key_id == NULL) {
|
||
- D(("strdup failed"));
|
||
- break;
|
||
- }
|
||
- D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]",
|
||
- pi->cert_user, pi->token_name, pi->module_name,
|
||
- pi->key_id));
|
||
break;
|
||
case SSS_PASSWORD_PROMPTING:
|
||
D(("Password prompting available."));
|
||
@@ -1175,10 +1232,8 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags,
|
||
pi->otp_challenge = NULL;
|
||
pi->password_prompting = false;
|
||
|
||
- pi->cert_user = NULL;
|
||
- pi->token_name = NULL;
|
||
- pi->module_name = NULL;
|
||
- pi->key_id = NULL;
|
||
+ pi->cert_list = NULL;
|
||
+ pi->selected_cert = NULL;
|
||
|
||
return PAM_SUCCESS;
|
||
}
|
||
@@ -1484,6 +1539,184 @@ done:
|
||
|
||
#define SC_PROMPT_FMT "PIN for %s"
|
||
|
||
+#ifndef discard_const
|
||
+#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
|
||
+#endif
|
||
+
|
||
+#define CERT_SEL_PROMPT_FMT "Certificate: %s"
|
||
+#define SEL_TITLE discard_const("Please select a certificate")
|
||
+
|
||
+static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi)
|
||
+{
|
||
+#ifdef HAVE_GDM_PAM_EXTENSIONS
|
||
+ int ret;
|
||
+ size_t cert_count = 0;
|
||
+ size_t c;
|
||
+ const struct pam_conv *conv;
|
||
+ struct cert_auth_info *cai;
|
||
+ GdmPamExtensionChoiceListRequest *request = NULL;
|
||
+ GdmPamExtensionChoiceListResponse *response = NULL;
|
||
+ struct pam_message prompt_message;
|
||
+ const struct pam_message *prompt_messages[1];
|
||
+ struct pam_response *reply = NULL;
|
||
+ char *prompt;
|
||
+
|
||
+ if (!GDM_PAM_EXTENSION_SUPPORTED(GDM_PAM_EXTENSION_CHOICE_LIST)) {
|
||
+ return ENOTSUP;
|
||
+ }
|
||
+
|
||
+ if (pi->cert_list == NULL) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ DLIST_FOR_EACH(cai, pi->cert_list) {
|
||
+ cert_count++;
|
||
+ }
|
||
+
|
||
+ ret = pam_get_item(pamh, PAM_CONV, (const void **)&conv);
|
||
+ if (ret != PAM_SUCCESS) {
|
||
+ ret = EIO;
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ request = calloc(1, GDM_PAM_EXTENSION_CHOICE_LIST_REQUEST_SIZE(cert_count));
|
||
+ if (request == NULL) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ GDM_PAM_EXTENSION_CHOICE_LIST_REQUEST_INIT(request, SEL_TITLE, cert_count);
|
||
+
|
||
+ c = 0;
|
||
+ DLIST_FOR_EACH(cai, pi->cert_list) {
|
||
+ ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->key_id);
|
||
+ if (ret == -1) {
|
||
+ ret = ENOMEM;
|
||
+ goto done;
|
||
+ }
|
||
+ request->list.items[c].key = cai->key_id;
|
||
+ request->list.items[c++].text = prompt;
|
||
+ }
|
||
+
|
||
+ GDM_PAM_EXTENSION_MESSAGE_TO_BINARY_PROMPT_MESSAGE(request,
|
||
+ &prompt_message);
|
||
+ prompt_messages[0] = &prompt_message;
|
||
+
|
||
+ ret = conv->conv(1, prompt_messages, &reply, conv->appdata_ptr);
|
||
+ if (ret != PAM_SUCCESS) {
|
||
+ ret = EIO;
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ ret = EIO;
|
||
+ response = GDM_PAM_EXTENSION_REPLY_TO_CHOICE_LIST_RESPONSE(reply);
|
||
+ if (response->key == NULL) {
|
||
+ goto done;
|
||
+ }
|
||
+
|
||
+ DLIST_FOR_EACH(cai, pi->cert_list) {
|
||
+ if (strcmp(response->key, cai->key_id) == 0) {
|
||
+ pam_info(pamh, "Certificate ‘%s’ selected", cai->key_id);
|
||
+ pi->selected_cert = cai;
|
||
+ ret = 0;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+
|
||
+done:
|
||
+ if (request != NULL) {
|
||
+ for (c = 0; c < cert_count; c++) {
|
||
+ free(discard_const(request->list.items[c++].text));
|
||
+ }
|
||
+ free(request);
|
||
+ }
|
||
+ free(response);
|
||
+
|
||
+ return ret;
|
||
+#else
|
||
+ return ENOTSUP;
|
||
+#endif
|
||
+}
|
||
+
|
||
+#define TEXT_CERT_SEL_PROMPT_FMT "%s[%zu] Certificate: %s\n"
|
||
+#define TEXT_SEL_TITLE discard_const("Please select a certificate by typing " \
|
||
+ "the corresponding number\n")
|
||
+static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi)
|
||
+{
|
||
+ int ret;
|
||
+ size_t cert_count = 0;
|
||
+ size_t tries = 0;
|
||
+ long int resp = -1;
|
||
+ struct cert_auth_info *cai;
|
||
+ char *prompt;
|
||
+ char *tmp;
|
||
+ char *answer;
|
||
+ char *ep;
|
||
+
|
||
+ /* First check if gdm extension is supported */
|
||
+ ret = prompt_multi_cert_gdm(pamh, pi);
|
||
+ if (ret != ENOTSUP) {
|
||
+ return ret;
|
||
+ }
|
||
+
|
||
+ if (pi->cert_list == NULL) {
|
||
+ return EINVAL;
|
||
+ }
|
||
+
|
||
+ prompt = strdup(TEXT_SEL_TITLE);
|
||
+ if (prompt == NULL) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ DLIST_FOR_EACH(cai, pi->cert_list) {
|
||
+ cert_count++;
|
||
+ ret = asprintf(&tmp, TEXT_CERT_SEL_PROMPT_FMT, prompt, cert_count,
|
||
+ cai->key_id);
|
||
+ free(prompt);
|
||
+ if (ret == -1) {
|
||
+ return ENOMEM;
|
||
+ }
|
||
+
|
||
+ prompt = tmp;
|
||
+ }
|
||
+
|
||
+ do {
|
||
+ ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_ON, prompt, NULL,
|
||
+ &answer);
|
||
+ if (ret != PAM_SUCCESS) {
|
||
+ D(("do_pam_conversation failed."));
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ errno = 0;
|
||
+ resp = strtol(answer, &ep, 10);
|
||
+ if (errno == 0 && *ep == '\0' && resp > 0 && resp <= cert_count) {
|
||
+ /* do not free answer ealier because ep is pointing to it */
|
||
+ free(answer);
|
||
+ break;
|
||
+ }
|
||
+ free(answer);
|
||
+ resp = -1;
|
||
+ } while (++tries < 5);
|
||
+ free(prompt);
|
||
+
|
||
+ pi->selected_cert = NULL;
|
||
+ ret = ENOENT;
|
||
+ if (resp > 0 && resp <= cert_count) {
|
||
+ cert_count = 0;
|
||
+ DLIST_FOR_EACH(cai, pi->cert_list) {
|
||
+ cert_count++;
|
||
+ if (resp == cert_count) {
|
||
+ pam_info(pamh, "Certificate ‘%s’ selected", cai->key_id);
|
||
+ pi->selected_cert = cai;
|
||
+ ret = 0;
|
||
+ break;
|
||
+ }
|
||
+ }
|
||
+ }
|
||
+
|
||
+ return ret;
|
||
+}
|
||
+
|
||
static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
|
||
{
|
||
int ret;
|
||
@@ -1495,19 +1728,20 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
|
||
const struct pam_message *mesg[2] = { NULL, NULL };
|
||
struct pam_message m[2] = { { 0 }, { 0 } };
|
||
struct pam_response *resp = NULL;
|
||
+ struct cert_auth_info *cai = pi->selected_cert;
|
||
|
||
- if (pi->token_name == NULL || *pi->token_name == '\0') {
|
||
+ if (cai == NULL || cai->token_name == NULL || *cai->token_name == '\0') {
|
||
return EINVAL;
|
||
}
|
||
|
||
- size = sizeof(SC_PROMPT_FMT) + strlen(pi->token_name);
|
||
+ size = sizeof(SC_PROMPT_FMT) + strlen(cai->token_name);
|
||
prompt = malloc(size);
|
||
if (prompt == NULL) {
|
||
D(("malloc failed."));
|
||
return ENOMEM;
|
||
}
|
||
|
||
- ret = snprintf(prompt, size, SC_PROMPT_FMT, pi->token_name);
|
||
+ ret = snprintf(prompt, size, SC_PROMPT_FMT, cai->token_name);
|
||
if (ret < 0 || ret >= size) {
|
||
D(("snprintf failed."));
|
||
free(prompt);
|
||
@@ -1604,9 +1838,9 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
|
||
pi->pam_authtok_size=0;
|
||
} else {
|
||
|
||
- ret = sss_auth_pack_sc_blob(answer, 0, pi->token_name, 0,
|
||
- pi->module_name, 0,
|
||
- pi->key_id, 0,
|
||
+ ret = sss_auth_pack_sc_blob(answer, 0, cai->token_name, 0,
|
||
+ cai->module_name, 0,
|
||
+ cai->key_id, 0,
|
||
NULL, 0, &needed_size);
|
||
if (ret != EAGAIN) {
|
||
D(("sss_auth_pack_sc_blob failed."));
|
||
@@ -1621,9 +1855,9 @@ static int prompt_sc_pin(pam_handle_t *pamh, struct pam_items *pi)
|
||
goto done;
|
||
}
|
||
|
||
- ret = sss_auth_pack_sc_blob(answer, 0, pi->token_name, 0,
|
||
- pi->module_name, 0,
|
||
- pi->key_id, 0,
|
||
+ ret = sss_auth_pack_sc_blob(answer, 0, cai->token_name, 0,
|
||
+ cai->module_name, 0,
|
||
+ cai->key_id, 0,
|
||
(uint8_t *) pi->pam_authtok, needed_size,
|
||
&needed_size);
|
||
if (ret != EOK) {
|
||
@@ -1786,7 +2020,17 @@ static int get_authtok_for_authentication(pam_handle_t *pamh,
|
||
ret = prompt_2fa(pamh, pi, _("First Factor: "),
|
||
_("Second Factor: "));
|
||
}
|
||
- } else if (pi->token_name != NULL && *(pi->token_name) != '\0') {
|
||
+ } else if (pi->cert_list != NULL) {
|
||
+ if (pi->cert_list->next == NULL) {
|
||
+ /* Only one certificate */
|
||
+ pi->selected_cert = pi->cert_list;
|
||
+ } else {
|
||
+ ret = prompt_multi_cert(pamh, pi);
|
||
+ if (ret != 0) {
|
||
+ D(("Failed to select certificate"));
|
||
+ return PAM_AUTHTOK_ERR;
|
||
+ }
|
||
+ }
|
||
ret = prompt_sc_pin(pamh, pi);
|
||
} else {
|
||
ret = prompt_password(pamh, pi, _("Password: "));
|
||
@@ -1905,14 +2149,21 @@ static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi,
|
||
char *prompt = NULL;
|
||
size_t size;
|
||
char *answer = NULL;
|
||
+ /* TODO: check multiple cert case */
|
||
+ struct cert_auth_info *cai = pi->cert_list;
|
||
+
|
||
+ if (cai == NULL) {
|
||
+ D(("No certificate information available"));
|
||
+ return EINVAL;
|
||
+ }
|
||
|
||
login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");
|
||
if (login_token_name == NULL) {
|
||
return PAM_SUCCESS;
|
||
}
|
||
|
||
- while (pi->token_name == NULL
|
||
- || strcmp(login_token_name, pi->token_name) != 0) {
|
||
+ while (cai->token_name == NULL
|
||
+ || strcmp(login_token_name, cai->token_name) != 0) {
|
||
size = sizeof(SC_ENTER_FMT) + strlen(login_token_name);
|
||
prompt = malloc(size);
|
||
if (prompt == NULL) {
|
||
--
|
||
2.15.1
|
||
|