|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/src/confdb/confdb.h
|
|
|
6cf099 |
+++ b/src/confdb/confdb.h
|
|
|
6cf099 |
@@ -115,6 +115,8 @@
|
|
|
6cf099 |
#define CONFDB_PAM_TRUSTED_USERS "pam_trusted_users"
|
|
|
6cf099 |
#define CONFDB_PAM_PUBLIC_DOMAINS "pam_public_domains"
|
|
|
6cf099 |
#define CONFDB_PAM_ACCOUNT_EXPIRED_MESSAGE "pam_account_expired_message"
|
|
|
6cf099 |
+#define CONFDB_PAM_CERT_AUTH "pam_cert_auth"
|
|
|
6cf099 |
+#define CONFDB_PAM_CERT_DB_PATH "pam_cert_db_path"
|
|
|
6cf099 |
|
|
|
6cf099 |
/* SUDO */
|
|
|
6cf099 |
#define CONFDB_SUDO_CONF_ENTRY "config/sudo"
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/Makefile.am
|
|
|
6cf099 |
+++ b/Makefile.am
|
|
|
6cf099 |
@@ -382,6 +382,8 @@ dist_noinst_DATA = \
|
|
|
6cf099 |
contrib/ci/distro.sh \
|
|
|
6cf099 |
contrib/ci/misc.sh \
|
|
|
6cf099 |
contrib/ci/sssd.supp \
|
|
|
6cf099 |
+ src/tests/cmocka/p11_nssdb/cert9.db \
|
|
|
6cf099 |
+ src/tests/cmocka/p11_nssdb/key4.db \
|
|
|
6cf099 |
$(NULL)
|
|
|
6cf099 |
|
|
|
6cf099 |
###############################
|
|
|
6cf099 |
@@ -1086,6 +1088,7 @@ sssd_pam_SOURCES = \
|
|
|
6cf099 |
src/responder/pam/pam_LOCAL_domain.c \
|
|
|
6cf099 |
src/responder/pam/pamsrv.c \
|
|
|
6cf099 |
src/responder/pam/pamsrv_cmd.c \
|
|
|
6cf099 |
+ src/responder/pam/pamsrv_p11.c \
|
|
|
6cf099 |
src/responder/pam/pamsrv_dp.c \
|
|
|
6cf099 |
src/responder/pam/pam_helpers.c \
|
|
|
6cf099 |
$(SSSD_RESPONDER_OBJ)
|
|
|
6cf099 |
@@ -1877,11 +1880,13 @@ pam_srv_tests_SOURCES = \
|
|
|
6cf099 |
src/tests/cmocka/test_pam_srv.c \
|
|
|
6cf099 |
src/sss_client/pam_message.c \
|
|
|
6cf099 |
src/responder/pam/pamsrv_cmd.c \
|
|
|
6cf099 |
+ src/responder/pam/pamsrv_p11.c \
|
|
|
6cf099 |
src/responder/pam/pam_helpers.c \
|
|
|
6cf099 |
src/responder/pam/pamsrv_dp.c \
|
|
|
6cf099 |
src/responder/pam/pam_LOCAL_domain.c \
|
|
|
6cf099 |
$(NULL)
|
|
|
6cf099 |
pam_srv_tests_CFLAGS = \
|
|
|
6cf099 |
+ -U SSSD_LIBEXEC_PATH -DSSSD_LIBEXEC_PATH=\"$(abs_builddir)\" \
|
|
|
6cf099 |
$(AM_CFLAGS) \
|
|
|
6cf099 |
$(NULL)
|
|
|
6cf099 |
pam_srv_tests_LDFLAGS = \
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/configure.ac
|
|
|
6cf099 |
+++ b/configure.ac
|
|
|
6cf099 |
@@ -400,6 +400,9 @@ abs_build_dir=`pwd`
|
|
|
6cf099 |
AC_DEFINE_UNQUOTED([ABS_BUILD_DIR], ["$abs_build_dir"], [Absolute path to the build directory])
|
|
|
6cf099 |
AC_SUBST([abs_builddir], $abs_build_dir)
|
|
|
6cf099 |
|
|
|
6cf099 |
+my_srcdir=`readlink -f $srcdir`
|
|
|
6cf099 |
+AC_DEFINE_UNQUOTED([ABS_SRC_DIR], ["$my_srcdir"], [Absolute path to the source directory])
|
|
|
6cf099 |
+
|
|
|
6cf099 |
AC_CONFIG_FILES([Makefile contrib/sssd.spec src/examples/rwtab src/doxy.config
|
|
|
6cf099 |
src/sysv/sssd src/sysv/gentoo/sssd src/sysv/SUSE/sssd
|
|
|
6cf099 |
po/Makefile.in src/man/Makefile src/tests/cwrap/Makefile
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/src/responder/pam/pamsrv.c
|
|
|
6cf099 |
+++ b/src/responder/pam/pamsrv.c
|
|
|
6cf099 |
@@ -50,6 +50,8 @@
|
|
|
6cf099 |
#define ALL_DOMAIMS_ARE_PUBLIC "all"
|
|
|
6cf099 |
#define NO_DOMAIMS_ARE_PUBLIC "none"
|
|
|
6cf099 |
#define DEFAULT_ALLOWED_UIDS ALL_UIDS_ALLOWED
|
|
|
6cf099 |
+#define DEFAULT_PAM_CERT_AUTH false
|
|
|
6cf099 |
+#define DEFAULT_PAM_CERT_DB_PATH SYSCONFDIR"/pki/nssdb"
|
|
|
6cf099 |
|
|
|
6cf099 |
struct mon_cli_iface monitor_pam_methods = {
|
|
|
6cf099 |
{ &mon_cli_iface_meta, 0 },
|
|
|
6cf099 |
@@ -302,6 +304,38 @@ static int pam_process_init(TALLOC_CTX *mem_ctx,
|
|
|
6cf099 |
goto done;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
+ /* Check if certificate based authentication is enabled */
|
|
|
6cf099 |
+ ret = confdb_get_bool(pctx->rctx->cdb,
|
|
|
6cf099 |
+ CONFDB_PAM_CONF_ENTRY,
|
|
|
6cf099 |
+ CONFDB_PAM_CERT_AUTH,
|
|
|
6cf099 |
+ DEFAULT_PAM_CERT_AUTH,
|
|
|
6cf099 |
+ &pctx->cert_auth);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to determine get cert db path.\n");
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ pctx->p11_child_debug_fd = -1;
|
|
|
6cf099 |
+ if (pctx->cert_auth) {
|
|
|
6cf099 |
+ ret = p11_child_init(pctx);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "p11_child_init failed.\n");
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = confdb_get_string(pctx->rctx->cdb, pctx,
|
|
|
6cf099 |
+ CONFDB_PAM_CONF_ENTRY,
|
|
|
6cf099 |
+ CONFDB_PAM_CERT_DB_PATH,
|
|
|
6cf099 |
+ DEFAULT_PAM_CERT_DB_PATH,
|
|
|
6cf099 |
+ &pctx->nss_db);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE,
|
|
|
6cf099 |
+ "Failed to determine if certificate based authentication is " \
|
|
|
6cf099 |
+ "enabled or not.\n");
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
ret = EOK;
|
|
|
6cf099 |
|
|
|
6cf099 |
done:
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/src/responder/pam/pamsrv.h
|
|
|
6cf099 |
+++ b/src/responder/pam/pamsrv.h
|
|
|
6cf099 |
@@ -43,6 +43,10 @@ struct pam_ctx {
|
|
|
6cf099 |
/* List of domains that are accessible even for untrusted users. */
|
|
|
6cf099 |
char **public_domains;
|
|
|
6cf099 |
int public_domains_count;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ bool cert_auth;
|
|
|
6cf099 |
+ int p11_child_debug_fd;
|
|
|
6cf099 |
+ char *nss_db;
|
|
|
6cf099 |
};
|
|
|
6cf099 |
|
|
|
6cf099 |
struct pam_auth_dp_req {
|
|
|
6cf099 |
@@ -65,6 +69,9 @@ struct pam_auth_req {
|
|
|
6cf099 |
bool cached_auth_failed;
|
|
|
6cf099 |
|
|
|
6cf099 |
struct pam_auth_dp_req *dpreq_spy;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ struct ldb_message *cert_user_obj;
|
|
|
6cf099 |
+ char *token_name;
|
|
|
6cf099 |
};
|
|
|
6cf099 |
|
|
|
6cf099 |
struct sss_cmd_table *get_pam_cmds(void);
|
|
|
6cf099 |
@@ -73,4 +80,19 @@ int pam_dp_send_req(struct pam_auth_req *preq, int timeout);
|
|
|
6cf099 |
|
|
|
6cf099 |
int LOCAL_pam_handler(struct pam_auth_req *preq);
|
|
|
6cf099 |
|
|
|
6cf099 |
+errno_t p11_child_init(struct pam_ctx *pctx);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
|
|
|
6cf099 |
+ struct tevent_context *ev,
|
|
|
6cf099 |
+ int child_debug_fd,
|
|
|
6cf099 |
+ const char *nss_db,
|
|
|
6cf099 |
+ time_t timeout,
|
|
|
6cf099 |
+ struct pam_data *pd);
|
|
|
6cf099 |
+errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
|
|
|
6cf099 |
+ char **cert, char **token_name);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+errno_t add_pam_cert_response(struct pam_data *pd, const char *user,
|
|
|
6cf099 |
+ const char *token_name);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd);
|
|
|
6cf099 |
#endif /* __PAMSRV_H__ */
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/src/responder/pam/pamsrv_cmd.c
|
|
|
6cf099 |
+++ b/src/responder/pam/pamsrv_cmd.c
|
|
|
6cf099 |
@@ -31,6 +31,7 @@
|
|
|
6cf099 |
#include "providers/data_provider.h"
|
|
|
6cf099 |
#include "responder/pam/pamsrv.h"
|
|
|
6cf099 |
#include "responder/pam/pam_helpers.h"
|
|
|
6cf099 |
+#include "responder/common/responder_cache_req.h"
|
|
|
6cf099 |
#include "db/sysdb.h"
|
|
|
6cf099 |
|
|
|
6cf099 |
enum pam_verbosity {
|
|
|
6cf099 |
@@ -49,6 +50,7 @@ static errno_t
|
|
|
6cf099 |
pam_get_last_online_auth_with_curr_token(struct sss_domain_info *domain,
|
|
|
6cf099 |
const char *name,
|
|
|
6cf099 |
uint64_t *_value);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
static void pam_reply(struct pam_auth_req *preq);
|
|
|
6cf099 |
|
|
|
6cf099 |
static errno_t pack_user_info_account_expired(TALLOC_CTX *mem_ctx,
|
|
|
6cf099 |
@@ -154,6 +156,13 @@ static int extract_authtok_v2(struct sss_auth_token *tok,
|
|
|
6cf099 |
ret = sss_authtok_set(tok, SSS_AUTHTOK_TYPE_2FA,
|
|
|
6cf099 |
auth_token_data, auth_token_length);
|
|
|
6cf099 |
break;
|
|
|
6cf099 |
+ case SSS_AUTHTOK_TYPE_SC_PIN:
|
|
|
6cf099 |
+ ret = sss_authtok_set_sc_pin(tok, (const char *) auth_token_data,
|
|
|
6cf099 |
+ auth_token_length);
|
|
|
6cf099 |
+ break;
|
|
|
6cf099 |
+ case SSS_AUTHTOK_TYPE_SC_KEYPAD:
|
|
|
6cf099 |
+ sss_authtok_set_sc_keypad(tok);
|
|
|
6cf099 |
+ break;
|
|
|
6cf099 |
default:
|
|
|
6cf099 |
return EINVAL;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
@@ -892,6 +901,7 @@ static void pam_handle_cached_login(struct pam_auth_req *preq, int ret,
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
static void pam_forwarder_cb(struct tevent_req *req);
|
|
|
6cf099 |
+static void pam_forwarder_cert_cb(struct tevent_req *req);
|
|
|
6cf099 |
static void pam_check_user_dp_callback(uint16_t err_maj, uint32_t err_min,
|
|
|
6cf099 |
const char *err_msg, void *ptr);
|
|
|
6cf099 |
static int pam_check_user_search(struct pam_auth_req *preq);
|
|
|
6cf099 |
@@ -939,9 +949,22 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p
|
|
|
6cf099 |
goto done;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
- ret = sss_parse_name_for_domains(pd, cctx->rctx->domains,
|
|
|
6cf099 |
- cctx->rctx->default_domain, pd->logon_name,
|
|
|
6cf099 |
- &pd->domain, &pd->user);
|
|
|
6cf099 |
+ if (pd->logon_name != NULL) {
|
|
|
6cf099 |
+ ret = sss_parse_name_for_domains(pd, cctx->rctx->domains,
|
|
|
6cf099 |
+ cctx->rctx->default_domain,
|
|
|
6cf099 |
+ pd->logon_name,
|
|
|
6cf099 |
+ &pd->domain, &pd->user);
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the
|
|
|
6cf099 |
+ * name is determined with the help of a certificate */
|
|
|
6cf099 |
+ if (pd->cmd == SSS_PAM_PREAUTH) {
|
|
|
6cf099 |
+ ret = EOK;
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing logon name in PAM request.\n");
|
|
|
6cf099 |
+ ret = EINVAL;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
|
|
|
6cf099 |
DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
|
|
|
6cf099 |
|
|
|
6cf099 |
@@ -1052,49 +1075,66 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd)
|
|
|
6cf099 |
goto done;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
- /* now check user is valid */
|
|
|
6cf099 |
- if (pd->domain) {
|
|
|
6cf099 |
- preq->domain = responder_get_domain(cctx->rctx, pd->domain);
|
|
|
6cf099 |
- if (!preq->domain) {
|
|
|
6cf099 |
- ret = ENOENT;
|
|
|
6cf099 |
- goto done;
|
|
|
6cf099 |
- }
|
|
|
6cf099 |
-
|
|
|
6cf099 |
- ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
|
|
|
6cf099 |
- preq->domain, pd->user);
|
|
|
6cf099 |
- if (ncret == EEXIST) {
|
|
|
6cf099 |
- /* User found in the negative cache */
|
|
|
6cf099 |
- ret = ENOENT;
|
|
|
6cf099 |
- goto done;
|
|
|
6cf099 |
- }
|
|
|
6cf099 |
- } else {
|
|
|
6cf099 |
- for (dom = preq->cctx->rctx->domains;
|
|
|
6cf099 |
- dom;
|
|
|
6cf099 |
- dom = get_next_domain(dom, false)) {
|
|
|
6cf099 |
- if (dom->fqnames) continue;
|
|
|
6cf099 |
+ if (pd->user != NULL) {
|
|
|
6cf099 |
+ /* now check user is valid */
|
|
|
6cf099 |
+ if (pd->domain) {
|
|
|
6cf099 |
+ preq->domain = responder_get_domain(cctx->rctx, pd->domain);
|
|
|
6cf099 |
+ if (!preq->domain) {
|
|
|
6cf099 |
+ ret = ENOENT;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
|
|
|
6cf099 |
ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
|
|
|
6cf099 |
- dom, pd->user);
|
|
|
6cf099 |
- if (ncret == ENOENT) {
|
|
|
6cf099 |
- /* User not found in the negative cache
|
|
|
6cf099 |
- * Proceed with PAM actions
|
|
|
6cf099 |
- */
|
|
|
6cf099 |
- break;
|
|
|
6cf099 |
+ preq->domain, pd->user);
|
|
|
6cf099 |
+ if (ncret == EEXIST) {
|
|
|
6cf099 |
+ /* User found in the negative cache */
|
|
|
6cf099 |
+ ret = ENOENT;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ for (dom = preq->cctx->rctx->domains;
|
|
|
6cf099 |
+ dom;
|
|
|
6cf099 |
+ dom = get_next_domain(dom, false)) {
|
|
|
6cf099 |
+ if (dom->fqnames) continue;
|
|
|
6cf099 |
|
|
|
6cf099 |
- /* Try the next domain */
|
|
|
6cf099 |
- DEBUG(SSSDBG_TRACE_FUNC,
|
|
|
6cf099 |
- "User [%s@%s] filtered out (negative cache). "
|
|
|
6cf099 |
- "Trying next domain.\n", pd->user, dom->name);
|
|
|
6cf099 |
+ ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,
|
|
|
6cf099 |
+ dom, pd->user);
|
|
|
6cf099 |
+ if (ncret == ENOENT) {
|
|
|
6cf099 |
+ /* User not found in the negative cache
|
|
|
6cf099 |
+ * Proceed with PAM actions
|
|
|
6cf099 |
+ */
|
|
|
6cf099 |
+ break;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Try the next domain */
|
|
|
6cf099 |
+ DEBUG(SSSDBG_TRACE_FUNC,
|
|
|
6cf099 |
+ "User [%s@%s] filtered out (negative cache). "
|
|
|
6cf099 |
+ "Trying next domain.\n", pd->user, dom->name);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (!dom) {
|
|
|
6cf099 |
+ ret = ENOENT;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ preq->domain = dom;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
|
|
|
6cf099 |
- if (!dom) {
|
|
|
6cf099 |
- ret = ENOENT;
|
|
|
6cf099 |
- goto done;
|
|
|
6cf099 |
+ if (may_do_cert_auth(pctx, pd)) {
|
|
|
6cf099 |
+ req = pam_check_cert_send(cctx, cctx->ev, pctx->p11_child_debug_fd,
|
|
|
6cf099 |
+ pctx->nss_db, 10, pd);
|
|
|
6cf099 |
+ if (req == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
|
|
|
6cf099 |
+ ret = ENOMEM;
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ tevent_req_set_callback(req, pam_forwarder_cert_cb, preq);
|
|
|
6cf099 |
+ ret = EAGAIN;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
- preq->domain = dom;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
+
|
|
|
6cf099 |
if (preq->domain->provider == NULL) {
|
|
|
6cf099 |
DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
"Domain [%s] has no auth provider.\n", preq->domain->name);
|
|
|
6cf099 |
@@ -1113,6 +1153,142 @@ done:
|
|
|
6cf099 |
return pam_check_user_done(preq, ret);
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
+static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req);
|
|
|
6cf099 |
+static void pam_forwarder_cert_cb(struct tevent_req *req)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ struct pam_auth_req *preq = tevent_req_callback_data(req,
|
|
|
6cf099 |
+ struct pam_auth_req);
|
|
|
6cf099 |
+ struct cli_ctx *cctx = preq->cctx;
|
|
|
6cf099 |
+ struct pam_data *pd;
|
|
|
6cf099 |
+ errno_t ret = EOK;
|
|
|
6cf099 |
+ char *cert;
|
|
|
6cf099 |
+ struct pam_ctx *pctx =
|
|
|
6cf099 |
+ talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name);
|
|
|
6cf099 |
+ talloc_free(req);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "get_cert request failed.\n");
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ pd = preq->pd;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (cert == NULL) {
|
|
|
6cf099 |
+ if (pd->logon_name == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "No certificate found and no logon name given, " \
|
|
|
6cf099 |
+ "authentication not possible.\n");;
|
|
|
6cf099 |
+ ret = ENOENT;
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ if (pd->cmd == SSS_PAM_AUTHENTICATE) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "No certificate returned, authentication failed.\n");
|
|
|
6cf099 |
+ ret = ENOENT;
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ ret = pam_check_user_search(preq);
|
|
|
6cf099 |
+ if (ret == EOK) {
|
|
|
6cf099 |
+ pam_dom_forwarder(preq);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx,
|
|
|
6cf099 |
+ pctx->ncache, pctx->neg_timeout,
|
|
|
6cf099 |
+ 0, NULL, cert);
|
|
|
6cf099 |
+ if (req == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n");
|
|
|
6cf099 |
+ ret = ENOMEM;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ tevent_req_set_callback(req, pam_forwarder_lookup_by_cert_done, preq);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+done:
|
|
|
6cf099 |
+ pam_check_user_done(preq, ret);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+ struct ldb_result *res;
|
|
|
6cf099 |
+ struct sss_domain_info *domain;
|
|
|
6cf099 |
+ struct pam_auth_req *preq = tevent_req_callback_data(req,
|
|
|
6cf099 |
+ struct pam_auth_req);
|
|
|
6cf099 |
+ const char *cert_user;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = cache_req_user_by_cert_recv(preq, req, &res, &domain, NULL);
|
|
|
6cf099 |
+ talloc_zfree(req);
|
|
|
6cf099 |
+ if (ret != EOK && ret != ENOENT) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n");
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (ret == EOK && res->count > 1) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "Search by certificate returned more than one result.\n");
|
|
|
6cf099 |
+ ret = EINVAL;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (ret == EOK) {
|
|
|
6cf099 |
+ if (preq->domain == NULL) {
|
|
|
6cf099 |
+ preq->domain = domain;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ preq->cert_user_obj = talloc_steal(preq, res->msgs[0]);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (preq->pd->logon_name == NULL) {
|
|
|
6cf099 |
+ cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj,
|
|
|
6cf099 |
+ SYSDB_NAME, NULL);
|
|
|
6cf099 |
+ if (cert_user == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "Certificate user object has not name.\n");
|
|
|
6cf099 |
+ ret = ENOENT;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FUNC_DATA, "Found certificate user [%s].\n",
|
|
|
6cf099 |
+ cert_user);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = add_pam_cert_response(preq->pd, cert_user, preq->token_name);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ preq->pd->domain = talloc_strdup(preq->pd, domain->name);
|
|
|
6cf099 |
+ if (preq->pd->domain == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
|
|
|
6cf099 |
+ ret = ENOMEM;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ preq->pd->pam_status = PAM_SUCCESS;
|
|
|
6cf099 |
+ pam_reply(preq);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ if (preq->pd->logon_name == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "Missing logon name and no certificate user found.\n");
|
|
|
6cf099 |
+ ret = ENOENT;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = pam_check_user_search(preq);
|
|
|
6cf099 |
+ if (ret == EOK) {
|
|
|
6cf099 |
+ pam_dom_forwarder(preq);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+done:
|
|
|
6cf099 |
+ pam_check_user_done(preq, ret);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
static void pam_forwarder_cb(struct tevent_req *req)
|
|
|
6cf099 |
{
|
|
|
6cf099 |
struct pam_auth_req *preq = tevent_req_callback_data(req,
|
|
|
6cf099 |
@@ -1120,6 +1296,8 @@ static void pam_forwarder_cb(struct tevent_req *req)
|
|
|
6cf099 |
struct cli_ctx *cctx = preq->cctx;
|
|
|
6cf099 |
struct pam_data *pd;
|
|
|
6cf099 |
errno_t ret = EOK;
|
|
|
6cf099 |
+ struct pam_ctx *pctx =
|
|
|
6cf099 |
+ talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
|
|
|
6cf099 |
|
|
|
6cf099 |
ret = sss_dp_get_domains_recv(req);
|
|
|
6cf099 |
talloc_free(req);
|
|
|
6cf099 |
@@ -1158,6 +1336,20 @@ static void pam_forwarder_cb(struct tevent_req *req)
|
|
|
6cf099 |
}
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
+ if (may_do_cert_auth(pctx, pd)) {
|
|
|
6cf099 |
+ req = pam_check_cert_send(cctx, cctx->ev, pctx->p11_child_debug_fd,
|
|
|
6cf099 |
+ pctx->nss_db, 10, pd);
|
|
|
6cf099 |
+ if (req == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n");
|
|
|
6cf099 |
+ ret = ENOMEM;
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ tevent_req_set_callback(req, pam_forwarder_cert_cb, preq);
|
|
|
6cf099 |
+ ret = EAGAIN;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
ret = pam_check_user_search(preq);
|
|
|
6cf099 |
if (ret == EOK) {
|
|
|
6cf099 |
pam_dom_forwarder(preq);
|
|
|
6cf099 |
@@ -1542,6 +1734,7 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
|
|
|
6cf099 |
int ret;
|
|
|
6cf099 |
struct pam_ctx *pctx =
|
|
|
6cf099 |
talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
|
|
|
6cf099 |
+ const char *cert_user;
|
|
|
6cf099 |
|
|
|
6cf099 |
if (!preq->pd->domain) {
|
|
|
6cf099 |
preq->pd->domain = preq->domain->name;
|
|
|
6cf099 |
@@ -1579,6 +1772,51 @@ static void pam_dom_forwarder(struct pam_auth_req *preq)
|
|
|
6cf099 |
return;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
+ if (may_do_cert_auth(pctx, preq->pd) && preq->cert_user_obj != NULL) {
|
|
|
6cf099 |
+ /* Check if user matches certificate user */
|
|
|
6cf099 |
+ cert_user = ldb_msg_find_attr_as_string(preq->cert_user_obj, SYSDB_NAME,
|
|
|
6cf099 |
+ NULL);
|
|
|
6cf099 |
+ if (cert_user == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "Certificate user object has not name.\n");
|
|
|
6cf099 |
+ preq->pd->pam_status = PAM_USER_UNKNOWN;
|
|
|
6cf099 |
+ pam_reply(preq);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* pam_check_user_search() calls pd_set_primary_name() is the search
|
|
|
6cf099 |
+ * was successful, so pd->user contains the canonical name as well */
|
|
|
6cf099 |
+ if (strcmp(cert_user, preq->pd->user) == 0) {
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ preq->pd->pam_status = PAM_SUCCESS;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (preq->pd->cmd == SSS_PAM_PREAUTH) {
|
|
|
6cf099 |
+ ret = add_pam_cert_response(preq->pd, cert_user,
|
|
|
6cf099 |
+ preq->token_name);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n");
|
|
|
6cf099 |
+ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ preq->callback = pam_reply;
|
|
|
6cf099 |
+ pam_reply(preq);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ if (preq->pd->cmd == SSS_PAM_PREAUTH) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_TRACE_FUNC,
|
|
|
6cf099 |
+ "User and certificate user do not match, " \
|
|
|
6cf099 |
+ "continue with other authentication methods.\n");
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "User and certificate user do not match.\n");
|
|
|
6cf099 |
+ preq->pd->pam_status = PAM_AUTH_ERR;
|
|
|
6cf099 |
+ pam_reply(preq);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
if (!NEED_CHECK_PROVIDER(preq->domain->provider) ) {
|
|
|
6cf099 |
preq->callback = pam_reply;
|
|
|
6cf099 |
ret = LOCAL_pam_handler(preq);
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- /dev/null
|
|
|
6cf099 |
+++ b/src/responder/pam/pamsrv_p11.c
|
|
|
6cf099 |
@@ -0,0 +1,527 @@
|
|
|
6cf099 |
+/*
|
|
|
6cf099 |
+ SSSD
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ PAM Responder - certificate realted requests
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ Copyright (C) Sumit Bose <sbose@redhat.com> 2015
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ This program is free software; you can redistribute it and/or modify
|
|
|
6cf099 |
+ it under the terms of the GNU General Public License as published by
|
|
|
6cf099 |
+ the Free Software Foundation; either version 3 of the License, or
|
|
|
6cf099 |
+ (at your option) any later version.
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ This program is distributed in the hope that it will be useful,
|
|
|
6cf099 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
6cf099 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
6cf099 |
+ GNU General Public License for more details.
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ You should have received a copy of the GNU General Public License
|
|
|
6cf099 |
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
6cf099 |
+*/
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+#include <time.h>
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+#include "util/util.h"
|
|
|
6cf099 |
+#include "providers/data_provider.h"
|
|
|
6cf099 |
+#include "util/child_common.h"
|
|
|
6cf099 |
+#include "util/strtonum.h"
|
|
|
6cf099 |
+#include "responder/pam/pamsrv.h"
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+#ifndef SSSD_LIBEXEC_PATH
|
|
|
6cf099 |
+#error "SSSD_LIBEXEC_PATH not defined"
|
|
|
6cf099 |
+#endif /* SSSD_LIBEXEC_PATH */
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+#define P11_CHILD_LOG_FILE "p11_child"
|
|
|
6cf099 |
+#define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child"
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+errno_t p11_child_init(struct pam_ctx *pctx)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ size_t c;
|
|
|
6cf099 |
+ const char *sc_services[] = { "login", "su", "su-l", "gdm-smartcard",
|
|
|
6cf099 |
+ "gdm-password", "kdm", "sudo", "sudo-i",
|
|
|
6cf099 |
+ NULL };
|
|
|
6cf099 |
+ if (!pctx->cert_auth) {
|
|
|
6cf099 |
+ return false;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (pd->cmd != SSS_PAM_PREAUTH && pd->cmd != SSS_PAM_AUTHENTICATE) {
|
|
|
6cf099 |
+ return false;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (pd->cmd == SSS_PAM_AUTHENTICATE
|
|
|
6cf099 |
+ && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN
|
|
|
6cf099 |
+ && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_SC_KEYPAD) {
|
|
|
6cf099 |
+ return false;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* TODO: make services configurable */
|
|
|
6cf099 |
+ if (pd->service == NULL || *pd->service == '\0') {
|
|
|
6cf099 |
+ return false;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ for (c = 0; sc_services[c] != NULL; c++) {
|
|
|
6cf099 |
+ if (strcmp(pd->service, sc_services[c]) == 0) {
|
|
|
6cf099 |
+ break;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ if (sc_services[c] == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "Smartcard authentication for service [%s] not supported.\n",
|
|
|
6cf099 |
+ pd->service);
|
|
|
6cf099 |
+ return false;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return true;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx,
|
|
|
6cf099 |
+ struct pam_data *pd,
|
|
|
6cf099 |
+ uint8_t **_buf, size_t *_len)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+ uint8_t *buf;
|
|
|
6cf099 |
+ size_t len;
|
|
|
6cf099 |
+ const char *pin = NULL;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (pd == NULL || pd->authtok == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing authtok.\n");
|
|
|
6cf099 |
+ return EINVAL;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ switch (sss_authtok_get_type(pd->authtok)) {
|
|
|
6cf099 |
+ case SSS_AUTHTOK_TYPE_SC_PIN:
|
|
|
6cf099 |
+ ret = sss_authtok_get_sc_pin(pd->authtok, &pin, &len;;
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc_pin failed.\n");
|
|
|
6cf099 |
+ return ret;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ if (pin == NULL || len == 0) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing PIN.\n");
|
|
|
6cf099 |
+ return EINVAL;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ buf = talloc_size(mem_ctx, len);
|
|
|
6cf099 |
+ if (buf == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
|
|
|
6cf099 |
+ return ENOMEM;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ safealign_memcpy(buf, pin, len, NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ break;
|
|
|
6cf099 |
+ case SSS_AUTHTOK_TYPE_SC_KEYPAD:
|
|
|
6cf099 |
+ /* Nothing to send */
|
|
|
6cf099 |
+ len = 0;
|
|
|
6cf099 |
+ buf = NULL;
|
|
|
6cf099 |
+ break;
|
|
|
6cf099 |
+ default:
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported authtok type [%d].\n",
|
|
|
6cf099 |
+ sss_authtok_get_type(pd->authtok));
|
|
|
6cf099 |
+ return EINVAL;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ *_len = len;
|
|
|
6cf099 |
+ *_buf = buf;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return EOK;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
|
|
|
6cf099 |
+ ssize_t buf_len, char **_cert,
|
|
|
6cf099 |
+ char **_token_name)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+ TALLOC_CTX *tmp_ctx = NULL;
|
|
|
6cf099 |
+ uint8_t *p;
|
|
|
6cf099 |
+ uint8_t *pn;
|
|
|
6cf099 |
+ char *cert = NULL;
|
|
|
6cf099 |
+ char *token_name = NULL;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (buf_len < 0) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "Error occured while reading data from p11_child.\n");
|
|
|
6cf099 |
+ return EIO;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (buf_len == 0) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_TRACE_LIBS, "No certificate found.\n");
|
|
|
6cf099 |
+ ret = EOK;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ p = memchr(buf, '\n', buf_len);
|
|
|
6cf099 |
+ if (p == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "Missing new-line in p11_child response.\n");
|
|
|
6cf099 |
+ return EINVAL;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ if (p == buf) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "Missing counter in p11_child response.\n");
|
|
|
6cf099 |
+ return EINVAL;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ tmp_ctx = talloc_new(NULL);
|
|
|
6cf099 |
+ if (tmp_ctx == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
|
|
|
6cf099 |
+ return ENOMEM;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ token_name = talloc_strndup(tmp_ctx, (char*) buf, (p - buf));
|
|
|
6cf099 |
+ if (token_name == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
|
|
|
6cf099 |
+ ret = ENOMEM;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ p++;
|
|
|
6cf099 |
+ pn = memchr(p, '\n', buf_len - (p - buf));
|
|
|
6cf099 |
+ if (pn == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
|
6cf099 |
+ "Missing new-line in p11_child response.\n");
|
|
|
6cf099 |
+ ret = EINVAL;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (pn == p) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n");
|
|
|
6cf099 |
+ ret = EINVAL;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ cert = talloc_strndup(tmp_ctx, (char *) p, (pn - p));
|
|
|
6cf099 |
+ if(cert == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
|
|
|
6cf099 |
+ ret = ENOMEM;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = EOK;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+done:
|
|
|
6cf099 |
+ if (ret == EOK) {
|
|
|
6cf099 |
+ *_token_name = talloc_steal(mem_ctx, token_name);
|
|
|
6cf099 |
+ *_cert = talloc_steal(mem_ctx, cert);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ talloc_free(tmp_ctx);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return ret;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+struct pam_check_cert_state {
|
|
|
6cf099 |
+ int child_status;
|
|
|
6cf099 |
+ struct sss_child_ctx_old *child_ctx;
|
|
|
6cf099 |
+ struct tevent_timer *timeout_handler;
|
|
|
6cf099 |
+ struct tevent_context *ev;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ int write_to_child_fd;
|
|
|
6cf099 |
+ int read_from_child_fd;
|
|
|
6cf099 |
+ char *cert;
|
|
|
6cf099 |
+ char *token_name;
|
|
|
6cf099 |
+};
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static void p11_child_write_done(struct tevent_req *subreq);
|
|
|
6cf099 |
+static void p11_child_done(struct tevent_req *subreq);
|
|
|
6cf099 |
+static void p11_child_timeout(struct tevent_context *ev,
|
|
|
6cf099 |
+ struct tevent_timer *te,
|
|
|
6cf099 |
+ struct timeval tv, void *pvt);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
|
|
|
6cf099 |
+ struct tevent_context *ev,
|
|
|
6cf099 |
+ int child_debug_fd,
|
|
|
6cf099 |
+ const char *nss_db,
|
|
|
6cf099 |
+ time_t timeout,
|
|
|
6cf099 |
+ struct pam_data *pd)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ errno_t ret;
|
|
|
6cf099 |
+ struct tevent_req *req;
|
|
|
6cf099 |
+ struct tevent_req *subreq;
|
|
|
6cf099 |
+ struct pam_check_cert_state *state;
|
|
|
6cf099 |
+ pid_t child_pid;
|
|
|
6cf099 |
+ struct timeval tv;
|
|
|
6cf099 |
+ int pipefd_to_child[2];
|
|
|
6cf099 |
+ int pipefd_from_child[2];
|
|
|
6cf099 |
+ const char *extra_args[5] = {NULL, NULL, NULL, NULL, NULL};
|
|
|
6cf099 |
+ uint8_t *write_buf = NULL;
|
|
|
6cf099 |
+ size_t write_buf_len = 0;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ req = tevent_req_create(mem_ctx, &state, struct pam_check_cert_state);
|
|
|
6cf099 |
+ if (req == NULL) {
|
|
|
6cf099 |
+ return NULL;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (nss_db == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing NSS DB.\n");
|
|
|
6cf099 |
+ ret = EINVAL;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* extra_args are added in revers order */
|
|
|
6cf099 |
+ extra_args[1] = "--nssdb";
|
|
|
6cf099 |
+ extra_args[0] = nss_db;
|
|
|
6cf099 |
+ if (pd->cmd == SSS_PAM_AUTHENTICATE) {
|
|
|
6cf099 |
+ extra_args[2] = "--auth";
|
|
|
6cf099 |
+ switch (sss_authtok_get_type(pd->authtok)) {
|
|
|
6cf099 |
+ case SSS_AUTHTOK_TYPE_SC_PIN:
|
|
|
6cf099 |
+ extra_args[3] = "--pin";
|
|
|
6cf099 |
+ break;
|
|
|
6cf099 |
+ case SSS_AUTHTOK_TYPE_SC_KEYPAD:
|
|
|
6cf099 |
+ extra_args[3] = "--keypad";
|
|
|
6cf099 |
+ break;
|
|
|
6cf099 |
+ default:
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "Unsupported authtok type.\n");
|
|
|
6cf099 |
+ ret = EINVAL;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ } else if (pd->cmd == SSS_PAM_PREAUTH) {
|
|
|
6cf099 |
+ extra_args[2] = "--pre";
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM command [%d}.\n", pd->cmd);
|
|
|
6cf099 |
+ ret = EINVAL;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ state->ev = ev;
|
|
|
6cf099 |
+ state->child_status = EFAULT;
|
|
|
6cf099 |
+ state->read_from_child_fd = -1;
|
|
|
6cf099 |
+ state->write_to_child_fd = -1;
|
|
|
6cf099 |
+ state->cert = NULL;
|
|
|
6cf099 |
+ state->token_name = NULL;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = pipe(pipefd_from_child);
|
|
|
6cf099 |
+ if (ret == -1) {
|
|
|
6cf099 |
+ ret = errno;
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "pipe failed [%d][%s].\n", ret, strerror(ret));
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ ret = pipe(pipefd_to_child);
|
|
|
6cf099 |
+ if (ret == -1) {
|
|
|
6cf099 |
+ ret = errno;
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE,
|
|
|
6cf099 |
+ "pipe failed [%d][%s].\n", ret, strerror(ret));
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (child_debug_fd == -1) {
|
|
|
6cf099 |
+ child_debug_fd = STDERR_FILENO;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ child_pid = fork();
|
|
|
6cf099 |
+ if (child_pid == 0) { /* child */
|
|
|
6cf099 |
+ ret = exec_child_ex(state, pipefd_to_child, pipefd_from_child,
|
|
|
6cf099 |
+ P11_CHILD_PATH, child_debug_fd, extra_args,
|
|
|
6cf099 |
+ STDIN_FILENO, STDOUT_FILENO);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec p11 child: [%d][%s].\n",
|
|
|
6cf099 |
+ ret, strerror(ret));
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ } else if (child_pid > 0) { /* parent */
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ state->read_from_child_fd = pipefd_from_child[0];
|
|
|
6cf099 |
+ close(pipefd_from_child[1]);
|
|
|
6cf099 |
+ sss_fd_nonblocking(state->read_from_child_fd);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ state->write_to_child_fd = pipefd_to_child[1];
|
|
|
6cf099 |
+ close(pipefd_to_child[0]);
|
|
|
6cf099 |
+ sss_fd_nonblocking(state->write_to_child_fd);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Set up SIGCHLD handler */
|
|
|
6cf099 |
+ ret = child_handler_setup(ev, child_pid, NULL, NULL, &state->child_ctx);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
|
|
|
6cf099 |
+ ret, sss_strerror(ret));
|
|
|
6cf099 |
+ ret = ERR_P11_CHILD;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Set up timeout handler */
|
|
|
6cf099 |
+ tv = tevent_timeval_current_ofs(timeout, 0);
|
|
|
6cf099 |
+ state->timeout_handler = tevent_add_timer(ev, req, tv,
|
|
|
6cf099 |
+ p11_child_timeout, req);
|
|
|
6cf099 |
+ if(state->timeout_handler == NULL) {
|
|
|
6cf099 |
+ ret = ERR_P11_CHILD;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (pd->cmd == SSS_PAM_AUTHENTICATE) {
|
|
|
6cf099 |
+ ret = get_p11_child_write_buffer(state, pd, &write_buf,
|
|
|
6cf099 |
+ &write_buf_len);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE,
|
|
|
6cf099 |
+ "get_p11_child_write_buffer failed.\n");
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (write_buf_len != 0) {
|
|
|
6cf099 |
+ subreq = write_pipe_send(state, ev, write_buf, write_buf_len,
|
|
|
6cf099 |
+ state->write_to_child_fd);
|
|
|
6cf099 |
+ if (subreq == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "write_pipe_send failed.\n");
|
|
|
6cf099 |
+ ret = ERR_P11_CHILD;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ tevent_req_set_callback(subreq, p11_child_write_done, req);
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ subreq = read_pipe_send(state, ev, state->read_from_child_fd);
|
|
|
6cf099 |
+ if (subreq == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "read_pipe_send failed.\n");
|
|
|
6cf099 |
+ ret = ERR_P11_CHILD;
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ tevent_req_set_callback(subreq, p11_child_done, req);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Now either wait for the timeout to fire or the child
|
|
|
6cf099 |
+ * to finish
|
|
|
6cf099 |
+ */
|
|
|
6cf099 |
+ } else { /* error */
|
|
|
6cf099 |
+ ret = errno;
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "fork failed [%d][%s].\n",
|
|
|
6cf099 |
+ ret, sss_strerror(ret));
|
|
|
6cf099 |
+ goto done;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = EOK;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+done:
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ tevent_req_error(req, ret);
|
|
|
6cf099 |
+ tevent_req_post(req, ev);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ return req;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static void p11_child_write_done(struct tevent_req *subreq)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
|
6cf099 |
+ struct tevent_req);
|
|
|
6cf099 |
+ struct pam_check_cert_state *state = tevent_req_data(req,
|
|
|
6cf099 |
+ struct pam_check_cert_state);
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = write_pipe_recv(subreq);
|
|
|
6cf099 |
+ talloc_zfree(subreq);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ tevent_req_error(req, ret);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ close(state->write_to_child_fd);
|
|
|
6cf099 |
+ state->write_to_child_fd = -1;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ subreq = read_pipe_send(state, state->ev, state->read_from_child_fd);
|
|
|
6cf099 |
+ if (subreq == NULL) {
|
|
|
6cf099 |
+ tevent_req_error(req, ENOMEM);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ tevent_req_set_callback(subreq, p11_child_done, req);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static void p11_child_done(struct tevent_req *subreq)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ uint8_t *buf;
|
|
|
6cf099 |
+ ssize_t buf_len;
|
|
|
6cf099 |
+ struct tevent_req *req = tevent_req_callback_data(subreq,
|
|
|
6cf099 |
+ struct tevent_req);
|
|
|
6cf099 |
+ struct pam_check_cert_state *state = tevent_req_data(req,
|
|
|
6cf099 |
+ struct pam_check_cert_state);
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ talloc_zfree(state->timeout_handler);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = read_pipe_recv(subreq, state, &buf, &buf_len);
|
|
|
6cf099 |
+ talloc_zfree(subreq);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ tevent_req_error(req, ret);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ close(state->read_from_child_fd);
|
|
|
6cf099 |
+ state->read_from_child_fd = -1;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = parse_p11_child_response(state, buf, buf_len, &state->cert,
|
|
|
6cf099 |
+ &state->token_name);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_respose failed.\n");
|
|
|
6cf099 |
+ tevent_req_error(req, ret);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ tevent_req_done(req);
|
|
|
6cf099 |
+ return;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static void p11_child_timeout(struct tevent_context *ev,
|
|
|
6cf099 |
+ struct tevent_timer *te,
|
|
|
6cf099 |
+ struct timeval tv, void *pvt)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
|
|
|
6cf099 |
+ struct pam_check_cert_state *state =
|
|
|
6cf099 |
+ tevent_req_data(req, struct pam_check_cert_state);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for p11_child.\n");
|
|
|
6cf099 |
+ child_handler_destroy(state->child_ctx);
|
|
|
6cf099 |
+ state->child_ctx = NULL;
|
|
|
6cf099 |
+ state->child_status = ETIMEDOUT;
|
|
|
6cf099 |
+ tevent_req_error(req, ERR_P11_CHILD);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
|
|
|
6cf099 |
+ char **cert, char **token_name)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ struct pam_check_cert_state *state =
|
|
|
6cf099 |
+ tevent_req_data(req, struct pam_check_cert_state);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ TEVENT_REQ_RETURN_ON_ERROR(req);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (cert != NULL) {
|
|
|
6cf099 |
+ *cert = talloc_steal(mem_ctx, state->cert);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (token_name != NULL) {
|
|
|
6cf099 |
+ *token_name = talloc_steal(mem_ctx, state->token_name);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return EOK;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+errno_t add_pam_cert_response(struct pam_data *pd, const char *user,
|
|
|
6cf099 |
+ const char *token_name)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ uint8_t *msg = NULL;
|
|
|
6cf099 |
+ size_t user_len;
|
|
|
6cf099 |
+ size_t msg_len;
|
|
|
6cf099 |
+ size_t slot_len;
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (user == NULL || token_name == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n");
|
|
|
6cf099 |
+ return EINVAL;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ user_len = strlen(user) + 1;
|
|
|
6cf099 |
+ slot_len = strlen(token_name) + 1;
|
|
|
6cf099 |
+ msg_len = user_len + slot_len;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ msg = talloc_zero_size(pd, msg_len);
|
|
|
6cf099 |
+ if (msg == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
|
|
|
6cf099 |
+ return ENOMEM;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ memcpy(msg, user, user_len);
|
|
|
6cf099 |
+ memcpy(msg + user_len, token_name, slot_len);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = pam_add_response(pd, SSS_PAM_CERT_INFO, msg_len, msg);
|
|
|
6cf099 |
+ talloc_free(msg);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return ret;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/src/sss_client/sss_cli.h
|
|
|
6cf099 |
+++ b/src/sss_client/sss_cli.h
|
|
|
6cf099 |
@@ -417,6 +417,7 @@ enum response_type {
|
|
|
6cf099 |
* @param Three zero terminated strings, if one of the
|
|
|
6cf099 |
* strings is missing the message will contain only
|
|
|
6cf099 |
* an empty string (\0) for that component. */
|
|
|
6cf099 |
+ SSS_PAM_CERT_INFO,
|
|
|
6cf099 |
SSS_OTP, /**< Indicates that the autotok was a OTP, so don't
|
|
|
6cf099 |
* cache it. There is no message.
|
|
|
6cf099 |
* @param None. */
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/src/tests/cmocka/test_pam_srv.c
|
|
|
6cf099 |
+++ b/src/tests/cmocka/test_pam_srv.c
|
|
|
6cf099 |
@@ -32,7 +32,10 @@
|
|
|
6cf099 |
#include "sss_client/pam_message.h"
|
|
|
6cf099 |
#include "sss_client/sss_cli.h"
|
|
|
6cf099 |
|
|
|
6cf099 |
+#include "util/crypto/sss_crypto.h"
|
|
|
6cf099 |
+#ifdef HAVE_NSS
|
|
|
6cf099 |
#include "util/crypto/nss/nss_util.h"
|
|
|
6cf099 |
+#endif
|
|
|
6cf099 |
|
|
|
6cf099 |
#define TESTS_PATH "tests_pam"
|
|
|
6cf099 |
#define TEST_CONF_DB "test_pam_conf.ldb"
|
|
|
6cf099 |
@@ -40,6 +43,34 @@
|
|
|
6cf099 |
#define TEST_SUBDOM_NAME "test.subdomain"
|
|
|
6cf099 |
#define TEST_ID_PROVIDER "ldap"
|
|
|
6cf099 |
|
|
|
6cf099 |
+#define NSS_DB_PATH "./sssd_test_nssdb"
|
|
|
6cf099 |
+#define NSS_DB "sql:"NSS_DB_PATH
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+#define TEST_TOKEN_NAME "SSSD Test Token"
|
|
|
6cf099 |
+#define TEST_TOKEN_CERT \
|
|
|
6cf099 |
+"MIIECTCCAvGgAwIBAgIBCDANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \
|
|
|
6cf099 |
+"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNTA2MjMx" \
|
|
|
6cf099 |
+"NjMyMDdaFw0xNzA2MjMxNjMyMDdaMDIxEjAQBgNVBAoMCUlQQS5ERVZFTDEcMBoG" \
|
|
|
6cf099 |
+"A1UEAwwTaXBhLWRldmVsLmlwYS5kZXZlbDCCASIwDQYJKoZIhvcNAQEBBQADggEP" \
|
|
|
6cf099 |
+"ADCCAQoCggEBALXUq56VlY+Z0aWLLpFAjFfbElPBXGQsbZb85J3cGyPjaMHC9wS+" \
|
|
|
6cf099 |
+"wjB6Ve4HmQyPLx8hbINdDmbawMHYQvTScLYfsqLtj0Lqw20sUUmedk+Es5Oh9VHo" \
|
|
|
6cf099 |
+"nd8MavYx25Du2u+T0iSgNIDikXguiwCmtAj8VC49ebbgITcjJGzMmiiuJkV3o93Y" \
|
|
|
6cf099 |
+"vvYF0VjLGDQbQWOy7IxzYJeNVJnZWKo67CHdok6qOrm9rxQt81rzwV/mGLbCMUbr" \
|
|
|
6cf099 |
+"+N4M8URtd7EmzaYZQmNm//s2owFrCYMxpLiURPj+URZVuB72504/Ix7X0HCbA/AV" \
|
|
|
6cf099 |
+"26J27fPY5nc8DMwfhUDCbTqPH/JEjd3mvY8CAwEAAaOCASYwggEiMB8GA1UdIwQY" \
|
|
|
6cf099 |
+"MBaAFJOq+KAQmPEnNp8Wok23eGTdE7aDMDsGCCsGAQUFBwEBBC8wLTArBggrBgEF" \
|
|
|
6cf099 |
+"BQcwAYYfaHR0cDovL2lwYS1jYS5pcGEuZGV2ZWwvY2Evb2NzcDAOBgNVHQ8BAf8E" \
|
|
|
6cf099 |
+"BAMCBPAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHQGA1UdHwRtMGsw" \
|
|
|
6cf099 |
+"aaAxoC+GLWh0dHA6Ly9pcGEtY2EuaXBhLmRldmVsL2lwYS9jcmwvTWFzdGVyQ1JM" \
|
|
|
6cf099 |
+"LmJpbqI0pDIwMDEOMAwGA1UECgwFaXBhY2ExHjAcBgNVBAMMFUNlcnRpZmljYXRl" \
|
|
|
6cf099 |
+"IEF1dGhvcml0eTAdBgNVHQ4EFgQUFaDNd5a53QGpaw5m63hnwXicMQ8wDQYJKoZI" \
|
|
|
6cf099 |
+"hvcNAQELBQADggEBADH7Nj00qqGhGJeXJQAsepqSskz/wooqXh8vgVyb8SS4N0/c" \
|
|
|
6cf099 |
+"0aQtVmY81xamlXE12ZFpwDX43d+EufBkwCUKFX/+8JFDd2doAyeJxv1xM22kKRpc" \
|
|
|
6cf099 |
+"AqITPgMsa9ToGMWxjbVpc/X/5YfZixWPF0/eZUTotBj9oaR039UrhGfyN7OguF/G" \
|
|
|
6cf099 |
+"rzmxtB5y4ZrMpcD/Oe90mkd9HY7sA/fB8OWOUgeRfQoh97HNS0UiDWsPtfxmjQG5" \
|
|
|
6cf099 |
+"zotpoBIZmdH+ipYsu58HohHVlM9Wi5H4QmiiXl+Soldkq7eXYlafcmT7wv8+cKwz" \
|
|
|
6cf099 |
+"Nz0Tm3+eYpFqRo3skr6QzXi525Jkg3r6r+kkhxU=" \
|
|
|
6cf099 |
+
|
|
|
6cf099 |
struct pam_test_ctx {
|
|
|
6cf099 |
struct sss_test_ctx *tctx;
|
|
|
6cf099 |
struct sss_domain_info *subdom;
|
|
|
6cf099 |
@@ -56,6 +87,84 @@ struct pam_test_ctx {
|
|
|
6cf099 |
/* Must be global because it is needed in some wrappers */
|
|
|
6cf099 |
struct pam_test_ctx *pam_test_ctx;
|
|
|
6cf099 |
|
|
|
6cf099 |
+static errno_t setup_nss_db(void)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+ FILE *fp;
|
|
|
6cf099 |
+ int status;
|
|
|
6cf099 |
+ pid_t child_pid;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = mkdir(NSS_DB_PATH, 0775);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "Failed to create " NSS_DB_PATH ".\n");
|
|
|
6cf099 |
+ return ret;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ child_pid = fork();
|
|
|
6cf099 |
+ if (child_pid == 0) { /* child */
|
|
|
6cf099 |
+ ret = execlp("certutil", "certutil", "-N", "--empty-password", "-d",
|
|
|
6cf099 |
+ NSS_DB, NULL);
|
|
|
6cf099 |
+ if (ret == -1) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "execl() failed.\n");
|
|
|
6cf099 |
+ exit(-1);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ } else if (child_pid > 0) {
|
|
|
6cf099 |
+ wait(&status);
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ ret = errno;
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "fork() failed\n");
|
|
|
6cf099 |
+ return ret;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ fp = fopen(NSS_DB_PATH"/pkcs11.txt", "w");
|
|
|
6cf099 |
+ if (fp == NULL) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "fopen() failed.\n");
|
|
|
6cf099 |
+ return ret;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ ret = fprintf(fp, "library=libsoftokn3.so\nname=soft\n");
|
|
|
6cf099 |
+ if (ret < 0) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n");
|
|
|
6cf099 |
+ return ret;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/cmocka/p11_nssdb' dbSlotDescription='SSSD Test Slot' dbTokenDescription='SSSD Test Token' secmod='secmod.db' flags=readOnly \n\n", ABS_SRC_DIR);
|
|
|
6cf099 |
+ if (ret < 0) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n");
|
|
|
6cf099 |
+ return ret;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+ ret = fclose(fp);
|
|
|
6cf099 |
+ if (ret != 0) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "fclose() failed.\n");
|
|
|
6cf099 |
+ return ret;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return EOK;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static void cleanup_nss_db(void)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = unlink(NSS_DB_PATH"/cert9.db");
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove cert9.db.\n");
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = unlink(NSS_DB_PATH"/key4.db");
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove key4.db.\n");
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = unlink(NSS_DB_PATH"/pkcs11.txt");
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove pkcs11.db.\n");
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = rmdir(NSS_DB_PATH);
|
|
|
6cf099 |
+ if (ret != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove " NSS_DB_PATH "\n");
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx)
|
|
|
6cf099 |
{
|
|
|
6cf099 |
struct pam_ctx *pctx;
|
|
|
6cf099 |
@@ -113,6 +222,7 @@ void test_pam_setup(struct sss_test_conf_param params[],
|
|
|
6cf099 |
assert_non_null(pam_test_ctx->cctx);
|
|
|
6cf099 |
|
|
|
6cf099 |
pam_test_ctx->cctx->cli_protocol_version = register_cli_protocol_version();
|
|
|
6cf099 |
+ pam_test_ctx->cctx->ev = pam_test_ctx->tctx->ev;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
static int pam_test_setup(void **state)
|
|
|
6cf099 |
@@ -141,6 +251,22 @@ static int pam_test_setup(void **state)
|
|
|
6cf099 |
discard_const("pamuser"),
|
|
|
6cf099 |
pam_test_ctx->pctx->id_timeout);
|
|
|
6cf099 |
assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Prime the cache with a user for wrong matches */
|
|
|
6cf099 |
+ ret = sysdb_add_user(pam_test_ctx->tctx->dom,
|
|
|
6cf099 |
+ "wronguser", 321, 654, "wrong user",
|
|
|
6cf099 |
+ "/home/wringuser", "/bin/sh", NULL,
|
|
|
6cf099 |
+ NULL, 300, 0);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Add entry to the initgr cache to make sure no initgr request is sent to
|
|
|
6cf099 |
+ * the backend */
|
|
|
6cf099 |
+ ret = pam_initgr_cache_set(pam_test_ctx->pctx->rctx->ev,
|
|
|
6cf099 |
+ pam_test_ctx->pctx->id_table,
|
|
|
6cf099 |
+ discard_const("wronguser"),
|
|
|
6cf099 |
+ pam_test_ctx->pctx->id_timeout);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
return 0;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
@@ -151,12 +277,19 @@ static int pam_test_teardown(void **state)
|
|
|
6cf099 |
ret = sysdb_delete_user(pam_test_ctx->tctx->dom, "pamuser", 0);
|
|
|
6cf099 |
assert_int_equal(ret, EOK);
|
|
|
6cf099 |
|
|
|
6cf099 |
+ ret = sysdb_delete_user(pam_test_ctx->tctx->dom, "wronguser", 0);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
talloc_free(pam_test_ctx);
|
|
|
6cf099 |
return 0;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
typedef int (*cmd_cb_fn_t)(uint32_t, uint8_t *, size_t);
|
|
|
6cf099 |
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+int __real_read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
|
|
|
6cf099 |
+ uint8_t **buf, ssize_t *len);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
void __real_sss_packet_get_body(struct sss_packet *packet,
|
|
|
6cf099 |
uint8_t **body, size_t *blen);
|
|
|
6cf099 |
|
|
|
6cf099 |
@@ -239,8 +372,13 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name,
|
|
|
6cf099 |
size_t needed_size;
|
|
|
6cf099 |
uint8_t *authtok;
|
|
|
6cf099 |
|
|
|
6cf099 |
- pi.pam_user = name;
|
|
|
6cf099 |
- pi.pam_user_size = strlen(pi.pam_user) + 1;
|
|
|
6cf099 |
+ if (name != NULL) {
|
|
|
6cf099 |
+ pi.pam_user = name;
|
|
|
6cf099 |
+ pi.pam_user_size = strlen(pi.pam_user) + 1;
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ pi.pam_user = "";
|
|
|
6cf099 |
+ pi.pam_user_size = 0;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
|
|
|
6cf099 |
if (pwd != NULL) {
|
|
|
6cf099 |
if (fa2 != NULL) {
|
|
|
6cf099 |
@@ -287,6 +425,52 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, const char *name,
|
|
|
6cf099 |
will_return(__wrap_sss_packet_get_body, buf_size);
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
+static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name,
|
|
|
6cf099 |
+ const char *pin)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ size_t buf_size;
|
|
|
6cf099 |
+ uint8_t *m_buf;
|
|
|
6cf099 |
+ uint8_t *buf;
|
|
|
6cf099 |
+ struct pam_items pi = { 0 };
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (name != NULL) {
|
|
|
6cf099 |
+ pi.pam_user = name;
|
|
|
6cf099 |
+ pi.pam_user_size = strlen(pi.pam_user) + 1;
|
|
|
6cf099 |
+ } else {
|
|
|
6cf099 |
+ pi.pam_user = "";
|
|
|
6cf099 |
+ pi.pam_user_size = 0;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (pin != NULL) {
|
|
|
6cf099 |
+ pi.pam_authtok = discard_const(pin);
|
|
|
6cf099 |
+ pi.pam_authtok_size = strlen(pi.pam_authtok) + 1;
|
|
|
6cf099 |
+ pi.pam_authtok_type = SSS_AUTHTOK_TYPE_SC_PIN;
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ pi.pam_service = "login";
|
|
|
6cf099 |
+ pi.pam_service_size = strlen(pi.pam_service) + 1;
|
|
|
6cf099 |
+ pi.pam_tty = "/dev/tty";
|
|
|
6cf099 |
+ pi.pam_tty_size = strlen(pi.pam_tty) + 1;
|
|
|
6cf099 |
+ pi.pam_ruser = "remuser";
|
|
|
6cf099 |
+ pi.pam_ruser_size = strlen(pi.pam_ruser) + 1;
|
|
|
6cf099 |
+ pi.pam_rhost = "remhost";
|
|
|
6cf099 |
+ pi.pam_rhost_size = strlen(pi.pam_rhost) + 1;
|
|
|
6cf099 |
+ pi.requested_domains = "";
|
|
|
6cf099 |
+ pi.cli_pid = 12345;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = pack_message_v3(&pi, &buf_size, &m_buf);
|
|
|
6cf099 |
+ assert_int_equal(ret, 0);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ buf = talloc_memdup(mem_ctx, m_buf, buf_size);
|
|
|
6cf099 |
+ free(m_buf);
|
|
|
6cf099 |
+ assert_non_null(buf);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_WRAPPER);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, buf);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, buf_size);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
static int test_pam_simple_check(uint32_t status, uint8_t *body, size_t blen)
|
|
|
6cf099 |
{
|
|
|
6cf099 |
size_t rp = 0;
|
|
|
6cf099 |
@@ -312,6 +496,46 @@ static int test_pam_simple_check(uint32_t status, uint8_t *body, size_t blen)
|
|
|
6cf099 |
return EOK;
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
+static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ size_t rp = 0;
|
|
|
6cf099 |
+ uint32_t val;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ assert_int_equal(status, 0);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
|
|
|
6cf099 |
+ assert_int_equal(val, pam_test_ctx->exp_pam_status);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
|
|
|
6cf099 |
+ assert_int_equal(val, 2);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
|
|
|
6cf099 |
+ assert_int_equal(val, SSS_PAM_DOMAIN_NAME);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
|
|
|
6cf099 |
+ assert_int_equal(val, 9);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ assert_int_equal(*(body + rp + val - 1), 0);
|
|
|
6cf099 |
+ assert_string_equal(body + rp, TEST_DOM_NAME);
|
|
|
6cf099 |
+ rp += val;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
|
|
|
6cf099 |
+ assert_int_equal(val, SSS_PAM_CERT_INFO);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
|
|
|
6cf099 |
+ assert_int_equal(val, (sizeof("pamuser") + sizeof(TEST_TOKEN_NAME)));
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ assert_int_equal(*(body + rp + sizeof("pamuser") - 1), 0);
|
|
|
6cf099 |
+ assert_string_equal(body + rp, "pamuser");
|
|
|
6cf099 |
+ rp += sizeof("pamuser");
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0);
|
|
|
6cf099 |
+ assert_string_equal(body + rp, TEST_TOKEN_NAME);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return EOK;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+
|
|
|
6cf099 |
static int test_pam_offline_chauthtok_check(uint32_t status,
|
|
|
6cf099 |
uint8_t *body, size_t blen)
|
|
|
6cf099 |
{
|
|
|
6cf099 |
@@ -372,6 +596,23 @@ static int test_pam_wrong_pw_offline_auth_check(uint32_t status,
|
|
|
6cf099 |
return test_pam_simple_check(status, body, blen);
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
+static int test_pam_user_unknown_check(uint32_t status,
|
|
|
6cf099 |
+ uint8_t *body, size_t blen)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ size_t rp = 0;
|
|
|
6cf099 |
+ uint32_t val;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ assert_int_equal(status, 0);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
|
|
|
6cf099 |
+ assert_int_equal(val, PAM_USER_UNKNOWN);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
|
|
|
6cf099 |
+ assert_int_equal(val, 0);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return EOK;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
void test_pam_authenticate(void **state)
|
|
|
6cf099 |
{
|
|
|
6cf099 |
int ret;
|
|
|
6cf099 |
@@ -859,6 +1100,245 @@ void test_pam_offline_chauthtok(void **state)
|
|
|
6cf099 |
assert_int_equal(ret, EOK);
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
+static void set_cert_auth_param(struct pam_ctx *pctx, const char *dbpath)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ pam_test_ctx->pctx->cert_auth = true;
|
|
|
6cf099 |
+ pam_test_ctx->pctx->nss_db = discard_const(dbpath);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+void test_pam_preauth_cert_nocert(void **state)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cert_auth_param(pam_test_ctx->pctx, "/no/path");
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cmd_cb(test_pam_simple_check);
|
|
|
6cf099 |
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
|
|
|
6cf099 |
+ pam_test_ctx->pam_cmds);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Wait until the test finishes with EOK */
|
|
|
6cf099 |
+ ret = test_ev_loop(pam_test_ctx->tctx);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static int test_lookup_by_cert_cb(void *pvt)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+ struct sysdb_attrs *attrs;
|
|
|
6cf099 |
+ unsigned char *der = NULL;
|
|
|
6cf099 |
+ size_t der_size;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (pvt != NULL) {
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ attrs = sysdb_new_attrs(pam_test_ctx);
|
|
|
6cf099 |
+ assert_non_null(attrs);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ der = sss_base64_decode(pam_test_ctx, pvt, &der_size);
|
|
|
6cf099 |
+ assert_non_null(der);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
|
|
|
6cf099 |
+ talloc_free(der);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = sysdb_set_user_attr(pam_test_ctx->tctx->dom, "pamuser", attrs,
|
|
|
6cf099 |
+ LDB_FLAG_MOD_ADD);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return EOK;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+static int test_lookup_by_cert_wrong_user_cb(void *pvt)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+ struct sysdb_attrs *attrs;
|
|
|
6cf099 |
+ unsigned char *der = NULL;
|
|
|
6cf099 |
+ size_t der_size;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ if (pvt != NULL) {
|
|
|
6cf099 |
+ attrs = sysdb_new_attrs(pam_test_ctx);
|
|
|
6cf099 |
+ assert_non_null(attrs);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ der = sss_base64_decode(pam_test_ctx, pvt, &der_size);
|
|
|
6cf099 |
+ assert_non_null(der);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size);
|
|
|
6cf099 |
+ talloc_free(der);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ ret = sysdb_set_user_attr(pam_test_ctx->tctx->dom, "wronguser", attrs,
|
|
|
6cf099 |
+ LDB_FLAG_MOD_ADD);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ return EOK;
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+void test_pam_preauth_cert_nomatch(void **state)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
6cf099 |
+ mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb, NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cmd_cb(test_pam_simple_check);
|
|
|
6cf099 |
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
|
|
|
6cf099 |
+ pam_test_ctx->pam_cmds);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Wait until the test finishes with EOK */
|
|
|
6cf099 |
+ ret = test_ev_loop(pam_test_ctx->tctx);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+void test_pam_preauth_cert_match(void **state)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
6cf099 |
+ mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb,
|
|
|
6cf099 |
+ discard_const(TEST_TOKEN_CERT));
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cmd_cb(test_pam_cert_check);
|
|
|
6cf099 |
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
|
|
|
6cf099 |
+ pam_test_ctx->pam_cmds);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Wait until the test finishes with EOK */
|
|
|
6cf099 |
+ ret = test_ev_loop(pam_test_ctx->tctx);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+void test_pam_preauth_cert_match_wrong_user(void **state)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
6cf099 |
+ mock_account_recv(0, 0, NULL, test_lookup_by_cert_wrong_user_cb,
|
|
|
6cf099 |
+ discard_const(TEST_TOKEN_CERT));
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cmd_cb(test_pam_simple_check);
|
|
|
6cf099 |
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
|
|
|
6cf099 |
+ pam_test_ctx->pam_cmds);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Wait until the test finishes with EOK */
|
|
|
6cf099 |
+ ret = test_ev_loop(pam_test_ctx->tctx);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+void test_pam_preauth_cert_no_logon_name(void **state)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ mock_input_pam_cert(pam_test_ctx, NULL, NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
6cf099 |
+ mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb,
|
|
|
6cf099 |
+ discard_const(TEST_TOKEN_CERT));
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cmd_cb(test_pam_cert_check);
|
|
|
6cf099 |
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
|
|
|
6cf099 |
+ pam_test_ctx->pam_cmds);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Wait until the test finishes with EOK */
|
|
|
6cf099 |
+ ret = test_ev_loop(pam_test_ctx->tctx);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+void test_pam_preauth_no_cert_no_logon_name(void **state)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cert_auth_param(pam_test_ctx->pctx, "/no/path");
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ mock_input_pam_cert(pam_test_ctx, NULL, NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cmd_cb(test_pam_user_unknown_check);
|
|
|
6cf099 |
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
|
|
|
6cf099 |
+ pam_test_ctx->pam_cmds);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Wait until the test finishes with EOK */
|
|
|
6cf099 |
+ ret = test_ev_loop(pam_test_ctx->tctx);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+void test_pam_preauth_cert_no_logon_name_no_match(void **state)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ mock_input_pam_cert(pam_test_ctx, NULL, NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
6cf099 |
+ mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb, NULL);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cmd_cb(test_pam_user_unknown_check);
|
|
|
6cf099 |
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
|
|
|
6cf099 |
+ pam_test_ctx->pam_cmds);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Wait until the test finishes with EOK */
|
|
|
6cf099 |
+ ret = test_ev_loop(pam_test_ctx->tctx);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+void test_pam_cert_auth(void **state)
|
|
|
6cf099 |
+{
|
|
|
6cf099 |
+ int ret;
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ mock_input_pam_cert(pam_test_ctx, "pamuser", "123456");
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE);
|
|
|
6cf099 |
+ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);
|
|
|
6cf099 |
+ mock_account_recv(0, 0, NULL, test_lookup_by_cert_cb,
|
|
|
6cf099 |
+ discard_const(TEST_TOKEN_CERT));
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ set_cmd_cb(test_pam_simple_check);
|
|
|
6cf099 |
+ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE,
|
|
|
6cf099 |
+ pam_test_ctx->pam_cmds);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+
|
|
|
6cf099 |
+ /* Wait until the test finishes with EOK */
|
|
|
6cf099 |
+ ret = test_ev_loop(pam_test_ctx->tctx);
|
|
|
6cf099 |
+ assert_int_equal(ret, EOK);
|
|
|
6cf099 |
+}
|
|
|
6cf099 |
+
|
|
|
6cf099 |
int main(int argc, const char *argv[])
|
|
|
6cf099 |
{
|
|
|
6cf099 |
int rv;
|
|
|
6cf099 |
@@ -925,6 +1405,23 @@ int main(int argc, const char *argv[])
|
|
|
6cf099 |
pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
cmocka_unit_test_setup_teardown(test_pam_offline_chauthtok,
|
|
|
6cf099 |
pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
+ cmocka_unit_test_setup_teardown(test_pam_preauth_cert_nocert,
|
|
|
6cf099 |
+ pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
+ cmocka_unit_test_setup_teardown(test_pam_preauth_cert_nomatch,
|
|
|
6cf099 |
+ pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
+ cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match,
|
|
|
6cf099 |
+ pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
+ cmocka_unit_test_setup_teardown(test_pam_preauth_cert_match_wrong_user,
|
|
|
6cf099 |
+ pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
+ cmocka_unit_test_setup_teardown(test_pam_preauth_cert_no_logon_name,
|
|
|
6cf099 |
+ pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
+ cmocka_unit_test_setup_teardown(test_pam_preauth_no_cert_no_logon_name,
|
|
|
6cf099 |
+ pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
+ cmocka_unit_test_setup_teardown(
|
|
|
6cf099 |
+ test_pam_preauth_cert_no_logon_name_no_match,
|
|
|
6cf099 |
+ pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
+ cmocka_unit_test_setup_teardown(test_pam_cert_auth,
|
|
|
6cf099 |
+ pam_test_setup, pam_test_teardown),
|
|
|
6cf099 |
};
|
|
|
6cf099 |
|
|
|
6cf099 |
/* Set debug level to invalid value so we can deside if -d 0 was used. */
|
|
|
6cf099 |
@@ -950,8 +1447,16 @@ int main(int argc, const char *argv[])
|
|
|
6cf099 |
test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
|
|
|
6cf099 |
test_dom_suite_setup(TESTS_PATH);
|
|
|
6cf099 |
|
|
|
6cf099 |
+ cleanup_nss_db();
|
|
|
6cf099 |
+ rv = setup_nss_db();
|
|
|
6cf099 |
+ if (rv != EOK) {
|
|
|
6cf099 |
+ DEBUG(SSSDBG_FATAL_FAILURE, "setup_nss_db failed.\n");
|
|
|
6cf099 |
+ exit(-1);
|
|
|
6cf099 |
+ }
|
|
|
6cf099 |
+
|
|
|
6cf099 |
rv = cmocka_run_group_tests(tests, NULL, NULL);
|
|
|
6cf099 |
if (rv == 0 && !no_cleanup) {
|
|
|
6cf099 |
+ cleanup_nss_db();
|
|
|
6cf099 |
test_dom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, TEST_DOM_NAME);
|
|
|
6cf099 |
}
|
|
|
6cf099 |
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/src/util/util_errors.c
|
|
|
6cf099 |
+++ b/src/util/util_errors.c
|
|
|
6cf099 |
@@ -78,6 +78,7 @@ struct err_string error_to_str[] = {
|
|
|
6cf099 |
{ "Unsupported trust direction" }, /* ERR_TRUST_NOT_SUPPORTED */
|
|
|
6cf099 |
{ "Retrieving keytab failed" }, /* ERR_IPA_GETKEYTAB_FAILED */
|
|
|
6cf099 |
{ "Trusted forest root unknown" }, /* ERR_TRUST_FOREST_UNKNOWN */
|
|
|
6cf099 |
+ { "p11_child failed" }, /* ERR_P11_CHILD */
|
|
|
6cf099 |
{ "ERR_LAST" } /* ERR_LAST */
|
|
|
6cf099 |
};
|
|
|
6cf099 |
|
|
|
6cf099 |
only in patch2:
|
|
|
6cf099 |
unchanged:
|
|
|
6cf099 |
--- a/src/util/util_errors.h
|
|
|
6cf099 |
+++ b/src/util/util_errors.h
|
|
|
6cf099 |
@@ -100,6 +100,7 @@ enum sssd_errors {
|
|
|
6cf099 |
ERR_TRUST_NOT_SUPPORTED,
|
|
|
6cf099 |
ERR_IPA_GETKEYTAB_FAILED,
|
|
|
6cf099 |
ERR_TRUST_FOREST_UNKNOWN,
|
|
|
6cf099 |
+ ERR_P11_CHILD,
|
|
|
6cf099 |
ERR_LAST /* ALWAYS LAST */
|
|
|
6cf099 |
};
|
|
|
6cf099 |
|