371 lines
14 KiB
Diff
371 lines
14 KiB
Diff
|
From 49be8974b490c368d349752f3196af0c9ed28dd5 Mon Sep 17 00:00:00 2001
|
||
|
From: Sumit Bose <sbose@redhat.com>
|
||
|
Date: Tue, 18 Sep 2018 09:53:37 +0200
|
||
|
Subject: [PATCH 63/83] pam_sss: add option require_cert_auth
|
||
|
|
||
|
With this new option pam_sss will wait until a Smartcard is available
|
||
|
and then try to authenticate with the help of the Smartcard.
|
||
|
|
||
|
Related https://pagure.io/SSSD/sssd/issue/3650
|
||
|
|
||
|
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
|
||
|
---
|
||
|
src/man/pam_sss.8.xml | 25 ++++++++++++
|
||
|
src/responder/pam/pamsrv_cmd.c | 12 ++++++
|
||
|
src/responder/pam/pamsrv_p11.c | 5 ++-
|
||
|
src/sss_client/pam_message.c | 4 ++
|
||
|
src/sss_client/pam_message.h | 1 +
|
||
|
src/sss_client/pam_sss.c | 90 ++++++++++++++++++++++++++----------------
|
||
|
src/sss_client/sss_cli.h | 2 +
|
||
|
src/util/sss_pam_data.c | 1 +
|
||
|
src/util/sss_pam_data.h | 1 +
|
||
|
9 files changed, 106 insertions(+), 35 deletions(-)
|
||
|
|
||
|
diff --git a/src/man/pam_sss.8.xml b/src/man/pam_sss.8.xml
|
||
|
index ca2e8e2..9998519 100644
|
||
|
--- a/src/man/pam_sss.8.xml
|
||
|
+++ b/src/man/pam_sss.8.xml
|
||
|
@@ -53,6 +53,9 @@
|
||
|
<arg choice='opt'>
|
||
|
<replaceable>try_cert_auth</replaceable>
|
||
|
</arg>
|
||
|
+ <arg choice='opt'>
|
||
|
+ <replaceable>require_cert_auth</replaceable>
|
||
|
+ </arg>
|
||
|
</cmdsynopsis>
|
||
|
</refsynopsisdiv>
|
||
|
|
||
|
@@ -223,6 +226,28 @@ auth sufficient pam_sss.so allow_missing_name
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
+ <varlistentry>
|
||
|
+ <term>
|
||
|
+ <option>require_cert_auth</option>
|
||
|
+ </term>
|
||
|
+ <listitem>
|
||
|
+ <para>
|
||
|
+ Do certificate based authentication, i.e.
|
||
|
+ authentication with a Smartcard or similar devices. If a
|
||
|
+ Smartcard is not available the user will be prompted to
|
||
|
+ insert one. SSSD will wait for a Smartcard until the
|
||
|
+ timeout defined by p11_wait_for_card_timeout passed,
|
||
|
+ please see
|
||
|
+ <citerefentry><refentrytitle>sssd.conf</refentrytitle>
|
||
|
+ <manvolnum>5</manvolnum></citerefentry> for details.
|
||
|
+ </para>
|
||
|
+ <para>
|
||
|
+ If no Smartcard is available after the timeout or
|
||
|
+ certificate based authentication is not allowed for the
|
||
|
+ current service PAM_AUTHINFO_UNAVAIL is returned.
|
||
|
+ </para>
|
||
|
+ </listitem>
|
||
|
+ </varlistentry>
|
||
|
</variablelist>
|
||
|
</refsect1>
|
||
|
|
||
|
diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c
|
||
|
index c8df32d..6e37f83 100644
|
||
|
--- a/src/responder/pam/pamsrv_cmd.c
|
||
|
+++ b/src/responder/pam/pamsrv_cmd.c
|
||
|
@@ -317,6 +317,11 @@ static int pam_parse_in_data_v2(struct pam_data *pd,
|
||
|
size, body, blen, &c);
|
||
|
if (ret != EOK) return ret;
|
||
|
break;
|
||
|
+ case SSS_PAM_ITEM_FLAGS:
|
||
|
+ ret = extract_uint32_t(&pd->cli_flags, size,
|
||
|
+ body, blen, &c);
|
||
|
+ if (ret != EOK) return ret;
|
||
|
+ break;
|
||
|
default:
|
||
|
DEBUG(SSSDBG_CRIT_FAILURE,
|
||
|
"Ignoring unknown data type [%d].\n", type);
|
||
|
@@ -1447,6 +1452,13 @@ static void pam_forwarder_cert_cb(struct tevent_req *req)
|
||
|
"No certificate found and no logon name given, " \
|
||
|
"authentication not possible.\n");
|
||
|
ret = ENOENT;
|
||
|
+ } else if (pd->cli_flags & PAM_CLI_FLAGS_TRY_CERT_AUTH) {
|
||
|
+ DEBUG(SSSDBG_TRACE_ALL,
|
||
|
+ "try_cert_auth flag set but no certificate available, "
|
||
|
+ "request finished.\n");
|
||
|
+ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
|
||
|
+ pam_reply(preq);
|
||
|
+ return;
|
||
|
} else {
|
||
|
if (pd->cmd == SSS_PAM_AUTHENTICATE) {
|
||
|
DEBUG(SSSDBG_CRIT_FAILURE,
|
||
|
diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c
|
||
|
index ffa6787..8b8859d 100644
|
||
|
--- a/src/responder/pam/pamsrv_p11.c
|
||
|
+++ b/src/responder/pam/pamsrv_p11.c
|
||
|
@@ -721,7 +721,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
|
||
|
struct timeval tv;
|
||
|
int pipefd_to_child[2] = PIPE_INIT;
|
||
|
int pipefd_from_child[2] = PIPE_INIT;
|
||
|
- const char *extra_args[13] = { NULL };
|
||
|
+ const char *extra_args[14] = { NULL };
|
||
|
uint8_t *write_buf = NULL;
|
||
|
size_t write_buf_len = 0;
|
||
|
size_t arg_c;
|
||
|
@@ -748,6 +748,9 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
|
||
|
|
||
|
/* extra_args are added in revers order */
|
||
|
arg_c = 0;
|
||
|
+ if ((pd->cli_flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH) && pd->priv == 1) {
|
||
|
+ extra_args[arg_c++] = "--wait_for_card";
|
||
|
+ }
|
||
|
extra_args[arg_c++] = nss_db;
|
||
|
extra_args[arg_c++] = "--nssdb";
|
||
|
if (verify_opts != NULL) {
|
||
|
diff --git a/src/sss_client/pam_message.c b/src/sss_client/pam_message.c
|
||
|
index b239f6f..036ae2a 100644
|
||
|
--- a/src/sss_client/pam_message.c
|
||
|
+++ b/src/sss_client/pam_message.c
|
||
|
@@ -126,6 +126,7 @@ int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer)
|
||
|
len += 3*sizeof(uint32_t); /* cli_pid */
|
||
|
len += *pi->requested_domains != '\0' ?
|
||
|
2*sizeof(uint32_t) + pi->requested_domains_size : 0;
|
||
|
+ len += 3*sizeof(uint32_t); /* flags */
|
||
|
|
||
|
buf = malloc(len);
|
||
|
if (buf == NULL) {
|
||
|
@@ -164,6 +165,9 @@ int pack_message_v3(struct pam_items *pi, size_t *size, uint8_t **buffer)
|
||
|
pi->pam_newauthtok, pi->pam_newauthtok_size,
|
||
|
&buf[rp]);
|
||
|
|
||
|
+ rp += add_uint32_t_item(SSS_PAM_ITEM_FLAGS, (uint32_t) pi->flags,
|
||
|
+ &buf[rp]);
|
||
|
+
|
||
|
SAFEALIGN_SETMEM_UINT32(buf + rp, SSS_END_OF_PAM_REQUEST, &rp);
|
||
|
|
||
|
if (rp != len) {
|
||
|
diff --git a/src/sss_client/pam_message.h b/src/sss_client/pam_message.h
|
||
|
index 11526a8..50fedcd 100644
|
||
|
--- a/src/sss_client/pam_message.h
|
||
|
+++ b/src/sss_client/pam_message.h
|
||
|
@@ -51,6 +51,7 @@ struct pam_items {
|
||
|
enum sss_authtok_type pam_newauthtok_type;
|
||
|
size_t pam_newauthtok_size;
|
||
|
pid_t cli_pid;
|
||
|
+ uint32_t flags;
|
||
|
const char *login_name;
|
||
|
char *domain_name;
|
||
|
const char *requested_domains;
|
||
|
diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c
|
||
|
index 96ff15a..b4c1036 100644
|
||
|
--- a/src/sss_client/pam_sss.c
|
||
|
+++ b/src/sss_client/pam_sss.c
|
||
|
@@ -134,6 +134,7 @@ static void free_cai(struct cert_auth_info *cai)
|
||
|
free(cai->cert_user);
|
||
|
free(cai->cert);
|
||
|
free(cai->token_name);
|
||
|
+ free(cai->module_name);
|
||
|
free(cai->key_id);
|
||
|
free(cai->prompt_str);
|
||
|
free(cai);
|
||
|
@@ -1247,6 +1248,8 @@ static int get_pam_items(pam_handle_t *pamh, uint32_t flags,
|
||
|
pi->cert_list = NULL;
|
||
|
pi->selected_cert = NULL;
|
||
|
|
||
|
+ pi->flags = flags;
|
||
|
+
|
||
|
return PAM_SUCCESS;
|
||
|
}
|
||
|
|
||
|
@@ -1267,6 +1270,7 @@ static void print_pam_items(struct pam_items *pi)
|
||
|
D(("Newauthtok: %s", CHECK_AND_RETURN_PI_STRING(pi->pam_newauthtok)));
|
||
|
D(("Cli_PID: %d", pi->cli_pid));
|
||
|
D(("Requested domains: %s", pi->requested_domains));
|
||
|
+ D(("Flags: %d", pi->flags));
|
||
|
}
|
||
|
|
||
|
static int send_and_receive(pam_handle_t *pamh, struct pam_items *pi,
|
||
|
@@ -1999,6 +2003,8 @@ static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,
|
||
|
*flags |= PAM_CLI_FLAGS_PROMPT_ALWAYS;
|
||
|
} else if (strcmp(*argv, "try_cert_auth") == 0) {
|
||
|
*flags |= PAM_CLI_FLAGS_TRY_CERT_AUTH;
|
||
|
+ } else if (strcmp(*argv, "require_cert_auth") == 0) {
|
||
|
+ *flags |= PAM_CLI_FLAGS_REQUIRE_CERT_AUTH;
|
||
|
} else {
|
||
|
logger(pamh, LOG_WARNING, "unknown option: %s", *argv);
|
||
|
}
|
||
|
@@ -2274,55 +2280,51 @@ static int get_authtok_for_password_change(pam_handle_t *pamh,
|
||
|
return PAM_SUCCESS;
|
||
|
}
|
||
|
|
||
|
-#define SC_ENTER_FMT "Please enter smart card labeled\n %s\nand press enter"
|
||
|
+#define SC_ENTER_LABEL_FMT "Please enter smart card labeled\n %s"
|
||
|
+#define SC_ENTER_FMT "Please enter smart card"
|
||
|
|
||
|
static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi,
|
||
|
- bool quiet_mode)
|
||
|
+ int retries, bool quiet_mode)
|
||
|
{
|
||
|
int ret;
|
||
|
int pam_status;
|
||
|
char *login_token_name;
|
||
|
char *prompt = NULL;
|
||
|
- size_t size;
|
||
|
- char *answer = NULL;
|
||
|
- /* TODO: check multiple cert case */
|
||
|
- struct cert_auth_info *cai = pi->cert_list;
|
||
|
+ uint32_t orig_flags = pi->flags;
|
||
|
|
||
|
- if (cai == NULL) {
|
||
|
- D(("No certificate information available"));
|
||
|
- return EINVAL;
|
||
|
+ login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");
|
||
|
+ if (login_token_name == NULL
|
||
|
+ && !(pi->flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH)) {
|
||
|
+ return PAM_SUCCESS;
|
||
|
}
|
||
|
|
||
|
- login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");
|
||
|
if (login_token_name == NULL) {
|
||
|
- return PAM_SUCCESS;
|
||
|
+ ret = asprintf(&prompt, SC_ENTER_FMT);
|
||
|
+ } else {
|
||
|
+ ret = asprintf(&prompt, SC_ENTER_LABEL_FMT, login_token_name);
|
||
|
+ }
|
||
|
+ if (ret == -1) {
|
||
|
+ return ENOMEM;
|
||
|
}
|
||
|
|
||
|
- 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) {
|
||
|
- D(("malloc failed."));
|
||
|
- return ENOMEM;
|
||
|
- }
|
||
|
+ pi->flags |= PAM_CLI_FLAGS_REQUIRE_CERT_AUTH;
|
||
|
|
||
|
- ret = snprintf(prompt, size, SC_ENTER_FMT,
|
||
|
- login_token_name);
|
||
|
- if (ret < 0 || ret >= size) {
|
||
|
- D(("snprintf failed."));
|
||
|
- free(prompt);
|
||
|
- return EFAULT;
|
||
|
+ /* TODO: check multiple cert case */
|
||
|
+ while (pi->cert_list == NULL || pi->cert_list->token_name == NULL
|
||
|
+ || (login_token_name != NULL
|
||
|
+ && strcmp(login_token_name,
|
||
|
+ pi->cert_list->token_name) != 0)) {
|
||
|
+
|
||
|
+ if (retries < 0) {
|
||
|
+ ret = PAM_AUTHINFO_UNAVAIL;
|
||
|
+ goto done;
|
||
|
}
|
||
|
+ retries--;
|
||
|
|
||
|
- ret = do_pam_conversation(pamh, PAM_PROMPT_ECHO_OFF, prompt,
|
||
|
- NULL, &answer);
|
||
|
- free(prompt);
|
||
|
+ ret = do_pam_conversation(pamh, PAM_TEXT_INFO, prompt, NULL, NULL);
|
||
|
if (ret != PAM_SUCCESS) {
|
||
|
D(("do_pam_conversation failed."));
|
||
|
- return ret;
|
||
|
- } else {
|
||
|
- free(answer);
|
||
|
+ goto done;
|
||
|
}
|
||
|
|
||
|
pam_status = send_and_receive(pamh, pi, SSS_PAM_PREAUTH, quiet_mode);
|
||
|
@@ -2335,7 +2337,14 @@ static int check_login_token_name(pam_handle_t *pamh, struct pam_items *pi,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- return PAM_SUCCESS;
|
||
|
+ ret = PAM_SUCCESS;
|
||
|
+
|
||
|
+done:
|
||
|
+
|
||
|
+ pi->flags = orig_flags;
|
||
|
+ free(prompt);
|
||
|
+
|
||
|
+ return ret;
|
||
|
}
|
||
|
|
||
|
static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
|
||
|
@@ -2394,8 +2403,19 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
|
||
|
&& (pi.pam_authtok == NULL
|
||
|
|| (flags & PAM_CLI_FLAGS_PROMPT_ALWAYS))
|
||
|
&& access(PAM_PREAUTH_INDICATOR, F_OK) == 0) {
|
||
|
+
|
||
|
+ if (flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH) {
|
||
|
+ /* Do not use PAM_CLI_FLAGS_REQUIRE_CERT_AUTH in the first
|
||
|
+ * SSS_PAM_PREAUTH run. In case a card is already inserted
|
||
|
+ * we do not have to prompt to insert a card. */
|
||
|
+ pi.flags &= ~PAM_CLI_FLAGS_REQUIRE_CERT_AUTH;
|
||
|
+ pi.flags |= PAM_CLI_FLAGS_TRY_CERT_AUTH;
|
||
|
+ }
|
||
|
+
|
||
|
pam_status = send_and_receive(pamh, &pi, SSS_PAM_PREAUTH,
|
||
|
quiet_mode);
|
||
|
+
|
||
|
+ pi.flags = flags;
|
||
|
if (pam_status != PAM_SUCCESS) {
|
||
|
D(("send_and_receive returned [%d] during pre-auth",
|
||
|
pam_status));
|
||
|
@@ -2414,8 +2434,10 @@ static int pam_sss(enum sss_cli_command task, pam_handle_t *pamh,
|
||
|
return PAM_AUTHINFO_UNAVAIL;
|
||
|
}
|
||
|
|
||
|
- if (strcmp(pi.pam_service, "gdm-smartcard") == 0) {
|
||
|
- ret = check_login_token_name(pamh, &pi, quiet_mode);
|
||
|
+ if (strcmp(pi.pam_service, "gdm-smartcard") == 0
|
||
|
+ || (flags & PAM_CLI_FLAGS_REQUIRE_CERT_AUTH)) {
|
||
|
+ ret = check_login_token_name(pamh, &pi, retries,
|
||
|
+ quiet_mode);
|
||
|
if (ret != PAM_SUCCESS) {
|
||
|
D(("check_login_token_name failed.\n"));
|
||
|
return ret;
|
||
|
diff --git a/src/sss_client/sss_cli.h b/src/sss_client/sss_cli.h
|
||
|
index 38e3f99..af8a439 100644
|
||
|
--- a/src/sss_client/sss_cli.h
|
||
|
+++ b/src/sss_client/sss_cli.h
|
||
|
@@ -363,6 +363,7 @@ enum pam_item_type {
|
||
|
SSS_PAM_ITEM_CLI_LOCALE,
|
||
|
SSS_PAM_ITEM_CLI_PID,
|
||
|
SSS_PAM_ITEM_REQUESTED_DOMAINS,
|
||
|
+ SSS_PAM_ITEM_FLAGS,
|
||
|
};
|
||
|
|
||
|
#define PAM_CLI_FLAGS_USE_FIRST_PASS (1 << 0)
|
||
|
@@ -374,6 +375,7 @@ enum pam_item_type {
|
||
|
#define PAM_CLI_FLAGS_ALLOW_MISSING_NAME (1 << 6)
|
||
|
#define PAM_CLI_FLAGS_PROMPT_ALWAYS (1 << 7)
|
||
|
#define PAM_CLI_FLAGS_TRY_CERT_AUTH (1 << 8)
|
||
|
+#define PAM_CLI_FLAGS_REQUIRE_CERT_AUTH (1 << 9)
|
||
|
|
||
|
#define SSS_NSS_MAX_ENTRIES 256
|
||
|
#define SSS_NSS_HEADER_SIZE (sizeof(uint32_t) * 4)
|
||
|
diff --git a/src/util/sss_pam_data.c b/src/util/sss_pam_data.c
|
||
|
index 5e41349..cb8779c 100644
|
||
|
--- a/src/util/sss_pam_data.c
|
||
|
+++ b/src/util/sss_pam_data.c
|
||
|
@@ -176,6 +176,7 @@ void pam_print_data(int l, struct pam_data *pd)
|
||
|
DEBUG(l, "priv: %d\n", pd->priv);
|
||
|
DEBUG(l, "cli_pid: %d\n", pd->cli_pid);
|
||
|
DEBUG(l, "logon name: %s\n", PAM_SAFE_ITEM(pd->logon_name));
|
||
|
+ DEBUG(l, "flags: %d\n", pd->cli_flags);
|
||
|
}
|
||
|
|
||
|
int pam_add_response(struct pam_data *pd, enum response_type type,
|
||
|
diff --git a/src/util/sss_pam_data.h b/src/util/sss_pam_data.h
|
||
|
index 7d74fa6..c989810 100644
|
||
|
--- a/src/util/sss_pam_data.h
|
||
|
+++ b/src/util/sss_pam_data.h
|
||
|
@@ -58,6 +58,7 @@ struct pam_data {
|
||
|
struct sss_auth_token *newauthtok;
|
||
|
uint32_t cli_pid;
|
||
|
char *logon_name;
|
||
|
+ uint32_t cli_flags;
|
||
|
|
||
|
int pam_status;
|
||
|
int response_delay;
|
||
|
--
|
||
|
2.9.5
|
||
|
|