diff --git a/0001-KCM-Fix-typo-in-comments.patch b/0001-KCM-Fix-typo-in-comments.patch new file mode 100644 index 0000000..d4cbd46 --- /dev/null +++ b/0001-KCM-Fix-typo-in-comments.patch @@ -0,0 +1,38 @@ +From fd7226ff51eb9af70d0fcb63727cd1a48ab0534b Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 23 Oct 2017 07:35:52 +0200 +Subject: [PATCH 01/79] KCM: Fix typo in comments +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +--- + src/responder/kcm/kcmsrv_ccache_json.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c +index 8199bc613e4204859438e1cd820f3f4b2123dd7e..f1cca9880d128d05ad1edfc5c3b2f709d1a67d48 100644 +--- a/src/responder/kcm/kcmsrv_ccache_json.c ++++ b/src/responder/kcm/kcmsrv_ccache_json.c +@@ -265,7 +265,7 @@ static json_t *princ_data_to_json(TALLOC_CTX *mem_ctx, + * { + * "type": "number", + * "realm": "string", +- * "componenents": [ "elem1", "elem2", ...] ++ * "components": [ "elem1", "elem2", ...] + * } + */ + static json_t *princ_to_json(TALLOC_CTX *mem_ctx, +@@ -400,7 +400,7 @@ static json_t *creds_to_json_array(struct kcm_cred *creds) + * principal : { + * "type": "number", + * "realm": "string", +- * "componenents": [ "elem1", "elem2", ...] ++ * "components": [ "elem1", "elem2", ...] + * } + * creds : [ + * { +-- +2.15.1 + diff --git a/0002-Fix-minor-spelling-mistakes.patch b/0002-Fix-minor-spelling-mistakes.patch new file mode 100644 index 0000000..984c8ec --- /dev/null +++ b/0002-Fix-minor-spelling-mistakes.patch @@ -0,0 +1,556 @@ +From aeb34cfcb9ded4cd7d272220a3d3802be89b7dd8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ren=C3=A9=20Genz?= +Date: Sun, 22 Oct 2017 22:24:27 +0200 +Subject: [PATCH 02/79] Fix minor spelling mistakes +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Merges: https://pagure.io/SSSD/sssd/pull-request/3556 + +Reviewed-by: Lukáš Slebodník +--- + contrib/sssd.spec.in | 6 +++--- + src/db/sysdb_private.h | 2 +- + src/db/sysdb_views.c | 4 ++-- + src/examples/sssd-example.conf | 2 +- + src/lib/idmap/sss_idmap.doxy.in | 2 +- + src/man/sssd-secrets.5.xml | 2 +- + src/providers/ad/ad_gpo.c | 4 ++-- + src/providers/be_dyndns.c | 2 +- + src/providers/data_provider/dp_request.c | 2 +- + src/providers/krb5/krb5_child.c | 2 +- + src/providers/ldap/sdap_async_sudo.c | 2 +- + src/responder/kcm/kcmsrv_ccache_json.c | 2 +- + src/responder/kcm/kcmsrv_op_queue.c | 4 ++-- + src/sbus/sssd_dbus_connection.c | 4 ++-- + src/shared/safealign.h | 4 ++-- + src/sss_client/autofs/sss_autofs.c | 4 ++-- + src/sss_client/idmap/sss_nss_idmap.doxy.in | 2 +- + src/sss_client/libwbclient/wbc_pwd_sssd.c | 2 +- + src/sss_client/sudo/sss_sudo.h | 10 +++++----- + src/tests/cmocka/common_mock_resp_dp.c | 2 +- + src/tests/cmocka/test_sbus_opath.c | 2 +- + src/tools/common/sss_process.c | 2 +- + src/tools/common/sss_process.h | 2 +- + src/tools/sssctl/sssctl.c | 4 ++-- + src/tools/sssctl/sssctl_data.c | 2 +- + src/util/crypto/libcrypto/crypto_sha512crypt.c | 2 +- + src/util/crypto/nss/nss_sha512crypt.c | 2 +- + src/util/server.c | 6 +++--- + src/util/sss_ini.h | 2 +- + src/util/tev_curl.c | 2 +- + src/util/util_lock.c | 2 +- + 31 files changed, 46 insertions(+), 46 deletions(-) + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index e76b51833d5dfa3207d28add4af1016c00f25e1f..d6ab73e60863316cbf239d34242959fdfe8d4b1b 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -241,7 +241,7 @@ the system and a pluggable backend system to connect to multiple different + account sources. It is also the basis to provide client auditing and policy + services for projects like FreeIPA. + +-The sssd subpackage is a meta-package that contains the deamon as well as all ++The sssd subpackage is a meta-package that contains the daemon as well as all + the existing back ends. + + %package common +@@ -496,7 +496,7 @@ Requires(post): /sbin/ldconfig + Requires(postun): /sbin/ldconfig + + %description -n libsss_idmap +-Utility library to convert SIDs to Unix uids and gids ++Utility library to convert SIDs to UNIX UIDs and GIDs + + %package -n libsss_idmap-devel + Summary: FreeIPA Idmap library +@@ -505,7 +505,7 @@ License: LGPLv3+ + Requires: libsss_idmap = %{version}-%{release} + + %description -n libsss_idmap-devel +-Utility library to SIDs to Unix uids and gids ++Utility library to SIDs to UNIX UIDs and GIDs + + %package -n libipa_hbac + Summary: FreeIPA HBAC Evaluator library +diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h +index dbd75615bc212e73c4338a76dceaa68a5889ed1d..7c3347fec99f60160804a6eed178baedafb81d33 100644 +--- a/src/db/sysdb_private.h ++++ b/src/db/sysdb_private.h +@@ -185,7 +185,7 @@ int sysdb_delete_ulong(struct ldb_message *msg, + + /* The utility function to create a subdomain sss_domain_info object is handy + * for unit tests, so it should be available in a header, but not a public util +- * one, because the only interface for the deamon itself should be adding ++ * one, because the only interface for the daemon itself should be adding + * the sysdb domain object and calling sysdb_update_subdomains() + */ + struct sss_domain_info *new_subdomain(TALLOC_CTX *mem_ctx, +diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c +index afc7852ecf402ef144beca9c1b94fbe3cc4bbb6a..f640c813acf4deafe98eb15708d3a94790502dcb 100644 +--- a/src/db/sysdb_views.c ++++ b/src/db/sysdb_views.c +@@ -722,7 +722,7 @@ static errno_t safe_original_attributes(struct sss_domain_info *domain, + goto done; + } + +- /* Safe orginal values in attributes prefixed by OriginalAD. */ ++ /* Safe original values in attributes prefixed by OriginalAD. */ + for (c = 0; allowed_attrs[c] != NULL; c++) { + el = ldb_msg_find_element(orig_obj->msgs[0], allowed_attrs[c]); + if (el != NULL) { +@@ -753,7 +753,7 @@ static errno_t safe_original_attributes(struct sss_domain_info *domain, + el = ldb_msg_find_element(orig_obj->msgs[0], SYSDB_NAME_ALIAS); + if (el != NULL) { + for (c = 0; c < el->num_values; c++) { +- /* To avoid issue with ldb_modify if e.g. the orginal and the ++ /* To avoid issue with ldb_modify if e.g. the original and the + * override name are the same, we use the *_safe version here. */ + ret = sysdb_attrs_add_val_safe(attrs, SYSDB_NAME_ALIAS, + &el->values[c]); +diff --git a/src/examples/sssd-example.conf b/src/examples/sssd-example.conf +index 59df41673586d5c7d2602cc5290c40ec5bd64986..34b2b22c5f619f49bb9aa1edf04849df5e40c787 100644 +--- a/src/examples/sssd-example.conf ++++ b/src/examples/sssd-example.conf +@@ -32,7 +32,7 @@ services = nss, pam + # An example Active Directory domain. Please note that this configuration + # works for AD 2003R2 and AD 2008, because they use pretty much RFC2307bis + # compliant attribute names. To support UNIX clients with AD 2003 or older, +-# you must install Microsoft Services For Unix and map LDAP attributes onto ++# you must install Microsoft Services For UNIX and map LDAP attributes onto + # msSFU30* attribute names. + ; [domain/AD] + ; id_provider = ldap +diff --git a/src/lib/idmap/sss_idmap.doxy.in b/src/lib/idmap/sss_idmap.doxy.in +index 991028f65c251e2bc0086487817271b527fa439b..833498b189a038a06414ff623179ef69d24affb7 100644 +--- a/src/lib/idmap/sss_idmap.doxy.in ++++ b/src/lib/idmap/sss_idmap.doxy.in +@@ -719,7 +719,7 @@ RECURSIVE = NO + EXCLUDE = + + # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +-# directories that are symbolic links (a Unix file system feature) are excluded ++# directories that are symbolic links (a UNIX file system feature) are excluded + # from the input. + + EXCLUDE_SYMLINKS = NO +diff --git a/src/man/sssd-secrets.5.xml b/src/man/sssd-secrets.5.xml +index 08ab371c64eb49e4f153bb2183c07681b1050bb0..a738fbfffa1bdb7038e70a4a49651eb6a9286b1c 100644 +--- a/src/man/sssd-secrets.5.xml ++++ b/src/man/sssd-secrets.5.xml +@@ -46,7 +46,7 @@ + project was born to deal with this problem in cloud like + environments, but we found the idea compelling even at a + single system level. As a security service, SSSD is ideal to +- host this capability while offering the same API via a Unix ++ host this capability while offering the same API via a UNIX + Socket. This will make it possible to use local calls and have + them transparently routed to a local or a remote key management + store like IPA Vault for storage, escrow and recovery. +diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c +index a5237f6fad7fc79fbcbafc8aac28cff15677009f..d9ea311417fc5d57850aa9a6c3736964844675bd 100644 +--- a/src/providers/ad/ad_gpo.c ++++ b/src/providers/ad/ad_gpo.c +@@ -680,7 +680,7 @@ ad_gpo_ace_includes_client_sid(const char *user_sid, + * named "ApplyGroupPolicy" (AGP) is allowed, by comparing the specified + * user_sid and group_sids against the specified access control entry (ACE). + * This function returns ALLOWED, DENIED, or NEUTRAL depending on whether +- * the ACE explictly allows, explicitly denies, or does neither. ++ * the ACE explicitly allows, explicitly denies, or does neither. + * + * Note that the 'M' abbreviation used in the evaluation algorithm stands for + * "access_mask", which represents the set of access rights associated with an +@@ -3860,7 +3860,7 @@ ad_gpo_sd_process_attrs(struct tevent_req *req, + ret = sysdb_attrs_get_int32_t(result, AD_AT_FUNC_VERSION, + &gp_gpo->gpo_func_version); + if (ret == ENOENT) { +- /* If this attrbute is missing we can skip the GPO. It will ++ /* If this attribute is missing we can skip the GPO. It will + * be filtered out according to MS-GPOL: + * https://msdn.microsoft.com/en-us/library/cc232538.aspx */ + DEBUG(SSSDBG_TRACE_ALL, "GPO with GUID %s is missing attribute " +diff --git a/src/providers/be_dyndns.c b/src/providers/be_dyndns.c +index ee264156824d7c5ab27c919ae0c56bbd6c0bc54f..b968e67b3e3e6a4f2937dce502c2c9b4ad136a4b 100644 +--- a/src/providers/be_dyndns.c ++++ b/src/providers/be_dyndns.c +@@ -706,7 +706,7 @@ nsupdate_get_addrs_done(struct tevent_req *subreq) + return; + } + +- /* The second address matched either immediatelly or after a retry. ++ /* The second address matched either immediately or after a retry. + * No need to retry again. */ + ret = EOK; + +diff --git a/src/providers/data_provider/dp_request.c b/src/providers/data_provider/dp_request.c +index a6bc020e0649760c46637d6f90569248792f7f04..295758a765bfdedd539d44f86a37efae0846763f 100644 +--- a/src/providers/data_provider/dp_request.c ++++ b/src/providers/data_provider/dp_request.c +@@ -412,7 +412,7 @@ static void dp_terminate_request(struct dp_req *dp_req) + { + if (dp_req->handler_req == NULL) { + /* This may occur when the handler already finished but the caller +- * of dp request did not yet recieved data/free dp_req. We just ++ * of dp request did not yet received data/free dp_req. We just + * return here. */ + return; + } +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 888cc5d6f5c554901cc46d4315844d7bbbe582b8..b8ee497728b4b70fae89e528172e9d5bd42239c0 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -1612,7 +1612,7 @@ static krb5_error_code get_and_save_tgt(struct krb5_req *kr, + goto done; + } + +- /* Successfull authentication! Check if ccache contains the ++ /* Successful authentication! Check if ccache contains the + * right principal... + */ + kerr = sss_krb5_check_ccache_princ(kr->ctx, kr->ccname, kr->creds->client); +diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c +index 3c69837fda313b2645c3a8497252670312f600ea..f33d5b5fa86dc1806695482d627bd71a2b040d6e 100644 +--- a/src/providers/ldap/sdap_async_sudo.c ++++ b/src/providers/ldap/sdap_async_sudo.c +@@ -616,7 +616,7 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) + } + in_transaction = false; + +- DEBUG(SSSDBG_TRACE_FUNC, "Sudoers is successfuly stored in cache\n"); ++ DEBUG(SSSDBG_TRACE_FUNC, "Sudoers is successfully stored in cache\n"); + + /* remember new usn */ + ret = sysdb_get_highest_usn(state, rules, rules_count, &usn); +diff --git a/src/responder/kcm/kcmsrv_ccache_json.c b/src/responder/kcm/kcmsrv_ccache_json.c +index f1cca9880d128d05ad1edfc5c3b2f709d1a67d48..33cb51621f26a11051e2fac4c5d7c959b30d9f00 100644 +--- a/src/responder/kcm/kcmsrv_ccache_json.c ++++ b/src/responder/kcm/kcmsrv_ccache_json.c +@@ -210,7 +210,7 @@ bool sec_key_match_uuid(const char *sec_key, + /* + * Creates an array of principal elements that will be used later + * in the form of: +- * "componenets": [ "elem1", "elem2", ...] ++ * "components": [ "elem1", "elem2", ...] + */ + static json_t *princ_data_to_json(TALLOC_CTX *mem_ctx, + krb5_principal princ) +diff --git a/src/responder/kcm/kcmsrv_op_queue.c b/src/responder/kcm/kcmsrv_op_queue.c +index 55c8b65d94f70979fe56fcc4d8747547a9cc9d33..ee1aa47ab629022bb726c4d5deb1eb1456124df1 100644 +--- a/src/responder/kcm/kcmsrv_op_queue.c ++++ b/src/responder/kcm/kcmsrv_op_queue.c +@@ -179,7 +179,7 @@ static struct kcm_ops_queue *kcm_op_queue_get(struct kcm_ops_queue_ctx *qctx, + case HASH_ERROR_KEY_NOT_FOUND: + /* No request for this UID yet. Enqueue this request in case + * another one comes in and return EOK to run the current request +- * immediatelly ++ * immediately + */ + DEBUG(SSSDBG_TRACE_LIBS, "No existing queue for this ID\n"); + +@@ -220,7 +220,7 @@ static errno_t kcm_op_queue_add_req(struct kcm_ops_queue *kq, + * Enqueue a request. + * + * If the request queue /for the given ID/ is empty, that is, if this +- * request is the first one in the queue, run the request immediatelly. ++ * request is the first one in the queue, run the request immediately. + * + * Otherwise just add it to the queue and wait until the previous request + * finishes and only at that point mark the current request as done, which +diff --git a/src/sbus/sssd_dbus_connection.c b/src/sbus/sssd_dbus_connection.c +index de134f2f21bfb9697fcc8a42622817bc50b54f2a..bdd4a247a670f1928573a1bd18dc8e585b997b7d 100644 +--- a/src/sbus/sssd_dbus_connection.c ++++ b/src/sbus/sssd_dbus_connection.c +@@ -179,7 +179,7 @@ int sbus_init_connection(TALLOC_CTX *ctx, + + conn->incoming_signals = sbus_incoming_signal_hash_init(conn); + if (conn->incoming_signals == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create incoming singals " ++ DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create incoming signals " + "hash table\n"); + talloc_free(conn); + return EIO; +@@ -327,7 +327,7 @@ static int connection_destructor(void *ctx) + + /* + * sbus_get_connection +- * Utility function to retreive the DBusConnection object ++ * Utility function to retrieve the DBusConnection object + * from a sbus_connection + */ + DBusConnection *sbus_get_connection(struct sbus_connection *conn) +diff --git a/src/shared/safealign.h b/src/shared/safealign.h +index 2316ed14245c4469171f9eb4a42e70fc6b3fd8a8..b00c37f5b98bd4bf7ff6cea8e1208d80c77f0228 100644 +--- a/src/shared/safealign.h ++++ b/src/shared/safealign.h +@@ -98,8 +98,8 @@ safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter) + SAFEALIGN_SETMEM_VALUE(dest, value, uint16_t, pctr) + + /* These macros are the same as their equivalents without _CHECK suffix, +- * but additionally make the caller return EINVAL immediatelly if *pctr +- * would excceed len. */ ++ * but additionally make the caller return EINVAL immediately if *pctr ++ * would exceed len. */ + #define SAFEALIGN_COPY_UINT32_CHECK(dest, src, len, pctr) do { \ + if ((*(pctr) + sizeof(uint32_t)) > (len) || \ + SIZE_T_OVERFLOW(*(pctr), sizeof(uint32_t))) { return EINVAL; } \ +diff --git a/src/sss_client/autofs/sss_autofs.c b/src/sss_client/autofs/sss_autofs.c +index 02f91ab2b3d29a189e949f6a8d645ea4ccd7f6e3..482ff2c400b10829ccb6d6a921c8c2e15c7fcdd2 100644 +--- a/src/sss_client/autofs/sss_autofs.c ++++ b/src/sss_client/autofs/sss_autofs.c +@@ -30,7 +30,7 @@ + #define MAX_AUTOMNTMAPNAME_LEN NAME_MAX + #define MAX_AUTOMNTKEYNAME_LEN PATH_MAX + +-/* How many entries shall _sss_getautomntent_r retreive at once */ ++/* How many entries shall _sss_getautomntent_r retrieve at once */ + #define GETAUTOMNTENT_MAX_ENTRIES 512 + + struct automtent { +@@ -287,7 +287,7 @@ _sss_getautomntent_r(char **key, char **value, void *context) + data_len = sizeof(uint32_t) + /* mapname len */ + name_len + 1 + /* mapname\0 */ + sizeof(uint32_t) + /* index into the map */ +- sizeof(uint32_t); /* num entries to retreive */ ++ sizeof(uint32_t); /* num entries to retrieve */ + + data = malloc(data_len); + if (!data) { +diff --git a/src/sss_client/idmap/sss_nss_idmap.doxy.in b/src/sss_client/idmap/sss_nss_idmap.doxy.in +index d75237622507d2a43ef382815544b8339054f474..f6c18ba1f0d368e989ce0d18a500b6523622b9c1 100644 +--- a/src/sss_client/idmap/sss_nss_idmap.doxy.in ++++ b/src/sss_client/idmap/sss_nss_idmap.doxy.in +@@ -616,7 +616,7 @@ RECURSIVE = NO + EXCLUDE = + + # The EXCLUDE_SYMLINKS tag can be used select whether or not files or +-# directories that are symbolic links (a Unix filesystem feature) are excluded ++# directories that are symbolic links (a UNIX filesystem feature) are excluded + # from the input. + + EXCLUDE_SYMLINKS = NO +diff --git a/src/sss_client/libwbclient/wbc_pwd_sssd.c b/src/sss_client/libwbclient/wbc_pwd_sssd.c +index 08c3b86372c86f228aeeb584068f82bd97cfe0fe..cacad9d3230c341ae478a4e4e41864ecdc4209b3 100644 +--- a/src/sss_client/libwbclient/wbc_pwd_sssd.c ++++ b/src/sss_client/libwbclient/wbc_pwd_sssd.c +@@ -606,7 +606,7 @@ wbcErr wbcGetgrlist(struct group **grp) + WBC_SSSD_NOT_IMPLEMENTED; + } + +-/* Return the unix group array belonging to the given user */ ++/* Return the Unix group array belonging to the given user */ + wbcErr wbcGetGroups(const char *account, + uint32_t *num_groups, + gid_t **_groups) +diff --git a/src/sss_client/sudo/sss_sudo.h b/src/sss_client/sudo/sss_sudo.h +index 1a275cfafbb0476b163599854cbbc1f91101f360..1dcd569a59cde2eec88476aef2bc3ab35a089c86 100644 +--- a/src/sss_client/sudo/sss_sudo.h ++++ b/src/sss_client/sudo/sss_sudo.h +@@ -87,11 +87,11 @@ struct sss_sudo_result { + }; + + /** +- * @brief Send a request to SSSD to retreive all SUDO rules for a given ++ * @brief Send a request to SSSD to retrieve all SUDO rules for a given + * user. + * +- * @param[in] uid The uid of the user to retreive the rules for. +- * @param[in] username The username to retreive the rules for ++ * @param[in] uid The uid of the user to retrieve the rules for. ++ * @param[in] username The username to retrieve the rules for + * @param[in] domainname The domain name the user is a member of. + * @param[out] _error The result of the search in SSSD's domains. If the + * user was present in the domain, the _error code is +@@ -122,9 +122,9 @@ int sss_sudo_send_recv(uid_t uid, + * @brief Send a request to SSSD to retrieve the default options, commonly + * stored in the "cn=defaults" record, + * +- * @param[in] uid The uid of the user to retreive the rules for. ++ * @param[in] uid The uid of the user to retrieve the rules for. + * +- * @param[in] username The username to retreive the rules for. ++ * @param[in] username The username to retrieve the rules for. + * + * @param[out] _error The result of the search in SSSD's domains. If the + * options were present in the domain, the _error code +diff --git a/src/tests/cmocka/common_mock_resp_dp.c b/src/tests/cmocka/common_mock_resp_dp.c +index 4b38a38e6f53499132f9fe14a0ec0af157cf85ca..ece887b12d472c3fb01477d213f4308a535f8fe7 100644 +--- a/src/tests/cmocka/common_mock_resp_dp.c ++++ b/src/tests/cmocka/common_mock_resp_dp.c +@@ -24,7 +24,7 @@ + #include "responder/common/responder.h" + #include "tests/cmocka/common_mock_resp.h" + +-/* Mock DP requests that finish immediatelly and return ++/* Mock DP requests that finish immediately and return + * mocked values as per previous set by mock_account_recv + */ + struct tevent_req * +diff --git a/src/tests/cmocka/test_sbus_opath.c b/src/tests/cmocka/test_sbus_opath.c +index e38eaf1972b55f01d712584b67c731ac0031736d..b469fa8da90b6f54e15a590014be650e32221136 100644 +--- a/src/tests/cmocka/test_sbus_opath.c ++++ b/src/tests/cmocka/test_sbus_opath.c +@@ -72,7 +72,7 @@ void test_sbus_opath_escape_unescape(void **state) + + escaped = sbus_opath_escape_part(mem_ctx, "path_with_underscore"); + assert_non_null(escaped); +- /* underscore is 0x5F in ascii */ ++ /* underscore is 0x5F in ASCII */ + assert_string_equal(escaped, "path_5fwith_5funderscore"); + raw = sbus_opath_unescape_part(mem_ctx, escaped); + talloc_free(escaped); +diff --git a/src/tools/common/sss_process.c b/src/tools/common/sss_process.c +index 574ccab24d0ff20784f6223e743bf9561ea2281e..fc710a553dbf6a27e23693be79bb333dcbcd3a3e 100644 +--- a/src/tools/common/sss_process.c ++++ b/src/tools/common/sss_process.c +@@ -97,7 +97,7 @@ done: + return ret; + } + +-bool sss_deamon_running(void) ++bool sss_daemon_running(void) + { + return sss_signal(0) == EOK; + } +diff --git a/src/tools/common/sss_process.h b/src/tools/common/sss_process.h +index 43408afc7fab3caed3febd1a159dbfc6acbbb3f9..6bbb0947570a5fc9e77b479c7386db1cead05aaf 100644 +--- a/src/tools/common/sss_process.h ++++ b/src/tools/common/sss_process.h +@@ -23,7 +23,7 @@ + + #include "util/util.h" + +-bool sss_deamon_running(void); ++bool sss_daemon_running(void); + errno_t sss_signal(int signum); + + #endif /* _SSS_PROCESS_H_ */ +diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c +index 1e061c00d2238bf34adff4183e560dc127dd62c7..d9bc897c1a32954bbdd2d4ae2b0a9fb6d2c34752 100644 +--- a/src/tools/sssctl/sssctl.c ++++ b/src/tools/sssctl/sssctl.c +@@ -148,7 +148,7 @@ bool sssctl_start_sssd(bool force) + enum sssctl_prompt_result prompt; + errno_t ret; + +- if (sss_deamon_running()) { ++ if (sss_daemon_running()) { + return true; + } + +@@ -187,7 +187,7 @@ bool sssctl_stop_sssd(bool force) + enum sssctl_prompt_result prompt; + errno_t ret; + +- if (!sss_deamon_running()) { ++ if (!sss_daemon_running()) { + return true; + } + +diff --git a/src/tools/sssctl/sssctl_data.c b/src/tools/sssctl/sssctl_data.c +index 4b7f1dfff666743f9c47bc34515bbe63ee85eff1..b16fede1e2f3f743f65f8f86b0a5bdcfdca71f0b 100644 +--- a/src/tools/sssctl/sssctl_data.c ++++ b/src/tools/sssctl/sssctl_data.c +@@ -270,7 +270,7 @@ errno_t sssctl_cache_upgrade(struct sss_cmdline *cmdline, + return ret; + } + +- if (sss_deamon_running()) { ++ if (sss_daemon_running()) { + return ERR_SSSD_RUNNING; + } + +diff --git a/src/util/crypto/libcrypto/crypto_sha512crypt.c b/src/util/crypto/libcrypto/crypto_sha512crypt.c +index 1023566624f0e7b8fc08e30d4ea7ad031fbffff9..b074eee555fafac6e486bfdf9efb9ddf4964a990 100644 +--- a/src/util/crypto/libcrypto/crypto_sha512crypt.c ++++ b/src/util/crypto/libcrypto/crypto_sha512crypt.c +@@ -7,7 +7,7 @@ + * Sumit Bose + * George McCollister + */ +-/* SHA512-based Unix crypt implementation. ++/* SHA512-based UNIX crypt implementation. + Released into the Public Domain by Ulrich Drepper . */ + + #include "config.h" +diff --git a/src/util/crypto/nss/nss_sha512crypt.c b/src/util/crypto/nss/nss_sha512crypt.c +index 9fedd5ec6c62855d9cc0c9c2869d8c9be7fb5ade..2f1624e6396c40f539a4e2034ab545cad8f05434 100644 +--- a/src/util/crypto/nss/nss_sha512crypt.c ++++ b/src/util/crypto/nss/nss_sha512crypt.c +@@ -5,7 +5,7 @@ + * + * Sumit Bose + */ +-/* SHA512-based Unix crypt implementation. ++/* SHA512-based UNIX crypt implementation. + Released into the Public Domain by Ulrich Drepper . */ + + #include "config.h" +diff --git a/src/util/server.c b/src/util/server.c +index 0046c9737bc0d9aea7be59b4fed5e0f8930ff66e..4e65cc66c01ba020b13a88df8e017765ac97f76e 100644 +--- a/src/util/server.c ++++ b/src/util/server.c +@@ -69,7 +69,7 @@ static void close_low_fds(void) + #endif + } + +-static void deamon_parent_sigterm(int sig) ++static void daemon_parent_sigterm(int sig) + { + _exit(0); + } +@@ -88,10 +88,10 @@ void become_daemon(bool Fork) + pid = fork(); + if (pid != 0) { + /* Terminate parent process on demand so we can hold systemd +- * or initd from starting next service until sssd in initialized. ++ * or initd from starting next service until sssd is initialized. + * We use signals directly here because we don't have a tevent + * context yet. */ +- CatchSignal(SIGTERM, deamon_parent_sigterm); ++ CatchSignal(SIGTERM, daemon_parent_sigterm); + + /* or exit when sssd monitor is terminated */ + do { +diff --git a/src/util/sss_ini.h b/src/util/sss_ini.h +index 77fbddc3ab073d930eecd68dacb00dae52847744..0b173831d4fd7c283fa939a2f3bfda2a3bb97515 100644 +--- a/src/util/sss_ini.h ++++ b/src/util/sss_ini.h +@@ -94,7 +94,7 @@ int sss_ini_call_validators_strs(TALLOC_CTX *mem_ctx, + struct ref_array * + sss_ini_get_ra_error_list(struct sss_ini_initdata *init_data); + +-/* Get pointer to list of successfuly merged snippet files */ ++/* Get pointer to list of successfully merged snippet files */ + struct ref_array * + sss_ini_get_ra_success_list(struct sss_ini_initdata *init_data); + +diff --git a/src/util/tev_curl.c b/src/util/tev_curl.c +index 52c86adde65c173a874534a7001d7859789581cd..4c2f1ec9ff0127ccfd72010460ed75dad43e9ce3 100644 +--- a/src/util/tev_curl.c ++++ b/src/util/tev_curl.c +@@ -67,7 +67,7 @@ struct tcurl_ctx { + struct tcurl_sock { + struct tcurl_ctx *tctx; /* Backchannel to the main context */ + +- curl_socket_t sockfd; /* curl socket is an int typedef on Unix */ ++ curl_socket_t sockfd; /* curl socket is an int typedef on UNIX */ + struct tevent_fd *fde; /* tevent tracker of the fd events */ + }; + +diff --git a/src/util/util_lock.c b/src/util/util_lock.c +index b8e41cc29fbdcf3b5b75bf1507a4d33f5ba07be0..58d3b1bdf60f411fb7116055a5de775355d1839e 100644 +--- a/src/util/util_lock.c ++++ b/src/util/util_lock.c +@@ -74,7 +74,7 @@ errno_t sss_br_lock_file(int fd, size_t start, size_t len, + return ret; + } + } else if (ret == 0) { +- /* File successfuly locked */ ++ /* File successfully locked */ + break; + } + } +-- +2.15.1 + diff --git a/0003-CONFIG-Add-a-new-option-auto_private_groups.patch b/0003-CONFIG-Add-a-new-option-auto_private_groups.patch new file mode 100644 index 0000000..3a619c0 --- /dev/null +++ b/0003-CONFIG-Add-a-new-option-auto_private_groups.patch @@ -0,0 +1,158 @@ +From 04fc0d758ae1e5c4ab71ab3bf8b8f50b99a6c63a Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 12:34:33 +0200 +Subject: [PATCH 03/79] CONFIG: Add a new option auto_private_groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The auto_private_groups option is used to configure the domain->mpg flag +which was already set automatically for subdomains, but for some time was +not settable by the admin via the configuration file. + +The new option name, instead of the old magic_private_groups, was chosen +purely because this name would hopefully be better understood by admins. + +The option doesn't do anything yet, it is just added to all the places a +new option should be added to. + +Related: + https://pagure.io/SSSD/sssd/issue/1872 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +--- + src/confdb/confdb.c | 8 ++++++++ + src/confdb/confdb.h | 1 + + src/config/SSSDConfig/__init__.py.in | 1 + + src/config/SSSDConfigTest.py | 6 ++++-- + src/config/cfg_rules.ini | 1 + + src/config/etc/sssd.api.conf | 1 + + src/man/sssd.conf.5.xml | 20 ++++++++++++++++++++ + 7 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index fefecc03d554f6eca12efe07990bfae17033bd02..a028224817f12ace2a0c4165d7b9cb0bb80ce5a1 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -936,6 +936,14 @@ static int confdb_get_domain_internal(struct confdb_ctx *cdb, + goto done; + } + ++ ret = get_entry_as_bool(res->msgs[0], &domain->mpg, ++ CONFDB_DOMAIN_AUTO_UPG, 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Invalid value for %s\n", CONFDB_DOMAIN_AUTO_UPG); ++ goto done; ++ } ++ + if (strcasecmp(domain->provider, "local") == 0) { + /* If this is the local provider, we need to ensure that + * no other provider was specified for other types, since +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index bcea99ae49a3fa5f0393ce6b2c215b5b2d4bc3fc..2539b906993edbceb38aac9265e04deed69cf2e4 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -198,6 +198,7 @@ + #define CONFDB_DEFAULT_CACHE_CREDS_MIN_FF_LENGTH 8 + #define CONFDB_DOMAIN_LEGACY_PASS "store_legacy_passwords" + #define CONFDB_DOMAIN_MPG "magic_private_groups" ++#define CONFDB_DOMAIN_AUTO_UPG "auto_private_groups" + #define CONFDB_DOMAIN_FQ "use_fully_qualified_names" + #define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout" + #define CONFDB_DOMAIN_ACCOUNT_CACHE_EXPIRATION "account_cache_expiration" +diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in +index d99b718e09283d113f73639e0f94e7f1cec55f68..d2bb709d69c8790558b5c06a7e405463b508c189 100644 +--- a/src/config/SSSDConfig/__init__.py.in ++++ b/src/config/SSSDConfig/__init__.py.in +@@ -195,6 +195,7 @@ option_strings = { + 'cached_auth_timeout' : _('How long can cached credentials be used for cached authentication'), + 'full_name_format' : _('Printf-compatible format for displaying fully-qualified names'), + 're_expression' : _('Regex to parse username and domain'), ++ 'auto_private_groups' : _('Whether to automatically create private groups for users'), + + # [provider/ipa] + 'ipa_domain' : _('IPA domain'), +diff --git a/src/config/SSSDConfigTest.py b/src/config/SSSDConfigTest.py +index 4a583bdd3124dc05a116d2e6bd48afb92aa0b54d..87d1f6e6410dfeafc77d578cf0b950dc71a1f0a2 100755 +--- a/src/config/SSSDConfigTest.py ++++ b/src/config/SSSDConfigTest.py +@@ -624,7 +624,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'subdomain_homedir', + 'full_name_format', + 're_expression', +- 'cached_auth_timeout'] ++ 'cached_auth_timeout', ++ 'auto_private_groups'] + + self.assertTrue(type(options) == dict, + "Options should be a dictionary") +@@ -994,7 +995,8 @@ class SSSDConfigTestSSSDDomain(unittest.TestCase): + 'subdomain_homedir', + 'full_name_format', + 're_expression', +- 'cached_auth_timeout'] ++ 'cached_auth_timeout', ++ 'auto_private_groups'] + + self.assertTrue(type(options) == dict, + "Options should be a dictionary") +diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini +index e49e8d43f4aead14d833866110784fd62382cc2b..4e70bf7b6f0fa7421a0c35bd4279830265bf3470 100644 +--- a/src/config/cfg_rules.ini ++++ b/src/config/cfg_rules.ini +@@ -382,6 +382,7 @@ option = cached_auth_timeout + option = wildcard_limit + option = full_name_format + option = re_expression ++option = auto_private_groups + + #Entry cache timeouts + option = entry_cache_user_timeout +diff --git a/src/config/etc/sssd.api.conf b/src/config/etc/sssd.api.conf +index 7f2b8977b7e67fcfc20df49056cda8ebe6da0be8..2be2e3e685ba3abd9a4a419f93332a89ff774262 100644 +--- a/src/config/etc/sssd.api.conf ++++ b/src/config/etc/sssd.api.conf +@@ -185,6 +185,7 @@ subdomain_homedir = str, None, false + cached_auth_timeout = int, None, false + full_name_format = str, None, false + re_expression = str, None, false ++auto_private_groups = str, None, false + + #Entry cache timeouts + entry_cache_user_timeout = int, None, false +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 7752e450835b5beba50ddc4c635ff985d38ca421..1e8d9537517c85c3021b9c2c4185ea272c5bfffa 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -2816,6 +2816,26 @@ subdomain_inherit = ldap_purge_cache_timeout + + + ++ ++ auto_private_groups (string) ++ ++ ++ If this option is enabled, SSSD will automatically ++ create user private groups based on user's ++ UID number. The GID number is ignored in this case. ++ ++ ++ NOTE: Because the GID number and the user private group ++ are inferred frm the UID number, it is not supported ++ to have multiple entries with the same UID or GID number ++ with this option. In other words, enabling this option ++ enforces uniqueness across the ID space. ++ ++ ++ Default: False ++ ++ ++ + + + +-- +2.15.1 + diff --git a/0004-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch b/0004-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch new file mode 100644 index 0000000..8e7abe1 --- /dev/null +++ b/0004-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch @@ -0,0 +1,32 @@ +From bd4e962128c7ea95fa0bdc5aa8f360ab11cda178 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 12:36:02 +0200 +Subject: [PATCH 04/79] CONFDB: Remove the obsolete option magic_private_groups +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since this confdb definition was completely unused across the codebase, +this patch just removes the definition. + +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +--- + src/confdb/confdb.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h +index 2539b906993edbceb38aac9265e04deed69cf2e4..1471949623e9dd7a8536e3ac3048a10227a5d857 100644 +--- a/src/confdb/confdb.h ++++ b/src/confdb/confdb.h +@@ -197,7 +197,6 @@ + "cache_credentials_minimal_first_factor_length" + #define CONFDB_DEFAULT_CACHE_CREDS_MIN_FF_LENGTH 8 + #define CONFDB_DOMAIN_LEGACY_PASS "store_legacy_passwords" +-#define CONFDB_DOMAIN_MPG "magic_private_groups" + #define CONFDB_DOMAIN_AUTO_UPG "auto_private_groups" + #define CONFDB_DOMAIN_FQ "use_fully_qualified_names" + #define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout" +-- +2.15.1 + diff --git a/0005-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch b/0005-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch new file mode 100644 index 0000000..ed77921 --- /dev/null +++ b/0005-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch @@ -0,0 +1,166 @@ +From f7c559955ab380d097f8e98786ba710c7bff812c Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 12:34:49 +0200 +Subject: [PATCH 05/79] SDAP: Allow the mpg flag for the main domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit allows saving the users in the MPG domain in the SDAP +layer. + +The commit contains the following changes: + - abstracts the change where if the primary GID exists in the original + object, it is saved instead as the SYSDB_PRIMARY_GROUP_GIDNUM attribute, + which will allow the original primary GID to be exposed as a + secondary group + + - if the primary GID does not exist, no SYSDB_PRIMARY_GROUP_GIDNUM + is added. This will allow to handle LDAP objects that only contain + the UID but no GID. Since this is a new use-case, a test is added + later + + - a branch that handles the above is added to sdap_save_user() also + for joined domains that set the MPG flag. Previously, only + subdomains were handled. + + - to allow passing GID=0 to the sysdb layer, the range check is + relaxed. + +Related: + https://pagure.io/SSSD/sssd/issue/1872 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +--- + src/providers/ldap/sdap_async_users.c | 83 +++++++++++++++++++++++++++++++---- + 1 file changed, 75 insertions(+), 8 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c +index 09d096e84cac6c9d52bcde0e1587c47dbd88b504..7338b4a15694b1d0a16723990130a23a7280af5f 100644 +--- a/src/providers/ldap/sdap_async_users.c ++++ b/src/providers/ldap/sdap_async_users.c +@@ -136,6 +136,38 @@ static errno_t sdap_set_non_posix_flag(struct sysdb_attrs *attrs, + return EOK; + } + ++static int sdap_user_set_mpg(struct sysdb_attrs *user_attrs, ++ gid_t *_gid) ++{ ++ errno_t ret; ++ ++ if (_gid == NULL) { ++ return EINVAL; ++ } ++ ++ if (*_gid == 0) { ++ /* The original entry had no GID number. This is OK, we just won't add ++ * the SYSDB_PRIMARY_GROUP_GIDNUM attribute ++ */ ++ return EOK; ++ } ++ ++ ret = sysdb_attrs_add_uint32(user_attrs, ++ SYSDB_PRIMARY_GROUP_GIDNUM, ++ (uint32_t) *_gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_uint32 failed.\n"); ++ return ret; ++ } ++ ++ /* We won't really store gidNumber=0, but the zero value tells ++ * the sysdb layer that no GID is set, which sysdb requires for ++ * MPG-enabled domains ++ */ ++ *_gid = 0; ++ return EOK; ++} ++ + /* FIXME: support storing additional attributes */ + int sdap_save_user(TALLOC_CTX *memctx, + struct sdap_options *opts, +@@ -357,7 +389,7 @@ int sdap_save_user(TALLOC_CTX *memctx, + goto done; + } + +- if (IS_SUBDOMAIN(dom)) { ++ if (IS_SUBDOMAIN(dom) || dom->mpg == true) { + /* For subdomain users, only create the private group as + * the subdomain is an MPG domain. + * But we have to save the GID of the original primary group +@@ -365,14 +397,13 @@ int sdap_save_user(TALLOC_CTX *memctx, + * typically (Unix and AD) the user is not listed in his primary + * group as a member. + */ +- ret = sysdb_attrs_add_uint32(user_attrs, SYSDB_PRIMARY_GROUP_GIDNUM, +- (uint32_t) gid); ++ ret = sdap_user_set_mpg(user_attrs, &gid); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_uint32 failed.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sdap_user_set_mpg failed [%d]: %s\n", ret, ++ sss_strerror(ret)); + goto done; + } +- +- gid = 0; + } + + /* Store the GID in the ldap_attrs so it doesn't get +@@ -380,6 +411,41 @@ int sdap_save_user(TALLOC_CTX *memctx, + */ + ret = sysdb_attrs_add_uint32(attrs, SYSDB_GIDNUM, gid); + if (ret != EOK) goto done; ++ } else if (dom->mpg) { ++ /* Likewise, if a domain is set to contain 'magic private groups', do ++ * not process the real GID, but save it in the cache as originalGID ++ * (if available) ++ */ ++ ret = sysdb_attrs_get_uint32_t(attrs, ++ opts->user_map[SDAP_AT_USER_GID].sys_name, ++ &gid); ++ if (ret == ENOENT) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Missing GID, won't save the %s attribute\n", ++ SYSDB_PRIMARY_GROUP_GIDNUM); ++ ++ /* Store the UID as GID (since we're in a MPG domain so that it doesn't ++ * get treated as a missing attribute and removed ++ */ ++ ret = sdap_replace_id(attrs, SYSDB_GIDNUM, uid); ++ if (ret) { ++ DEBUG(SSSDBG_OP_FAILURE, "Cannot set the id-mapped UID\n"); ++ goto done; ++ } ++ gid = 0; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Cannot retrieve GID, won't save the %s attribute\n", ++ SYSDB_PRIMARY_GROUP_GIDNUM); ++ gid = 0; ++ } ++ ++ ret = sdap_user_set_mpg(user_attrs, &gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sdap_user_set_mpg failed [%d]: %s\n", ret, sss_strerror(ret)); ++ goto done; ++ } + } else { + ret = sysdb_attrs_get_uint32_t(attrs, + opts->user_map[SDAP_AT_USER_GID].sys_name, +@@ -403,8 +469,9 @@ int sdap_save_user(TALLOC_CTX *memctx, + } + + /* check that the gid is valid for this domain */ +- if (is_posix == true && IS_SUBDOMAIN(dom) == false && +- OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) { ++ if (is_posix == true && IS_SUBDOMAIN(dom) == false ++ && dom->mpg == false ++ && OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) { + DEBUG(SSSDBG_CRIT_FAILURE, + "User [%s] filtered out! (primary gid out of range)\n", + user_name); +-- +2.15.1 + diff --git a/0006-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch b/0006-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch new file mode 100644 index 0000000..2cf181c --- /dev/null +++ b/0006-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch @@ -0,0 +1,221 @@ +From 80ea108ab4263c1a1ac67ce6eac41dc6040b21dd Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 14:31:18 +0200 +Subject: [PATCH 06/79] LDAP: Turn group request into user request for MPG + domains if needed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the primary group GID or the group name is requested before the user +is, we need to also search the user space to save the user in the back +end which then allows the responder to generate the group from the +user entry. + +Related: + https://pagure.io/SSSD/sssd/issue/1872 + +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +--- + src/providers/ldap/ldap_id.c | 162 +++++++++++++++++++++++++++++++------------ + 1 file changed, 118 insertions(+), 44 deletions(-) + +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index 93204d35ea3782c9aa5d622a962c295869472631..e89fc6133316f684810afe4c1a0731b8a04f2931 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -694,6 +694,8 @@ struct groups_get_state { + static int groups_get_retry(struct tevent_req *req); + static void groups_get_connect_done(struct tevent_req *subreq); + static void groups_get_posix_check_done(struct tevent_req *subreq); ++static void groups_get_mpg_done(struct tevent_req *subreq); ++static errno_t groups_get_handle_no_group(struct tevent_req *req); + static void groups_get_search(struct tevent_req *req); + static void groups_get_done(struct tevent_req *subreq); + +@@ -1051,8 +1053,6 @@ static void groups_get_done(struct tevent_req *subreq) + struct tevent_req); + struct groups_get_state *state = tevent_req_data(req, + struct groups_get_state); +- char *endptr; +- gid_t gid; + int dp_error = DP_ERR_FATAL; + int ret; + +@@ -1078,49 +1078,33 @@ static void groups_get_done(struct tevent_req *subreq) + return; + } + +- if (ret == ENOENT && state->noexist_delete == true) { +- switch (state->filter_type) { +- case BE_FILTER_ENUM: +- tevent_req_error(req, ret); ++ if (ret == ENOENT ++ && state->domain->mpg == true) { ++ /* The requested filter did not find a group. Before giving up, we must ++ * also check if the GID can be resolved through a primary group of a ++ * user ++ */ ++ subreq = users_get_send(state, ++ state->ev, ++ state->ctx, ++ state->sdom, ++ state->conn, ++ state->filter_value, ++ state->filter_type, ++ NULL, ++ state->noexist_delete); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); + return; +- case BE_FILTER_NAME: +- ret = sysdb_delete_group(state->domain, state->filter_value, 0); +- if (ret != EOK && ret != ENOENT) { +- tevent_req_error(req, ret); +- return; +- } +- break; +- +- case BE_FILTER_IDNUM: +- gid = (gid_t) strtouint32(state->filter_value, &endptr, 10); +- if (errno || *endptr || (state->filter_value == endptr)) { +- tevent_req_error(req, errno ? errno : EINVAL); +- return; +- } +- +- ret = sysdb_delete_group(state->domain, NULL, gid); +- if (ret != EOK && ret != ENOENT) { +- tevent_req_error(req, ret); +- return; +- } +- break; +- +- case BE_FILTER_SECID: +- case BE_FILTER_UUID: +- /* Since it is not clear if the SID/UUID belongs to a user or a +- * group we have nothing to do here. */ +- break; +- +- case BE_FILTER_WILDCARD: +- /* We can't know if all groups are up-to-date, especially in +- * a large environment. Do not delete any records, let the +- * responder fetch the entries they are requested in. +- */ +- break; +- +- +- default: +- tevent_req_error(req, EINVAL); ++ } ++ tevent_req_set_callback(subreq, groups_get_mpg_done, req); ++ return; ++ } else if (ret == ENOENT && state->noexist_delete == true) { ++ ret = groups_get_handle_no_group(req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not delete group [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); + return; + } + } +@@ -1129,6 +1113,96 @@ static void groups_get_done(struct tevent_req *subreq) + tevent_req_done(req); + } + ++static void groups_get_mpg_done(struct tevent_req *subreq) ++{ ++ errno_t ret; ++ struct tevent_req *req = tevent_req_callback_data(subreq, ++ struct tevent_req); ++ struct groups_get_state *state = tevent_req_data(req, ++ struct groups_get_state); ++ ++ ret = users_get_recv(subreq, &state->dp_error, &state->sdap_ret); ++ talloc_zfree(subreq); ++ ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ if (state->sdap_ret == ENOENT && state->noexist_delete == true) { ++ ret = groups_get_handle_no_group(req); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Could not delete group [%d]: %s\n", ret, sss_strerror(ret)); ++ tevent_req_error(req, ret); ++ return; ++ } ++ } ++ ++ /* GID resolved to a user private group, done */ ++ tevent_req_done(req); ++ return; ++} ++ ++static errno_t groups_get_handle_no_group(struct tevent_req *req) ++{ ++ struct groups_get_state *state = tevent_req_data(req, ++ struct groups_get_state); ++ errno_t ret; ++ char *endptr; ++ gid_t gid; ++ ++ switch (state->filter_type) { ++ case BE_FILTER_ENUM: ++ ret = ENOENT; ++ break; ++ case BE_FILTER_NAME: ++ ret = sysdb_delete_group(state->domain, state->filter_value, 0); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot delete group %s [%d]: %s\n", ++ state->filter_value, ret, sss_strerror(ret)); ++ return ret; ++ } ++ ret = EOK; ++ break; ++ case BE_FILTER_IDNUM: ++ gid = (gid_t) strtouint32(state->filter_value, &endptr, 10); ++ if (errno || *endptr || (state->filter_value == endptr)) { ++ ret = errno ? errno : EINVAL; ++ break; ++ } ++ ++ ret = sysdb_delete_group(state->domain, NULL, gid); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Cannot delete group %"SPRIgid" [%d]: %s\n", ++ gid, ret, sss_strerror(ret)); ++ return ret; ++ } ++ ret = EOK; ++ break; ++ case BE_FILTER_SECID: ++ case BE_FILTER_UUID: ++ /* Since it is not clear if the SID/UUID belongs to a user or a ++ * group we have nothing to do here. */ ++ ret = EOK; ++ break; ++ case BE_FILTER_WILDCARD: ++ /* We can't know if all groups are up-to-date, especially in ++ * a large environment. Do not delete any records, let the ++ * responder fetch the entries they are requested in. ++ */ ++ ret = EOK; ++ break; ++ default: ++ ret = EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ + int groups_get_recv(struct tevent_req *req, int *dp_error_out, int *sdap_ret) + { + struct groups_get_state *state = tevent_req_data(req, +-- +2.15.1 + diff --git a/0007-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch b/0007-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch new file mode 100644 index 0000000..384691b --- /dev/null +++ b/0007-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch @@ -0,0 +1,96 @@ +From 561b887c08c6199a50f1295071626b3e9040a7d1 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 19 Oct 2017 17:18:15 +0200 +Subject: [PATCH 07/79] SYSDB: Prevent users and groups ID collision in MPG + domains except for id_provider=local +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This commit makes the check when adding an object in a MPG domain +stricter in the sense that not only same names are allowed in a MPG +domain, but also the same groups are not allowed either. + +This commit is a backwards-incompatible change, but one that is needed, +otherwise requesting the duplicate group first and then requesting the +user entry would yield two object when searching by GID. + +In order to keep backwards-compatibility, this uniqueness is NOT +enforced with id_provider=local. This constraint can be removed in +the future (or the local provider can be dropped altogether) + +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +--- + src/db/sysdb_ops.c | 41 ++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 38 insertions(+), 3 deletions(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 0e39a629a5823ff49ed02ec4c08a21b66119f06f..2f8e36c6c9a2c2cefe4af5fb78957763304d989a 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -1960,16 +1960,34 @@ int sysdb_add_user(struct sss_domain_info *domain, + } + + if (domain->mpg) { +- /* In MPG domains you can't have groups with the same name as users, +- * search if a group with the same name exists. ++ /* In MPG domains you can't have groups with the same name or GID ++ * as users, search if a group with the same name exists. + * Don't worry about users, if we try to add a user with the same + * name the operation will fail */ + + ret = sysdb_search_group_by_name(tmp_ctx, domain, name, NULL, &msg); + if (ret != ENOENT) { +- if (ret == EOK) ret = EEXIST; ++ if (ret == EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Group named %s already exists in an MPG domain\n", ++ name); ++ ret = EEXIST; ++ } + goto done; + } ++ ++ if (strcasecmp(domain->provider, "local") != 0) { ++ ret = sysdb_search_group_by_gid(tmp_ctx, domain, uid, NULL, &msg); ++ if (ret != ENOENT) { ++ if (ret == EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Group with GID [%"SPRIgid"] already exists in an " ++ "MPG domain\n", gid); ++ ret = EEXIST; ++ } ++ goto done; ++ } ++ } + } + + /* check no other user with the same uid exist */ +@@ -2177,6 +2195,23 @@ int sysdb_add_group(struct sss_domain_info *domain, + } + goto done; + } ++ ++ if (strcasecmp(domain->provider, "local") != 0) { ++ ret = sysdb_search_user_by_uid(tmp_ctx, domain, gid, NULL, &msg); ++ if (ret != ENOENT) { ++ if (ret == EOK) { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "User with the same UID exists in MPG domain: " ++ "[%"SPRIgid"].\n", gid); ++ ret = EEXIST; ++ } else { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "sysdb_search_user_by_uid failed for gid: " ++ "[%"SPRIgid"].\n", gid); ++ } ++ goto done; ++ } ++ } + } + + /* check no other groups with the same gid exist */ +-- +2.15.1 + diff --git a/0008-TESTS-Add-integration-tests-for-the-auto_private_gro.patch b/0008-TESTS-Add-integration-tests-for-the-auto_private_gro.patch new file mode 100644 index 0000000..62ba27a --- /dev/null +++ b/0008-TESTS-Add-integration-tests-for-the-auto_private_gro.patch @@ -0,0 +1,345 @@ +From dc8e3fcdd6807974122e47ff97e9bbd3be16557f Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Tue, 3 Oct 2017 16:55:40 +0200 +Subject: [PATCH 08/79] TESTS: Add integration tests for the + auto_private_groups option +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: + https://pagure.io/SSSD/sssd/issue/1872 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Pavel Březina +--- + src/tests/intg/test_enumeration.py | 79 +++++++++++++- + src/tests/intg/test_ldap.py | 214 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 290 insertions(+), 3 deletions(-) + +diff --git a/src/tests/intg/test_enumeration.py b/src/tests/intg/test_enumeration.py +index fdb8d376879f756957f8f25fd28b37d7178aeff5..c7d78155c64dc6c85cb4dc070b205bdcfceff6af 100644 +--- a/src/tests/intg/test_enumeration.py ++++ b/src/tests/intg/test_enumeration.py +@@ -237,9 +237,7 @@ def sanity_rfc2307(request, ldap_conn): + create_sssd_fixture(request) + return None + +- +-@pytest.fixture +-def sanity_rfc2307_bis(request, ldap_conn): ++def populate_rfc2307bis(request, ldap_conn): + ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) + ent_list.add_user("user1", 1001, 2001) + ent_list.add_user("user2", 1002, 2002) +@@ -266,6 +264,11 @@ def sanity_rfc2307_bis(request, ldap_conn): + [], ["one_user_group1", "one_user_group2"]) + + create_ldap_fixture(request, ldap_conn, ent_list) ++ ++ ++@pytest.fixture ++def sanity_rfc2307_bis(request, ldap_conn): ++ populate_rfc2307bis(request, ldap_conn) + conf = format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + create_conf_fixture(request, conf) + create_sssd_fixture(request) +@@ -695,3 +698,73 @@ def test_vetoed_shells(vetoed_shells): + shell="/bin/default") + ) + ) ++ ++ ++@pytest.fixture ++def sanity_rfc2307_bis_mpg(request, ldap_conn): ++ populate_rfc2307bis(request, ldap_conn) ++ ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_group_bis("conflict1", 1001) ++ ent_list.add_group_bis("conflict2", 1002) ++ create_ldap_fixture(request, ldap_conn, ent_list) ++ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ ++ unindent(""" ++ [domain/LDAP] ++ auto_private_groups = True ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++def test_ldap_auto_private_groups_enumerate(ldap_conn, ++ sanity_rfc2307_bis_mpg): ++ """ ++ Test the auto_private_groups together with enumeration ++ """ ++ passwd_pattern = ent.contains_only( ++ dict(name='user1', passwd='*', uid=1001, gid=1001, gecos='1001', ++ dir='/home/user1', shell='/bin/bash'), ++ dict(name='user2', passwd='*', uid=1002, gid=1002, gecos='1002', ++ dir='/home/user2', shell='/bin/bash'), ++ dict(name='user3', passwd='*', uid=1003, gid=1003, gecos='1003', ++ dir='/home/user3', shell='/bin/bash') ++ ) ++ ent.assert_passwd(passwd_pattern) ++ ++ group_pattern = ent.contains_only( ++ dict(name='user1', passwd='*', gid=1001, mem=ent.contains_only()), ++ dict(name='user2', passwd='*', gid=1002, mem=ent.contains_only()), ++ dict(name='user3', passwd='*', gid=1003, mem=ent.contains_only()), ++ dict(name='group1', passwd='*', gid=2001, mem=ent.contains_only()), ++ dict(name='group2', passwd='*', gid=2002, mem=ent.contains_only()), ++ dict(name='group3', passwd='*', gid=2003, mem=ent.contains_only()), ++ dict(name='empty_group1', passwd='*', gid=2010, ++ mem=ent.contains_only()), ++ dict(name='empty_group2', passwd='*', gid=2011, ++ mem=ent.contains_only()), ++ dict(name='two_user_group', passwd='*', gid=2012, ++ mem=ent.contains_only("user1", "user2")), ++ dict(name='group_empty_group', passwd='*', gid=2013, ++ mem=ent.contains_only()), ++ dict(name='group_two_empty_groups', passwd='*', gid=2014, ++ mem=ent.contains_only()), ++ dict(name='one_user_group1', passwd='*', gid=2015, ++ mem=ent.contains_only("user1")), ++ dict(name='one_user_group2', passwd='*', gid=2016, ++ mem=ent.contains_only("user2")), ++ dict(name='group_one_user_group', passwd='*', gid=2017, ++ mem=ent.contains_only("user1")), ++ dict(name='group_two_user_group', passwd='*', gid=2018, ++ mem=ent.contains_only("user1", "user2")), ++ dict(name='group_two_one_user_groups', passwd='*', gid=2019, ++ mem=ent.contains_only("user1", "user2")) ++ ) ++ ent.assert_group(group_pattern) ++ ++ with pytest.raises(KeyError): ++ grp.getgrnam("conflict1") ++ ent.assert_group_by_gid(1002, dict(name="user2", mem=ent.contains_only())) +diff --git a/src/tests/intg/test_ldap.py b/src/tests/intg/test_ldap.py +index f2467f1ffe9890049ad73bba6432102d029510e8..a6659b1b78df4d72eb98c208d67ee5d10c9c88ea 100644 +--- a/src/tests/intg/test_ldap.py ++++ b/src/tests/intg/test_ldap.py +@@ -1169,3 +1169,217 @@ def test_nss_filters_cached(ldap_conn, sanity_nss_filter_cached): + + res, _ = call_sssd_getgrgid(0) + assert res == NssReturnCode.NOTFOUND ++ ++ ++@pytest.fixture ++def mpg_setup(request, ldap_conn): ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_user("user1", 1001, 2001) ++ ent_list.add_user("user2", 1002, 2002) ++ ent_list.add_user("user3", 1003, 2003) ++ ++ ent_list.add_group_bis("group1", 2001) ++ ent_list.add_group_bis("group2", 2002) ++ ent_list.add_group_bis("group3", 2003) ++ ++ ent_list.add_group_bis("two_user_group", 2012, ["user1", "user2"]) ++ ent_list.add_group_bis("one_user_group1", 2015, ["user1"]) ++ ent_list.add_group_bis("one_user_group2", 2016, ["user2"]) ++ ++ create_ldap_entries(ldap_conn, ent_list) ++ create_ldap_cleanup(request, ldap_conn, None) ++ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ ++ unindent(""" ++ [domain/LDAP] ++ auto_private_groups = True ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++def test_ldap_auto_private_groups_direct(ldap_conn, mpg_setup): ++ """ ++ Integration test for auto_private_groups ++ ++ See also ticket https://pagure.io/SSSD/sssd/issue/1872 ++ """ ++ # Make sure the user's GID is taken from their uidNumber ++ ent.assert_passwd_by_name("user1", dict(name="user1", uid=1001, gid=1001)) ++ # Make sure the private group is resolvable by name and by GID ++ ent.assert_group_by_name("user1", dict(gid=1001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(1001, dict(name="user1", mem=ent.contains_only())) ++ ++ # The group referenced in user's gidNumber attribute should be still ++ # visible, but it's fine that it doesn't contain the user as a member ++ # as the group is currently added during the initgroups operation only ++ ent.assert_group_by_name("group1", dict(gid=2001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(2001, dict(name="group1", mem=ent.contains_only())) ++ ++ # The user's secondary groups list must be correct as well ++ # Note that the original GID is listed as well -- this is correct and expected ++ # because we save the original GID in the SYSDB_PRIMARY_GROUP_GIDNUM attribute ++ user1_expected_gids = [1001, 2001, 2012, 2015] ++ (res, errno, gids) = sssd_id.call_sssd_initgroups("user1", 1001) ++ assert res == sssd_id.NssReturnCode.SUCCESS ++ ++ assert sorted(gids) == sorted(user1_expected_gids), \ ++ "result: %s\n expected %s" % ( ++ ", ".join(["%s" % s for s in sorted(gids)]), ++ ", ".join(["%s" % s for s in sorted(user1_expected_gids)]) ++ ) ++ ++ # Request user2's private group by GID without resolving the user first. ++ # This must trigger user resolution through by-GID resolution, since the GID ++ # doesn't exist on its own in LDAP ++ ent.assert_group_by_gid(1002, dict(name="user2", mem=ent.contains_only())) ++ ++ # Test supplementary groups for user2 as well ++ user1_expected_gids = [1002, 2002, 2012, 2016] ++ (res, errno, gids) = sssd_id.call_sssd_initgroups("user2", 1002) ++ assert res == sssd_id.NssReturnCode.SUCCESS ++ ++ assert sorted(gids) == sorted(user1_expected_gids), \ ++ "result: %s\n expected %s" % ( ++ ", ".join(["%s" % s for s in sorted(gids)]), ++ ", ".join(["%s" % s for s in sorted(user1_expected_gids)]) ++ ) ++ ++ # Request user3's private group by name without resolving the user first ++ # This must trigger user resolution through by-name resolution, since the ++ # name doesn't exist on its own in LDAP ++ ent.assert_group_by_name("user3", dict(gid=1003, mem=ent.contains_only())) ++ ++ # Remove entries and request them again to make sure they are not ++ # resolvable anymore ++ cleanup_ldap_entries(ldap_conn, None) ++ ++ if subprocess.call(["sss_cache", "-GU"]) != 0: ++ raise Exception("sssd_cache failed") ++ ++ with pytest.raises(KeyError): ++ pwd.getpwnam("user1") ++ with pytest.raises(KeyError): ++ grp.getgrnam("user1") ++ with pytest.raises(KeyError): ++ grp.getgrgid(1002) ++ with pytest.raises(KeyError): ++ grp.getgrnam("user3") ++ ++ ++@pytest.fixture ++def mpg_setup_conflict(request, ldap_conn): ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_user("user1", 1001, 2001) ++ ent_list.add_user("user2", 1002, 2002) ++ ent_list.add_user("user3", 1003, 1003) ++ ent_list.add_group_bis("group1", 1001) ++ ent_list.add_group_bis("group2", 1002) ++ ent_list.add_group_bis("group3", 1003) ++ ent_list.add_group_bis("supp_group", 2015, ["user3"]) ++ create_ldap_fixture(request, ldap_conn, ent_list) ++ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ ++ unindent(""" ++ [domain/LDAP] ++ auto_private_groups = True ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++def test_ldap_auto_private_groups_conflict(ldap_conn, mpg_setup_conflict): ++ """ ++ Make sure that conflicts between groups that are auto-created with the ++ help of the auto_private_groups option and between 'real' LDAP groups ++ are handled in a predictable manner. ++ """ ++ # Make sure the user's GID is taken from their uidNumber ++ ent.assert_passwd_by_name("user1", dict(name="user1", uid=1001, gid=1001)) ++ # Make sure the private group is resolvable by name and by GID ++ ent.assert_group_by_name("user1", dict(gid=1001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(1001, dict(name="user1", mem=ent.contains_only())) ++ ++ # Let's request the group with the same ID as user2's private group ++ # The request should match the 'real' group ++ ent.assert_group_by_gid(1002, dict(name="group2", mem=ent.contains_only())) ++ # But because of the GID conflict, the user cannot be resolved ++ with pytest.raises(KeyError): ++ pwd.getpwnam("user2") ++ ++ # This user's GID is the same as the UID in this entry. The most important ++ # thing here is that the supplementary groups are correct and the GID ++ # resolves to the private group (as long as the user was requested first) ++ user3_expected_gids = [1003, 2015] ++ ent.assert_passwd_by_name("user3", dict(name="user3", uid=1003, gid=1003)) ++ (res, errno, gids) = sssd_id.call_sssd_initgroups("user3", 1003) ++ assert res == sssd_id.NssReturnCode.SUCCESS ++ ++ assert sorted(gids) == sorted(user3_expected_gids), \ ++ "result: %s\n expected %s" % ( ++ ", ".join(["%s" % s for s in sorted(gids)]), ++ ", ".join(["%s" % s for s in sorted(user3_expected_gids)]) ++ ) ++ # Make sure the private group is resolvable by name and by GID ++ ent.assert_group_by_gid(1003, dict(name="user3", mem=ent.contains_only())) ++ ent.assert_group_by_name("user3", dict(gid=1003, mem=ent.contains_only())) ++ ++ ++@pytest.fixture ++def mpg_setup_no_gid(request, ldap_conn): ++ ent_list = ldap_ent.List(ldap_conn.ds_inst.base_dn) ++ ent_list.add_user("user1", 1001, 2001) ++ ++ ent_list.add_group_bis("group1", 2001) ++ ent_list.add_group_bis("one_user_group1", 2015, ["user1"]) ++ ++ create_ldap_entries(ldap_conn, ent_list) ++ create_ldap_cleanup(request, ldap_conn, None) ++ ++ conf = \ ++ format_basic_conf(ldap_conn, SCHEMA_RFC2307_BIS) + \ ++ unindent(""" ++ [domain/LDAP] ++ auto_private_groups = True ++ ldap_user_gid_number = no_such_attribute ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ ++def test_ldap_auto_private_groups_direct_no_gid(ldap_conn, mpg_setup_no_gid): ++ """ ++ Integration test for auto_private_groups - test that even a user with ++ no GID assigned at all can be resolved including their autogenerated ++ primary group. ++ ++ See also ticket https://pagure.io/SSSD/sssd/issue/1872 ++ """ ++ # Make sure the user's GID is taken from their uidNumber ++ ent.assert_passwd_by_name("user1", dict(name="user1", uid=1001, gid=1001)) ++ # Make sure the private group is resolvable by name and by GID ++ ent.assert_group_by_name("user1", dict(gid=1001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(1001, dict(name="user1", mem=ent.contains_only())) ++ ++ # The group referenced in user's gidNumber attribute should be still ++ # visible, but shouldn't have any relation to the user ++ ent.assert_group_by_name("group1", dict(gid=2001, mem=ent.contains_only())) ++ ent.assert_group_by_gid(2001, dict(name="group1", mem=ent.contains_only())) ++ ++ # The user's secondary groups list must be correct as well. This time only ++ # the generated group and the explicit secondary group are added, since ++ # there is no original GID ++ user1_expected_gids = [1001, 2015] ++ (res, errno, gids) = sssd_id.call_sssd_initgroups("user1", 1001) ++ assert res == sssd_id.NssReturnCode.SUCCESS ++ ++ assert sorted(gids) == sorted(user1_expected_gids), \ ++ "result: %s\n expected %s" % ( ++ ", ".join(["%s" % s for s in sorted(gids)]), ++ ", ".join(["%s" % s for s in sorted(user1_expected_gids)]) ++ ) +-- +2.15.1 + diff --git a/0013-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch b/0009-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch similarity index 97% rename from 0013-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch rename to 0009-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch index 97bf6be..277e633 100644 --- a/0013-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch +++ b/0009-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch @@ -1,7 +1,7 @@ -From 0f44eefe2ce75a0814c8688495477f6c57f3d39a Mon Sep 17 00:00:00 2001 +From ec2489ab1ba7075e69f1f3747d96656ac2b0aab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= Date: Fri, 20 Oct 2017 09:26:43 +0200 -Subject: [PATCH] CACHE_REQ: Copy the cr_domain list for each request +Subject: [PATCH 09/79] CACHE_REQ: Copy the cr_domain list for each request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -137,5 +137,5 @@ index 3780a5d8d88d76e100738d28d1dd0e697edf5eae..ebdc71dd635d5d8a5d06e30e96c5d410 -- -2.15.0 +2.15.1 diff --git a/0010-sudo-document-background-activity.patch b/0010-sudo-document-background-activity.patch new file mode 100644 index 0000000..122c336 --- /dev/null +++ b/0010-sudo-document-background-activity.patch @@ -0,0 +1,41 @@ +From a0f79dd38cffc5ad382aae9baba76863678c26ee Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Fri, 20 Oct 2017 11:49:26 +0200 +Subject: [PATCH 10/79] sudo: document background activity +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When we introduced socket activation, we changed the internall behaviour. +Previously we disabled sudo if it was not listed in services, with +socket activation we removed this feature. Some users were confused +so this change documents current behaviour. + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +--- + src/man/sssd.conf.5.xml | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index 1e8d9537517c85c3021b9c2c4185ea272c5bfffa..b247b5ac75a82d45f29023f5f9ca24a3a7a5ce0c 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -2348,6 +2348,14 @@ pam_account_locked_message = Account locked, please contact help desk. + 5 + . + ++ ++ NOTE: Sudo rules are ++ periodically downloaded in the background unless ++ the sudo provider is explicitly disabled. Set ++ sudo_provider = None to ++ disable all sudo-related activity in SSSD if you do ++ not want to use sudo with SSSD at all. ++ + + + +-- +2.15.1 + diff --git a/0011-MAN-GPO-Security-Filtering-limitation.patch b/0011-MAN-GPO-Security-Filtering-limitation.patch new file mode 100644 index 0000000..7747636 --- /dev/null +++ b/0011-MAN-GPO-Security-Filtering-limitation.patch @@ -0,0 +1,40 @@ +From bb20c565417a2c2ab274b254e6238657c5d8c73a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Thu, 26 Oct 2017 17:12:17 +0200 +Subject: [PATCH 11/79] MAN: GPO Security Filtering limitation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Note in the man pages that current version of SSSD does not support +host entries in the 'Security filtering' list. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3444 + +Reviewed-by: Fabiano Fidêncio +--- + src/man/sssd-ad.5.xml | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml +index 08c1dd09fb829c6cffb416250b9b518668ec5790..649042d587de3d3600fff59866681e302c721af8 100644 +--- a/src/man/sssd-ad.5.xml ++++ b/src/man/sssd-ad.5.xml +@@ -345,6 +345,13 @@ DOM:dom1:(memberOf:1.2.840.113556.1.4.1941:=cn=nestedgroup,ou=groups,dc=example, + particular user is allowed to logon to a particular + host. + ++ ++ NOTE: The current version of SSSD does not support ++ host (computer) entries in the GPO 'Security ++ Filtering' list. Only user and group entries are ++ supported. Host entries in the list have no ++ effect. ++ + + NOTE: If the operation mode is set to enforcing, it + is possible that users that were previously allowed +-- +2.15.1 + diff --git a/0012-CI-Ignore-source-file-generated-by-systemtap.patch b/0012-CI-Ignore-source-file-generated-by-systemtap.patch new file mode 100644 index 0000000..f571dbc --- /dev/null +++ b/0012-CI-Ignore-source-file-generated-by-systemtap.patch @@ -0,0 +1,55 @@ +From 5b34c650b387192282f3c2cd6211db0fd4944870 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 30 Oct 2017 14:54:07 +0100 +Subject: [PATCH 12/79] CI: Ignore source file generated by systemtap + +There are some changes in systemtap 3.2 which generate temporary +source files and remove them later. We are not interested in code +coverage in this area. Lets ignore them. + +... +genhtml: failure 00:00:01 ci-build-coverage/ci-genhtml.log +FAILURE + +sh$ cat ci-build-coverage/ci-genhtml.log +Start: Mon Oct 30 13:43:52 UTC 2017 ++ eval 'genhtml --output-directory \ + "$coverage_report_dir" \ + --title "sssd" --show-details \ + --legend --prefix "$BASE_DIR" \ + ci.info |& tee ci-genhtml.out' +++ genhtml --output-directory ci-report-coverage --title sssd \ + --show-details --legend --prefix /home/build/sssd ci.info +++ tee ci-genhtml.out +Reading data file ci.info +Found 447 entries. +Using user-specified filename prefix "/home/build/sssd" +Writing .css and .png files. +Generating output. +genhtml: ERROR: cannot read /home/build/sssd/stap_generated_probes.o.dtrace-temp.c +Processing file stap_generated_probes.o.dtrace-temp.c +End: Mon Oct 30 13:43:53 UTC 2017 + +sh$ ls -l /home/build/sssd/stap_generated_probes.o.dtrace-temp.c +ls: cannot access '/home/build/sssd/stap_generated_probes.o.dtrace-temp.c': No such file or directory + +Reviewed-by: Jakub Hrozek +--- + contrib/ci/run | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/contrib/ci/run b/contrib/ci/run +index aa6d35abedbd24fce49651e43f4a704b2b1b9880..26cd32b3316eb9fdfd9fd07e26dd862fec7b669d 100755 +--- a/contrib/ci/run ++++ b/contrib/ci/run +@@ -300,6 +300,7 @@ function build_coverage() + --output-file ci-dirty.info + stage lcov-clean lcov --remove ci-dirty.info \ + "/usr/*" "src/tests/*" "/tmp/*" \ ++ "*dtrace-temp.c" \ + --output-file ci.info + stage genhtml eval 'genhtml --output-directory \ + "$coverage_report_dir" \ +-- +2.15.1 + diff --git a/0013-sudo-always-use-srv_opts-from-id-context.patch b/0013-sudo-always-use-srv_opts-from-id-context.patch new file mode 100644 index 0000000..ac0fb0b --- /dev/null +++ b/0013-sudo-always-use-srv_opts-from-id-context.patch @@ -0,0 +1,63 @@ +From 25bc436bccacb7f995314465b2923c6e08f654d4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 19 Oct 2017 10:39:21 +0200 +Subject: [PATCH 13/79] sudo: always use srv_opts from id context + +Prior this patch, we remember id_ctx->srv_opts in sudo request to switch +the latest usn values. This works fine most of the time but it may cause +a crash. + +If we have two concurrent sudo refresh and one of these fails, it causes +failover to try the next server and possibly replacing the old srv_opts +with new one and it causes an access after free in the other refresh. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3562 + +Reviewed-by: Jakub Hrozek +--- + src/providers/ldap/sdap_async_sudo.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/src/providers/ldap/sdap_async_sudo.c b/src/providers/ldap/sdap_async_sudo.c +index f33d5b5fa86dc1806695482d627bd71a2b040d6e..5dc58012845b7109f0fa138e2e291b8ec3267799 100644 +--- a/src/providers/ldap/sdap_async_sudo.c ++++ b/src/providers/ldap/sdap_async_sudo.c +@@ -279,7 +279,6 @@ done: + struct sdap_sudo_refresh_state { + struct sdap_sudo_ctx *sudo_ctx; + struct tevent_context *ev; +- struct sdap_server_opts *srv_opts; + struct sdap_options *opts; + struct sdap_id_op *sdap_op; + struct sysdb_ctx *sysdb; +@@ -405,9 +404,6 @@ static void sdap_sudo_refresh_connect_done(struct tevent_req *subreq) + + DEBUG(SSSDBG_TRACE_FUNC, "SUDO LDAP connection successful\n"); + +- /* Obtain srv_opts here in case of first connection. */ +- state->srv_opts = state->sudo_ctx->id_ctx->srv_opts; +- + /* Renew host information if needed. */ + if (state->sudo_ctx->run_hostinfo) { + subreq = sdap_sudo_get_hostinfo_send(state, state->opts, +@@ -586,7 +582,6 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) + goto done; + } + +- + /* start transaction */ + ret = sysdb_transaction_start(state->sysdb); + if (ret != EOK) { +@@ -621,7 +616,7 @@ static void sdap_sudo_refresh_done(struct tevent_req *subreq) + /* remember new usn */ + ret = sysdb_get_highest_usn(state, rules, rules_count, &usn); + if (ret == EOK) { +- sdap_sudo_set_usn(state->srv_opts, usn); ++ sdap_sudo_set_usn(state->sudo_ctx->id_ctx->srv_opts, usn); + } else { + DEBUG(SSSDBG_MINOR_FAILURE, "Unable to get highest USN [%d]: %s\n", + ret, sss_strerror(ret)); +-- +2.15.1 + diff --git a/0014-AD-Remember-last-site-discovered.patch b/0014-AD-Remember-last-site-discovered.patch new file mode 100644 index 0000000..7c80fe7 --- /dev/null +++ b/0014-AD-Remember-last-site-discovered.patch @@ -0,0 +1,108 @@ +From ceb9cc228793551eb0fc42234ee3f9b3c9d6cb9b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 18 Oct 2017 15:20:34 +0200 +Subject: [PATCH 14/79] AD: Remember last site discovered + +To discover Active Directory site for a client we must first contact any +directory controller for an LDAP ping. This is done by searching +domain-wide DNS tree which may however contain servers that are not +reachable from current site and than we face long timeouts or failure. + +This patch makes sssd remember the last successfuly discovered site +and use this for DNS search to lookup a site and forest again similar +to what we do when ad_site option is set. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3265 + +Reviewed-by: Jakub Hrozek +--- + src/providers/ad/ad_srv.c | 44 +++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 43 insertions(+), 1 deletion(-) + +diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c +index ff01ee95c4d2c6875a989394489f1a0495cc3003..be1ba0f237add894566ae713ce5e29fd202d414c 100644 +--- a/src/providers/ad/ad_srv.c ++++ b/src/providers/ad/ad_srv.c +@@ -481,6 +481,7 @@ struct ad_srv_plugin_ctx { + const char *hostname; + const char *ad_domain; + const char *ad_site_override; ++ const char *current_site; + }; + + struct ad_srv_plugin_ctx * +@@ -518,6 +519,11 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + if (ctx->ad_site_override == NULL) { + goto fail; + } ++ ++ ctx->current_site = talloc_strdup(ctx, ad_site_override); ++ if (ctx->current_site == NULL) { ++ goto fail; ++ } + } + + return ctx; +@@ -527,6 +533,32 @@ fail: + return NULL; + } + ++static errno_t ++ad_srv_plugin_ctx_switch_site(struct ad_srv_plugin_ctx *ctx, ++ const char *new_site) ++{ ++ const char *site; ++ errno_t ret; ++ ++ if (new_site == NULL) { ++ return EOK; ++ } ++ ++ if (ctx->current_site != NULL && strcmp(ctx->current_site, new_site) == 0) { ++ return EOK; ++ } ++ ++ site = talloc_strdup(ctx, new_site); ++ if (site == NULL) { ++ return ENOMEM; ++ } ++ ++ talloc_zfree(ctx->current_site); ++ ctx->current_site = site; ++ ++ return EOK; ++} ++ + struct ad_srv_plugin_state { + struct tevent_context *ev; + struct ad_srv_plugin_ctx *ctx; +@@ -613,7 +645,7 @@ struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx, + + subreq = ad_get_dc_servers_send(state, ev, ctx->be_res->resolv, + state->discovery_domain, +- state->ctx->ad_site_override); ++ state->ctx->current_site); + if (subreq == NULL) { + ret = ENOMEM; + goto immediately; +@@ -709,6 +741,16 @@ static void ad_srv_plugin_site_done(struct tevent_req *subreq) + backup_domain = NULL; + + if (ret == EOK) { ++ /* Remember current site so it can be used during next lookup so ++ * we can contact directory controllers within a known reachable ++ * site first. */ ++ ret = ad_srv_plugin_ctx_switch_site(state->ctx, state->site); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to set site [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ + if (strcmp(state->service, "gc") == 0) { + if (state->forest != NULL) { + if (state->site != NULL) { +-- +2.15.1 + diff --git a/0015-sysdb-add-functions-to-get-set-client-site.patch b/0015-sysdb-add-functions-to-get-set-client-site.patch new file mode 100644 index 0000000..1b9c6f7 --- /dev/null +++ b/0015-sysdb-add-functions-to-get-set-client-site.patch @@ -0,0 +1,205 @@ +From 8687782eb971d0fa6f8f4420a8616ba943d7252b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Tue, 24 Oct 2017 12:09:39 +0200 +Subject: [PATCH 15/79] sysdb: add functions to get/set client site + +Reviewed-by: Jakub Hrozek +--- + src/db/sysdb.h | 10 +++ + src/db/sysdb_subdomains.c | 108 +++++++++++++++++++++++++++++++ + src/tests/cmocka/test_sysdb_subdomains.c | 28 ++++++++ + 3 files changed, 146 insertions(+) + +diff --git a/src/db/sysdb.h b/src/db/sysdb.h +index fbbe321072385bd43353ef2f7d0e30667887d128..4192f9085d941814eccd2ac60ce8fb6d4e1bfa67 100644 +--- a/src/db/sysdb.h ++++ b/src/db/sysdb.h +@@ -154,6 +154,7 @@ + #define SYSDB_SUBDOMAIN_FOREST "memberOfForest" + #define SYSDB_SUBDOMAIN_TRUST_DIRECTION "trustDirection" + #define SYSDB_UPN_SUFFIXES "upnSuffixes" ++#define SYSDB_SITE "site" + + #define SYSDB_BASE_ID "baseID" + #define SYSDB_ID_RANGE_SIZE "idRangeSize" +@@ -509,6 +510,15 @@ errno_t sysdb_domain_update_domain_resolution_order( + const char *domain_name, + const char *domain_resolution_order); + ++errno_t ++sysdb_get_site(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *dom, ++ const char **_site); ++ ++errno_t ++sysdb_set_site(struct sss_domain_info *dom, ++ const char *site); ++ + errno_t sysdb_subdomain_store(struct sysdb_ctx *sysdb, + const char *name, const char *realm, + const char *flat_name, const char *domain_id, +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index 2789cc4949fb7be9ad272d7613ed18a64fa8a20a..cb5de1afe3e8c9692789c5d2679eb3a4e6e1cdb2 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -1284,3 +1284,111 @@ done: + talloc_free(tmp_ctx); + return ret; + } ++ ++errno_t ++sysdb_get_site(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *dom, ++ const char **_site) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_res *res; ++ struct ldb_dn *dn; ++ const char *attrs[] = { SYSDB_SITE, NULL }; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new_fmt(tmp_ctx, dom->sysdb->ldb, SYSDB_DOM_BASE, dom->name); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_search(dom->sysdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_BASE, ++ attrs, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ if (res->count == 0) { ++ *_site = NULL; ++ ret = EOK; ++ goto done; ++ } else if (res->count != 1) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Got more than one reply for base search!\n"); ++ ret = EIO; ++ goto done; ++ } ++ ++ *_site = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_SITE, NULL); ++ talloc_steal(mem_ctx, *_site); ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ ++errno_t ++sysdb_set_site(struct sss_domain_info *dom, ++ const char *site) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_message *msg; ++ struct ldb_dn *dn; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new_fmt(tmp_ctx, dom->sysdb->ldb, SYSDB_DOM_BASE, dom->name); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg = ldb_msg_new(tmp_ctx); ++ if (msg == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ msg->dn = dn; ++ ++ ret = ldb_msg_add_empty(msg, SYSDB_SITE, LDB_FLAG_MOD_REPLACE, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ if (site != NULL) { ++ ret = ldb_msg_add_string(msg, SYSDB_SITE, site); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ } ++ ++ ret = ldb_modify(dom->sysdb->ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_modify()_failed: [%s][%d][%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(dom->sysdb->ldb)); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} +diff --git a/src/tests/cmocka/test_sysdb_subdomains.c b/src/tests/cmocka/test_sysdb_subdomains.c +index 84bcdc17b39dbc8822097c2006f157a09ea5e466..f8e3e1d915dba0f3a79adbf5af733980bf23a265 100644 +--- a/src/tests/cmocka/test_sysdb_subdomains.c ++++ b/src/tests/cmocka/test_sysdb_subdomains.c +@@ -513,6 +513,31 @@ static void test_sysdb_link_ad_multidom(void **state) + + } + ++static void test_sysdb_set_and_get_site(void **state) ++{ ++ TALLOC_CTX *tmp_ctx; ++ struct subdom_test_ctx *test_ctx = ++ talloc_get_type(*state, struct subdom_test_ctx); ++ const char *site; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ assert_non_null(test_ctx); ++ ++ ret = sysdb_get_site(test_ctx, test_ctx->tctx->dom, &site); ++ assert_int_equal(ret, EOK); ++ assert_null(site); ++ ++ ret = sysdb_set_site(test_ctx->tctx->dom, "TestSite"); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_get_site(tmp_ctx, test_ctx->tctx->dom, &site); ++ assert_int_equal(ret, EOK); ++ assert_string_equal(site, "TestSite"); ++ ++ talloc_free(tmp_ctx); ++} ++ + int main(int argc, const char *argv[]) + { + int rv; +@@ -546,6 +571,9 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_sysdb_link_ad_multidom, + test_sysdb_subdom_setup, + test_sysdb_subdom_teardown), ++ cmocka_unit_test_setup_teardown(test_sysdb_set_and_get_site, ++ test_sysdb_subdom_setup, ++ test_sysdb_subdom_teardown), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.15.1 + diff --git a/0016-AD-Remember-last-site-discovered-in-sysdb.patch b/0016-AD-Remember-last-site-discovered-in-sysdb.patch new file mode 100644 index 0000000..f3b05a9 --- /dev/null +++ b/0016-AD-Remember-last-site-discovered-in-sysdb.patch @@ -0,0 +1,160 @@ +From 48f58549e2b687ba405162bd5db23f1c323732f7 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Wed, 1 Nov 2017 14:57:17 +0100 +Subject: [PATCH 16/79] AD: Remember last site discovered in sysdb + +This can speed up sssd startup. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3265 + +Reviewed-by: Jakub Hrozek +--- + src/db/sysdb_subdomains.c | 2 +- + src/providers/ad/ad_init.c | 2 +- + src/providers/ad/ad_srv.c | 21 +++++++++++++++++++++ + src/providers/ad/ad_srv.h | 1 + + src/providers/ad/ad_subdomains.c | 2 +- + src/providers/ipa/ipa_subdomains_server.c | 2 +- + 6 files changed, 26 insertions(+), 4 deletions(-) + +diff --git a/src/db/sysdb_subdomains.c b/src/db/sysdb_subdomains.c +index cb5de1afe3e8c9692789c5d2679eb3a4e6e1cdb2..353561765904efe4bd698c38949a1b290ecf0b80 100644 +--- a/src/db/sysdb_subdomains.c ++++ b/src/db/sysdb_subdomains.c +@@ -1291,7 +1291,7 @@ sysdb_get_site(TALLOC_CTX *mem_ctx, + const char **_site) + { + TALLOC_CTX *tmp_ctx; +- struct ldb_res *res; ++ struct ldb_result *res; + struct ldb_dn *dn; + const char *attrs[] = { SYSDB_SITE, NULL }; + errno_t ret; +diff --git a/src/providers/ad/ad_init.c b/src/providers/ad/ad_init.c +index 131e960d4c623398506f834742400df9c786b86b..e62025d4acd24844a5c7082d00c597516f35de16 100644 +--- a/src/providers/ad/ad_init.c ++++ b/src/providers/ad/ad_init.c +@@ -199,7 +199,7 @@ static errno_t ad_init_srv_plugin(struct be_ctx *be_ctx, + return EOK; + } + +- srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, ++ srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res, + default_host_dbs, ad_options->id, + hostname, ad_domain, + ad_site_override); +diff --git a/src/providers/ad/ad_srv.c b/src/providers/ad/ad_srv.c +index be1ba0f237add894566ae713ce5e29fd202d414c..4fa1668605e131b2e31802b1401f49fc6e00a23b 100644 +--- a/src/providers/ad/ad_srv.c ++++ b/src/providers/ad/ad_srv.c +@@ -34,6 +34,7 @@ + #include "providers/fail_over_srv.h" + #include "providers/ldap/sdap.h" + #include "providers/ldap/sdap_async.h" ++#include "db/sysdb.h" + + #define AD_SITE_DOMAIN_FMT "%s._sites.%s" + +@@ -475,6 +476,7 @@ int ad_get_client_site_recv(TALLOC_CTX *mem_ctx, + } + + struct ad_srv_plugin_ctx { ++ struct be_ctx *be_ctx; + struct be_resolv_ctx *be_res; + enum host_database *host_dbs; + struct sdap_options *opts; +@@ -486,6 +488,7 @@ struct ad_srv_plugin_ctx { + + struct ad_srv_plugin_ctx * + ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, ++ struct be_ctx *be_ctx, + struct be_resolv_ctx *be_res, + enum host_database *host_dbs, + struct sdap_options *opts, +@@ -494,12 +497,14 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + const char *ad_site_override) + { + struct ad_srv_plugin_ctx *ctx = NULL; ++ errno_t ret; + + ctx = talloc_zero(mem_ctx, struct ad_srv_plugin_ctx); + if (ctx == NULL) { + return NULL; + } + ++ ctx->be_ctx = be_ctx; + ctx->be_res = be_res; + ctx->host_dbs = host_dbs; + ctx->opts = opts; +@@ -524,6 +529,15 @@ ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, + if (ctx->current_site == NULL) { + goto fail; + } ++ } else { ++ ret = sysdb_get_site(ctx, be_ctx->domain, &ctx->current_site); ++ if (ret != EOK) { ++ /* Not fatal. */ ++ DEBUG(SSSDBG_MINOR_FAILURE, ++ "Unable to get current site from cache [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ ctx->current_site = NULL; ++ } + } + + return ctx; +@@ -556,6 +570,13 @@ ad_srv_plugin_ctx_switch_site(struct ad_srv_plugin_ctx *ctx, + talloc_zfree(ctx->current_site); + ctx->current_site = site; + ++ ret = sysdb_set_site(ctx->be_ctx->domain, ctx->current_site); ++ if (ret != EOK) { ++ /* Not fatal. */ ++ DEBUG(SSSDBG_MINOR_FAILURE, "Unable to store site information " ++ "[%d]: %s\n", ret, sss_strerror(ret)); ++ } ++ + return EOK; + } + +diff --git a/src/providers/ad/ad_srv.h b/src/providers/ad/ad_srv.h +index ae5efe44755fa09f74064014cce749e35b1831da..fddef686762e57bb95d648247131d39a797aa516 100644 +--- a/src/providers/ad/ad_srv.h ++++ b/src/providers/ad/ad_srv.h +@@ -25,6 +25,7 @@ struct ad_srv_plugin_ctx; + + struct ad_srv_plugin_ctx * + ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx, ++ struct be_ctx *be_ctx, + struct be_resolv_ctx *be_res, + enum host_database *host_dbs, + struct sdap_options *opts, +diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c +index 280aa54c23bf61e60d23ea91bd44a39f9f43d155..3fb9b950f171d85817cce35ac92ad7c4974ccb68 100644 +--- a/src/providers/ad/ad_subdomains.c ++++ b/src/providers/ad/ad_subdomains.c +@@ -245,7 +245,7 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx, + ad_options->id_ctx = ad_id_ctx; + + /* use AD plugin */ +- srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, ++ srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res, + default_host_dbs, + ad_id_ctx->ad_options->id, + hostname, +diff --git a/src/providers/ipa/ipa_subdomains_server.c b/src/providers/ipa/ipa_subdomains_server.c +index 10166d162f746fde176e6c7c2bfbe3906b1bfddc..d670a156b37608d20d49d79131138f02e4abf82b 100644 +--- a/src/providers/ipa/ipa_subdomains_server.c ++++ b/src/providers/ipa/ipa_subdomains_server.c +@@ -305,7 +305,7 @@ ipa_ad_ctx_new(struct be_ctx *be_ctx, + ad_site_override = dp_opt_get_string(ad_options->basic, AD_SITE); + + /* use AD plugin */ +- srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx->be_res, ++ srv_ctx = ad_srv_plugin_ctx_init(be_ctx, be_ctx, be_ctx->be_res, + default_host_dbs, + ad_id_ctx->ad_options->id, + id_ctx->server_mode->hostname, +-- +2.15.1 + diff --git a/0017-UTIL-Add-wrapper-function-to-configure-logger.patch b/0017-UTIL-Add-wrapper-function-to-configure-logger.patch new file mode 100644 index 0000000..2e0f13f --- /dev/null +++ b/0017-UTIL-Add-wrapper-function-to-configure-logger.patch @@ -0,0 +1,132 @@ +From dad79765d9ccafb3ba5d31a20462d73af96fa058 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 23 Oct 2017 14:58:14 +0200 +Subject: [PATCH 17/79] UTIL: Add wrapper function to configure logger +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Let's use one enum for logger type instead of many integers (debug_to_file, +debug_to_stderr plus some weird combination for journald). +Old variable were also transformed to enum for backward compatibility + +Reviewed-by: Fabiano Fidêncio +--- + src/util/debug.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/util/debug.h | 18 ++++++++++++++++++ + 2 files changed, 72 insertions(+) + +diff --git a/src/util/debug.c b/src/util/debug.c +index ca4fa4c6f5b150700a0a136d8a7ca9df30c29d73..4e469447e5ab8aa89cd57bcd6d00269875a12bc6 100644 +--- a/src/util/debug.c ++++ b/src/util/debug.c +@@ -43,9 +43,63 @@ int debug_timestamps = SSSDBG_TIMESTAMP_UNRESOLVED; + int debug_microseconds = SSSDBG_MICROSECONDS_UNRESOLVED; + int debug_to_file = 0; + int debug_to_stderr = 0; ++enum sss_logger_t sss_logger; + const char *debug_log_file = "sssd"; + FILE *debug_file = NULL; + ++const char *sss_logger_str[] = { ++ [STDERR_LOGGER] = "stderr", ++ [FILES_LOGGER] = "files", ++#ifdef WITH_JOURNALD ++ [JOURNALD_LOGGER] = "journald", ++#endif ++ NULL, ++}; ++ ++#ifdef WITH_JOURNALD ++#define JOURNALD_STR " journald," ++#else ++#define JOURNALD_STR "" ++#endif ++ ++void sss_set_logger(const char *logger) ++{ ++ /* use old flags */ ++ if (logger == NULL) { ++ if (debug_to_stderr != 0) { ++ sss_logger = STDERR_LOGGER; ++ } ++ /* It is never described what should be used in case of ++ * debug_to_stderr == 1 && debug_to_file == 1. Because neither ++ * of binaries provide both command line arguments. ++ * Let files have higher priority. ++ */ ++ if (debug_to_file != 0) { ++ sss_logger = FILES_LOGGER; ++ } ++#ifdef WITH_JOURNALD ++ if (debug_to_file == 0 && debug_to_stderr == 0) { ++ sss_logger = JOURNALD_LOGGER; ++ } ++#endif ++ } else { ++ if (strcmp(logger, "stderr") == 0) { ++ sss_logger = STDERR_LOGGER; ++ } else if (strcmp(logger, "files") == 0) { ++ sss_logger = FILES_LOGGER; ++#ifdef WITH_JOURNALD ++ } else if (strcmp(logger, "journald") == 0) { ++ sss_logger = JOURNALD_LOGGER; ++#endif ++ } else { ++ /* unexpected value */ ++ fprintf(stderr, "Unexpected logger: %s\nExpected:%s stderr, " ++ "files\n", logger, JOURNALD_STR); ++ sss_logger = STDERR_LOGGER; ++ } ++ } ++} ++ + errno_t set_debug_file_from_fd(const int fd) + { + FILE *dummy; +diff --git a/src/util/debug.h b/src/util/debug.h +index 2a1bd4ffd30817d7128805996c21105fe40982a2..4adafb7cfc03f7381c4d03071eb44edad04bee00 100644 +--- a/src/util/debug.h ++++ b/src/util/debug.h +@@ -31,13 +31,26 @@ + + #define APPEND_LINE_FEED 0x1 + ++enum sss_logger_t { ++ STDERR_LOGGER = 0, ++ FILES_LOGGER, ++#ifdef WITH_JOURNALD ++ JOURNALD_LOGGER, ++#endif ++}; ++ ++extern const char *sss_logger_str[]; + extern const char *debug_prg_name; + extern int debug_level; + extern int debug_timestamps; + extern int debug_microseconds; + extern int debug_to_file; + extern int debug_to_stderr; ++extern enum sss_logger_t sss_logger; + extern const char *debug_log_file; ++ ++void sss_set_logger(const char *logger); ++ + void sss_vdebug_fn(const char *file, + long line, + const char *function, +@@ -80,6 +93,11 @@ int get_fd_from_debug_file(void); + #define SSSDBG_MICROSECONDS_UNRESOLVED -1 + #define SSSDBG_MICROSECONDS_DEFAULT 0 + ++#define SSSD_LOGGER_OPTS \ ++ {"logger", '\0', POPT_ARG_STRING, &opt_logger, 0, \ ++ _("Set logger"), "stderr|files|journald"}, ++ ++ + #define SSSD_DEBUG_OPTS \ + {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0, \ + _("Debug level"), NULL}, \ +-- +2.15.1 + diff --git a/0018-Add-parameter-logger-to-daemons.patch b/0018-Add-parameter-logger-to-daemons.patch new file mode 100644 index 0000000..4d8585c --- /dev/null +++ b/0018-Add-parameter-logger-to-daemons.patch @@ -0,0 +1,829 @@ +From 0256b7734738302da9752db5297a3d41fccd40ac Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 23 Oct 2017 15:18:47 +0200 +Subject: [PATCH 18/79] Add parameter --logger to daemons +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Different binary handled information about logging differently + e,g, --debug-to-files --debug-to-stderr +And logging to journald was a special case of previous options +(!debug_file && !debug_to_stderr). It was also tied to the monitor option +"--daemon" and therefore loggind to stderr was used in interactive mode ++ systemd Type=notify. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3433 + +Reviewed-by: Justin Stephenson +Reviewed-by: Fabiano Fidêncio +--- + src/man/sssd.8.xml | 31 +++++++++++++++++++++++++ + src/monitor/monitor.c | 48 ++++++++++++--------------------------- + src/p11_child/p11_child_nss.c | 3 +++ + src/providers/ad/ad_gpo_child.c | 4 ++++ + src/providers/data_provider_be.c | 4 ++++ + src/providers/ipa/selinux_child.c | 4 ++++ + src/providers/krb5/krb5_child.c | 4 ++++ + src/providers/ldap/ldap_child.c | 4 ++++ + src/providers/proxy/proxy_auth.c | 4 ++-- + src/providers/proxy/proxy_child.c | 4 ++++ + src/responder/autofs/autofssrv.c | 4 ++++ + src/responder/ifp/ifpsrv.c | 4 ++++ + src/responder/kcm/kcm.c | 4 ++++ + src/responder/nss/nsssrv.c | 4 ++++ + src/responder/pac/pacsrv.c | 4 ++++ + src/responder/pam/pamsrv.c | 4 ++++ + src/responder/secrets/secsrv.c | 4 ++++ + src/responder/ssh/sshsrv.c | 4 ++++ + src/responder/sudo/sudosrv.c | 4 ++++ + src/tests/cmocka/dummy_child.c | 4 ++++ + src/tests/debug-tests.c | 10 ++++++++ + src/util/child_common.c | 2 +- + src/util/debug.c | 4 ++-- + src/util/server.c | 12 ++++++---- + 24 files changed, 135 insertions(+), 43 deletions(-) + +diff --git a/src/man/sssd.8.xml b/src/man/sssd.8.xml +index 923da6824907f0d2d140d9ca83f87338e7664f83..0b725628ff93f48f832140dd5dc15b040a8b179f 100644 +--- a/src/man/sssd.8.xml ++++ b/src/man/sssd.8.xml +@@ -92,6 +92,37 @@ + + + ++ ++ ++ value ++ ++ ++ ++ Location where SSSD will send log messages. This option ++ overrides the value of the deprecated option ++ . The deprecated ++ option will still work if the ++ is not used. ++ ++ ++ stderr: Redirect debug messages to ++ standard error output. ++ ++ ++ files: Redirect debug messages to ++ the log files. By default, the log files are stored in ++ /var/log/sssd and there are ++ separate log files for every SSSD service and domain. ++ ++ ++ journald: Redirect debug messages ++ to systemd-journald ++ ++ ++ Default: not set ++ ++ ++ + + + , +diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c +index 7726548bbb666bb189667efc1de2295f8a001105..3c0b7ab2dac10fe15a8a5b807cb68ea4b7ab8461 100644 +--- a/src/monitor/monitor.c ++++ b/src/monitor/monitor.c +@@ -1211,22 +1211,11 @@ static int get_service_config(struct mt_ctx *ctx, const char *name, + } + } + +- if (debug_to_file) { +- svc->command = talloc_strdup_append( +- svc->command, " --debug-to-files" +- ); +- if (!svc->command) { +- talloc_free(svc); +- return ENOMEM; +- } +- } else if (ctx->is_daemon == false) { +- svc->command = talloc_strdup_append( +- svc->command, " --debug-to-stderr" +- ); +- if (!svc->command) { +- talloc_free(svc); +- return ENOMEM; +- } ++ svc->command = talloc_asprintf_append( ++ svc->command, " --logger=%s", sss_logger_str[sss_logger]); ++ if (!svc->command) { ++ talloc_free(svc); ++ return ENOMEM; + } + } + +@@ -1374,22 +1363,11 @@ static int get_provider_config(struct mt_ctx *ctx, const char *name, + } + } + +- if (debug_to_file) { +- svc->command = talloc_strdup_append( +- svc->command, " --debug-to-files" +- ); +- if (!svc->command) { +- talloc_free(svc); +- return ENOMEM; +- } +- } else if (ctx->is_daemon == false) { +- svc->command = talloc_strdup_append( +- svc->command, " --debug-to-stderr" +- ); +- if (!svc->command) { +- talloc_free(svc); +- return ENOMEM; +- } ++ svc->command = talloc_asprintf_append( ++ svc->command, " --logger=%s", sss_logger_str[sss_logger]); ++ if (!svc->command) { ++ talloc_free(svc); ++ return ENOMEM; + } + } + +@@ -2454,6 +2432,7 @@ int main(int argc, const char *argv[]) + int opt_version = 0; + int opt_netlinkoff = 0; + char *opt_config_file = NULL; ++ char *opt_logger = NULL; + char *config_file = NULL; + int flags = 0; + struct main_context *main_ctx; +@@ -2465,6 +2444,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + {"daemon", 'D', POPT_ARG_NONE, &opt_daemon, 0, \ + _("Become a daemon (default)"), NULL }, \ + {"interactive", 'i', POPT_ARG_NONE, &opt_interactive, 0, \ +@@ -2551,6 +2531,8 @@ int main(int argc, const char *argv[]) + debug_to_stderr = 1; + } + ++ sss_set_logger(opt_logger); ++ + if (opt_config_file) { + config_file = talloc_strdup(tmp_ctx, opt_config_file); + } else { +@@ -2575,7 +2557,7 @@ int main(int argc, const char *argv[]) + + /* Open before server_setup() does to have logging + * during configuration checking */ +- if (debug_to_file) { ++ if (sss_logger == FILES_LOGGER) { + ret = open_debug_file(); + if (ret) { + return 7; +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index f165b58e63d2b8a6f26acf8bd89e7b41713e7359..e7dbcb689220d1cd2585fbde5f26e84f8fa15cc2 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -537,6 +537,7 @@ int main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; ++ char *opt_logger = NULL; + errno_t ret; + TALLOC_CTX *main_ctx = NULL; + char *cert; +@@ -564,6 +565,7 @@ int main(int argc, const char *argv[]) + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, + &debug_to_stderr, 0, + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + {"auth", 0, POPT_ARG_NONE, NULL, 'a', _("Run in auth mode"), NULL}, + {"pre", 0, POPT_ARG_NONE, NULL, 'p', _("Run in pre-auth mode"), NULL}, + {"pin", 0, POPT_ARG_NONE, NULL, 'i', _("Expect PIN on stdin"), NULL}, +@@ -672,6 +674,7 @@ int main(int argc, const char *argv[]) + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } + } ++ sss_set_logger(opt_logger); + + DEBUG(SSSDBG_TRACE_FUNC, "p11_child started.\n"); + +diff --git a/src/providers/ad/ad_gpo_child.c b/src/providers/ad/ad_gpo_child.c +index 8e5e062547721567cb450f9d0f72f1ec8cb99f96..5375cc691e8649c289672b74c4bfe5266c8222c9 100644 +--- a/src/providers/ad/ad_gpo_child.c ++++ b/src/providers/ad/ad_gpo_child.c +@@ -687,6 +687,7 @@ main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; ++ char *opt_logger = NULL; + errno_t ret; + int sysvol_gpt_version; + int result; +@@ -710,6 +711,7 @@ main(int argc, const char *argv[]) + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, + &debug_to_stderr, 0, + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + POPT_TABLEEND + }; + +@@ -744,6 +746,8 @@ main(int argc, const char *argv[]) + } + } + ++ sss_set_logger(opt_logger); ++ + DEBUG(SSSDBG_TRACE_FUNC, "gpo_child started.\n"); + + main_ctx = talloc_new(NULL); +diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c +index 2e55dc4e3fe9ba1aa8c1c51c426efee00b9ae91d..56ddac112a209b6937313d3d3c94a73d2067331f 100644 +--- a/src/providers/data_provider_be.c ++++ b/src/providers/data_provider_be.c +@@ -537,6 +537,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + char *be_domain = NULL; + char *srv_name = NULL; + struct main_context *main_ctx; +@@ -548,6 +549,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + {"domain", 0, POPT_ARG_STRING, &be_domain, 0, + _("Domain of the information provider (mandatory)"), NULL }, +@@ -582,6 +584,8 @@ int main(int argc, const char *argv[]) + debug_log_file = talloc_asprintf(NULL, "sssd_%s", be_domain); + if (!debug_log_file) return 2; + ++ sss_set_logger(opt_logger); ++ + srv_name = talloc_asprintf(NULL, "sssd[be[%s]]", be_domain); + if (!srv_name) return 2; + +diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c +index 073475094ee491bd5453898c6ba65214fa14fe59..120492686963241b7e419413f489cc38953e32f2 100644 +--- a/src/providers/ipa/selinux_child.c ++++ b/src/providers/ipa/selinux_child.c +@@ -206,6 +206,7 @@ int main(int argc, const char *argv[]) + struct response *resp = NULL; + ssize_t written; + bool needs_update; ++ char *opt_logger = NULL; + + struct poptOption long_options[] = { + POPT_AUTOHELP +@@ -220,6 +221,7 @@ int main(int argc, const char *argv[]) + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, + &debug_to_stderr, 0, + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + POPT_TABLEEND + }; + +@@ -254,6 +256,8 @@ int main(int argc, const char *argv[]) + } + } + ++ sss_set_logger(opt_logger); ++ + DEBUG(SSSDBG_TRACE_FUNC, "selinux_child started.\n"); + DEBUG(SSSDBG_TRACE_INTERNAL, + "Running with effective IDs: [%"SPRIuid"][%"SPRIgid"].\n", +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index b8ee497728b4b70fae89e528172e9d5bd42239c0..b44f3a20f1c0725304a37620d36f8872cf9ca5d7 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -3020,6 +3020,7 @@ int main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; ++ char *opt_logger = NULL; + errno_t ret; + krb5_error_code kerr; + uid_t fast_uid; +@@ -3039,6 +3040,7 @@ int main(int argc, const char *argv[]) + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, + &debug_to_stderr, 0, + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + {CHILD_OPT_FAST_CCACHE_UID, 0, POPT_ARG_INT, &fast_uid, 0, + _("The user to create FAST ccache as"), NULL}, + {CHILD_OPT_FAST_CCACHE_GID, 0, POPT_ARG_INT, &fast_gid, 0, +@@ -3097,6 +3099,8 @@ int main(int argc, const char *argv[]) + } + } + ++ sss_set_logger(opt_logger); ++ + DEBUG(SSSDBG_TRACE_FUNC, "krb5_child started.\n"); + + kr = talloc_zero(NULL, struct krb5_req); +diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c +index b796e5cae01517c85c2fc1605b1e5877454691dc..baeed239db5dc7ffa482edcbc155f25f718c8249 100644 +--- a/src/providers/ldap/ldap_child.c ++++ b/src/providers/ldap/ldap_child.c +@@ -599,6 +599,7 @@ int main(int argc, const char *argv[]) + int kerr; + int opt; + int debug_fd = -1; ++ char *opt_logger = NULL; + poptContext pc; + TALLOC_CTX *main_ctx = NULL; + uint8_t *buf = NULL; +@@ -622,6 +623,7 @@ int main(int argc, const char *argv[]) + _("An open file descriptor for the debug logs"), NULL}, + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \ + _("Send the debug output to stderr directly."), NULL }, \ ++ SSSD_LOGGER_OPTS + POPT_TABLEEND + }; + +@@ -657,6 +659,8 @@ int main(int argc, const char *argv[]) + } + } + ++ sss_set_logger(opt_logger); ++ + BlockSignals(false, SIGTERM); + CatchSignal(SIGTERM, sig_term_handler); + +diff --git a/src/providers/proxy/proxy_auth.c b/src/providers/proxy/proxy_auth.c +index a05586e60b6ef894b0fcf1b8b3f30fdbf51a808d..665a29cf779290b8d35973245a36a1b5224bca78 100644 +--- a/src/providers/proxy/proxy_auth.c ++++ b/src/providers/proxy/proxy_auth.c +@@ -178,9 +178,9 @@ static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx, + + state->command = talloc_asprintf(req, + "%s/proxy_child -d %#.4x --debug-timestamps=%d " +- "--debug-microseconds=%d%s --domain %s --id %d", ++ "--debug-microseconds=%d --logger=%s --domain %s --id %d", + SSSD_LIBEXEC_PATH, debug_level, debug_timestamps, +- debug_microseconds, (debug_to_file ? " --debug-to-files" : ""), ++ debug_microseconds, sss_logger_str[sss_logger], + auth_ctx->be->domain->name, + child_ctx->id); + if (state->command == NULL) { +diff --git a/src/providers/proxy/proxy_child.c b/src/providers/proxy/proxy_child.c +index be58622eb8b26231eeb6699976d51f57dc44de98..ae4855adeb5cc68f1a19003355a5d94f5b1bb378 100644 +--- a/src/providers/proxy/proxy_child.c ++++ b/src/providers/proxy/proxy_child.c +@@ -504,6 +504,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + char *domain = NULL; + char *srv_name = NULL; + char *conf_entry = NULL; +@@ -517,6 +518,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + {"domain", 0, POPT_ARG_STRING, &domain, 0, + _("Domain of the information provider (mandatory)"), NULL }, +@@ -561,6 +563,8 @@ int main(int argc, const char *argv[]) + debug_log_file = talloc_asprintf(NULL, "proxy_child_%s", domain); + if (!debug_log_file) return 2; + ++ sss_set_logger(opt_logger); ++ + srv_name = talloc_asprintf(NULL, "sssd[proxy_child[%s]]", domain); + if (!srv_name) return 2; + +diff --git a/src/responder/autofs/autofssrv.c b/src/responder/autofs/autofssrv.c +index cfb2233fdfc346bf27b128ee8c4261f4c73e3470..b0762a2b685a7c5ab3abfa281f0906ad8bfe1c88 100644 +--- a/src/responder/autofs/autofssrv.c ++++ b/src/responder/autofs/autofssrv.c +@@ -185,6 +185,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -193,6 +194,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -221,6 +223,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_autofs"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[autofs]", 0, uid, gid, + CONFDB_AUTOFS_CONF_ENTRY, &main_ctx); + if (ret != EOK) { +diff --git a/src/responder/ifp/ifpsrv.c b/src/responder/ifp/ifpsrv.c +index 0dc61a42200cc79fc6f12515a8f581ad0201a043..85dfbacc217e2870dd7517e36a1d39e7f2054a8b 100644 +--- a/src/responder/ifp/ifpsrv.c ++++ b/src/responder/ifp/ifpsrv.c +@@ -355,6 +355,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -363,6 +364,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -391,6 +393,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_ifp"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[ifp]", 0, 0, 0, + CONFDB_IFP_CONF_ENTRY, &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c +index 2202f96381a2622a2c5433e281172287b325f960..358fcc18165dec7b41a7389a3ef22660ac04b4a8 100644 +--- a/src/responder/kcm/kcm.c ++++ b/src/responder/kcm/kcm.c +@@ -258,6 +258,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -266,6 +267,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + POPT_TABLEEND + }; +@@ -293,6 +295,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_kcm"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[kcm]", 0, uid, gid, CONFDB_KCM_CONF_ENTRY, + &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/nss/nsssrv.c b/src/responder/nss/nsssrv.c +index d67b9fac8d770d113560e41b259e2d5edd219343..1559c314e5353d41c61c83ecc712311ac18a7202 100644 +--- a/src/responder/nss/nsssrv.c ++++ b/src/responder/nss/nsssrv.c +@@ -405,6 +405,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -413,6 +414,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -441,6 +443,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_nss"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[nss]", 0, uid, gid, CONFDB_NSS_CONF_ENTRY, + &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/pac/pacsrv.c b/src/responder/pac/pacsrv.c +index 1f820c07f5c55fe8df75cce05b403c41075d9f94..b72e5c8d2a42bc85f0974dcb81a1290d3f740986 100644 +--- a/src/responder/pac/pacsrv.c ++++ b/src/responder/pac/pacsrv.c +@@ -209,6 +209,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -217,6 +218,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -245,6 +247,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_pac"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[pac]", 0, uid, gid, + CONFDB_PAC_CONF_ENTRY, &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/pam/pamsrv.c b/src/responder/pam/pamsrv.c +index 79470823d18138da6ef9235e6336a3220ead1797..cc0e4bddcdbecfadabea78a6d2815d0ac6d651b6 100644 +--- a/src/responder/pam/pamsrv.c ++++ b/src/responder/pam/pamsrv.c +@@ -355,6 +355,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -365,6 +366,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -393,6 +395,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_pam"; + ++ sss_set_logger(opt_logger); ++ + if (!is_socket_activated()) { + /* Crate pipe file descriptors here before privileges are dropped + * in server_setup() */ +diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c +index 2b661b165ef0c174557f53012b2dbaa236a6e359..59c0f3a56040a6fc0c092247fbd124a069f97153 100644 +--- a/src/responder/secrets/secsrv.c ++++ b/src/responder/secrets/secsrv.c +@@ -324,6 +324,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -332,6 +333,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + POPT_TABLEEND + }; +@@ -359,6 +361,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_secrets"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[secrets]", 0, uid, gid, CONFDB_SEC_CONF_ENTRY, + &main_ctx); + if (ret != EOK) return 2; +diff --git a/src/responder/ssh/sshsrv.c b/src/responder/ssh/sshsrv.c +index 440f0e2b9dc06e3dc52ff96d7207b8a3727865c0..8b0e7cc2d71044d7ab3bd2439041f678ddedb4cd 100644 +--- a/src/responder/ssh/sshsrv.c ++++ b/src/responder/ssh/sshsrv.c +@@ -177,6 +177,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -185,6 +186,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -213,6 +215,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_ssh"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[ssh]", 0, uid, gid, + CONFDB_SSH_CONF_ENTRY, &main_ctx); + if (ret != EOK) { +diff --git a/src/responder/sudo/sudosrv.c b/src/responder/sudo/sudosrv.c +index dca70ea4afc0e6df6d1b1864338c7b1091a98fee..19058321a25022d7704556ec0ef79729db3ac1f2 100644 +--- a/src/responder/sudo/sudosrv.c ++++ b/src/responder/sudo/sudosrv.c +@@ -178,6 +178,7 @@ int main(int argc, const char *argv[]) + { + int opt; + poptContext pc; ++ char *opt_logger = NULL; + struct main_context *main_ctx; + int ret; + uid_t uid; +@@ -186,6 +187,7 @@ int main(int argc, const char *argv[]) + struct poptOption long_options[] = { + POPT_AUTOHELP + SSSD_MAIN_OPTS ++ SSSD_LOGGER_OPTS + SSSD_SERVER_OPTS(uid, gid) + SSSD_RESPONDER_OPTS + POPT_TABLEEND +@@ -214,6 +216,8 @@ int main(int argc, const char *argv[]) + /* set up things like debug, signals, daemonization, etc... */ + debug_log_file = "sssd_sudo"; + ++ sss_set_logger(opt_logger); ++ + ret = server_setup("sssd[sudo]", 0, uid, gid, CONFDB_SUDO_CONF_ENTRY, + &main_ctx); + if (ret != EOK) { +diff --git a/src/tests/cmocka/dummy_child.c b/src/tests/cmocka/dummy_child.c +index bcaa9455037a0604422750bf7cc719a25cef4a99..811cb40490c89c4250401e0d8d3e9d1c277f57af 100644 +--- a/src/tests/cmocka/dummy_child.c ++++ b/src/tests/cmocka/dummy_child.c +@@ -34,6 +34,7 @@ int main(int argc, const char *argv[]) + { + int opt; + int debug_fd = -1; ++ char *opt_logger = NULL; + poptContext pc; + ssize_t len; + ssize_t written; +@@ -55,6 +56,7 @@ int main(int argc, const char *argv[]) + _("An open file descriptor for the debug logs"), NULL}, + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \ + _("Send the debug output to stderr directly."), NULL }, ++ SSSD_LOGGER_OPTS + {"guitar", 0, POPT_ARG_STRING, &guitar, 0, _("Who plays guitar"), NULL }, + {"drums", 0, POPT_ARG_STRING, &drums, 0, _("Who plays drums"), NULL }, + POPT_TABLEEND +@@ -76,6 +78,8 @@ int main(int argc, const char *argv[]) + } + poptFreeContext(pc); + ++ sss_set_logger(opt_logger); ++ + action = getenv("TEST_CHILD_ACTION"); + if (action) { + if (strcasecmp(action, "check_extra_args") == 0) { +diff --git a/src/tests/debug-tests.c b/src/tests/debug-tests.c +index d904d7eb8b5418608023faca0d62067f3106d23b..1446ec0474ab4bf72e66b58831fef59defd7be76 100644 +--- a/src/tests/debug-tests.c ++++ b/src/tests/debug-tests.c +@@ -343,6 +343,7 @@ START_TEST(test_debug_is_set_single_no_timestamp) + debug_microseconds = 0; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); + + for (i = 0; i <= 9; i++) { + debug_level = levels[i]; +@@ -385,6 +386,8 @@ START_TEST(test_debug_is_set_single_timestamp) + debug_microseconds = 0; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ + + for (i = 0; i <= 9; i++) { + debug_level = levels[i]; +@@ -432,6 +435,8 @@ START_TEST(test_debug_is_set_single_timestamp_microseconds) + debug_microseconds = 1; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ + + for (i = 0; i <= 9; i++) { + debug_level = levels[i]; +@@ -480,6 +485,8 @@ START_TEST(test_debug_is_notset_no_timestamp) + debug_microseconds = 0; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ + + for (i = 0; i <= 9; i++) { + debug_level = all_set & ~levels[i]; +@@ -525,6 +532,8 @@ START_TEST(test_debug_is_notset_timestamp) + debug_microseconds = 0; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ + + for (i = 0; i <= 9; i++) { + debug_level = all_set & ~levels[i]; +@@ -570,6 +579,7 @@ START_TEST(test_debug_is_notset_timestamp_microseconds) + debug_microseconds = 1; + debug_to_file = 1; + debug_prg_name = "sssd"; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); + + for (i = 0; i <= 9; i++) { + debug_level = all_set & ~levels[i]; +diff --git a/src/util/child_common.c b/src/util/child_common.c +index b300d84bf432608db96de36e04637b5fb115212e..dc070f26446305e07cbb34edd1e4d72db72aedc5 100644 +--- a/src/util/child_common.c ++++ b/src/util/child_common.c +@@ -676,7 +676,7 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, + } + + if (child_debug_stderr) { +- argv[--argc] = talloc_strdup(argv, "--debug-to-stderr"); ++ argv[--argc] = talloc_strdup(argv, "--logger=stderr"); + if (argv[argc] == NULL) { + ret = ENOMEM; + goto fail; +diff --git a/src/util/debug.c b/src/util/debug.c +index 4e469447e5ab8aa89cd57bcd6d00269875a12bc6..30801fce7c27b115d1cafd4ed826a57c7d444a72 100644 +--- a/src/util/debug.c ++++ b/src/util/debug.c +@@ -277,7 +277,7 @@ void sss_vdebug_fn(const char *file, + errno_t ret; + va_list ap_fallback; + +- if (!debug_file && !debug_to_stderr) { ++ if (sss_logger == JOURNALD_LOGGER) { + /* If we are not outputting logs to files, we should be sending them + * to journald. + * NOTE: on modern systems, this is where stdout/stderr will end up +@@ -470,7 +470,7 @@ int rotate_debug_files(void) + int ret; + errno_t error; + +- if (!debug_to_file) return EOK; ++ if (sss_logger != FILES_LOGGER) return EOK; + + do { + error = 0; +diff --git a/src/util/server.c b/src/util/server.c +index 4e65cc66c01ba020b13a88df8e017765ac97f76e..f76cb6a0838324d4fc3ed376eb425fee2412a817 100644 +--- a/src/util/server.c ++++ b/src/util/server.c +@@ -455,7 +455,7 @@ int server_setup(const char *name, int flags, + char *conf_db; + int ret = EOK; + bool dt; +- bool dl; ++ bool dl = false; + bool dm; + struct tevent_signal *tes; + struct logrotate_ctx *lctx; +@@ -637,16 +637,18 @@ int server_setup(const char *name, int flags, + } + + /* same for debug to file */ +- dl = (debug_to_file != 0); + ret = confdb_get_bool(ctx->confdb_ctx, conf_entry, + CONFDB_SERVICE_DEBUG_TO_FILES, +- dl, &dl); ++ false, &dl); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Error reading from confdb (%d) [%s]\n", + ret, strerror(ret)); + return ret; + } +- if (dl) debug_to_file = 1; ++ if (dl) { ++ debug_to_file = 1; ++ sss_set_logger(sss_logger_str[FILES_LOGGER]); ++ } + + /* before opening the log file set up log rotation */ + lctx = talloc_zero(ctx, struct logrotate_ctx); +@@ -662,7 +664,7 @@ int server_setup(const char *name, int flags, + } + + /* open log file if told so */ +- if (debug_to_file) { ++ if (sss_logger == FILES_LOGGER) { + ret = open_debug_file(); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) " +-- +2.15.1 + diff --git a/0019-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch b/0019-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch new file mode 100644 index 0000000..13166f1 --- /dev/null +++ b/0019-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch @@ -0,0 +1,258 @@ +From e2c0eecb49af621de77426cb46fff9bbb9a3f220 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Mon, 23 Oct 2017 18:03:46 +0200 +Subject: [PATCH 19/79] SYSTEMD: Replace parameter --debug-to-files with + ${DEBUG_LOGGER} +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Users can set variable DEBUG_LOGGER in environment files +(/etc/sysconfig/sssd or /etc/default/sssd; depending on the distribution) +to override default logging to files. + +e.g. +DEBUG_LOGGER=--logger=stderr +DEBUG_LOGGER=--logger=journald + +Resolves: +https://pagure.io/SSSD/sssd/issue/3433 + +Reviewed-by: Fabiano Fidêncio +--- + Makefile.am | 12 +----------- + contrib/sssd.spec.in | 4 ---- + src/sysv/systemd/journal.conf.in | 7 ------- + src/sysv/systemd/sssd-autofs.service.in | 3 ++- + src/sysv/systemd/sssd-ifp.service.in | 3 ++- + src/sysv/systemd/sssd-kcm.service.in | 3 ++- + src/sysv/systemd/sssd-nss.service.in | 3 ++- + src/sysv/systemd/sssd-pac.service.in | 3 ++- + src/sysv/systemd/sssd-pam.service.in | 3 ++- + src/sysv/systemd/sssd-secrets.service.in | 3 ++- + src/sysv/systemd/sssd-ssh.service.in | 3 ++- + src/sysv/systemd/sssd-sudo.service.in | 3 ++- + src/sysv/systemd/sssd.service.in | 3 ++- + 13 files changed, 21 insertions(+), 32 deletions(-) + delete mode 100644 src/sysv/systemd/journal.conf.in + +diff --git a/Makefile.am b/Makefile.am +index 41a8f32f4e76fdcbd09ad833161f0bdada19e389..5483375167d99568e8313c9a0488900419be6ec3 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -91,7 +91,7 @@ sssdkcmdatadir = $(datadir)/sssd-kcm + deskprofilepath = $(sss_statedir)/deskprofile + + if HAVE_SYSTEMD_UNIT +-ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --debug-to-files --dbus-activated ++ifp_exec_cmd = $(sssdlibexecdir)/sssd_ifp --uid 0 --gid 0 --dbus-activated + ifp_systemdservice = SystemdService=sssd-ifp.service + ifp_restart = Restart=on-failure + else +@@ -4483,10 +4483,6 @@ if BUILD_KCM + src/sysv/systemd/sssd-kcm.service \ + $(NULL) + endif +-if WITH_JOURNALD +- systemdconf_DATA += \ +- src/sysv/systemd/journal.conf +-endif + else + if HAVE_SUSE + init_SCRIPTS += \ +@@ -4535,7 +4531,6 @@ replace_script = \ + + EXTRA_DIST += \ + src/sysv/systemd/sssd.service.in \ +- src/sysv/systemd/journal.conf.in \ + src/sysv/systemd/sssd-nss.socket.in \ + src/sysv/systemd/sssd-nss.service.in \ + src/sysv/systemd/sssd-pam.socket.in \ +@@ -4585,10 +4580,6 @@ src/sysv/systemd/sssd.service: src/sysv/systemd/sssd.service.in Makefile + @$(MKDIR_P) src/sysv/systemd/ + $(replace_script) + +-src/sysv/systemd/journal.conf: src/sysv/systemd/journal.conf.in Makefile +- @$(MKDIR_P) src/sysv/systemd/ +- $(replace_script) +- + src/sysv/systemd/sssd-nss.socket: src/sysv/systemd/sssd-nss.socket.in Makefile + @$(MKDIR_P) src/sysv/systemd/ + $(replace_script) +@@ -4924,7 +4915,6 @@ endif + rm -f $(builddir)/src/sysv/systemd/sssd-secrets.service + rm -f $(builddir)/src/sysv/systemd/sssd-kcm.socket + rm -f $(builddir)/src/sysv/systemd/sssd-kcm.service +- rm -f $(builddir)/src/sysv/systemd/journal.conf + rm -f $(builddir)/src/tools/wrappers/sss_debuglevel + + CLEANFILES += *.X */*.X */*/*.X +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index d6ab73e60863316cbf239d34242959fdfe8d4b1b..4aafd1832b67161ff1c25a4e9ad689586a227a25 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -971,10 +971,6 @@ done + %attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd + %attr(711,sssd,sssd) %dir %{_sysconfdir}/sssd/conf.d + %ghost %attr(0600,sssd,sssd) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf +-%if (0%{?use_systemd} == 1) +-%attr(755,root,root) %dir %{_sysconfdir}/systemd/system/sssd.service.d +-%config(noreplace) %{_sysconfdir}/systemd/system/sssd.service.d/journal.conf +-%endif + %dir %{_sysconfdir}/logrotate.d + %config(noreplace) %{_sysconfdir}/logrotate.d/sssd + %dir %{_sysconfdir}/rwtab.d +diff --git a/src/sysv/systemd/journal.conf.in b/src/sysv/systemd/journal.conf.in +deleted file mode 100644 +index 9ce170b4893629792516aab41573adea1fb741f0..0000000000000000000000000000000000000000 +--- a/src/sysv/systemd/journal.conf.in ++++ /dev/null +@@ -1,7 +0,0 @@ +-[Service] +-# Uncomment *both* of the following lines to enable debug logging +-# to go to journald instead of /var/log/sssd. You will need to +-# run 'systemctl daemon-reload' and then restart the SSSD service +-# for this to take effect +-#ExecStart= +-#ExecStart=@sbindir@/sssd -i +diff --git a/src/sysv/systemd/sssd-autofs.service.in b/src/sysv/systemd/sssd-autofs.service.in +index 32ea6e19ca7f9aa65599c0cf296a8c5e73362271..c2dc254c8f3f56cb6ae4dc481781688aa702b102 100644 +--- a/src/sysv/systemd/sssd-autofs.service.in ++++ b/src/sysv/systemd/sssd-autofs.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-autofs.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_autofs.log +-ExecStart=@libexecdir@/sssd/sssd_autofs --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_autofs ${DEBUG_LOGGER} --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd-ifp.service.in b/src/sysv/systemd/sssd-ifp.service.in +index 8e7abdb0e8c5ec83f9423c688daf845a16c57e7e..05a9a602b2d27c54a4faa79c58e0ecba90267100 100644 +--- a/src/sysv/systemd/sssd-ifp.service.in ++++ b/src/sysv/systemd/sssd-ifp.service.in +@@ -5,7 +5,8 @@ After=sssd.service + BindsTo=sssd.service + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + Type=dbus + BusName=org.freedesktop.sssd.infopipe +-ExecStart=@ifp_exec_cmd@ ++ExecStart=@ifp_exec_cmd@ ${DEBUG_LOGGER} + @ifp_restart@ +diff --git a/src/sysv/systemd/sssd-kcm.service.in b/src/sysv/systemd/sssd-kcm.service.in +index 1e2bee12dc3bedd17d41b86f91c9b2b52d985c40..92306f97ec73a775739bfdb4454df14956e5e133 100644 +--- a/src/sysv/systemd/sssd-kcm.service.in ++++ b/src/sysv/systemd/sssd-kcm.service.in +@@ -6,4 +6,5 @@ Documentation=man:sssd-kcm(5) + Also=sssd-kcm.socket + + [Service] +-ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 --debug-to-files ++Environment=DEBUG_LOGGER=--logger=files ++ExecStart=@libexecdir@/sssd/sssd_kcm --uid 0 --gid 0 ${DEBUG_LOGGER} +diff --git a/src/sysv/systemd/sssd-nss.service.in b/src/sysv/systemd/sssd-nss.service.in +index 6a29078d5a36dff229e47bf7ce953e46443ce023..fe771ad0fa99968bb1d42037abf2f960271589b1 100644 +--- a/src/sysv/systemd/sssd-nss.service.in ++++ b/src/sysv/systemd/sssd-nss.service.in +@@ -9,5 +9,6 @@ RefuseManualStart=true + Also=sssd-nss.socket + + [Service] +-ExecStart=@libexecdir@/sssd/sssd_nss --debug-to-files --socket-activated ++Environment=DEBUG_LOGGER=--logger=files ++ExecStart=@libexecdir@/sssd/sssd_nss ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-pac.service.in b/src/sysv/systemd/sssd-pac.service.in +index ffbfdec030ba6d5cf75c989854c27bc46b6983a5..dbd25abc476f579c9d8cce171fdeafa06e567610 100644 +--- a/src/sysv/systemd/sssd-pac.service.in ++++ b/src/sysv/systemd/sssd-pac.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-pac.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pac.log +-ExecStart=@libexecdir@/sssd/sssd_pac --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_pac ${DEBUG_LOGGER} --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd-pam.service.in b/src/sysv/systemd/sssd-pam.service.in +index 6dec46f0c5d384c500268dafcd00af894088e0b6..df722d1f3014bf62cc60114c30331424d14f411b 100644 +--- a/src/sysv/systemd/sssd-pam.service.in ++++ b/src/sysv/systemd/sssd-pam.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-pam.socket sssd-pam-priv.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pam.log +-ExecStart=@libexecdir@/sssd/sssd_pam --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_pam ${DEBUG_LOGGER} --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd-secrets.service.in b/src/sysv/systemd/sssd-secrets.service.in +index f45d647677a62900c01c7eb103597f2b1387498c..a7b41e0b16a5fa882546b41047e616fd2140329f 100644 +--- a/src/sysv/systemd/sssd-secrets.service.in ++++ b/src/sysv/systemd/sssd-secrets.service.in +@@ -6,4 +6,5 @@ Documentation=man:sssd-secrets(5) + Also=sssd-secrets.socket + + [Service] +-ExecStart=@libexecdir@/sssd/sssd_secrets --uid 0 --gid 0 --debug-to-files ++Environment=DEBUG_LOGGER=--logger=files ++ExecStart=@libexecdir@/sssd/sssd_secrets --uid 0 --gid 0 ${DEBUG_LOGGER} +diff --git a/src/sysv/systemd/sssd-ssh.service.in b/src/sysv/systemd/sssd-ssh.service.in +index 6f233b4854018d79cc0ad9d67d53ebd67a49f7b7..f41249ea0fe19e5044d5d06ba195ab604d8e6a29 100644 +--- a/src/sysv/systemd/sssd-ssh.service.in ++++ b/src/sysv/systemd/sssd-ssh.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-ssh.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_ssh.log +-ExecStart=@libexecdir@/sssd/sssd_ssh --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_ssh ${DEBUG_LOGGER} --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd-sudo.service.in b/src/sysv/systemd/sssd-sudo.service.in +index b59bcbcd817c3986d7ee245b1083f90ff5a3775a..da022f768af91e360182fad0ff885fad43ecfdc0 100644 +--- a/src/sysv/systemd/sssd-sudo.service.in ++++ b/src/sysv/systemd/sssd-sudo.service.in +@@ -9,8 +9,9 @@ RefuseManualStart=true + Also=sssd-sudo.socket + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_sudo.log +-ExecStart=@libexecdir@/sssd/sssd_sudo --debug-to-files --socket-activated ++ExecStart=@libexecdir@/sssd/sssd_sudo --socket-activated + Restart=on-failure + User=@SSSD_USER@ + Group=@SSSD_USER@ +diff --git a/src/sysv/systemd/sssd.service.in b/src/sysv/systemd/sssd.service.in +index 05cfd3705084dbff8b46fb07e736612612c58b70..cea848fac80303d6fae12dd84316a91dbc60072d 100644 +--- a/src/sysv/systemd/sssd.service.in ++++ b/src/sysv/systemd/sssd.service.in +@@ -5,8 +5,9 @@ Before=systemd-user-sessions.service nss-user-lookup.target + Wants=nss-user-lookup.target + + [Service] ++Environment=DEBUG_LOGGER=--logger=files + EnvironmentFile=-@environment_file@ +-ExecStart=@sbindir@/sssd -i -f ++ExecStart=@sbindir@/sssd -i ${DEBUG_LOGGER} + Type=notify + NotifyAccess=main + +-- +2.15.1 + diff --git a/0020-SYSTEMD-Add-environment-file-to-responder-service-fi.patch b/0020-SYSTEMD-Add-environment-file-to-responder-service-fi.patch new file mode 100644 index 0000000..6f860c3 --- /dev/null +++ b/0020-SYSTEMD-Add-environment-file-to-responder-service-fi.patch @@ -0,0 +1,106 @@ +From 536c8687921a0afe072bf81fca0bbb618a4c92fc Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 24 Oct 2017 12:15:48 +0200 +Subject: [PATCH 20/79] SYSTEMD: Add environment file to responder service + files +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +--- + src/sysv/systemd/sssd-autofs.service.in | 1 + + src/sysv/systemd/sssd-ifp.service.in | 1 + + src/sysv/systemd/sssd-nss.service.in | 1 + + src/sysv/systemd/sssd-pac.service.in | 1 + + src/sysv/systemd/sssd-pam.service.in | 1 + + src/sysv/systemd/sssd-ssh.service.in | 1 + + src/sysv/systemd/sssd-sudo.service.in | 1 + + 7 files changed, 7 insertions(+) + +diff --git a/src/sysv/systemd/sssd-autofs.service.in b/src/sysv/systemd/sssd-autofs.service.in +index c2dc254c8f3f56cb6ae4dc481781688aa702b102..7f920ad66a46bb0785c3f947bc26c15d0e370259 100644 +--- a/src/sysv/systemd/sssd-autofs.service.in ++++ b/src/sysv/systemd/sssd-autofs.service.in +@@ -10,6 +10,7 @@ Also=sssd-autofs.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_autofs.log + ExecStart=@libexecdir@/sssd/sssd_autofs ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-ifp.service.in b/src/sysv/systemd/sssd-ifp.service.in +index 05a9a602b2d27c54a4faa79c58e0ecba90267100..f3bf92223ce8847858f57c2bb04b97c858be0ead 100644 +--- a/src/sysv/systemd/sssd-ifp.service.in ++++ b/src/sysv/systemd/sssd-ifp.service.in +@@ -6,6 +6,7 @@ BindsTo=sssd.service + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + Type=dbus + BusName=org.freedesktop.sssd.infopipe + ExecStart=@ifp_exec_cmd@ ${DEBUG_LOGGER} +diff --git a/src/sysv/systemd/sssd-nss.service.in b/src/sysv/systemd/sssd-nss.service.in +index fe771ad0fa99968bb1d42037abf2f960271589b1..c671280f2c8a7f85fd09a72983a21db0c30df3b9 100644 +--- a/src/sysv/systemd/sssd-nss.service.in ++++ b/src/sysv/systemd/sssd-nss.service.in +@@ -10,5 +10,6 @@ Also=sssd-nss.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStart=@libexecdir@/sssd/sssd_nss ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-pac.service.in b/src/sysv/systemd/sssd-pac.service.in +index dbd25abc476f579c9d8cce171fdeafa06e567610..590449b01223fe799eebb12b63229dfb8f2438f9 100644 +--- a/src/sysv/systemd/sssd-pac.service.in ++++ b/src/sysv/systemd/sssd-pac.service.in +@@ -10,6 +10,7 @@ Also=sssd-pac.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pac.log + ExecStart=@libexecdir@/sssd/sssd_pac ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-pam.service.in b/src/sysv/systemd/sssd-pam.service.in +index df722d1f3014bf62cc60114c30331424d14f411b..f2e938579c7ef4254bb2e05231bfe83d7e20f395 100644 +--- a/src/sysv/systemd/sssd-pam.service.in ++++ b/src/sysv/systemd/sssd-pam.service.in +@@ -10,6 +10,7 @@ Also=sssd-pam.socket sssd-pam-priv.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_pam.log + ExecStart=@libexecdir@/sssd/sssd_pam ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-ssh.service.in b/src/sysv/systemd/sssd-ssh.service.in +index f41249ea0fe19e5044d5d06ba195ab604d8e6a29..1c185466dfa8c13804cc980bbbdbc997d4ebe955 100644 +--- a/src/sysv/systemd/sssd-ssh.service.in ++++ b/src/sysv/systemd/sssd-ssh.service.in +@@ -10,6 +10,7 @@ Also=sssd-ssh.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_ssh.log + ExecStart=@libexecdir@/sssd/sssd_ssh ${DEBUG_LOGGER} --socket-activated + Restart=on-failure +diff --git a/src/sysv/systemd/sssd-sudo.service.in b/src/sysv/systemd/sssd-sudo.service.in +index da022f768af91e360182fad0ff885fad43ecfdc0..f13d88107eccd9e80447390c9c0f8940ae933106 100644 +--- a/src/sysv/systemd/sssd-sudo.service.in ++++ b/src/sysv/systemd/sssd-sudo.service.in +@@ -10,6 +10,7 @@ Also=sssd-sudo.socket + + [Service] + Environment=DEBUG_LOGGER=--logger=files ++EnvironmentFile=-@environment_file@ + ExecStartPre=-/bin/chown @SSSD_USER@:@SSSD_USER@ @logpath@/sssd_sudo.log + ExecStart=@libexecdir@/sssd/sssd_sudo --socket-activated + Restart=on-failure +-- +2.15.1 + diff --git a/0021-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch b/0021-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch new file mode 100644 index 0000000..dadccdb --- /dev/null +++ b/0021-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch @@ -0,0 +1,46 @@ +From d344095ece6000e7641a9c867c8e00335b8d1ab0 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 24 Oct 2017 12:07:46 +0200 +Subject: [PATCH 21/79] UTIL: Hide and deprecate parameter --debug-to-files +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Justin Stephenson +Reviewed-by: Fabiano Fidêncio +--- + src/man/sssd.8.xml | 4 ++++ + src/util/debug.h | 2 +- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/man/sssd.8.xml b/src/man/sssd.8.xml +index 0b725628ff93f48f832140dd5dc15b040a8b179f..f2cbe015b844579af98aebd864770bc651dcf4b1 100644 +--- a/src/man/sssd.8.xml ++++ b/src/man/sssd.8.xml +@@ -90,6 +90,10 @@ + log files are stored in /var/log/sssd and + there are separate log files for every SSSD service and domain. + ++ ++ This option is deprecated. It is replaced by ++ . ++ + + + +diff --git a/src/util/debug.h b/src/util/debug.h +index 4adafb7cfc03f7381c4d03071eb44edad04bee00..09f50cc9f3122f02d8ba2092dfb7ee633332de9b 100644 +--- a/src/util/debug.h ++++ b/src/util/debug.h +@@ -101,7 +101,7 @@ int get_fd_from_debug_file(void); + #define SSSD_DEBUG_OPTS \ + {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0, \ + _("Debug level"), NULL}, \ +- {"debug-to-files", 'f', POPT_ARG_NONE, &debug_to_file, 0, \ ++ {"debug-to-files", 'f', POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_file, 0, \ + _("Send the debug output to files instead of stderr"), NULL }, \ + {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \ + _("Send the debug output to stderr directly."), NULL }, \ +-- +2.15.1 + diff --git a/0023-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch b/0023-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch new file mode 100644 index 0000000..f844b89 --- /dev/null +++ b/0023-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch @@ -0,0 +1,212 @@ +From eafe5f3e981a951c0ff20807a0486cfa62dcc3ad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 25 Oct 2017 11:25:09 +0200 +Subject: [PATCH 23/79] LDAP: Bind to the LDAP server also in the auth +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When dealing with id_provider not being the same as auth_provider, SSSD +has to bind the DN of the user which wants to authenticate with the +ldap_default_bind_dn and the password provided by the user. + +In order to do so, the least intrusive way is just by replacing +sdap_connect*() functions by sdap_cli_connect*() functions in the LDAP's +auth module. + +The simple change also allowed us to remove some code that is already +executed as part of sdap_cli_connect*() and some functions had their +names adapted to reflect better their new purpose. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3451 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Sumit Bose +--- + src/providers/ldap/ldap_auth.c | 114 +++++++++-------------------------------- + 1 file changed, 25 insertions(+), 89 deletions(-) + +diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c +index 00ddd889b6294e457c13218491547b84f1468266..a3b1480aae4272d2e10f105a1eaf3a5816c3487c 100644 +--- a/src/providers/ldap/ldap_auth.c ++++ b/src/providers/ldap/ldap_auth.c +@@ -619,14 +619,11 @@ struct auth_state { + char *dn; + enum pwexpire pw_expire_type; + void *pw_expire_data; +- +- struct fo_server *srv; + }; + +-static struct tevent_req *auth_get_server(struct tevent_req *req); ++static struct tevent_req *auth_connect_send(struct tevent_req *req); + static void auth_get_dn_done(struct tevent_req *subreq); + static void auth_do_bind(struct tevent_req *req); +-static void auth_resolve_done(struct tevent_req *subreq); + static void auth_connect_done(struct tevent_req *subreq); + static void auth_bind_user_done(struct tevent_req *subreq); + +@@ -659,7 +656,6 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, + state->ctx = ctx; + state->username = username; + state->authtok = authtok; +- state->srv = NULL; + if (try_chpass_service && ctx->chpass_service != NULL && + ctx->chpass_service->name != NULL) { + state->sdap_service = ctx->chpass_service; +@@ -667,7 +663,7 @@ static struct tevent_req *auth_send(TALLOC_CTX *memctx, + state->sdap_service = ctx->service; + } + +- if (!auth_get_server(req)) goto fail; ++ if (!auth_connect_send(req)) goto fail; + + return req; + +@@ -676,75 +672,37 @@ fail: + return NULL; + } + +-static struct tevent_req *auth_get_server(struct tevent_req *req) ++static struct tevent_req *auth_connect_send(struct tevent_req *req) + { +- struct tevent_req *next_req; ++ struct tevent_req *subreq; + struct auth_state *state = tevent_req_data(req, + struct auth_state); +- +- /* NOTE: this call may cause service->uri to be refreshed +- * with a new valid server. Do not use service->uri before */ +- next_req = be_resolve_server_send(state, +- state->ev, +- state->ctx->be, +- state->sdap_service->name, +- state->srv == NULL ? true : false); +- if (!next_req) { +- DEBUG(SSSDBG_CRIT_FAILURE, "be_resolve_server_send failed.\n"); +- return NULL; +- } +- +- tevent_req_set_callback(next_req, auth_resolve_done, req); +- return next_req; +-} +- +-static void auth_resolve_done(struct tevent_req *subreq) +-{ +- struct tevent_req *req = tevent_req_callback_data(subreq, +- struct tevent_req); +- struct auth_state *state = tevent_req_data(req, +- struct auth_state); +- int ret; + bool use_tls; + +- ret = be_resolve_server_recv(subreq, state, &state->srv); +- talloc_zfree(subreq); +- if (ret) { +- /* all servers have been tried and none +- * was found good, go offline */ +- tevent_req_error(req, ETIMEDOUT); +- return; ++ /* Check for undocumented debugging feature to disable TLS ++ * for authentication. This should never be used in production ++ * for obvious reasons. ++ */ ++ use_tls = !dp_opt_get_bool(state->ctx->opts->basic, SDAP_DISABLE_AUTH_TLS); ++ if (!use_tls) { ++ sss_log(SSS_LOG_ALERT, "LDAP authentication being performed over " ++ "insecure connection. This should be done " ++ "for debugging purposes only."); + } + +- /* Determine whether we need to use TLS */ +- if (sdap_is_secure_uri(state->ctx->service->uri)) { +- DEBUG(SSSDBG_TRACE_INTERNAL, +- "[%s] is a secure channel. No need to run START_TLS\n", +- state->ctx->service->uri); +- use_tls = false; +- } else { ++ subreq = sdap_cli_connect_send(state, state->ev, state->ctx->opts, ++ state->ctx->be, ++ state->sdap_service, false, ++ use_tls ? CON_TLS_ON : CON_TLS_OFF, false); + +- /* Check for undocumented debugging feature to disable TLS +- * for authentication. This should never be used in production +- * for obvious reasons. +- */ +- use_tls = !dp_opt_get_bool(state->ctx->opts->basic, SDAP_DISABLE_AUTH_TLS); +- if (!use_tls) { +- sss_log(SSS_LOG_ALERT, "LDAP authentication being performed over " +- "insecure connection. This should be done " +- "for debugging purposes only."); +- } +- } +- +- subreq = sdap_connect_send(state, state->ev, state->ctx->opts, +- state->sdap_service->uri, +- state->sdap_service->sockaddr, use_tls); +- if (!subreq) { ++ if (subreq == NULL) { + tevent_req_error(req, ENOMEM); +- return; ++ return NULL; + } + + tevent_req_set_callback(subreq, auth_connect_done, req); ++ ++ return subreq; + } + + static void auth_connect_done(struct tevent_req *subreq) +@@ -755,35 +713,13 @@ static void auth_connect_done(struct tevent_req *subreq) + struct auth_state); + int ret; + +- ret = sdap_connect_recv(subreq, state, &state->sh); ++ ret = sdap_cli_connect_recv(subreq, state, NULL, &state->sh, NULL); + talloc_zfree(subreq); +- if (ret) { +- if (state->srv) { +- /* mark this server as bad if connection failed */ +- be_fo_set_port_status(state->ctx->be, +- state->sdap_service->name, +- state->srv, PORT_NOT_WORKING); +- } +- +- if (auth_get_server(req) == NULL) { ++ if (ret != EOK) { ++ if (auth_connect_send(req) == NULL) { + tevent_req_error(req, ENOMEM); + } + return; +- } else if (state->srv) { +- be_fo_set_port_status(state->ctx->be, state->sdap_service->name, +- state->srv, PORT_WORKING); +- } +- +- /* In case the ID provider is set to proxy, this might be the first +- * LDAP operation at all, so we need to set the connection status +- */ +- if (state->sh->connected == false) { +- ret = sdap_set_connected(state->sh, state->ev); +- if (ret) { +- DEBUG(SSSDBG_OP_FAILURE, "Cannot set connected status\n"); +- tevent_req_error(req, ret); +- return; +- } + } + + ret = get_user_dn(state, state->ctx->be->domain, +@@ -870,7 +806,7 @@ static void auth_bind_user_done(struct tevent_req *subreq) + break; + case ETIMEDOUT: + case ERR_NETWORK_IO: +- if (auth_get_server(req) == NULL) { ++ if (auth_connect_send(req) == NULL) { + tevent_req_error(req, ENOMEM); + } + return; +-- +2.15.1 + diff --git a/0001-KCM-Fix-restart-during-after-upgrade.patch b/0024-KCM-Fix-restart-during-after-upgrade.patch similarity index 93% rename from 0001-KCM-Fix-restart-during-after-upgrade.patch rename to 0024-KCM-Fix-restart-during-after-upgrade.patch index f37fc5a..8f0d619 100644 --- a/0001-KCM-Fix-restart-during-after-upgrade.patch +++ b/0024-KCM-Fix-restart-during-after-upgrade.patch @@ -1,7 +1,7 @@ -From 53d1459e9b87196b4f6e327f0f5db4d9229bf541 Mon Sep 17 00:00:00 2001 +From 6010476f08fb52bfcea9c2b10461b0d53ce0860c Mon Sep 17 00:00:00 2001 From: Lukas Slebodnik Date: Fri, 3 Nov 2017 11:43:18 +0100 -Subject: [PATCH] KCM: Fix restart during/after upgrade +Subject: [PATCH 24/79] KCM: Fix restart during/after upgrade MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -51,5 +51,5 @@ index a7b41e0b16a5fa882546b41047e616fd2140329f..a9756acf8a3c71e861b443259c071338 [Install] Also=sssd-secrets.socket -- -2.14.3 +2.15.1 diff --git a/0002-sss_client-create-nss_common.h.patch b/0025-sss_client-create-nss_common.h.patch similarity index 97% rename from 0002-sss_client-create-nss_common.h.patch rename to 0025-sss_client-create-nss_common.h.patch index 5c15e32..d06db0a 100644 --- a/0002-sss_client-create-nss_common.h.patch +++ b/0025-sss_client-create-nss_common.h.patch @@ -1,7 +1,7 @@ -From 7449b236523409cc8766fb957d6cba051fdfb483 Mon Sep 17 00:00:00 2001 +From ea07e6e149ec78bd50a92fe7dd12fa35cbdf81f3 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Fri, 29 Sep 2017 21:38:54 +0200 -Subject: [PATCH 02/11] sss_client: create nss_common.h +Subject: [PATCH 25/79] sss_client: create nss_common.h This patch makes sss_nss_getpw_readrep() and sss_nss_getgr_readrep() calls which parse SSSD's replies for user and group requests available @@ -138,5 +138,5 @@ index c43f9bc50f43599b541e97f5a5aa60de036a5cdf..61e2a567e684fbc7664b5d425e81cfa2 errno_t ret; size_t i, slen, dlen; -- -2.14.3 +2.15.1 diff --git a/0003-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch b/0026-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch similarity index 99% rename from 0003-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch rename to 0026-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch index e79a0ec..d0848a7 100644 --- a/0003-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch +++ b/0026-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch @@ -1,7 +1,7 @@ -From 5e6622722e84d594298a8324f3685a1bda2b5868 Mon Sep 17 00:00:00 2001 +From 3207b69503afe2328a747dd00f0cdb9e859bc699 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Fri, 29 Sep 2017 16:16:01 +0200 -Subject: [PATCH 03/11] nss-idmap: add nss like calls with timeout and flags +Subject: [PATCH 26/79] nss-idmap: add nss like calls with timeout and flags This patch adds new calls to libsss_nss_idmap to get NSS like user and group information directly from SSSD without using the system's NSS @@ -896,5 +896,5 @@ index 0000000000000000000000000000000000000000..afcd8e355981b9a2dc29a62bab143756 + +#endif /* SSS_NSS_IDMAP_PRIVATE_H_ */ -- -2.14.3 +2.15.1 diff --git a/0004-NSS-add-_EX-version-of-some-requests.patch b/0027-NSS-add-_EX-version-of-some-requests.patch similarity index 99% rename from 0004-NSS-add-_EX-version-of-some-requests.patch rename to 0027-NSS-add-_EX-version-of-some-requests.patch index 7c096c9..edbf172 100644 --- a/0004-NSS-add-_EX-version-of-some-requests.patch +++ b/0027-NSS-add-_EX-version-of-some-requests.patch @@ -1,7 +1,7 @@ -From cf93f7c2f2031078bbbff095dae01eb4f8deff85 Mon Sep 17 00:00:00 2001 +From bde80e6ec191e80231b24328209342cf92bb7723 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 11 Oct 2017 14:54:54 +0200 -Subject: [PATCH 04/11] NSS: add *_EX version of some requests +Subject: [PATCH 27/79] NSS: add *_EX version of some requests To be able to send the flags to the SSSD responder new request types with an _EX postfix are added which expect and additional 32bit flag @@ -601,5 +601,5 @@ index 5329651a9385d138b8ea7237cb5cf4e2b8e5f371..9d2cc00c9957f5680548461129e3e6b7 /* aliases */ -- -2.14.3 +2.15.1 diff --git a/0005-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch b/0028-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch similarity index 97% rename from 0005-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch rename to 0028-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch index 21775ae..506cda4 100644 --- a/0005-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch +++ b/0028-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch @@ -1,7 +1,7 @@ -From ac6b267ff3df6d0417062a128ec16b184ea2c1b7 Mon Sep 17 00:00:00 2001 +From 32f913dd143d45aee7f3d91785a86d8e2a85bb22 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 12 Oct 2017 10:42:41 +0200 -Subject: [PATCH 05/11] NSS: add support for SSS_NSS_EX_FLAG_NO_CACHE +Subject: [PATCH 28/79] NSS: add support for SSS_NSS_EX_FLAG_NO_CACHE If SSS_NSS_EX_FLAG_NO_CACHE is set the object is refresh by directly looking it up in the backend. @@ -144,5 +144,5 @@ index 2334b6cb3fb8ef62e4ce3a7187c7affaeaa034e7..1649830afbb80c617fd339f054aef8bc /** -- -2.14.3 +2.15.1 diff --git a/0006-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch b/0029-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch similarity index 96% rename from 0006-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch rename to 0029-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch index 7a6247a..cc2d7ac 100644 --- a/0006-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch +++ b/0029-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch @@ -1,7 +1,7 @@ -From 52e675ec4b160720515c81ae8c0e5a95feb50c57 Mon Sep 17 00:00:00 2001 +From c8cba255e7ad59e151693b1fc9ceb9feff744d2b Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Mon, 23 Oct 2017 18:26:55 +0200 -Subject: [PATCH 06/11] CACHE_REQ: Add cache_req_data_set_bypass_dp() +Subject: [PATCH 29/79] CACHE_REQ: Add cache_req_data_set_bypass_dp() Similar to cache_req_data_set_bypass_cache() cache_req_data_set_bypass_dp() can be used to control how the cache_req @@ -107,5 +107,5 @@ index 9b706ff7d678f543effb77089857a7e8a42a9c51..0f630542d38a277d1819063fa4134bd7 struct tevent_req * -- -2.14.3 +2.15.1 diff --git a/0007-nss-make-memcache_delete_entry-public.patch b/0030-nss-make-memcache_delete_entry-public.patch similarity index 92% rename from 0007-nss-make-memcache_delete_entry-public.patch rename to 0030-nss-make-memcache_delete_entry-public.patch index 157d3d9..925c077 100644 --- a/0007-nss-make-memcache_delete_entry-public.patch +++ b/0030-nss-make-memcache_delete_entry-public.patch @@ -1,7 +1,7 @@ -From a7d6ca275d6b2e5d396cbefb18d0ee880011e271 Mon Sep 17 00:00:00 2001 +From 5a09629d6d281565c3ce0d51e536bb73f4447758 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 24 Oct 2017 12:50:43 +0200 -Subject: [PATCH 07/11] nss: make memcache_delete_entry() public +Subject: [PATCH 30/79] nss: make memcache_delete_entry() public Related to https://pagure.io/SSSD/sssd/issue/2478 @@ -44,5 +44,5 @@ index a0b573d6ecba2d8ba6f55db0adcd7ee29cbec991..5fc19d26be9adda4d967086e7b239e49 nss_get_object_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, -- -2.14.3 +2.15.1 diff --git a/0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch b/0031-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch similarity index 98% rename from 0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch rename to 0031-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch index ca259e0..4298c7e 100644 --- a/0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch +++ b/0031-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch @@ -1,7 +1,7 @@ -From 55f7d8034d783c01789d76a2b9ffc901045e8af8 Mon Sep 17 00:00:00 2001 +From 500a170781fc24ddf83cb93cdb609c24efa13f4a Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Tue, 24 Oct 2017 14:10:53 +0200 -Subject: [PATCH 08/11] NSS: add support for SSS_NSS_EX_FLAG_INVALIDATE_CACHE +Subject: [PATCH 31/79] NSS: add support for SSS_NSS_EX_FLAG_INVALIDATE_CACHE The patch adds support for the SSS_NSS_EX_FLAG_INVALIDATE_CACHE flag and makes the existing code more flexible and handle additional flags. @@ -360,5 +360,5 @@ index 1649830afbb80c617fd339f054aef8bc8e585fb9..3755643312f05a31d1cf1aa76dfc2284 /** -- -2.14.3 +2.15.1 diff --git a/0009-NSS-TESTS-add-unit-tests-for-_EX-requests.patch b/0032-NSS-TESTS-add-unit-tests-for-_EX-requests.patch similarity index 99% rename from 0009-NSS-TESTS-add-unit-tests-for-_EX-requests.patch rename to 0032-NSS-TESTS-add-unit-tests-for-_EX-requests.patch index 3cf4745..897862d 100644 --- a/0009-NSS-TESTS-add-unit-tests-for-_EX-requests.patch +++ b/0032-NSS-TESTS-add-unit-tests-for-_EX-requests.patch @@ -1,7 +1,7 @@ -From 85da8a5e90bffc8b0fef5e0ea364a8d3cb50de86 Mon Sep 17 00:00:00 2001 +From 1a48574b723f05bc9a69099fee459b405c35dd36 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 25 Oct 2017 21:31:54 +0200 -Subject: [PATCH 09/11] NSS/TESTS: add unit tests for *_EX requests +Subject: [PATCH 32/79] NSS/TESTS: add unit tests for *_EX requests The patch adds unit tests for the new *_EX requests with different input types and flags. @@ -585,5 +585,5 @@ index ccedf96beaecfaa4232bbe456d5e5a8394098483..6aa726153183b5a871a75d398727ea71 /* Set debug level to invalid value so we can deside if -d 0 was used. */ -- -2.14.3 +2.15.1 diff --git a/0010-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch b/0033-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch similarity index 99% rename from 0010-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch rename to 0033-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch index e1c303a..691008e 100644 --- a/0010-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch +++ b/0033-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch @@ -1,7 +1,7 @@ -From e54db68cbb9c12d8a6867f2c7766fb2115ab0997 Mon Sep 17 00:00:00 2001 +From ecb91e135ebdb2a01831853e86e0165b51fcd2f9 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 2 Nov 2017 10:32:41 +0100 -Subject: [PATCH 10/11] nss-idmap: add timeout version of old sss_nss_* calls +Subject: [PATCH 33/79] nss-idmap: add timeout version of old sss_nss_* calls Reviewed-by: Jakub Hrozek --- @@ -489,5 +489,5 @@ index 8807eca619d7b07d919168e5629042cf38f654ac..2e37040d2d3523bea157804706685fa0 assert_int_equal(ret, EOK); assert_int_equal(type, SSS_ID_TYPE_UID); -- -2.14.3 +2.15.1 diff --git a/0011-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch b/0034-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch similarity index 97% rename from 0011-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch rename to 0034-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch index 839ffc7..ad1747a 100644 --- a/0011-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch +++ b/0034-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch @@ -1,7 +1,7 @@ -From 859bddc2bf51dc426a3dc56bd9f365e9c5722b65 Mon Sep 17 00:00:00 2001 +From ccde2fdcbe240f8a20524461abea10c8c5c5a79f Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Thu, 2 Nov 2017 11:09:20 +0100 -Subject: [PATCH 11/11] nss-idmap: allow empty buffer with +Subject: [PATCH 34/79] nss-idmap: allow empty buffer with SSS_NSS_EX_FLAG_INVALIDATE_CACHE Reviewed-by: Jakub Hrozek @@ -179,5 +179,5 @@ index 148eb7b35ec236b6272dd203a0035399cfdef73d..dcd9619a8b07ced7498f61b7e809fa46 if (ret != 0) { return ret; -- -2.14.3 +2.15.1 diff --git a/0035-RESP-Add-some-missing-NULL-checks.patch b/0035-RESP-Add-some-missing-NULL-checks.patch new file mode 100644 index 0000000..0b309dd --- /dev/null +++ b/0035-RESP-Add-some-missing-NULL-checks.patch @@ -0,0 +1,79 @@ +From 6e4b53c819d2cbc0a4e25b9813e24c47ad12febb Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Thu, 9 Nov 2017 13:24:47 +0100 +Subject: [PATCH 35/79] RESP: Add some missing NULL checks +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Reviewed-by: Fabiano Fidêncio +--- + src/responder/autofs/autofssrv_dp.c | 4 ++++ + src/responder/common/responder_dp.c | 4 ++++ + src/responder/common/responder_dp_ssh.c | 4 ++++ + src/responder/sudo/sudosrv_dp.c | 4 ++++ + 4 files changed, 16 insertions(+) + +diff --git a/src/responder/autofs/autofssrv_dp.c b/src/responder/autofs/autofssrv_dp.c +index a323d83d9deb4e51180da9ff291044f1b9f64f76..bb8c2a42899b163b7727af778e554a5f55ca2d56 100644 +--- a/src/responder/autofs/autofssrv_dp.c ++++ b/src/responder/autofs/autofssrv_dp.c +@@ -65,6 +65,10 @@ sss_dp_get_autofs_send(TALLOC_CTX *mem_ctx, + } + + info = talloc_zero(state, struct sss_dp_get_autofs_info); ++ if (info == NULL) { ++ ret = ENOMEM; ++ goto error; ++ } + info->fast_reply = fast_reply; + info->type = type; + info->name = name; +diff --git a/src/responder/common/responder_dp.c b/src/responder/common/responder_dp.c +index a75a611960801f5f5bdc95f00aea9ab921e8e293..935a36d28d15d1074a0971fe9781474072578b8f 100644 +--- a/src/responder/common/responder_dp.c ++++ b/src/responder/common/responder_dp.c +@@ -536,6 +536,10 @@ sss_dp_get_account_send(TALLOC_CTX *mem_ctx, + } + + info = talloc_zero(state, struct sss_dp_account_info); ++ if (info == NULL) { ++ ret = ENOMEM; ++ goto error; ++ } + info->fast_reply = fast_reply; + info->type = type; + info->opt_name = opt_name; +diff --git a/src/responder/common/responder_dp_ssh.c b/src/responder/common/responder_dp_ssh.c +index 303ba1568b6230b0d4dfa718e4a7c024ae84d4e9..f78052296f07d3e21d8d4841a58c85fcf178fa1a 100644 +--- a/src/responder/common/responder_dp_ssh.c ++++ b/src/responder/common/responder_dp_ssh.c +@@ -64,6 +64,10 @@ sss_dp_get_ssh_host_send(TALLOC_CTX *mem_ctx, + } + + info = talloc_zero(state, struct sss_dp_get_ssh_host_info); ++ if (info == NULL) { ++ ret = ENOMEM; ++ goto error; ++ } + info->fast_reply = fast_reply; + info->name = name; + info->alias = alias; +diff --git a/src/responder/sudo/sudosrv_dp.c b/src/responder/sudo/sudosrv_dp.c +index 3a4a79473ff9915b3845643505d63411585aa262..f8ec8abc26d9710a2bccaadc4f807f963fe35f89 100644 +--- a/src/responder/sudo/sudosrv_dp.c ++++ b/src/responder/sudo/sudosrv_dp.c +@@ -72,6 +72,10 @@ sss_dp_get_sudoers_send(TALLOC_CTX *mem_ctx, + } + + info = talloc_zero(state, struct sss_dp_get_sudoers_info); ++ if (info == NULL) { ++ ret = ENOMEM; ++ goto error; ++ } + info->fast_reply = fast_reply; + info->type = type; + info->name = name; +-- +2.15.1 + diff --git a/0036-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch b/0036-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch new file mode 100644 index 0000000..35e0ec7 --- /dev/null +++ b/0036-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch @@ -0,0 +1,50 @@ +From c514089df0e3c357bb8465bca297806b253569e9 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 7 Nov 2017 17:11:52 +0100 +Subject: [PATCH 36/79] BUILD: Properly expand variables in sssd-ifp.service +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +systemd[1]: [/usr/lib/systemd/system/sssd-ifp.service:9] + Path '-@environment_file@' is not absolute, ignoring. + +sh-4.2# systemctl cat sssd-ifp.service + # /usr/lib/systemd/system/sssd-ifp.service +[Unit] +Description=SSSD IFP Service responder +Documentation=man:sssd-ifp(5) +After=sssd.service +BindsTo=sssd.service + +[Service] +Environment=DEBUG_LOGGER=--logger=files +EnvironmentFile=-@environment_file@ +Type=dbus +BusName=org.freedesktop.sssd.infopipe +ExecStart=/usr/libexec/sssd/sssd_ifp --uid 0 --gid 0 --dbus-activated ${DEBUG_LOGGER} + +Resolves: +https://pagure.io/SSSD/sssd/issue/3433 + +Reviewed-by: Fabiano Fidêncio +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index 286ba47e3c421864362717be5258de960efca9f2..bbc90d9bad4d22ca0284ea95281a487d42399c05 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1491,7 +1491,7 @@ EXTRA_DIST += \ + src/responder/ifp/org.freedesktop.sssd.infopipe.service.in \ + $(NULL) + +-ifp_edit_cmd = $(SED) \ ++ifp_edit_cmd = $(edit_cmd) \ + -e 's|@ifp_exec_cmd[@]|$(ifp_exec_cmd)|g' \ + -e 's|@ifp_systemdservice[@]|$(ifp_systemdservice)|g' \ + -e 's|@ifp_restart[@]|$(ifp_restart)|g' +-- +2.15.1 + diff --git a/0037-SYSTEMD-Clean-pid-file-in-corner-cases.patch b/0037-SYSTEMD-Clean-pid-file-in-corner-cases.patch new file mode 100644 index 0000000..92a9a27 --- /dev/null +++ b/0037-SYSTEMD-Clean-pid-file-in-corner-cases.patch @@ -0,0 +1,38 @@ +From 8d1779240b4b193ecdc7ff8601def88a95cd7d47 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 8 Nov 2017 14:09:36 +0100 +Subject: [PATCH 37/79] SYSTEMD: Clean pid file in corner cases +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +SSSD can cleanup pid file in case of standard stopping of daemon. +It's done in function monitor_cleanup. However monitor does not have a +change to cleanup file in case of OOM or sending SIGKILL to monitor. + +Even though PIDFile is not necessary for services with Type notify +we should let systemd to clean this file in unexpected situations. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3528 + +Reviewed-by: Fabiano Fidêncio +--- + src/sysv/systemd/sssd.service.in | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/sysv/systemd/sssd.service.in b/src/sysv/systemd/sssd.service.in +index cea848fac80303d6fae12dd84316a91dbc60072d..0c515d34caaa3ea397c4c7e95eef0188df170840 100644 +--- a/src/sysv/systemd/sssd.service.in ++++ b/src/sysv/systemd/sssd.service.in +@@ -10,6 +10,7 @@ EnvironmentFile=-@environment_file@ + ExecStart=@sbindir@/sssd -i ${DEBUG_LOGGER} + Type=notify + NotifyAccess=main ++PIDFile=@localstatedir@/run/sssd.pid + + [Install] + WantedBy=multi-user.target +-- +2.15.1 + diff --git a/0038-CHILD-Pass-information-about-logger-to-children.patch b/0038-CHILD-Pass-information-about-logger-to-children.patch new file mode 100644 index 0000000..707f7d1 --- /dev/null +++ b/0038-CHILD-Pass-information-about-logger-to-children.patch @@ -0,0 +1,197 @@ +From 9ff9b0e5f6599d178d374753d7fbc99e7258ca4c Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 8 Nov 2017 08:13:02 +0100 +Subject: [PATCH 38/79] CHILD: Pass information about logger to children +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Variables debug_to_file or debug_to_stderr were not set +because back-end already user parameter --logger=%s. +And therefore logs were not sent to files. + +It could only work in case of direct usage of --debug-to-files in back-end via +command configuration option. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3433 + +Reviewed-by: Fabiano Fidêncio +--- + src/p11_child/p11_child_nss.c | 4 +++- + src/providers/ad/ad_gpo_child.c | 3 ++- + src/providers/ipa/selinux_child.c | 3 ++- + src/providers/krb5/krb5_child.c | 3 ++- + src/providers/ldap/ldap_child.c | 3 ++- + src/util/child_common.c | 24 ++++++++++-------------- + 6 files changed, 21 insertions(+), 19 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index e7dbcb689220d1cd2585fbde5f26e84f8fa15cc2..b0ec69be321c4b4186ce851c07bfcc3e1afe9694 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -537,7 +537,7 @@ int main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + errno_t ret; + TALLOC_CTX *main_ctx = NULL; + char *cert; +@@ -673,7 +673,9 @@ int main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } ++ + sss_set_logger(opt_logger); + + DEBUG(SSSDBG_TRACE_FUNC, "p11_child started.\n"); +diff --git a/src/providers/ad/ad_gpo_child.c b/src/providers/ad/ad_gpo_child.c +index 5375cc691e8649c289672b74c4bfe5266c8222c9..a0bd6e13a31fe0f92924d49302d1b8b17bac4d67 100644 +--- a/src/providers/ad/ad_gpo_child.c ++++ b/src/providers/ad/ad_gpo_child.c +@@ -687,7 +687,7 @@ main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + errno_t ret; + int sysvol_gpt_version; + int result; +@@ -744,6 +744,7 @@ main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } + + sss_set_logger(opt_logger); +diff --git a/src/providers/ipa/selinux_child.c b/src/providers/ipa/selinux_child.c +index 120492686963241b7e419413f489cc38953e32f2..a7e20f715626d0f3ecef7cc06f3de5d44b6a15c1 100644 +--- a/src/providers/ipa/selinux_child.c ++++ b/src/providers/ipa/selinux_child.c +@@ -206,7 +206,7 @@ int main(int argc, const char *argv[]) + struct response *resp = NULL; + ssize_t written; + bool needs_update; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + + struct poptOption long_options[] = { + POPT_AUTOHELP +@@ -254,6 +254,7 @@ int main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } + + sss_set_logger(opt_logger); +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index b44f3a20f1c0725304a37620d36f8872cf9ca5d7..7ee6c34eb1f8b78d5a6fd7b6f87996e3c9572d4f 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -3020,7 +3020,7 @@ int main(int argc, const char *argv[]) + int opt; + poptContext pc; + int debug_fd = -1; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + errno_t ret; + krb5_error_code kerr; + uid_t fast_uid; +@@ -3097,6 +3097,7 @@ int main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } + + sss_set_logger(opt_logger); +diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c +index baeed239db5dc7ffa482edcbc155f25f718c8249..c0618d6d8828f102c32cf56731995e2b370590e7 100644 +--- a/src/providers/ldap/ldap_child.c ++++ b/src/providers/ldap/ldap_child.c +@@ -599,7 +599,7 @@ int main(int argc, const char *argv[]) + int kerr; + int opt; + int debug_fd = -1; +- char *opt_logger = NULL; ++ const char *opt_logger = NULL; + poptContext pc; + TALLOC_CTX *main_ctx = NULL; + uint8_t *buf = NULL; +@@ -657,6 +657,7 @@ int main(int argc, const char *argv[]) + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n"); + } ++ opt_logger = sss_logger_str[FILES_LOGGER]; + } + + sss_set_logger(opt_logger); +diff --git a/src/util/child_common.c b/src/util/child_common.c +index dc070f26446305e07cbb34edd1e4d72db72aedc5..203c115f9e7c4ecc2178b5660473d4f960fbbb6d 100644 +--- a/src/util/child_common.c ++++ b/src/util/child_common.c +@@ -630,14 +630,11 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, + } + + /* Save the current state in case an interrupt changes it */ +- bool child_debug_to_file = debug_to_file; + bool child_debug_timestamps = debug_timestamps; + bool child_debug_microseconds = debug_microseconds; +- bool child_debug_stderr = debug_to_stderr; + + if (!extra_args_only) { +- if (child_debug_to_file) argc++; +- if (child_debug_stderr) argc++; ++ argc++; + } + + if (extra_argv) { +@@ -675,21 +672,20 @@ static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx, + goto fail; + } + +- if (child_debug_stderr) { +- argv[--argc] = talloc_strdup(argv, "--logger=stderr"); +- if (argv[argc] == NULL) { +- ret = ENOMEM; +- goto fail; +- } +- } +- +- if (child_debug_to_file) { ++ if (sss_logger == FILES_LOGGER) { + argv[--argc] = talloc_asprintf(argv, "--debug-fd=%d", + child_debug_fd); + if (argv[argc] == NULL) { + ret = ENOMEM; + goto fail; + } ++ } else { ++ argv[--argc] = talloc_asprintf(argv, "--logger=%s", ++ sss_logger_str[sss_logger]); ++ if (argv[argc] == NULL) { ++ ret = ENOMEM; ++ goto fail; ++ } + } + + argv[--argc] = talloc_asprintf(argv, "--debug-timestamps=%d", +@@ -816,7 +812,7 @@ errno_t child_debug_init(const char *logfile, int *debug_fd) + return EOK; + } + +- if (debug_to_file != 0 && *debug_fd == -1) { ++ if (sss_logger == FILES_LOGGER && *debug_fd == -1) { + ret = open_debug_file_ex(logfile, &debug_filep, false); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) [%s]\n", +-- +2.15.1 + diff --git a/0039-TOOLS-Double-quote-array-expansions-in-sss_debugleve.patch b/0039-TOOLS-Double-quote-array-expansions-in-sss_debugleve.patch new file mode 100644 index 0000000..61e18c3 --- /dev/null +++ b/0039-TOOLS-Double-quote-array-expansions-in-sss_debugleve.patch @@ -0,0 +1,33 @@ +From 6d15db05c0975fed2b18cc52056fa29aedec823c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 7 Nov 2017 09:09:55 +0100 +Subject: [PATCH 39/79] TOOLS: Double quote array expansions in sss_debuglevel +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Otherwise they're like $* and break on spaces. + +This issue has been caught by coverity: + Defect type: SHELLCHECK_WARNING + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Lukáš Slebodník +--- + src/tools/wrappers/sss_debuglevel.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/tools/wrappers/sss_debuglevel.in b/src/tools/wrappers/sss_debuglevel.in +index 4deeafff6bf472dbe63578f57bfacee7b774d09f..aa19f790a26c67186123c87675d527f403b06264 100644 +--- a/src/tools/wrappers/sss_debuglevel.in ++++ b/src/tools/wrappers/sss_debuglevel.in +@@ -1,4 +1,4 @@ + #!/bin/sh + sbindir=@sbindir@ + echo "Redirecting to $sbindir/sssctl debug-level" >&2 +-$sbindir/sssctl debug-level $@ ++$sbindir/sssctl debug-level "$@" +-- +2.15.1 + diff --git a/0040-TOOLS-Call-exec-for-sss_debuglevel.patch b/0040-TOOLS-Call-exec-for-sss_debuglevel.patch new file mode 100644 index 0000000..34f476b --- /dev/null +++ b/0040-TOOLS-Call-exec-for-sss_debuglevel.patch @@ -0,0 +1,31 @@ +From 58932b42802c93fdfc3eea8cdcdcca4534293941 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Wed, 8 Nov 2017 17:59:15 +0100 +Subject: [PATCH 40/79] TOOLS: Call "exec" for sss_debuglevel +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This suggestion came from Lukáš Slebodník. The advantage of calling +"exec" is to avoid forking another child of the process. + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Lukáš Slebodník +--- + src/tools/wrappers/sss_debuglevel.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/tools/wrappers/sss_debuglevel.in b/src/tools/wrappers/sss_debuglevel.in +index aa19f790a26c67186123c87675d527f403b06264..a55afcddc547dfda4ac0a7e22da5f9f9407fe45f 100644 +--- a/src/tools/wrappers/sss_debuglevel.in ++++ b/src/tools/wrappers/sss_debuglevel.in +@@ -1,4 +1,4 @@ + #!/bin/sh + sbindir=@sbindir@ + echo "Redirecting to $sbindir/sssctl debug-level" >&2 +-$sbindir/sssctl debug-level "$@" ++exec $sbindir/sssctl debug-level "$@" +-- +2.15.1 + diff --git a/0041-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch b/0041-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch new file mode 100644 index 0000000..26e71eb --- /dev/null +++ b/0041-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch @@ -0,0 +1,57 @@ +From 1e50148c7eadeff96b96811ede747399628a06c6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 7 Nov 2017 23:34:42 +0100 +Subject: [PATCH 41/79] LDAP: Improve error treatment from sdap_cli_connect() + in ldap_auth +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Because we weren't treating the errors coming from +sdap_cli_connect_recv() properly we ended up introducing a regression in +the commit add72860c7, related to offline authentication. + +From now on, let's properly treat errors coming from auth_connect_send(), +which were treated before by going offline when be_resolve_server_recv() +failed, and propagate ETIMEDOUT to the request, thus going offline and +allowing offline authentication on those cases. + +Related: +https://pagure.io/SSSD/sssd/issue/3451 + +Signed-off-by: Fabiano Fidêncio +Reviewed-by: Sumit Bose +--- + src/providers/ldap/ldap_auth.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ldap/ldap_auth.c b/src/providers/ldap/ldap_auth.c +index a3b1480aae4272d2e10f105a1eaf3a5816c3487c..2e0e2cfd6f8af2bf0c9ad15bd956a55a34777a3c 100644 +--- a/src/providers/ldap/ldap_auth.c ++++ b/src/providers/ldap/ldap_auth.c +@@ -716,8 +716,20 @@ static void auth_connect_done(struct tevent_req *subreq) + ret = sdap_cli_connect_recv(subreq, state, NULL, &state->sh, NULL); + talloc_zfree(subreq); + if (ret != EOK) { +- if (auth_connect_send(req) == NULL) { +- tevent_req_error(req, ENOMEM); ++ /* As sdap_cli_connect_recv() returns EIO in case all the servers are ++ * down and we have to go offline, let's treat it accordingly here and ++ * allow the PAM responder to with to offline authentication. ++ * ++ * Unfortunately, there's not much pattern within our code and the way ++ * to indicate we're going down in this part of the code is returning ++ * an ETIMEDOUT. ++ */ ++ if (ret == EIO) { ++ tevent_req_error(req, ETIMEDOUT); ++ } else { ++ if (auth_connect_send(req) == NULL) { ++ tevent_req_error(req, ENOMEM); ++ } + } + return; + } +-- +2.15.1 + diff --git a/0042-p11_child-return-multiple-certs.patch b/0042-p11_child-return-multiple-certs.patch new file mode 100644 index 0000000..f884010 --- /dev/null +++ b/0042-p11_child-return-multiple-certs.patch @@ -0,0 +1,597 @@ +From 78fd324fd1eb82319248987639376e85ad7204b1 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 17 Jan 2017 15:55:18 +0100 +Subject: [PATCH 42/79] p11_child: return multiple certs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch refactors the handling of certificates in p11_child. Not only +the first but all certificates suitable for authentication are returned. +The PAM responder component calling p11_child is refactored to handle +multiple certificate returned by p11_child but so far only returns the +first one to its callers. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +--- + src/p11_child/p11_child_nss.c | 131 +++++++++++++--------- + src/responder/pam/pamsrv.h | 2 + + src/responder/pam/pamsrv_p11.c | 242 +++++++++++++++++++++++------------------ + 3 files changed, 219 insertions(+), 156 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index b0ec69be321c4b4186ce851c07bfcc3e1afe9694..50bde2f4f91f6c00260b0db383d0962112686ebc 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -72,8 +72,7 @@ static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg) + int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + enum op_mode mode, const char *pin, + struct cert_verify_opts *cert_verify_opts, +- char **cert, char **token_name_out, char **module_name_out, +- char **key_id_out) ++ char **_multi) + { + int ret; + SECStatus rv; +@@ -110,7 +109,10 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + PK11SlotListElement *le; + SECItem *key_id = NULL; + char *key_id_str = NULL; +- ++ CERTCertList *valid_certs = NULL; ++ char *cert_b64 = NULL; ++ char *multi = NULL; ++ PRCList *node; + + nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, ¶meters, flags); + if (nss_ctx == NULL) { +@@ -303,6 +305,14 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + } + + found_cert = NULL; ++ valid_certs = CERT_NewCertList(); ++ if (valid_certs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_NewCertList failed [%d].\n", ++ PR_GetError()); ++ ret = ENOMEM; ++ goto done; ++ } ++ + DEBUG(SSSDBG_TRACE_ALL, "Filtered certificates:\n"); + for (cert_list_node = CERT_LIST_HEAD(cert_list); + !CERT_LIST_END(cert_list_node, cert_list); +@@ -326,6 +336,13 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + } + } + ++ rv = CERT_AddCertToListTail(valid_certs, cert_list_node->cert); ++ if (rv != SECSuccess) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "CERT_AddCertToListTail failed [%d].\n", PR_GetError()); ++ ret = EIO; ++ goto done; ++ } + + if (found_cert == NULL) { + found_cert = cert_list_node->cert; +@@ -352,9 +369,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + + if (found_cert == NULL) { + DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n"); +- *cert = NULL; +- *token_name_out = NULL; +- *module_name_out = NULL; ++ *_multi = NULL; + ret = EOK; + goto done; + } +@@ -421,51 +436,55 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + "Certificate verified and validated.\n"); + } + +- key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL); +- if (key_id == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_GetLowLevelKeyIDForCert failed [%d].\n", +- PR_GetError()); +- ret = EINVAL; +- goto done; +- } +- +- key_id_str = CERT_Hexify(key_id, PR_FALSE); +- if (key_id_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError()); ++ multi = talloc_strdup(mem_ctx, ""); ++ if (multi == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create output string.\n"); + ret = ENOMEM; + goto done; + } + +- DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n", key_id_str); ++ for (cert_list_node = CERT_LIST_HEAD(valid_certs); ++ !CERT_LIST_END(cert_list_node, valid_certs); ++ cert_list_node = CERT_LIST_NEXT(cert_list_node)) { + +- *key_id_out = talloc_strdup(mem_ctx, key_id_str); +- if (*key_id_out == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy key id.\n"); +- ret = ENOMEM; +- goto done; +- } ++ found_cert = cert_list_node->cert; + +- *cert = sss_base64_encode(mem_ctx, found_cert->derCert.data, +- found_cert->derCert.len); +- if (*cert == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "sss_base64_encode failed.\n"); +- ret = ENOMEM; +- goto done; +- } ++ SECITEM_FreeItem(key_id, PR_TRUE); ++ PORT_Free(key_id_str); ++ key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL); ++ if (key_id == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "PK11_GetLowLevelKeyIDForCert failed [%d].\n", ++ PR_GetError()); ++ ret = EINVAL; ++ goto done; ++ } + +- *token_name_out = talloc_strdup(mem_ctx, token_name); +- if (*token_name_out == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy slot name.\n"); +- ret = ENOMEM; +- goto done; +- } ++ key_id_str = CERT_Hexify(key_id, PR_FALSE); ++ if (key_id_str == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", ++ PR_GetError()); ++ ret = ENOMEM; ++ goto done; ++ } + +- *module_name_out = talloc_strdup(mem_ctx, module_name); +- if (*module_name_out == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to copy module_name_out name.\n"); +- ret = ENOMEM; +- goto done; ++ talloc_free(cert_b64); ++ cert_b64 = sss_base64_encode(mem_ctx, found_cert->derCert.data, ++ found_cert->derCert.len); ++ if (cert_b64 == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_base64_encode failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n", ++ key_id_str); ++ ++ multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n", ++ token_name, module_name, key_id_str, ++ cert_b64); + } ++ *_multi = multi; + + ret = EOK; + +@@ -474,6 +493,18 @@ done: + PK11_FreeSlot(slot); + } + ++ if (valid_certs != NULL) { ++ /* The certificates can be found in valid_certs and cert_list and ++ * CERT_DestroyCertList() will free the certificates as well. To avoid ++ * a double free the nodes from valid_certs are removed first because ++ * valid_certs will only have a sub-set of the certificates. */ ++ while (!PR_CLIST_IS_EMPTY(&valid_certs->list)) { ++ node = PR_LIST_HEAD(&valid_certs->list); ++ PR_REMOVE_LINK(node); ++ } ++ CERT_DestroyCertList(valid_certs); ++ } ++ + if (cert_list != NULL) { + CERT_DestroyCertList(cert_list); + } +@@ -483,6 +514,8 @@ done: + + PORT_Free(signed_random_value.data); + ++ talloc_free(cert_b64); ++ + rv = NSS_ShutdownContext(nss_ctx); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d].\n", +@@ -540,17 +573,14 @@ int main(int argc, const char *argv[]) + const char *opt_logger = NULL; + errno_t ret; + TALLOC_CTX *main_ctx = NULL; +- char *cert; + enum op_mode mode = OP_NONE; + enum pin_mode pin_mode = PIN_NONE; + char *pin = NULL; + char *slot_name_in = NULL; +- char *token_name_out = NULL; +- char *module_name_out = NULL; +- char *key_id_out = NULL; + char *nss_db = NULL; + struct cert_verify_opts *cert_verify_opts; + char *verify_opts = NULL; ++ char *multi = NULL; + + struct poptOption long_options[] = { + POPT_AUTOHELP +@@ -715,17 +745,14 @@ int main(int argc, const char *argv[]) + } + + ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, cert_verify_opts, +- &cert, &token_name_out, &module_name_out, &key_id_out); ++ &multi); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n"); + goto fail; + } + +- if (cert != NULL) { +- fprintf(stdout, "%s\n", token_name_out); +- fprintf(stdout, "%s\n", module_name_out); +- fprintf(stdout, "%s\n", key_id_out); +- fprintf(stdout, "%s\n", cert); ++ if (multi != NULL) { ++ fprintf(stdout, "%s", multi); + } + + talloc_free(main_ctx); +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 57a37b72594f030995f5e22255eb7a8fcd63d10e..896f71befbc9947a53b5eb20cba0bb3d104c4cf2 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -88,6 +88,8 @@ int LOCAL_pam_handler(struct pam_auth_req *preq); + + errno_t p11_child_init(struct pam_ctx *pctx); + ++struct cert_auth_info; ++ + struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int child_debug_fd, +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 4dce43800c3c6b026c545df35c846269cbb49610..ff32d1e726808caa36ca7cca557220866ef1a9ab 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -35,6 +35,15 @@ + #define P11_CHILD_LOG_FILE "p11_child" + #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child" + ++struct cert_auth_info { ++ char *cert; ++ char *token_name; ++ char *module_name; ++ char *key_id; ++ struct cert_auth_info *prev; ++ struct cert_auth_info *next; ++}; ++ + errno_t p11_child_init(struct pam_ctx *pctx) + { + return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd); +@@ -132,18 +141,15 @@ static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx, + } + + static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, +- ssize_t buf_len, char **_cert, +- char **_token_name, char **_module_name, +- char **_key_id) ++ ssize_t buf_len, ++ struct cert_auth_info **_cert_list) + { + int ret; + TALLOC_CTX *tmp_ctx = NULL; + uint8_t *p; + uint8_t *pn; +- char *cert = NULL; +- char *token_name = NULL; +- char *module_name = NULL; +- char *key_id = NULL; ++ struct cert_auth_info *cert_list = NULL; ++ struct cert_auth_info *cert_auth_info; + + if (buf_len < 0) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -157,108 +163,132 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + goto done; + } + +- p = memchr(buf, '\n', buf_len); +- if (p == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "Missing new-line in p11_child response.\n"); +- return EINVAL; +- } +- if (p == buf) { +- DEBUG(SSSDBG_OP_FAILURE, "Missing counter in p11_child response.\n"); +- return EINVAL; +- } +- + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + +- token_name = talloc_strndup(tmp_ctx, (char*) buf, (p - buf)); +- if (token_name == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); +- ret = ENOMEM; +- goto done; +- } ++ p = buf; + +- p++; +- pn = memchr(p, '\n', buf_len - (p - buf)); +- if (pn == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing new-line in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ do { ++ cert_auth_info = talloc_zero(tmp_ctx, struct cert_auth_info); ++ if (cert_auth_info == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n"); ++ return ENOMEM; ++ } + +- if (pn == p) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing module name in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ return EINVAL; ++ } ++ if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing counter in p11_child response.\n"); ++ return EINVAL; ++ } + +- module_name = talloc_strndup(tmp_ctx, (char *) p, (pn - p)); +- if (module_name == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_ALL, "Found module name [%s].\n", module_name); ++ cert_auth_info->token_name = talloc_strndup(cert_auth_info, (char *)p, ++ (pn - p)); ++ if (cert_auth_info->token_name == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found token name [%s].\n", ++ cert_auth_info->token_name); + +- p = ++pn; +- pn = memchr(p, '\n', buf_len - (p - buf)); +- if (pn == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing new-line in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ p = ++pn; ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } + +- if (pn == p) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing key id in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing module name in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } + +- key_id = talloc_strndup(tmp_ctx, (char *) p, (pn - p)); +- if (key_id == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_ALL, "Found key id [%s].\n", key_id); ++ cert_auth_info->module_name = talloc_strndup(cert_auth_info, (char *)p, ++ (pn - p)); ++ if (cert_auth_info->module_name == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found module name [%s].\n", ++ cert_auth_info->module_name); + +- p = pn + 1; +- pn = memchr(p, '\n', buf_len - (p - buf)); +- if (pn == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Missing new-line in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ p = ++pn; ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } + +- if (pn == p) { +- DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n"); +- ret = EINVAL; +- goto done; +- } ++ if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing key id in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } + +- cert = talloc_strndup(tmp_ctx, (char *) p, (pn - p)); +- if(cert == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert); ++ cert_auth_info->key_id = talloc_strndup(cert_auth_info, (char *)p, ++ (pn - p)); ++ if (cert_auth_info->key_id == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found key id [%s].\n", cert_auth_info->key_id); ++ ++ p = ++pn; ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cert_auth_info->cert = talloc_strndup(cert_auth_info, (char *)p, ++ (pn - p)); ++ if (cert_auth_info->cert == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert_auth_info->cert); ++ ++ DLIST_ADD(cert_list, cert_auth_info); ++ ++ p = ++pn; ++ } while ((pn - buf) < buf_len); + + ret = EOK; + + done: + if (ret == EOK) { +- *_token_name = talloc_steal(mem_ctx, token_name); +- *_cert = talloc_steal(mem_ctx, cert); +- *_module_name = talloc_steal(mem_ctx, module_name); +- *_key_id = talloc_steal(mem_ctx, key_id); ++ DLIST_FOR_EACH(cert_auth_info, cert_list) { ++ talloc_steal(mem_ctx, cert_auth_info); ++ } ++ ++ *_cert_list = cert_list; + } + + talloc_free(tmp_ctx); +@@ -273,10 +303,8 @@ struct pam_check_cert_state { + struct tevent_context *ev; + + struct child_io_fds *io; +- char *cert; +- char *token_name; +- char *module_name; +- char *key_id; ++ ++ struct cert_auth_info *cert_list; + }; + + static void p11_child_write_done(struct tevent_req *subreq); +@@ -349,9 +377,6 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + + state->ev = ev; + state->child_status = EFAULT; +- state->cert = NULL; +- state->token_name = NULL; +- state->module_name = NULL; + state->io = talloc(state, struct child_io_fds); + if (state->io == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n"); +@@ -514,11 +539,9 @@ static void p11_child_done(struct tevent_req *subreq) + + PIPE_FD_CLOSE(state->io->read_from_child_fd); + +- ret = parse_p11_child_response(state, buf, buf_len, &state->cert, +- &state->token_name, &state->module_name, +- &state->key_id); ++ ret = parse_p11_child_response(state, buf, buf_len, &state->cert_list); + if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_respose failed.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_response failed.\n"); + tevent_req_error(req, ret); + return; + } +@@ -551,20 +574,31 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + + TEVENT_REQ_RETURN_ON_ERROR(req); + ++ if (state->cert_list == NULL) { ++ *token_name = NULL; ++ *cert = NULL; ++ *module_name = NULL; ++ *key_id = NULL; ++ } ++ + if (cert != NULL) { +- *cert = talloc_steal(mem_ctx, state->cert); ++ *cert = (state->cert_list == NULL) ? NULL ++ : talloc_steal(mem_ctx, state->cert_list->cert); + } + + if (token_name != NULL) { +- *token_name = talloc_steal(mem_ctx, state->token_name); ++ *token_name = (state->cert_list == NULL) ? NULL ++ : talloc_steal(mem_ctx, state->cert_list->token_name); + } + + if (module_name != NULL) { +- *module_name = talloc_steal(mem_ctx, state->module_name); ++ *module_name = (state->cert_list == NULL) ? NULL ++ : talloc_steal(mem_ctx, state->cert_list->module_name); + } + + if (key_id != NULL) { +- *key_id = talloc_steal(mem_ctx, state->key_id); ++ *key_id = (state->cert_list == NULL) ? NULL ++ : talloc_steal(mem_ctx, state->cert_list->key_id); + } + + return EOK; +-- +2.15.1 + diff --git a/0043-PAM-handled-multiple-certs-in-the-responder.patch b/0043-PAM-handled-multiple-certs-in-the-responder.patch new file mode 100644 index 0000000..672761d --- /dev/null +++ b/0043-PAM-handled-multiple-certs-in-the-responder.patch @@ -0,0 +1,976 @@ +From 5649511243126866c97df0892c51227ab9257347 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 25 Aug 2017 12:51:09 +0200 +Subject: [PATCH 43/79] PAM: handled multiple certs in the responder +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This patch refactors the handling of the certificate and the attributes +to address the certificate on the Smartcard (module name, token name and +key id). Instead of using individual variables the values are put into a +new struct cert_auth_info. Since the new struct can be used as a list +the PAM responder can now handle multiple certificates on the Smartcard +and can send the needed data to pam_sss with multiple SSS_PAM_CERT_INFO +messages. + +Unit tests are added to confirm the expected behavior. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +--- + src/responder/pam/pamsrv.h | 25 ++-- + src/responder/pam/pamsrv_cmd.c | 257 ++++++++++++++++++++++++++-------------- + src/responder/pam/pamsrv_p11.c | 181 ++++++++++++++++++++-------- + src/tests/cmocka/test_pam_srv.c | 167 +++++++++++++++++++++++++- + src/tests/whitespace_test | 2 +- + 5 files changed, 483 insertions(+), 149 deletions(-) + +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 896f71befbc9947a53b5eb20cba0bb3d104c4cf2..f15f7f19f1f38626288416c9f2038371c6f58b47 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -73,10 +73,8 @@ struct pam_auth_req { + struct pam_auth_dp_req *dpreq_spy; + + struct ldb_message *user_obj; +- struct ldb_result *cert_user_objs; +- char *token_name; +- char *module_name; +- char *key_id; ++ struct cert_auth_info *cert_list; ++ struct cert_auth_info *current_cert; + bool cert_auth_local; + }; + +@@ -89,6 +87,16 @@ int LOCAL_pam_handler(struct pam_auth_req *preq); + errno_t p11_child_init(struct pam_ctx *pctx); + + struct cert_auth_info; ++const char *sss_cai_get_cert(struct cert_auth_info *i); ++const char *sss_cai_get_token_name(struct cert_auth_info *i); ++const char *sss_cai_get_module_name(struct cert_auth_info *i); ++const char *sss_cai_get_key_id(struct cert_auth_info *i); ++struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i); ++struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i); ++void sss_cai_set_cert_user_objs(struct cert_auth_info *i, ++ struct ldb_result *cert_user_objs); ++void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count, ++ size_t *_cert_user_count); + + struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +@@ -98,12 +106,11 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + const char *verify_opts, + struct pam_data *pd); + errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, +- char **cert, char **token_name, char **module_name, +- char **key_id); ++ struct cert_auth_info **cert_list); + +-errno_t add_pam_cert_response(struct pam_data *pd, const char *user, +- const char *token_name, const char *module_name, +- const char *key_id, enum response_type type); ++errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, ++ struct cert_auth_info *cert_info, ++ enum response_type type); + + bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd); + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 51d8185650cf823da289a3398b10133065d82ae4..8b2c086e206796ad4c977495be957c56b3255e7f 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1389,21 +1389,17 @@ done: + return pam_check_user_done(preq, ret); + } + ++static errno_t pam_user_by_cert_step(struct pam_auth_req *preq); + static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req); + static void pam_forwarder_cert_cb(struct tevent_req *req) + { + struct pam_auth_req *preq = tevent_req_callback_data(req, + struct pam_auth_req); +- struct cli_ctx *cctx = preq->cctx; + struct pam_data *pd; + errno_t ret = EOK; +- char *cert; +- struct pam_ctx *pctx = +- talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx); ++ const char *cert; + +- ret = pam_check_cert_recv(req, preq, &cert, &preq->token_name, +- &preq->module_name, +- &preq->key_id); ++ ret = pam_check_cert_recv(req, preq, &preq->cert_list); + talloc_free(req); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "get_cert request failed.\n"); +@@ -1412,6 +1408,8 @@ static void pam_forwarder_cert_cb(struct tevent_req *req) + + pd = preq->pd; + ++ cert = sss_cai_get_cert(preq->cert_list); ++ + if (cert == NULL) { + if (pd->logon_name == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -1431,21 +1429,42 @@ static void pam_forwarder_cert_cb(struct tevent_req *req) + goto done; + } + ++ preq->current_cert = preq->cert_list; ++ ret = pam_user_by_cert_step(preq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "pam_user_by_cert_step failed.\n"); ++ goto done; ++ } ++ ++ return; ++ ++done: ++ pam_check_user_done(preq, ret); ++} ++ ++static errno_t pam_user_by_cert_step(struct pam_auth_req *preq) ++{ ++ struct cli_ctx *cctx = preq->cctx; ++ struct tevent_req *req; ++ struct pam_ctx *pctx = ++ talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx); ++ ++ if (preq->current_cert == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate data.\n"); ++ return EINVAL; ++ } + + req = cache_req_user_by_cert_send(preq, cctx->ev, cctx->rctx, + pctx->rctx->ncache, 0, + preq->req_dom_type, NULL, +- cert); ++ sss_cai_get_cert(preq->current_cert)); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n"); +- ret = ENOMEM; +- goto done; ++ return ENOMEM; + } ++ + tevent_req_set_callback(req, pam_forwarder_lookup_by_cert_done, preq); +- return; +- +-done: +- pam_check_user_done(preq, ret); ++ return EOK; + } + + static errno_t get_results_from_all_domains(TALLOC_CTX *mem_ctx, +@@ -1511,6 +1530,9 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + struct pam_auth_req *preq = tevent_req_callback_data(req, + struct pam_auth_req); + const char *cert_user = NULL; ++ size_t cert_count = 0; ++ size_t cert_user_count = 0; ++ struct ldb_result *cert_user_objs; + + ret = cache_req_recv(preq, req, &results); + talloc_zfree(req); +@@ -1521,12 +1543,39 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + + if (ret == EOK) { + ret = get_results_from_all_domains(preq, results, +- &preq->cert_user_objs); ++ &cert_user_objs); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "get_results_from_all_domains failed.\n"); + goto done; + } + ++ sss_cai_set_cert_user_objs(preq->current_cert, cert_user_objs); ++ } ++ ++ preq->current_cert = sss_cai_get_next(preq->current_cert); ++ if (preq->current_cert != NULL) { ++ ret = pam_user_by_cert_step(preq); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "pam_user_by_cert_step failed.\n"); ++ goto done; ++ } ++ return; ++ } ++ ++ sss_cai_check_users(&preq->cert_list, &cert_count, &cert_user_count); ++ DEBUG(SSSDBG_TRACE_ALL, ++ "Found [%zu] certificates and [%zu] related users.\n", ++ cert_count, cert_user_count); ++ ++ if (cert_user_count == 0) { ++ if (preq->pd->logon_name == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Missing logon name and no certificate user found.\n"); ++ ret = ENOENT; ++ goto done; ++ } ++ } else { ++ + if (preq->pd->logon_name == NULL) { + if (preq->pd->cmd != SSS_PAM_PREAUTH) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -1535,9 +1584,39 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + goto done; + } + +- if (preq->cert_user_objs->count == 1) { ++ if (cert_count > 1) { ++ for (preq->current_cert = preq->cert_list; ++ preq->current_cert != NULL; ++ preq->current_cert = sss_cai_get_next(preq->current_cert)) { ++ ++ ret = add_pam_cert_response(preq->pd, "", ++ preq->current_cert, ++ preq->cctx->rctx->domains->user_name_hint ++ ? SSS_PAM_CERT_INFO_WITH_HINT ++ : SSS_PAM_CERT_INFO); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "add_pam_cert_response failed.\n"); ++ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; ++ } ++ } ++ ++ ret = EOK; ++ preq->pd->pam_status = PAM_SUCCESS; ++ pam_reply(preq); ++ goto done; ++ } ++ ++ if (cert_user_count == 1) { ++ cert_user_objs = sss_cai_get_cert_user_objs(preq->cert_list); ++ if (cert_user_objs == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate user.\n"); ++ ret = ENOENT; ++ goto done; ++ } ++ + cert_user = ldb_msg_find_attr_as_string( +- preq->cert_user_objs->msgs[0], ++ cert_user_objs->msgs[0], + SYSDB_NAME, NULL); + if (cert_user == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -1564,9 +1643,7 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + + if (preq->cctx->rctx->domains->user_name_hint) { + ret = add_pam_cert_response(preq->pd, cert_user, +- preq->token_name, +- preq->module_name, +- preq->key_id, ++ preq->cert_list, + SSS_PAM_CERT_INFO_WITH_HINT); + preq->pd->pam_status = PAM_SUCCESS; + if (ret != EOK) { +@@ -1596,13 +1673,6 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + goto done; + } + } +- } else { +- if (preq->pd->logon_name == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Missing logon name and no certificate user found.\n"); +- ret = ENOENT; +- goto done; +- } + } + + if (preq->user_obj == NULL) { +@@ -1884,7 +1954,9 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) + struct pam_ctx *pctx = + talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx); + const char *cert_user; ++ struct ldb_result *cert_user_objs; + size_t c; ++ bool found = false; + + if (!preq->pd->domain) { + preq->pd->domain = preq->domain->name; +@@ -1921,76 +1993,87 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) + return; + } + +- if (may_do_cert_auth(pctx, preq->pd) && preq->cert_user_objs != NULL) { ++ if (may_do_cert_auth(pctx, preq->pd) && preq->cert_list != NULL) { + /* Check if user matches certificate user */ +- for (c = 0; c < preq->cert_user_objs->count; c++) { +- cert_user = ldb_msg_find_attr_as_string( +- preq->cert_user_objs->msgs[c], +- SYSDB_NAME, +- NULL); +- if (cert_user == NULL) { +- /* Even if there might be other users mapped to the +- * certificate a missing SYSDB_NAME indicates some critical +- * condition which justifies that the whole request is aborted +- * */ +- DEBUG(SSSDBG_CRIT_FAILURE, +- "Certificate user object has no name.\n"); +- preq->pd->pam_status = PAM_USER_UNKNOWN; +- pam_reply(preq); +- return; ++ found = false; ++ for (preq->current_cert = preq->cert_list; ++ preq->current_cert != NULL; ++ preq->current_cert = sss_cai_get_next(preq->current_cert)) { ++ ++ cert_user_objs = sss_cai_get_cert_user_objs(preq->current_cert); ++ if (cert_user_objs == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Unexpteced missing certificate user, " ++ "trying next certificate.\n"); ++ continue; + } + +- /* pam_check_user_search() calls pd_set_primary_name() is the search +- * was successful, so pd->user contains the canonical sysdb name +- * as well */ +- if (ldb_dn_compare(preq->cert_user_objs->msgs[c]->dn, +- preq->user_obj->dn) == 0) { +- +- if (preq->pd->cmd == SSS_PAM_PREAUTH) { +- ret = sss_authtok_set_sc(preq->pd->authtok, +- SSS_AUTHTOK_TYPE_SC_PIN, NULL, 0, +- preq->token_name, 0, +- preq->module_name, 0, +- preq->key_id, 0); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_set_sc failed, " +- "Smartcard authentication " +- "detection might fail in the " +- "backend.\n"); +- } +- +- ret = add_pam_cert_response(preq->pd, cert_user, +- preq->token_name, +- preq->module_name, +- preq->key_id, +- SSS_PAM_CERT_INFO); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); +- preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; +- } +- } +- +- /* We are done if we do not have to call the backend */ +- if (preq->pd->cmd == SSS_PAM_AUTHENTICATE +- && preq->cert_auth_local) { +- preq->pd->pam_status = PAM_SUCCESS; +- preq->callback = pam_reply; ++ for (c = 0; c < cert_user_objs->count; c++) { ++ cert_user = ldb_msg_find_attr_as_string(cert_user_objs->msgs[c], ++ SYSDB_NAME, NULL); ++ if (cert_user == NULL) { ++ /* Even if there might be other users mapped to the ++ * certificate a missing SYSDB_NAME indicates some critical ++ * condition which justifies that the whole request is aborted ++ * */ ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Certificate user object has no name.\n"); ++ preq->pd->pam_status = PAM_USER_UNKNOWN; + pam_reply(preq); + return; + } ++ ++ if (ldb_dn_compare(cert_user_objs->msgs[c]->dn, ++ preq->user_obj->dn) == 0) { ++ found = true; ++ if (preq->pd->cmd == SSS_PAM_PREAUTH) { ++ ret = sss_authtok_set_sc(preq->pd->authtok, ++ SSS_AUTHTOK_TYPE_SC_PIN, NULL, 0, ++ sss_cai_get_token_name(preq->current_cert), 0, ++ sss_cai_get_module_name(preq->current_cert), 0, ++ sss_cai_get_key_id(preq->current_cert), 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sss_authtok_set_sc failed, Smartcard " ++ "authentication detection might fail in " ++ "the backend.\n"); ++ } ++ ++ /* FIXME: use the right cert info */ ++ ret = add_pam_cert_response(preq->pd, cert_user, ++ preq->current_cert, ++ SSS_PAM_CERT_INFO); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); ++ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; ++ } ++ } ++ ++ } + } + } + +- if (preq->pd->cmd == SSS_PAM_PREAUTH) { +- DEBUG(SSSDBG_TRACE_FUNC, +- "User and certificate user do not match, " +- "continue with other authentication methods.\n"); ++ if (found) { ++ /* We are done if we do not have to call the backend */ ++ if (preq->pd->cmd == SSS_PAM_AUTHENTICATE ++ && preq->cert_auth_local) { ++ preq->pd->pam_status = PAM_SUCCESS; ++ preq->callback = pam_reply; ++ pam_reply(preq); ++ return; ++ } + } else { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "User and certificate user do not match.\n"); +- preq->pd->pam_status = PAM_AUTH_ERR; +- pam_reply(preq); +- return; ++ if (preq->pd->cmd == SSS_PAM_PREAUTH) { ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "User and certificate user do not match, " ++ "continue with other authentication methods.\n"); ++ } else { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "User and certificate user do not match.\n"); ++ preq->pd->pam_status = PAM_AUTH_ERR; ++ pam_reply(preq); ++ return; ++ } + } + } + +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index ff32d1e726808caa36ca7cca557220866ef1a9ab..57c8e1e464f4262f2d78f869c52ca48bd469d90a 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -40,10 +40,80 @@ struct cert_auth_info { + char *token_name; + char *module_name; + char *key_id; ++ struct ldb_result *cert_user_objs; + struct cert_auth_info *prev; + struct cert_auth_info *next; + }; + ++const char *sss_cai_get_cert(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->cert : NULL; ++} ++ ++const char *sss_cai_get_token_name(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->token_name : NULL; ++} ++ ++const char *sss_cai_get_module_name(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->module_name : NULL; ++} ++ ++const char *sss_cai_get_key_id(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->key_id : NULL; ++} ++ ++struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->next : NULL; ++} ++ ++struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->cert_user_objs : NULL; ++} ++ ++void sss_cai_set_cert_user_objs(struct cert_auth_info *i, ++ struct ldb_result *cert_user_objs) ++{ ++ if (i->cert_user_objs != NULL) { ++ talloc_free(i->cert_user_objs); ++ } ++ i->cert_user_objs = talloc_steal(i, cert_user_objs); ++} ++ ++void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count, ++ size_t *_cert_user_count) ++{ ++ struct cert_auth_info *c; ++ struct cert_auth_info *tmp; ++ size_t cert_count = 0; ++ size_t cert_user_count = 0; ++ struct ldb_result *user_objs; ++ ++ DLIST_FOR_EACH_SAFE(c, tmp, *list) { ++ user_objs = sss_cai_get_cert_user_objs(c); ++ if (user_objs != NULL) { ++ cert_count++; ++ cert_user_count += user_objs->count; ++ } else { ++ DLIST_REMOVE(*list, c); ++ } ++ } ++ ++ if (_cert_count != NULL) { ++ *_cert_count = cert_count; ++ } ++ ++ if (_cert_user_count != NULL) { ++ *_cert_user_count = cert_user_count; ++ } ++ ++ return; ++} ++ + errno_t p11_child_init(struct pam_ctx *pctx) + { + return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd); +@@ -566,39 +636,71 @@ static void p11_child_timeout(struct tevent_context *ev, + } + + errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, +- char **cert, char **token_name, char **module_name, +- char **key_id) ++ struct cert_auth_info **cert_list) + { ++ struct cert_auth_info *tmp_cert_auth_info; + struct pam_check_cert_state *state = + tevent_req_data(req, struct pam_check_cert_state); + + TEVENT_REQ_RETURN_ON_ERROR(req); + +- if (state->cert_list == NULL) { +- *token_name = NULL; +- *cert = NULL; +- *module_name = NULL; +- *key_id = NULL; ++ if (cert_list != NULL) { ++ DLIST_FOR_EACH(tmp_cert_auth_info, state->cert_list) { ++ talloc_steal(mem_ctx, tmp_cert_auth_info); ++ } ++ ++ *cert_list = state->cert_list; + } + +- if (cert != NULL) { +- *cert = (state->cert_list == NULL) ? NULL +- : talloc_steal(mem_ctx, state->cert_list->cert); ++ return EOK; ++} ++ ++static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, ++ struct cert_auth_info *cert_info, ++ uint8_t **_msg, size_t *_msg_len) ++{ ++ uint8_t *msg = NULL; ++ size_t msg_len; ++ const char *token_name; ++ const char *module_name; ++ const char *key_id; ++ size_t user_len; ++ size_t token_len; ++ size_t module_len; ++ size_t key_id_len; ++ const char *username = ""; ++ ++ if (sysdb_username != NULL) { ++ username = sysdb_username; + } + +- if (token_name != NULL) { +- *token_name = (state->cert_list == NULL) ? NULL +- : talloc_steal(mem_ctx, state->cert_list->token_name); ++ token_name = sss_cai_get_token_name(cert_info); ++ module_name = sss_cai_get_module_name(cert_info); ++ key_id = sss_cai_get_key_id(cert_info); ++ ++ user_len = strlen(username) + 1; ++ token_len = strlen(token_name) + 1; ++ module_len = strlen(module_name) + 1; ++ key_id_len = strlen(key_id) + 1; ++ msg_len = user_len + token_len + module_len + key_id_len; ++ ++ msg = talloc_zero_size(mem_ctx, msg_len); ++ if (msg == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); ++ return ENOMEM; + } + +- if (module_name != NULL) { +- *module_name = (state->cert_list == NULL) ? NULL +- : talloc_steal(mem_ctx, state->cert_list->module_name); ++ memcpy(msg, username, user_len); ++ memcpy(msg + user_len, token_name, token_len); ++ memcpy(msg + user_len + token_len, module_name, module_len); ++ memcpy(msg + user_len + token_len + module_len, key_id, key_id_len); ++ ++ if (_msg != NULL) { ++ *_msg = msg; + } + +- if (key_id != NULL) { +- *key_id = (state->cert_list == NULL) ? NULL +- : talloc_steal(mem_ctx, state->cert_list->key_id); ++ if (_msg_len != NULL) { ++ *_msg_len = msg_len; + } + + return EOK; +@@ -613,18 +715,13 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME" + + errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, +- const char *token_name, const char *module_name, +- const char *key_id, enum response_type type) ++ struct cert_auth_info *cert_info, ++ enum response_type type) + { + uint8_t *msg = NULL; + char *env = NULL; +- size_t user_len; + size_t msg_len; +- size_t slot_len; +- size_t module_len; +- size_t key_id_len; + int ret; +- const char *username = ""; + + if (type != SSS_PAM_CERT_INFO && type != SSS_PAM_CERT_INFO_WITH_HINT) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid response type [%d].\n", type); +@@ -632,26 +729,14 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + } + + if ((type == SSS_PAM_CERT_INFO && sysdb_username == NULL) +- || token_name == NULL || module_name == NULL || key_id == NULL) { ++ || cert_info == NULL ++ || sss_cai_get_token_name(cert_info) == NULL ++ || sss_cai_get_module_name(cert_info) == NULL ++ || sss_cai_get_key_id(cert_info) == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n"); + return EINVAL; + } + +- if (sysdb_username != NULL) { +- username = sysdb_username; +- } +- user_len = strlen(username) + 1; +- slot_len = strlen(token_name) + 1; +- module_len = strlen(module_name) + 1; +- key_id_len = strlen(key_id) + 1; +- msg_len = user_len + slot_len + module_len + key_id_len; +- +- msg = talloc_zero_size(pd, msg_len); +- if (msg == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); +- return ENOMEM; +- } +- + /* sysdb_username is a fully-qualified name which is used by pam_sss when + * prompting the user for the PIN and as login name if it wasn't set by + * the PAM caller but has to be determined based on the inserted +@@ -659,10 +744,12 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + * re_expression config option was set in a way that user@domain cannot be + * handled anymore some more logic has to be added here. But for the time + * being I think using sysdb_username is fine. */ +- memcpy(msg, username, user_len); +- memcpy(msg + user_len, token_name, slot_len); +- memcpy(msg + user_len + slot_len, module_name, module_len); +- memcpy(msg + user_len + slot_len + module_len, key_id, key_id_len); ++ ++ ret = pack_cert_data(pd, sysdb_username, cert_info, &msg, &msg_len); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "pack_cert_data failed.\n"); ++ return ret; ++ } + + ret = pam_add_response(pd, type, msg_len, msg); + talloc_free(msg); +@@ -674,7 +761,7 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + + if (strcmp(pd->service, "gdm-smartcard") == 0) { + env = talloc_asprintf(pd, "%s=%s", PKCS11_LOGIN_TOKEN_ENV_NAME, +- token_name); ++ sss_cai_get_token_name(cert_info)); + if (env == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n"); + return ENOMEM; +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 351067eb664431cda159f73590de772920504380..6adbc15f580997c41a02819d0d6aa253f2d5a64b 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -47,6 +47,9 @@ + #define NSS_DB_PATH TESTS_PATH + #define NSS_DB "sql:"NSS_DB_PATH + ++#define NSS_DB_PATH_2CERTS TESTS_PATH "_2certs" ++#define NSS_DB_2CERTS "sql:"NSS_DB_PATH_2CERTS ++ + #define TEST_TOKEN_NAME "SSSD Test Token" + #define TEST_MODULE_NAME "NSS-Internal" + #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7" +@@ -74,6 +77,28 @@ + "8Z+9gqZhCa7FEKJOPNR9RVtJs0qUUutMZrp1zpyx0GTmXQBA7LbgPxy8L68uymEQ" \ + "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g=" + ++#define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C" ++#define TEST_TOKEN_2ND_CERT \ ++"MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ ++"REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ ++"NDEzMDFaFw0xODA1MTMxNDEzMDFaMCUxEjAQBgNVBAoMCUlQQS5ERVZFTDEPMA0G" \ ++"A1UEAwwGSVBBIFJBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3abE" \ ++"8LmIc6QN16VVxsMlN/rrCOoZKyyJolSzpP4+K66t+KZUiW/1j1MZogjyYyD39U1F" \ ++"zpa2H+pID74XYrdiqP7sp+uE9/k2XOv/nN3FobXDt+fSINLDriCmxNhUZqpgo2uq" \ ++"Mmka+yx2iJZwkntEoJTcd3aynoa2Sa2ZZbkMBy5p6/pUQKwnD6scOwe6mUDppIBK" \ ++"+ZZRm+u/NDdIRFI5wfKLRR1r/ONaJA9nz1TxSEsgLsjG/1m+Zbb6lGG4pePIFkQ9" \ ++"Iotpi64obBh93oIxzQR29lBG/FMjQVHlPIbx+xuGx11Vtp5pAomgFz0HRrj0leI7" \ ++"bROE+jnC/VGPLQD2aQIDAQABo4GWMIGTMB8GA1UdIwQYMBaAFPci/0Km5D/L5z7Y" \ ++"qwEc7E1/GwgcMEEGCCsGAQUFBwEBBDUwMzAxBggrBgEFBQcwAYYlaHR0cDovL2lw" \ ++"YS1kZXZlbC5pcGEuZGV2ZWw6ODAvY2Evb2NzcDAOBgNVHQ8BAf8EBAMCBPAwHQYD" \ ++"VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBg" \ ++"4Sppx2C3eXPJ4Pd9XElkQPOaBReXf1vV0uk/GlK+rG+aAqAkA2Lryx5PK/iAuzAU" \ ++"M6JUpELuQYgqugoCgBXMgsMlpAO/0C3CFq4ZH3KgIsRlRngKPrt6RG0UPMRD1CE2" \ ++"tSVkwUWvyK83lDiu2BbWDXyMyz5eZOlp7uHusf5BKvob8jEndHj1YzaNTmVSsDM5" \ ++"kiIwf8qgFhsO1HCq08PtAnbVHhqkcvnmIJN98eNWNfTKodDmFVbN8gB0wK+WB5ii" \ ++"WVOw7+3/zF1QgqnYX3t+kPLRryip/wvTZkzXWwMNj/W6UHgjNF/4gWGoBgCHu+u3" \ ++"EvjMmbVSrEkesibpGQS5" ++ + + static char CACHED_AUTH_TIMEOUT_STR[] = "4"; + static const int CACHED_AUTH_TIMEOUT = 4; +@@ -111,6 +136,13 @@ static errno_t setup_nss_db(void) + return ret; + } + ++ ret = mkdir(NSS_DB_PATH_2CERTS, 0775); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to create " NSS_DB_PATH_2CERTS ".\n"); ++ return ret; ++ } ++ + child_pid = fork(); + if (child_pid == 0) { /* child */ + ret = execlp("certutil", "certutil", "-N", "--empty-password", "-d", +@@ -127,6 +159,22 @@ static errno_t setup_nss_db(void) + return ret; + } + ++ child_pid = fork(); ++ if (child_pid == 0) { /* child */ ++ ret = execlp("certutil", "certutil", "-N", "--empty-password", "-d", ++ NSS_DB_2CERTS, NULL); ++ if (ret == -1) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "execl() failed.\n"); ++ exit(-1); ++ } ++ } else if (child_pid > 0) { ++ wait(&status); ++ } else { ++ ret = errno; ++ DEBUG(SSSDBG_FATAL_FAILURE, "fork() failed\n"); ++ return ret; ++ } ++ + fp = fopen(NSS_DB_PATH"/pkcs11.txt", "w"); + if (fp == NULL) { + DEBUG(SSSDBG_FATAL_FAILURE, "fopen() failed.\n"); +@@ -148,6 +196,27 @@ static errno_t setup_nss_db(void) + return ret; + } + ++ fp = fopen(NSS_DB_PATH_2CERTS"/pkcs11.txt", "w"); ++ if (fp == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fopen() failed.\n"); ++ return ret; ++ } ++ ret = fprintf(fp, "library=libsoftokn3.so\nname=soft\n"); ++ if (ret < 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n"); ++ return ret; ++ } ++ ret = fprintf(fp, "parameters=configdir='sql:%s/src/tests/cmocka/p11_nssdb_2certs' dbSlotDescription='SSSD Test Slot' dbTokenDescription='SSSD Test Token' secmod='secmod.db' flags=readOnly \n\n", ABS_SRC_DIR); ++ if (ret < 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fprintf() failed.\n"); ++ return ret; ++ } ++ ret = fclose(fp); ++ if (ret != 0) { ++ DEBUG(SSSDBG_FATAL_FAILURE, "fclose() failed.\n"); ++ return ret; ++ } ++ + return EOK; + } + +@@ -174,6 +243,26 @@ static void cleanup_nss_db(void) + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to remove " NSS_DB_PATH "\n"); + } ++ ++ ret = unlink(NSS_DB_PATH_2CERTS"/cert9.db"); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove cert9.db.\n"); ++ } ++ ++ ret = unlink(NSS_DB_PATH_2CERTS"/key4.db"); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove key4.db.\n"); ++ } ++ ++ ret = unlink(NSS_DB_PATH_2CERTS"/pkcs11.txt"); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove pkcs11.db.\n"); ++ } ++ ++ ret = rmdir(NSS_DB_PATH_2CERTS); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to remove " NSS_DB_PATH "\n"); ++ } + } + + struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx) +@@ -749,7 +838,8 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + } + + static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, +- enum response_type type, const char *name) ++ enum response_type type, const char *name, ++ const char *name2) + { + size_t rp = 0; + uint32_t val; +@@ -763,7 +853,11 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + if (name == NULL || *name == '\0') { + assert_int_equal(val, 1); + } else { +- assert_int_equal(val, 2); ++ if (name2 == NULL || *name2 == '\0') { ++ assert_int_equal(val, 2); ++ } else { ++ assert_int_equal(val, 3); ++ } + + SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); + assert_int_equal(val, SSS_PAM_DOMAIN_NAME); +@@ -801,6 +895,33 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + ++ if (name2 != NULL && *name2 != '\0') { ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ assert_int_equal(val, type); ++ ++ SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); ++ assert_int_equal(val, (strlen(name) + 1 ++ + sizeof(TEST_TOKEN_NAME) ++ + sizeof(TEST_MODULE_NAME) ++ + sizeof(TEST2_KEY_ID))); ++ ++ assert_int_equal(*(body + rp + strlen(name)), 0); ++ assert_string_equal(body + rp, name); ++ rp += strlen(name) + 1; ++ ++ assert_int_equal(*(body + rp + sizeof(TEST_TOKEN_NAME) - 1), 0); ++ assert_string_equal(body + rp, TEST_TOKEN_NAME); ++ rp += sizeof(TEST_TOKEN_NAME); ++ ++ assert_int_equal(*(body + rp + sizeof(TEST_MODULE_NAME) - 1), 0); ++ assert_string_equal(body + rp, TEST_MODULE_NAME); ++ rp += sizeof(TEST_MODULE_NAME); ++ ++ assert_int_equal(*(body + rp + sizeof(TEST2_KEY_ID) - 1), 0); ++ assert_string_equal(body + rp, TEST2_KEY_ID); ++ rp += sizeof(TEST2_KEY_ID); ++ } ++ + assert_int_equal(rp, blen); + + return EOK; +@@ -809,7 +930,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) + { + return test_pam_cert_check_ex(status, body, blen, +- SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME); ++ SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME, ++ NULL); + } + + static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, +@@ -817,14 +939,22 @@ static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, + { + return test_pam_cert_check_ex(status, body, blen, + SSS_PAM_CERT_INFO_WITH_HINT, +- "pamuser@"TEST_DOM_NAME); ++ "pamuser@"TEST_DOM_NAME, NULL); + } + + static int test_pam_cert_check_with_hint_no_user(uint32_t status, uint8_t *body, + size_t blen) + { + return test_pam_cert_check_ex(status, body, blen, +- SSS_PAM_CERT_INFO_WITH_HINT, ""); ++ SSS_PAM_CERT_INFO_WITH_HINT, "", NULL); ++} ++ ++int test_pam_cert_check_2certs(uint32_t status, uint8_t *body, ++ size_t blen) ++{ ++ return test_pam_cert_check_ex(status, body, blen, ++ SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME, ++ "pamuser@"TEST_DOM_NAME); + } + + static int test_pam_offline_chauthtok_check(uint32_t status, +@@ -1737,6 +1867,33 @@ static int test_lookup_by_cert_cb(void *pvt) + + return EOK; + } ++int test_lookup_by_cert_cb_2nd_cert_same_user(void *pvt) ++{ ++ int ret; ++ struct sysdb_attrs *attrs; ++ unsigned char *der = NULL; ++ size_t der_size; ++ ++ test_lookup_by_cert_cb(pvt); ++ ++ attrs = sysdb_new_attrs(pam_test_ctx); ++ assert_non_null(attrs); ++ ++ der = sss_base64_decode(pam_test_ctx, TEST_TOKEN_2ND_CERT, &der_size); ++ assert_non_null(der); ++ ++ ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); ++ talloc_free(der); ++ assert_int_equal(ret, EOK); ++ ++ ret = sysdb_set_user_attr(pam_test_ctx->tctx->dom, ++ pam_test_ctx->pam_user_fqdn, ++ attrs, ++ LDB_FLAG_MOD_ADD); ++ assert_int_equal(ret, EOK); ++ ++ return EOK; ++} + + static int test_lookup_by_cert_double_cb(void *pvt) + { +diff --git a/src/tests/whitespace_test b/src/tests/whitespace_test +index 799e35358b1d5ae4b10c4405068fb507cb234b6f..f055ed4c255db4001194844f45a9df7cda774b38 100755 +--- a/src/tests/whitespace_test ++++ b/src/tests/whitespace_test +@@ -39,7 +39,7 @@ fi + declare found_file=false + while read file; do + [[ $file == "src/config/testconfigs/noparse.api.conf" ]] && continue +- [[ $file =~ ^src/tests/cmocka/p11_nssdb/.*db ]] && continue ++ [[ $file =~ ^src/tests/cmocka/p11_nssdb.*/.*db ]] && continue + test `tail -c 1 $ABS_TOP_SRCDIR/$file` && \ + echo "Missing new line at the eof: $file" && \ + found_file=true +-- +2.15.1 + diff --git a/0044-pam_sss-refactoring-use-struct-cert_auth_info.patch b/0044-pam_sss-refactoring-use-struct-cert_auth_info.patch new file mode 100644 index 0000000..20cafa4 --- /dev/null +++ b/0044-pam_sss-refactoring-use-struct-cert_auth_info.patch @@ -0,0 +1,679 @@ +From 55deead9f2a98c3ba1fd5754bd38203b6c02b6a1 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +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 +Tested-by: Scott Poore +--- + 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 + #include + ++#ifdef HAVE_GDM_PAM_EXTENSIONS ++#include ++#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 + #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 + diff --git a/0045-p11_child-use-options-to-select-certificate-for-auth.patch b/0045-p11_child-use-options-to-select-certificate-for-auth.patch new file mode 100644 index 0000000..932b3d0 --- /dev/null +++ b/0045-p11_child-use-options-to-select-certificate-for-auth.patch @@ -0,0 +1,590 @@ +From 4aef95ff22cb926998773330cc860879b0dea5c2 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 27 Oct 2017 10:13:36 +0200 +Subject: [PATCH 45/79] p11_child: use options to select certificate for + authentication +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +New options are added to p11_child to select a specific certificate +during authentication. + +The related unit tests are updated by adding the needed attributes to +the requests. The was not necessary before because although the +attribute were already send by pam_sss they were not used in the PAM +responder but only forwarded to the back where they were used by the +PKINIT code to select the expected certificate. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +--- + src/p11_child/p11_child_nss.c | 213 ++++++++++++++++++++++++++-------------- + src/responder/pam/pamsrv_p11.c | 30 +++++- + src/tests/cmocka/test_pam_srv.c | 60 +++++++---- + 3 files changed, 208 insertions(+), 95 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index 50bde2f4f91f6c00260b0db383d0962112686ebc..c676375cf7f6677a1d7f38f09b9bb5fd820d60c5 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -67,12 +67,34 @@ static char *password_passthrough(PK11SlotInfo *slot, PRBool retry, void *arg) + return PL_strdup((char *)arg); + } + ++static char *get_key_id_str(PK11SlotInfo *slot, CERTCertificate *cert) ++{ ++ SECItem *key_id = NULL; ++ char *key_id_str = NULL; + ++ key_id = PK11_GetLowLevelKeyIDForCert(slot, cert, NULL); ++ if (key_id == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "PK11_GetLowLevelKeyIDForCert failed [%d].\n", ++ PR_GetError()); ++ return NULL; ++ } + +-int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, ++ key_id_str = CERT_Hexify(key_id, PR_FALSE); ++ SECITEM_FreeItem(key_id, PR_TRUE); ++ if (key_id_str == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError()); ++ return NULL; ++ } ++ ++ return key_id_str; ++} ++ ++int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + enum op_mode mode, const char *pin, + struct cert_verify_opts *cert_verify_opts, +- char **_multi) ++ const char *module_name_in, const char *token_name_in, ++ const char *key_id_in, char **_multi) + { + int ret; + SECStatus rv; +@@ -153,42 +175,31 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + mod_list_item->module->dllName); + } + +- if (slot_name_in != NULL) { +- slot = PK11_FindSlotByName(slot_name_in); +- if (slot == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_FindSlotByName failed for [%s]: [%d].\n", +- slot_name_in, PR_GetError()); +- return EIO; +- } +- } else { +- +- list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, +- NULL); +- if (list == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n"); +- return EIO; +- } ++ list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_TRUE, ++ NULL); ++ if (list == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "PK11_GetAllTokens failed.\n"); ++ return EIO; ++ } + +- for (le = list->head; le; le = le->next) { +- CK_SLOT_INFO slInfo; ++ for (le = list->head; le; le = le->next) { ++ CK_SLOT_INFO slInfo; + +- slInfo.flags = 0; +- rv = PK11_GetSlotInfo(le->slot, &slInfo); +- DEBUG(SSSDBG_TRACE_ALL, +- "Description [%s] Manufacturer [%s] flags [%lu].\n", +- slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags); +- if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) { +- slot = PK11_ReferenceSlot(le->slot); +- break; +- } +- } +- PK11_FreeSlotList(list); +- if (slot == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n"); +- return EIO; ++ slInfo.flags = 0; ++ rv = PK11_GetSlotInfo(le->slot, &slInfo); ++ DEBUG(SSSDBG_TRACE_ALL, ++ "Description [%s] Manufacturer [%s] flags [%lu].\n", ++ slInfo.slotDescription, slInfo.manufacturerID, slInfo.flags); ++ if (rv == SECSuccess && (slInfo.flags & CKF_REMOVABLE_DEVICE)) { ++ slot = PK11_ReferenceSlot(le->slot); ++ break; + } + } +- ++ PK11_FreeSlotList(list); ++ if (slot == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "No removable slots found.\n"); ++ return EIO; ++ } + + slot_id = PK11_GetSlotID(slot); + module_id = PK11_GetModuleID(slot); +@@ -317,24 +328,60 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + for (cert_list_node = CERT_LIST_HEAD(cert_list); + !CERT_LIST_END(cert_list_node, cert_list); + cert_list_node = CERT_LIST_NEXT(cert_list_node)) { +- if (cert_list_node->cert) { +- DEBUG(SSSDBG_TRACE_ALL, "found cert[%s][%s]\n", +- cert_list_node->cert->nickname, +- cert_list_node->cert->subjectName); ++ if (cert_list_node->cert == NULL) { ++ DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n"); ++ continue; ++ } + +- if (cert_verify_opts->do_verification) { +- rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert, +- PR_TRUE, +- certificateUsageSSLClient, +- NULL, NULL); +- if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Certificate [%s][%s] not valid [%d], skipping.\n", +- cert_list_node->cert->nickname, +- cert_list_node->cert->subjectName, PR_GetError()); +- continue; +- } ++ DEBUG(SSSDBG_TRACE_ALL, ++ "found cert[%s][%s]\n", ++ cert_list_node->cert->nickname, ++ cert_list_node->cert->subjectName); ++ ++ if (cert_verify_opts->do_verification) { ++ rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert, ++ PR_TRUE, ++ certificateUsageSSLClient, ++ NULL, NULL); ++ if (rv != SECSuccess) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Certificate [%s][%s] not valid [%d], skipping.\n", ++ cert_list_node->cert->nickname, ++ cert_list_node->cert->subjectName, PR_GetError()); ++ continue; + } ++ } ++ ++ if (key_id_in != NULL) { ++ PORT_Free(key_id_str); ++ key_id_str = NULL; ++ key_id_str = get_key_id_str(slot, cert_list_node->cert); ++ } ++ /* Check if we found the certificates we needed for authentication or ++ * the requested ones for pre-auth. For authentication all attributes ++ * must be given and match, for pre-auth only the given ones must ++ * match. */ ++ DEBUG(SSSDBG_TRACE_ALL, "%s %s %s %s %s %s.\n", ++ module_name_in, module_name, token_name_in, token_name, ++ key_id_in, key_id_str); ++ if ((mode == OP_AUTH ++ && module_name_in != NULL ++ && token_name_in != NULL ++ && key_id_in != NULL ++ && key_id_str != NULL ++ && strcmp(key_id_in, key_id_str) == 0 ++ && strcmp(token_name_in, token_name) == 0 ++ && strcmp(module_name_in, module_name) == 0) ++ || (mode == OP_PREAUTH ++ && (module_name_in == NULL ++ || (module_name_in != NULL ++ && strcmp(module_name_in, module_name) == 0)) ++ && (token_name_in == NULL ++ || (token_name_in != NULL ++ && strcmp(token_name_in, token_name) == 0)) ++ && (key_id_in == NULL ++ || (key_id_in != NULL && key_id_str != NULL ++ && strcmp(key_id_in, key_id_str) == 0)))) { + + rv = CERT_AddCertToListTail(valid_certs, cert_list_node->cert); + if (rv != SECSuccess) { +@@ -343,15 +390,6 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + ret = EIO; + goto done; + } +- +- if (found_cert == NULL) { +- found_cert = cert_list_node->cert; +- } else { +- DEBUG(SSSDBG_TRACE_ALL, "More than one certificate found, " \ +- "using just the first one.\n"); +- } +- } else { +- DEBUG(SSSDBG_TRACE_ALL, "--- empty cert list node ---\n"); + } + } + +@@ -367,7 +405,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + } + } + +- if (found_cert == NULL) { ++ if (CERT_LIST_EMPTY(valid_certs)) { + DEBUG(SSSDBG_TRACE_ALL, "No certificate found.\n"); + *_multi = NULL; + ret = EOK; +@@ -375,6 +413,23 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + } + + if (mode == OP_AUTH) { ++ cert_list_node = CERT_LIST_HEAD(valid_certs); ++ if (!CERT_LIST_END(CERT_LIST_NEXT(cert_list_node), valid_certs)) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "More than one certificate found for authentication, " ++ "aborting!\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ found_cert = cert_list_node->cert; ++ if (found_cert == NULL) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "No certificate found for authentication, aborting!\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ + rv = PK11_GenerateRandom(random_value, sizeof(random_value)); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +@@ -449,21 +504,10 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, const char *slot_name_in, + + found_cert = cert_list_node->cert; + +- SECITEM_FreeItem(key_id, PR_TRUE); + PORT_Free(key_id_str); +- key_id = PK11_GetLowLevelKeyIDForCert(slot, found_cert, NULL); +- if (key_id == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, +- "PK11_GetLowLevelKeyIDForCert failed [%d].\n", +- PR_GetError()); +- ret = EINVAL; +- goto done; +- } +- +- key_id_str = CERT_Hexify(key_id, PR_FALSE); ++ key_id_str = get_key_id_str(slot, found_cert); + if (key_id_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "get_key_id_str [%d].\n", PR_GetError()); + ret = ENOMEM; + goto done; + } +@@ -576,11 +620,13 @@ int main(int argc, const char *argv[]) + enum op_mode mode = OP_NONE; + enum pin_mode pin_mode = PIN_NONE; + char *pin = NULL; +- char *slot_name_in = NULL; + char *nss_db = NULL; + struct cert_verify_opts *cert_verify_opts; + char *verify_opts = NULL; + char *multi = NULL; ++ char *module_name = NULL; ++ char *token_name = NULL; ++ char *key_id = NULL; + + struct poptOption long_options[] = { + POPT_AUTOHELP +@@ -605,6 +651,12 @@ int main(int argc, const char *argv[]) + NULL}, + {"nssdb", 0, POPT_ARG_STRING, &nss_db, 0, _("NSS DB to use"), + NULL}, ++ {"module_name", 0, POPT_ARG_STRING, &module_name, 0, ++ _("Module name for authentication"), NULL}, ++ {"token_name", 0, POPT_ARG_STRING, &token_name, 0, ++ _("Token name for authentication"), NULL}, ++ {"key_id", 0, POPT_ARG_STRING, &key_id, 0, ++ _("Key ID for authentication"), NULL}, + POPT_TABLEEND + }; + +@@ -730,6 +782,15 @@ int main(int argc, const char *argv[]) + } + talloc_steal(main_ctx, debug_prg_name); + ++ if (mode == OP_AUTH && (module_name == NULL || token_name == NULL ++ || key_id == NULL)) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "--module_name, --token_name and --key_id must be for " ++ "authentication"); ++ ret = EINVAL; ++ goto fail; ++ } ++ + ret = parse_cert_verify_opts(main_ctx, verify_opts, &cert_verify_opts); + if (ret != EOK) { + DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse verifiy option.\n"); +@@ -744,8 +805,8 @@ int main(int argc, const char *argv[]) + } + } + +- ret = do_work(main_ctx, nss_db, slot_name_in, mode, pin, cert_verify_opts, +- &multi); ++ ret = do_work(main_ctx, nss_db, mode, pin, cert_verify_opts, module_name, ++ token_name, key_id, &multi); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "do_work failed.\n"); + goto fail; +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 57c8e1e464f4262f2d78f869c52ca48bd469d90a..4d5572164763ed0b3a842019f820680a4dc2dfdc 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -399,10 +399,13 @@ 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[7] = { NULL }; ++ const char *extra_args[13] = { NULL }; + uint8_t *write_buf = NULL; + size_t write_buf_len = 0; + size_t arg_c; ++ const char *module_name = NULL; ++ const char *token_name = NULL; ++ const char *key_id = NULL; + + req = tevent_req_create(mem_ctx, &state, struct pam_check_cert_state); + if (req == NULL) { +@@ -423,6 +426,30 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + extra_args[arg_c++] = verify_opts; + extra_args[arg_c++] = "--verify"; + } ++ ++ if (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_PIN ++ || sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_KEYPAD) { ++ ret = sss_authtok_get_sc(pd->authtok, NULL, NULL, &token_name, NULL, ++ &module_name, NULL, &key_id, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n"); ++ goto done; ++ } ++ ++ if (module_name != NULL && *module_name != '\0') { ++ extra_args[arg_c++] = module_name; ++ extra_args[arg_c++] = "--module_name"; ++ } ++ if (token_name != NULL && *token_name != '\0') { ++ extra_args[arg_c++] = token_name; ++ extra_args[arg_c++] = "--token_name"; ++ } ++ if (key_id != NULL && *key_id != '\0') { ++ extra_args[arg_c++] = key_id; ++ extra_args[arg_c++] = "--key_id"; ++ } ++ } ++ + if (pd->cmd == SSS_PAM_AUTHENTICATE) { + extra_args[arg_c++] = "--auth"; + switch (sss_authtok_get_type(pd->authtok)) { +@@ -437,6 +464,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + ret = EINVAL; + goto done; + } ++ + } else if (pd->cmd == SSS_PAM_PREAUTH) { + extra_args[arg_c++] = "--pre"; + } else { +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 6adbc15f580997c41a02819d0d6aa253f2d5a64b..ad5aeb6e252d989b6587525d9d2355ce9505f0e5 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -687,7 +687,9 @@ static void mock_input_pam(TALLOC_CTX *mem_ctx, + } + + static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, +- const char *pin, const char *service, ++ const char *pin, const char *token_name, ++ const char *module_name, const char *key_id, ++ const char *service, + acct_cb_t acct_cb, const char *cert, + bool only_one_provider_call) + { +@@ -697,6 +699,7 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, + struct pam_items pi = { 0 }; + int ret; + bool already_mocked = false; ++ size_t needed_size; + + if (name != NULL) { + pi.pam_user = name; +@@ -707,9 +710,21 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, + } + + if (pin != NULL) { +- pi.pam_authtok = discard_const(pin); +- pi.pam_authtok_size = strlen(pi.pam_authtok) + 1; ++ ret = sss_auth_pack_sc_blob(pin, 0, token_name, 0, module_name, 0, ++ key_id, 0, NULL, 0, &needed_size); ++ assert_int_equal(ret, EAGAIN); ++ ++ pi.pam_authtok = malloc(needed_size); ++ assert_non_null(pi.pam_authtok); ++ ++ ret = sss_auth_pack_sc_blob(pin, 0, token_name, 0, module_name, 0, ++ key_id, 0, ++ (uint8_t *)pi.pam_authtok, needed_size, ++ &needed_size); ++ assert_int_equal(ret, EOK); ++ + pi.pam_authtok_type = SSS_AUTHTOK_TYPE_SC_PIN; ++ pi.pam_authtok_size = needed_size; + } + + pi.pam_service = service == NULL ? "login" : service; +@@ -724,6 +739,7 @@ static void mock_input_pam_cert(TALLOC_CTX *mem_ctx, const char *name, + pi.cli_pid = 12345; + + ret = pack_message_v3(&pi, &buf_size, &m_buf); ++ free(pi.pam_authtok); + assert_int_equal(ret, 0); + + buf = talloc_memdup(mem_ctx, m_buf, buf_size); +@@ -1732,7 +1748,8 @@ void test_pam_preauth_no_logon_name(void **state) + { + int ret; + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, false); ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -1824,7 +1841,8 @@ void test_pam_preauth_cert_nocert(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, "/no/path"); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, false); ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -1962,7 +1980,7 @@ void test_pam_preauth_cert_nomatch(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -1984,7 +2002,7 @@ void test_pam_preauth_cert_match(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2007,8 +2025,9 @@ void test_pam_preauth_cert_match_gdm_smartcard(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, "gdm-smartcard", +- test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, ++ "gdm-smartcard", test_lookup_by_cert_cb, ++ TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2029,7 +2048,7 @@ void test_pam_preauth_cert_match_wrong_user(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_wrong_user_cb, + TEST_TOKEN_CERT, false); + +@@ -2061,7 +2080,7 @@ void test_pam_preauth_cert_no_logon_name(void **state) + * Additionally sss_parse_inp_recv() must be mocked because the cache + * request will be done with the username found by the certificate + * lookup. */ +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); + mock_account_recv_simple(); + mock_parse_inp("pamuser", NULL, EOK); +@@ -2090,7 +2109,7 @@ void test_pam_preauth_cert_no_logon_name_with_hint(void **state) + * Since user name hint is enabled we do not have to search the user + * during pre-auth and there is no need for an extra mocked response as in + * test_pam_preauth_cert_no_logon_name. */ +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2112,7 +2131,7 @@ void test_pam_preauth_cert_no_logon_name_double_cert(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2135,7 +2154,7 @@ void test_pam_preauth_cert_no_logon_name_double_cert_with_hint(void **state) + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + pam_test_ctx->rctx->domains->user_name_hint = true; + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2157,7 +2176,8 @@ void test_pam_preauth_no_cert_no_logon_name(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, "/no/path"); + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, false); ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ++ NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); + will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); +@@ -2178,7 +2198,7 @@ void test_pam_preauth_cert_no_logon_name_no_match(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, ++ mock_input_pam_cert(pam_test_ctx, NULL, NULL, NULL, NULL, NULL, NULL, + test_lookup_by_cert_cb, NULL, false); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH); +@@ -2206,7 +2226,9 @@ void test_pam_cert_auth(void **state) + * is looked up. Since the first mocked reply already adds the certificate + * to the user entry the lookup by certificate will already find the user + * in the cache and no second request to the backend is needed. */ +- mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", ++ "NSS-Internal", ++ "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL, + test_lookup_by_cert_cb, TEST_TOKEN_CERT, true); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); +@@ -2232,7 +2254,9 @@ void test_pam_cert_auth_double_cert(void **state) + + set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); + +- mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", NULL, ++ mock_input_pam_cert(pam_test_ctx, "pamuser", "123456", "SSSD Test Token", ++ "NSS-Internal", ++ "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL, + test_lookup_by_cert_double_cb, TEST_TOKEN_CERT, true); + + will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); +-- +2.15.1 + diff --git a/0046-pam-add-prompt-string-for-certificate-authentication.patch b/0046-pam-add-prompt-string-for-certificate-authentication.patch new file mode 100644 index 0000000..48ed92f --- /dev/null +++ b/0046-pam-add-prompt-string-for-certificate-authentication.patch @@ -0,0 +1,336 @@ +From 0d7127a62b76f0d0cd66902c59cddb78ff010b04 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 30 Oct 2017 08:03:42 +0100 +Subject: [PATCH 46/79] pam: add prompt string for certificate authentication +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A new certificate attribute is added which contains a string which is +used in the certificate selection list displayed to the user. The +Subject-DN of the certificate is used here because it is present in all +certificate and in general differs for certificate with different usage. +libsss_certmap is used to extract the subject-DN from the certificate +and convert it into a string. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +--- + Makefile.am | 2 ++ + src/responder/pam/pamsrv_p11.c | 65 ++++++++++++++++++++++++++++++++++++++++- + src/sss_client/pam_sss.c | 31 ++++++++++++++++---- + src/tests/cmocka/test_pam_srv.c | 23 +++++++++++++-- + 4 files changed, 111 insertions(+), 10 deletions(-) + +diff --git a/Makefile.am b/Makefile.am +index bbc90d9bad4d22ca0284ea95281a487d42399c05..04e7d59e9fb0fdbdd420573e7d737a9a465b66ea 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1398,6 +1398,7 @@ sssd_pam_LDADD = \ + $(SELINUX_LIBS) \ + $(PAM_LIBS) \ + $(SYSTEMD_DAEMON_LIBS) \ ++ libsss_certmap.la \ + $(SSSD_INTERNAL_LTLIBS) \ + $(NULL) + +@@ -2421,6 +2422,7 @@ pam_srv_tests_LDADD = \ + $(SYSTEMD_DAEMON_LIBS) \ + libsss_test_common.la \ + libsss_idmap.la \ ++ libsss_certmap.la \ + $(NULL) + + EXTRA_responder_get_domains_tests_DEPENDENCIES = \ +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 4d5572164763ed0b3a842019f820680a4dc2dfdc..5a3eeff0ec977829a9ad8c80b4fc6b2e06857097 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -26,6 +26,8 @@ + #include "util/child_common.h" + #include "util/strtonum.h" + #include "responder/pam/pamsrv.h" ++#include "lib/certmap/sss_certmap.h" ++#include "util/crypto/sss_crypto.h" + + + #ifndef SSSD_LIBEXEC_PATH +@@ -683,6 +685,54 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + return EOK; + } + ++static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert) ++{ ++ int ret; ++ struct sss_certmap_ctx *ctx = NULL; ++ unsigned char *der = NULL; ++ size_t der_size; ++ char *prompt = NULL; ++ char *filter = NULL; ++ char **domains = NULL; ++ ++ ret = sss_certmap_init(mem_ctx, NULL, NULL, &ctx); ++ if (ret != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n"); ++ return NULL; ++ } ++ ++ ret = sss_certmap_add_rule(ctx, 10, "KRB5:.*", ++ "LDAP:{subject_dn!nss}", NULL); ++ if (ret != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_add_rule failed.\n"); ++ goto done; ++ } ++ ++ der = sss_base64_decode(mem_ctx, cert, &der_size); ++ if (der == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n"); ++ goto done; ++ } ++ ++ ret = sss_certmap_get_search_filter(ctx, der, der_size, &filter, &domains); ++ if (ret != 0) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_get_search_filter failed.\n"); ++ goto done; ++ } ++ ++ prompt = talloc_strdup(mem_ctx, filter); ++ if (prompt == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ } ++ ++done: ++ sss_certmap_free_filter_and_domains(filter, domains); ++ sss_certmap_free_ctx(ctx); ++ talloc_free(der); ++ ++ return prompt; ++} ++ + static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + struct cert_auth_info *cert_info, + uint8_t **_msg, size_t *_msg_len) +@@ -692,16 +742,24 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + const char *token_name; + const char *module_name; + const char *key_id; ++ char *prompt; + size_t user_len; + size_t token_len; + size_t module_len; + size_t key_id_len; ++ size_t prompt_len; + const char *username = ""; + + if (sysdb_username != NULL) { + username = sysdb_username; + } + ++ prompt = get_cert_prompt(mem_ctx, sss_cai_get_cert(cert_info)); ++ if (prompt == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "get_cert_prompt failed.\n"); ++ return EIO; ++ } ++ + token_name = sss_cai_get_token_name(cert_info); + module_name = sss_cai_get_module_name(cert_info); + key_id = sss_cai_get_key_id(cert_info); +@@ -710,10 +768,12 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + token_len = strlen(token_name) + 1; + module_len = strlen(module_name) + 1; + key_id_len = strlen(key_id) + 1; +- msg_len = user_len + token_len + module_len + key_id_len; ++ prompt_len = strlen(prompt) + 1; ++ msg_len = user_len + token_len + module_len + key_id_len + prompt_len; + + msg = talloc_zero_size(mem_ctx, msg_len); + if (msg == NULL) { ++ talloc_free(prompt); + DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n"); + return ENOMEM; + } +@@ -722,6 +782,9 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + memcpy(msg + user_len, token_name, token_len); + memcpy(msg + user_len + token_len, module_name, module_len); + memcpy(msg + user_len + token_len + module_len, key_id, key_id_len); ++ memcpy(msg + user_len + token_len + module_len + key_id_len, ++ prompt, prompt_len); ++ talloc_free(prompt); + + if (_msg != NULL) { + *_msg = msg; +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index c147d4b3d76443d69e27eb2da042f8eebd1ae6ab..1dc51ea0536a92a63ec2f4d97f65dbb02604dbb3 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -129,6 +129,7 @@ struct cert_auth_info { + char *token_name; + char *module_name; + char *key_id; ++ char *prompt_str; + struct cert_auth_info *prev; + struct cert_auth_info *next; + }; +@@ -140,6 +141,7 @@ static void free_cai(struct cert_auth_info *cai) + free(cai->cert); + free(cai->token_name); + free(cai->key_id); ++ free(cai->prompt_str); + free(cai); + } + } +@@ -921,9 +923,25 @@ static int parse_cert_info(struct pam_items *pi, uint8_t *buf, size_t len, + goto done; + } + +- D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s]", ++ offset += strlen(cai->key_id) + 1; ++ if (offset >= len) { ++ D(("Cert message size mismatch")); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cai->prompt_str = strdup((char *) &buf[*p + offset]); ++ if (cai->prompt_str == NULL) { ++ D(("strdup failed")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ++ D(("cert user: [%s] token name: [%s] module: [%s] key id: [%s] " ++ "prompt: [%s]", + cai->cert_user, cai->token_name, cai->module_name, +- cai->key_id)); ++ cai->key_id, cai->prompt_str)); + + DLIST_ADD(pi->cert_list, cai); + ret = 0; +@@ -1543,7 +1561,7 @@ done: + #define discard_const(ptr) ((void *)((uintptr_t)(ptr))) + #endif + +-#define CERT_SEL_PROMPT_FMT "Certificate: %s" ++#define CERT_SEL_PROMPT_FMT "%s" + #define SEL_TITLE discard_const("Please select a certificate") + + static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi) +@@ -1588,7 +1606,7 @@ static int prompt_multi_cert_gdm(pam_handle_t *pamh, struct pam_items *pi) + + c = 0; + DLIST_FOR_EACH(cai, pi->cert_list) { +- ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->key_id); ++ ret = asprintf(&prompt, CERT_SEL_PROMPT_FMT, cai->prompt_str); + if (ret == -1) { + ret = ENOMEM; + goto done; +@@ -1637,9 +1655,10 @@ done: + #endif + } + +-#define TEXT_CERT_SEL_PROMPT_FMT "%s[%zu] Certificate: %s\n" ++#define TEXT_CERT_SEL_PROMPT_FMT "%s\n[%zu]:\n%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; +@@ -1670,7 +1689,7 @@ static int prompt_multi_cert(pam_handle_t *pamh, struct pam_items *pi) + DLIST_FOR_EACH(cai, pi->cert_list) { + cert_count++; + ret = asprintf(&tmp, TEXT_CERT_SEL_PROMPT_FMT, prompt, cert_count, +- cai->key_id); ++ cai->prompt_str); + free(prompt); + if (ret == -1) { + return ENOMEM; +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index ad5aeb6e252d989b6587525d9d2355ce9505f0e5..02b7ddd16e6d30fec4c703c676066ae1eef1cf89 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -53,6 +53,7 @@ + #define TEST_TOKEN_NAME "SSSD Test Token" + #define TEST_MODULE_NAME "NSS-Internal" + #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7" ++#define TEST_SUBJECT_DN "CN=ipa-devel.ipa.devel,O=IPA.DEVEL" + #define TEST_TOKEN_CERT \ + "MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ + "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ +@@ -78,6 +79,7 @@ + "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g=" + + #define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C" ++#define TEST2_SUBJECT_DN "CN=IPA RA,O=IPA.DEVEL" + #define TEST_TOKEN_2ND_CERT \ + "MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ + "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ +@@ -831,7 +833,8 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + assert_int_equal(val, (sizeof("pamuser@"TEST_DOM_NAME) + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) +- + sizeof(TEST_KEY_ID))); ++ + sizeof(TEST_KEY_ID) ++ + sizeof(TEST_SUBJECT_DN))); + + assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); + assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); +@@ -849,6 +852,10 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + ++ assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); ++ assert_string_equal(body + rp, TEST_SUBJECT_DN); ++ rp += sizeof(TEST_SUBJECT_DN); ++ + assert_int_equal(rp, blen); + return EOK; + } +@@ -893,7 +900,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_int_equal(val, (strlen(name) + 1 + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) +- + sizeof(TEST_KEY_ID))); ++ + sizeof(TEST_KEY_ID) ++ + sizeof(TEST_SUBJECT_DN))); + + assert_int_equal(*(body + rp + strlen(name)), 0); + assert_string_equal(body + rp, name); +@@ -911,6 +919,10 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + ++ assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); ++ assert_string_equal(body + rp, TEST_SUBJECT_DN); ++ rp += sizeof(TEST_SUBJECT_DN); ++ + if (name2 != NULL && *name2 != '\0') { + SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); + assert_int_equal(val, type); +@@ -919,7 +931,8 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_int_equal(val, (strlen(name) + 1 + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) +- + sizeof(TEST2_KEY_ID))); ++ + sizeof(TEST2_KEY_ID) ++ + sizeof(TEST2_SUBJECT_DN))); + + assert_int_equal(*(body + rp + strlen(name)), 0); + assert_string_equal(body + rp, name); +@@ -936,6 +949,10 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_int_equal(*(body + rp + sizeof(TEST2_KEY_ID) - 1), 0); + assert_string_equal(body + rp, TEST2_KEY_ID); + rp += sizeof(TEST2_KEY_ID); ++ ++ assert_int_equal(*(body + rp + sizeof(TEST2_SUBJECT_DN) - 1), 0); ++ assert_string_equal(body + rp, TEST2_SUBJECT_DN); ++ rp += sizeof(TEST2_SUBJECT_DN); + } + + assert_int_equal(rp, blen); +-- +2.15.1 + diff --git a/0047-PAM-allow-missing-logon_name-during-certificate-auth.patch b/0047-PAM-allow-missing-logon_name-during-certificate-auth.patch new file mode 100644 index 0000000..cd9d0db --- /dev/null +++ b/0047-PAM-allow-missing-logon_name-during-certificate-auth.patch @@ -0,0 +1,255 @@ +From 85c087a88ac5d45b68bef609b5b098bf50e95d39 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 30 Oct 2017 17:11:56 +0100 +Subject: [PATCH 47/79] PAM: allow missing logon_name during certificate + authentication +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If only one certificate is available and the logon_name is the user is +not given the PAM responder already tried to find the name during the +pre-auth step. With multiple certificates this might cause useless extra +effort and the name should be determined after the certificate is +selected in the authentication step. This might currently only happen +with GDM because all other PAM clients will prompt for the user name +unconditionally. + +New unit tests are added to cover this new case. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +--- + src/responder/pam/pamsrv_cmd.c | 63 ++++++++++++++++++++++++++----- + src/tests/cmocka/test_pam_srv.c | 82 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 135 insertions(+), 10 deletions(-) + +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index 8b2c086e206796ad4c977495be957c56b3255e7f..caf6c99489b8378d2e850473191223709920cd79 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1151,6 +1151,7 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p + size_t blen; + errno_t ret; + uint32_t terminator; ++ const char *key_id; + + prctx = talloc_get_type(cctx->protocol_ctx, struct cli_protocol); + +@@ -1191,9 +1192,33 @@ static errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *p + pd->logon_name, + &pd->domain, &pd->user); + } else { +- /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the +- * name is determined with the help of a certificate */ +- if (pd->cmd == SSS_PAM_PREAUTH ++ /* SSS_PAM_PREAUTH request may have a missing name, e.g. if the ++ * name is determined with the help of a certificate. During ++ * SSS_PAM_AUTHENTICATE at least a key ID is needed to identify the ++ * selected certificate. */ ++ if (pd->cmd == SSS_PAM_AUTHENTICATE ++ && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx, ++ struct pam_ctx), pd) ++ && (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_SC_PIN ++ || sss_authtok_get_type(pd->authtok) ++ == SSS_AUTHTOK_TYPE_SC_KEYPAD)) { ++ ret = sss_authtok_get_sc(pd->authtok, NULL, NULL, NULL, NULL, NULL, ++ NULL, &key_id, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc failed.\n"); ++ goto done; ++ } ++ ++ if (key_id == NULL || *key_id == '\0') { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Missing logon and Smartcard key ID during " ++ "authentication.\n"); ++ ret = ERR_NO_CREDS; ++ goto done; ++ } ++ ++ ret = EOK; ++ } else if (pd->cmd == SSS_PAM_PREAUTH + && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx, + struct pam_ctx), pd)) { + ret = EOK; +@@ -1375,9 +1400,12 @@ static int pam_forwarder(struct cli_ctx *cctx, int pam_cmd) + /* Determine what domain type to contact */ + preq->req_dom_type = get_domain_request_type(preq, pctx); + +- /* try backend first for authentication before doing local Smartcard +- * authentication */ +- if (pd->cmd != SSS_PAM_AUTHENTICATE && may_do_cert_auth(pctx, pd)) { ++ /* Try backend first for authentication before doing local Smartcard ++ * authentication if a logon name is available. Otherwise try to derive ++ * the logon name from the certificate first. */ ++ if ((pd->cmd != SSS_PAM_AUTHENTICATE ++ || (pd->cmd == SSS_PAM_AUTHENTICATE && pd->logon_name == NULL)) ++ && may_do_cert_auth(pctx, pd)) { + ret = check_cert(cctx, cctx->ev, pctx, preq, pd); + /* Finish here */ + goto done; +@@ -1577,9 +1605,10 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + } else { + + if (preq->pd->logon_name == NULL) { +- if (preq->pd->cmd != SSS_PAM_PREAUTH) { ++ if (preq->pd->cmd != SSS_PAM_PREAUTH ++ && preq->pd->cmd != SSS_PAM_AUTHENTICATE) { + DEBUG(SSSDBG_CRIT_FAILURE, +- "Missing logon name only allowed during pre-auth.\n"); ++ "Missing logon name only allowed during (pre-)auth.\n"); + ret = ENOENT; + goto done; + } +@@ -1641,7 +1670,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + } + } + +- if (preq->cctx->rctx->domains->user_name_hint) { ++ if (preq->cctx->rctx->domains->user_name_hint ++ && preq->pd->cmd == SSS_PAM_PREAUTH) { + ret = add_pam_cert_response(preq->pd, cert_user, + preq->cert_list, + SSS_PAM_CERT_INFO_WITH_HINT); +@@ -1664,6 +1694,20 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + goto done; + } + ++ /* If logon_name was not given during authentication add a ++ * SSS_PAM_CERT_INFO message to send the name to the caller. */ ++ if (preq->pd->cmd == SSS_PAM_AUTHENTICATE ++ && preq->pd->logon_name == NULL) { ++ ret = add_pam_cert_response(preq->pd, cert_user, ++ preq->cert_list, ++ SSS_PAM_CERT_INFO); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "add_pam_cert_response failed.\n"); ++ preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; ++ goto done; ++ } ++ } ++ + /* cert_user will be returned to the PAM client as user name, so + * we can use it here already e.g. to set in initgroups timeout */ + preq->pd->logon_name = talloc_strdup(preq->pd, cert_user); +@@ -2039,7 +2083,6 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) + "the backend.\n"); + } + +- /* FIXME: use the right cert info */ + ret = add_pam_cert_response(preq->pd, cert_user, + preq->current_cert, + SSS_PAM_CERT_INFO); +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index 02b7ddd16e6d30fec4c703c676066ae1eef1cf89..f5ba131357b536adac4b3466ebbc257a838d1420 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -967,6 +967,16 @@ static int test_pam_cert_check(uint32_t status, uint8_t *body, size_t blen) + NULL); + } + ++static int test_pam_cert_check_auth_success(uint32_t status, uint8_t *body, ++ size_t blen) ++{ ++ assert_int_equal(pam_test_ctx->exp_pam_status, PAM_BAD_ITEM); ++ pam_test_ctx->exp_pam_status = PAM_SUCCESS; ++ return test_pam_cert_check_ex(status, body, blen, ++ SSS_PAM_CERT_INFO, "pamuser@"TEST_DOM_NAME, ++ NULL); ++} ++ + static int test_pam_cert_check_with_hint(uint32_t status, uint8_t *body, + size_t blen) + { +@@ -2265,6 +2275,74 @@ void test_pam_cert_auth(void **state) + assert_int_equal(ret, EOK); + } + ++void test_pam_cert_auth_no_logon_name(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); ++ ++ /* Here the last option must be set to true because the backend is only ++ * connected once. During authentication the backend is connected first to ++ * see if it can handle Smartcard authentication, but before that the user ++ * is looked up. Since the first mocked reply already adds the certificate ++ * to the user entry the lookup by certificate will already find the user ++ * in the cache and no second request to the backend is needed. */ ++ mock_input_pam_cert(pam_test_ctx, NULL, "123456", "SSSD Test Token", ++ "NSS-Internal", ++ "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7", NULL, ++ test_lookup_by_cert_cb, TEST_TOKEN_CERT, true); ++ ++ mock_account_recv_simple(); ++ mock_parse_inp("pamuser", NULL, EOK); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ /* Assume backend cannot handle Smartcard credentials */ ++ pam_test_ctx->exp_pam_status = PAM_BAD_ITEM; ++ ++ set_cmd_cb(test_pam_cert_check_auth_success); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ ++void test_pam_cert_auth_no_logon_name_no_key_id(void **state) ++{ ++ int ret; ++ ++ set_cert_auth_param(pam_test_ctx->pctx, NSS_DB); ++ ++ /* Here the last option must be set to true because the backend is only ++ * connected once. During authentication the backend is connected first to ++ * see if it can handle Smartcard authentication, but before that the user ++ * is looked up. Since the first mocked reply already adds the certificate ++ * to the user entry the lookup by certificate will already find the user ++ * in the cache and no second request to the backend is needed. */ ++ mock_input_pam_cert(pam_test_ctx, NULL, "123456", "SSSD Test Token", ++ "NSS-Internal", NULL, NULL, ++ NULL, NULL, false); ++ ++ will_return(__wrap_sss_packet_get_cmd, SSS_PAM_AUTHENTICATE); ++ will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL); ++ ++ /* Assume backend cannot handle Smartcard credentials */ ++ pam_test_ctx->exp_pam_status = PAM_BAD_ITEM; ++ ++ set_cmd_cb(test_pam_creds_insufficient_check); ++ ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_AUTHENTICATE, ++ pam_test_ctx->pam_cmds); ++ assert_int_equal(ret, EOK); ++ ++ /* Wait until the test finishes with EOK */ ++ ret = test_ev_loop(pam_test_ctx->tctx); ++ assert_int_equal(ret, EOK); ++} ++ + void test_pam_cert_auth_double_cert(void **state) + { + int ret; +@@ -2721,6 +2799,10 @@ int main(int argc, const char *argv[]) + pam_test_teardown), + cmocka_unit_test_setup_teardown(test_pam_cert_auth_double_cert, + pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name, ++ pam_test_setup, pam_test_teardown), ++ cmocka_unit_test_setup_teardown(test_pam_cert_auth_no_logon_name_no_key_id, ++ pam_test_setup, pam_test_teardown), + #endif /* HAVE_NSS */ + + cmocka_unit_test_setup_teardown(test_filter_response, +-- +2.15.1 + diff --git a/0048-p11_child-add-descriptions-for-error-codes-to-debug-.patch b/0048-p11_child-add-descriptions-for-error-codes-to-debug-.patch new file mode 100644 index 0000000..b7b761d --- /dev/null +++ b/0048-p11_child-add-descriptions-for-error-codes-to-debug-.patch @@ -0,0 +1,275 @@ +From 5b0dacffcf33837390f46b6f25146fd0e3e17f3a Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 30 Oct 2017 10:22:33 +0100 +Subject: [PATCH 48/79] p11_child: add descriptions for error codes to debug + messages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Additionally to the NSS erro code a text message describing the error is +added. This will help to see why p11_child ignores specific +certificates. For example it would be more obvious why the certificate +is not valid (expired, missing CA cert, failed OCSP etc). + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +--- + src/p11_child/p11_child_nss.c | 91 ++++++++++++++++++++++++------------------- + 1 file changed, 50 insertions(+), 41 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index c676375cf7f6677a1d7f38f09b9bb5fd820d60c5..5f289688e41f4ea610292b907036e05cf95eb29d 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -75,15 +75,16 @@ static char *get_key_id_str(PK11SlotInfo *slot, CERTCertificate *cert) + key_id = PK11_GetLowLevelKeyIDForCert(slot, cert, NULL); + if (key_id == NULL) { + DEBUG(SSSDBG_OP_FAILURE, +- "PK11_GetLowLevelKeyIDForCert failed [%d].\n", +- PR_GetError()); ++ "PK11_GetLowLevelKeyIDForCert failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return NULL; + } + + key_id_str = CERT_Hexify(key_id, PR_FALSE); + SECITEM_FreeItem(key_id, PR_TRUE); + if (key_id_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d].\n", PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_Hexify failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return NULL; + } + +@@ -138,8 +139,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + + nss_ctx = NSS_InitContext(nss_db, "", "", SECMOD_DB, ¶meters, flags); + if (nss_ctx == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "NSS_InitContext failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + +@@ -232,8 +233,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + if (pin != NULL) { + rv = PK11_Authenticate(slot, PR_FALSE, discard_const(pin)); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_Authenticate failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "PK11_Authenticate failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + } else { +@@ -246,8 +247,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + + cert_list = PK11_ListCertsInSlot(slot); + if (cert_list == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "PK11_ListCertsInSlot failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "PK11_ListCertsInSlot failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + +@@ -265,31 +266,33 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + + rv = CERT_FilterCertListByUsage(cert_list, certUsageSSLClient, PR_FALSE); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + rv = CERT_FilterCertListForUserCerts(cert_list); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListForUserCerts failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, ++ "CERT_FilterCertListForUserCerts failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + + handle = CERT_GetDefaultCertDB(); + if (handle == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + if (cert_verify_opts->do_ocsp) { + rv = CERT_EnableOCSPChecking(handle); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_EnableOCSPChecking failed: [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, ++ "CERT_EnableOCSPChecking failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + +@@ -300,16 +303,16 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + cert_verify_opts->ocsp_default_responder_signing_cert); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_SetOCSPDefaultResponder failed: [%d].\n", +- PR_GetError()); ++ "CERT_SetOCSPDefaultResponder failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + rv = CERT_EnableOCSPDefaultResponder(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_EnableOCSPDefaultResponder failed: [%d].\n", +- PR_GetError()); ++ "CERT_EnableOCSPDefaultResponder failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + } +@@ -318,8 +321,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + found_cert = NULL; + valid_certs = CERT_NewCertList(); + if (valid_certs == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_NewCertList failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "CERT_NewCertList failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = ENOMEM; + goto done; + } +@@ -345,9 +348,10 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + NULL, NULL); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "Certificate [%s][%s] not valid [%d], skipping.\n", ++ "Certificate [%s][%s] not valid [%d][%s], skipping.\n", + cert_list_node->cert->nickname, +- cert_list_node->cert->subjectName, PR_GetError()); ++ cert_list_node->cert->subjectName, ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + continue; + } + } +@@ -386,7 +390,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + rv = CERT_AddCertToListTail(valid_certs, cert_list_node->cert); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_AddCertToListTail failed [%d].\n", PR_GetError()); ++ "CERT_AddCertToListTail failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -400,8 +405,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + rv = CERT_DisableOCSPDefaultResponder(handle); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_DisableOCSPDefaultResponder failed: [%d].\n", +- PR_GetError()); ++ "CERT_DisableOCSPDefaultResponder failed: [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + } + } + +@@ -433,15 +438,17 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + rv = PK11_GenerateRandom(random_value, sizeof(random_value)); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +- "PK11_GenerateRandom failed [%d].\n", PR_GetError()); ++ "PK11_GenerateRandom failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + return EIO; + } + + priv_key = PK11_FindPrivateKeyFromCert(slot, found_cert, NULL); + if (priv_key == NULL) { + DEBUG(SSSDBG_OP_FAILURE, +- "PK11_FindPrivateKeyFromCert failed [%d]." \ +- "Maybe pin is missing.\n", PR_GetError()); ++ "PK11_FindPrivateKeyFromCert failed [%d][%s]." ++ "Maybe pin is missing.\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -451,8 +458,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + if (algtag == SEC_OID_UNKNOWN) { + SECKEY_DestroyPrivateKey(priv_key); + DEBUG(SSSDBG_OP_FAILURE, +- "SEC_GetSignatureAlgorithmOidTag failed [%d].\n", +- PR_GetError()); ++ "SEC_GetSignatureAlgorithmOidTag failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -462,8 +469,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + priv_key, algtag); + SECKEY_DestroyPrivateKey(priv_key); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "SEC_SignData failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "SEC_SignData failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -471,7 +478,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + pub_key = CERT_ExtractPublicKey(found_cert); + if (pub_key == NULL) { + DEBUG(SSSDBG_OP_FAILURE, +- "CERT_ExtractPublicKey failed [%d].\n", PR_GetError()); ++ "CERT_ExtractPublicKey failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EIO; + goto done; + } +@@ -481,8 +489,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + NULL); + SECKEY_DestroyPublicKey(pub_key); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "VFY_VerifyData failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "VFY_VerifyData failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = EACCES; + goto done; + } +@@ -507,7 +515,8 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + PORT_Free(key_id_str); + key_id_str = get_key_id_str(slot, found_cert); + if (key_id_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "get_key_id_str [%d].\n", PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "get_key_id_str [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + ret = ENOMEM; + goto done; + } +@@ -562,8 +571,8 @@ done: + + rv = NSS_ShutdownContext(nss_ctx); + if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d].\n", +- PR_GetError()); ++ DEBUG(SSSDBG_OP_FAILURE, "NSS_ShutdownContext failed [%d][%s].\n", ++ PR_GetError(), PORT_ErrorToString(PR_GetError())); + } + + return ret; +-- +2.15.1 + diff --git a/0049-pam-filter-certificates-in-the-responder-not-in-the-.patch b/0049-pam-filter-certificates-in-the-responder-not-in-the-.patch new file mode 100644 index 0000000..d373f0a --- /dev/null +++ b/0049-pam-filter-certificates-in-the-responder-not-in-the-.patch @@ -0,0 +1,356 @@ +From 1889bd761a16a67cfb22063a2b277b4def670aae Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 6 Nov 2017 15:26:38 +0100 +Subject: [PATCH 49/79] pam: filter certificates in the responder not in the + child +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With the new selection option and the handling of multiple certificates +in the PAM responder it is not needed anymore to filter the certificates +in p11_child but the matching rules can be applied by the PAM responder +directly. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +--- + src/p11_child/p11_child_nss.c | 18 +----- + src/responder/pam/pamsrv.h | 6 ++ + src/responder/pam/pamsrv_cmd.c | 10 ++- + src/responder/pam/pamsrv_p11.c | 135 +++++++++++++++++++++++++++++++++++++++- + src/tests/cmocka/test_pam_srv.c | 3 + + 5 files changed, 152 insertions(+), 20 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index 5f289688e41f4ea610292b907036e05cf95eb29d..e59aba0d1561f58206252f7251ecd88315836b1b 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -264,22 +264,6 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + } + } + +- rv = CERT_FilterCertListByUsage(cert_list, certUsageSSLClient, PR_FALSE); +- if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, "CERT_FilterCertListByUsage failed: [%d][%s].\n", +- PR_GetError(), PORT_ErrorToString(PR_GetError())); +- return EIO; +- } +- +- rv = CERT_FilterCertListForUserCerts(cert_list); +- if (rv != SECSuccess) { +- DEBUG(SSSDBG_OP_FAILURE, +- "CERT_FilterCertListForUserCerts failed: [%d][%s].\n", +- PR_GetError(), PORT_ErrorToString(PR_GetError())); +- return EIO; +- } +- +- + handle = CERT_GetDefaultCertDB(); + if (handle == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "CERT_GetDefaultCertDB failed: [%d][%s].\n", +@@ -344,7 +328,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + if (cert_verify_opts->do_verification) { + rv = CERT_VerifyCertificateNow(handle, cert_list_node->cert, + PR_TRUE, +- certificateUsageSSLClient, ++ certificateUsageCheckAllUsages, + NULL, NULL); + if (rv != SECSuccess) { + DEBUG(SSSDBG_OP_FAILURE, +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index f15f7f19f1f38626288416c9f2038371c6f58b47..0bc229212844602ed461d1c7db48bf51ac2e2194 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -27,6 +27,7 @@ + #include "sbus/sssd_dbus.h" + #include "responder/common/responder.h" + #include "responder/common/cache_req/cache_req.h" ++#include "lib/certmap/sss_certmap.h" + + struct pam_auth_req; + +@@ -49,6 +50,7 @@ struct pam_ctx { + bool cert_auth; + int p11_child_debug_fd; + char *nss_db; ++ struct sss_certmap_ctx *sss_certmap_ctx; + }; + + struct pam_auth_dp_req { +@@ -104,6 +106,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + const char *nss_db, + time_t timeout, + const char *verify_opts, ++ struct sss_certmap_ctx *sss_certmap_ctx, + struct pam_data *pd); + errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + struct cert_auth_info **cert_list); +@@ -114,6 +117,9 @@ errno_t add_pam_cert_response(struct pam_data *pd, const char *sysdb_username, + + bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd); + ++errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx, ++ struct certmap_info **certmap_list); ++ + errno_t + pam_set_last_online_auth_with_curr_token(struct sss_domain_info *domain, + const char *username, +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index caf6c99489b8378d2e850473191223709920cd79..0e76c9e772f1775635677f35b870e9613b2faf64 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -1336,7 +1336,8 @@ static errno_t check_cert(TALLOC_CTX *mctx, + + req = pam_check_cert_send(mctx, ev, pctx->p11_child_debug_fd, + pctx->nss_db, p11_child_timeout, +- cert_verification_opts, pd); ++ cert_verification_opts, pctx->sss_certmap_ctx, ++ pd); + if (req == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "pam_check_cert_send failed.\n"); + return ENOMEM; +@@ -1749,6 +1750,13 @@ static void pam_forwarder_cb(struct tevent_req *req) + goto done; + } + ++ ret = p11_refresh_certmap_ctx(pctx, pctx->rctx->domains->certmaps); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "p11_refresh_certmap_ctx failed, " ++ "certificate matching might not work as expected"); ++ } ++ + pd = preq->pd; + + ret = pam_forwarder_parse_data(cctx, pd); +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index 5a3eeff0ec977829a9ad8c80b4fc6b2e06857097..ec52c5ae7163d41144fe082643a201b766a1e201 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -36,6 +36,7 @@ + + #define P11_CHILD_LOG_FILE "p11_child" + #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child" ++#define CERT_AUTH_DEFAULT_MATCHING_RULE "KRB5:clientAuth" + + struct cert_auth_info { + char *cert; +@@ -116,8 +117,110 @@ void sss_cai_check_users(struct cert_auth_info **list, size_t *_cert_count, + return; + } + ++struct priv_sss_debug { ++ int level; ++}; ++ ++static void ext_debug(void *private, const char *file, long line, ++ const char *function, const char *format, ...) ++{ ++ va_list ap; ++ struct priv_sss_debug *data = private; ++ int level = SSSDBG_OP_FAILURE; ++ ++ if (data != NULL) { ++ level = data->level; ++ } ++ ++ if (DEBUG_IS_SET(level)) { ++ va_start(ap, format); ++ sss_vdebug_fn(file, line, function, level, APPEND_LINE_FEED, ++ format, ap); ++ va_end(ap); ++ } ++} ++ ++errno_t p11_refresh_certmap_ctx(struct pam_ctx *pctx, ++ struct certmap_info **certmap_list) ++{ ++ int ret; ++ struct sss_certmap_ctx *sss_certmap_ctx = NULL; ++ size_t c; ++ ++ ret = sss_certmap_init(pctx, ext_debug, NULL, &sss_certmap_ctx); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_certmap_init failed.\n"); ++ goto done; ++ } ++ ++ if (certmap_list == NULL || *certmap_list == NULL) { ++ /* Try to add default matching rule */ ++ ret = sss_certmap_add_rule(sss_certmap_ctx, SSS_CERTMAP_MIN_PRIO, ++ CERT_AUTH_DEFAULT_MATCHING_RULE, NULL, NULL); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Failed to add default matching rule.\n"); ++ } ++ ++ goto done; ++ } ++ ++ for (c = 0; certmap_list[c] != NULL; c++) { ++ DEBUG(SSSDBG_TRACE_ALL, ++ "Trying to add rule [%s][%d][%s][%s].\n", ++ certmap_list[c]->name, certmap_list[c]->priority, ++ certmap_list[c]->match_rule, certmap_list[c]->map_rule); ++ ++ ret = sss_certmap_add_rule(sss_certmap_ctx, certmap_list[c]->priority, ++ certmap_list[c]->match_rule, ++ certmap_list[c]->map_rule, ++ certmap_list[c]->domains); ++ if (ret != 0) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "sss_certmap_add_rule failed for rule [%s] " ++ "with error [%d][%s], skipping. " ++ "Please check for typos and if rule syntax is supported.\n", ++ certmap_list[c]->name, ret, sss_strerror(ret)); ++ continue; ++ } ++ } ++ ++ ret = EOK; ++ ++done: ++ if (ret == EOK) { ++ sss_certmap_free_ctx(pctx->sss_certmap_ctx); ++ pctx->sss_certmap_ctx = sss_certmap_ctx; ++ } else { ++ sss_certmap_free_ctx(sss_certmap_ctx); ++ } ++ ++ return ret; ++} ++ + errno_t p11_child_init(struct pam_ctx *pctx) + { ++ int ret; ++ struct certmap_info **certmaps; ++ bool user_name_hint; ++ struct sss_domain_info *dom = pctx->rctx->domains; ++ ++ ret = sysdb_get_certmap(dom, dom->sysdb, &certmaps, &user_name_hint); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "sysdb_get_certmap failed.\n"); ++ return ret; ++ } ++ ++ dom->user_name_hint = user_name_hint; ++ talloc_free(dom->certmaps); ++ dom->certmaps = certmaps; ++ ++ ret = p11_refresh_certmap_ctx(pctx, dom->certmaps); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "p11_refresh_certmap_ctx failed.\n"); ++ return ret; ++ } ++ + return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd); + } + +@@ -214,6 +317,7 @@ static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx, + + static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + ssize_t buf_len, ++ struct sss_certmap_ctx *sss_certmap_ctx, + struct cert_auth_info **_cert_list) + { + int ret; +@@ -222,6 +326,8 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + uint8_t *pn; + struct cert_auth_info *cert_list = NULL; + struct cert_auth_info *cert_auth_info; ++ unsigned char *der = NULL; ++ size_t der_size; + + if (buf_len < 0) { + DEBUG(SSSDBG_CRIT_FAILURE, +@@ -347,7 +453,22 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + } + DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert_auth_info->cert); + +- DLIST_ADD(cert_list, cert_auth_info); ++ der = sss_base64_decode(tmp_ctx, cert_auth_info->cert, &der_size); ++ if (der == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n"); ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = sss_certmap_match_cert(sss_certmap_ctx, der, der_size); ++ if (ret == 0) { ++ DLIST_ADD(cert_list, cert_auth_info); ++ } else { ++ DEBUG(SSSDBG_TRACE_LIBS, ++ "Cert [%s] does not match matching rules and is ignored.\n", ++ cert_auth_info->cert); ++ talloc_free(cert_auth_info); ++ } + + p = ++pn; + } while ((pn - buf) < buf_len); +@@ -373,6 +494,7 @@ struct pam_check_cert_state { + struct sss_child_ctx_old *child_ctx; + struct tevent_timer *timeout_handler; + struct tevent_context *ev; ++ struct sss_certmap_ctx *sss_certmap_ctx; + + struct child_io_fds *io; + +@@ -391,6 +513,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + const char *nss_db, + time_t timeout, + const char *verify_opts, ++ struct sss_certmap_ctx *sss_certmap_ctx, + struct pam_data *pd) + { + errno_t ret; +@@ -420,6 +543,12 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + goto done; + } + ++ if (sss_certmap_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Missing certificate matching context.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ + /* extra_args are added in revers order */ + arg_c = 0; + extra_args[arg_c++] = nss_db; +@@ -476,6 +605,7 @@ struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx, + } + + state->ev = ev; ++ state->sss_certmap_ctx = sss_certmap_ctx; + state->child_status = EFAULT; + state->io = talloc(state, struct child_io_fds); + if (state->io == NULL) { +@@ -639,7 +769,8 @@ static void p11_child_done(struct tevent_req *subreq) + + PIPE_FD_CLOSE(state->io->read_from_child_fd); + +- ret = parse_p11_child_response(state, buf, buf_len, &state->cert_list); ++ ret = parse_p11_child_response(state, buf, buf_len, state->sss_certmap_ctx, ++ &state->cert_list); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_response failed.\n"); + tevent_req_error(req, ret); +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index f5ba131357b536adac4b3466ebbc257a838d1420..f86719f4fb154524fc9620aa8cb583690ca597f3 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -287,6 +287,9 @@ struct pam_ctx *mock_pctx(TALLOC_CTX *mem_ctx) + return NULL; + } + ++ ret = p11_refresh_certmap_ctx(pctx, NULL); ++ assert_int_equal(ret, 0); ++ + return pctx; + } + +-- +2.15.1 + diff --git a/0050-PAM-add-certificate-s-label-to-the-selection-prompt.patch b/0050-PAM-add-certificate-s-label-to-the-selection-prompt.patch new file mode 100644 index 0000000..d8921ed --- /dev/null +++ b/0050-PAM-add-certificate-s-label-to-the-selection-prompt.patch @@ -0,0 +1,273 @@ +From a89494e7c173bb82344099dd84c59cb3b7214484 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 7 Nov 2017 09:52:56 +0100 +Subject: [PATCH 50/79] PAM: add certificate's label to the selection prompt +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Some types of Smartcards contain multiple certificate with the same +subject-DN for different usages. To make it easier to choose between +them in case the matching rules allow more than one of them for +authentication the label assigned to the certificate on the Smartcard is +shown in the selection prompt as well. + +Related to https://pagure.io/SSSD/sssd/issue/3560 + +Reviewed-by: Fabiano Fidêncio +Tested-by: Scott Poore +--- + src/p11_child/p11_child_nss.c | 18 ++++++++++++++---- + src/responder/pam/pamsrv.h | 1 + + src/responder/pam/pamsrv_p11.c | 41 +++++++++++++++++++++++++++++++++++++---- + src/tests/cmocka/test_pam_srv.c | 28 ++++++++++++++-------------- + 4 files changed, 66 insertions(+), 22 deletions(-) + +diff --git a/src/p11_child/p11_child_nss.c b/src/p11_child/p11_child_nss.c +index e59aba0d1561f58206252f7251ecd88315836b1b..21c508eb1b1b68b3606d0a5eed36573b01f27a19 100644 +--- a/src/p11_child/p11_child_nss.c ++++ b/src/p11_child/p11_child_nss.c +@@ -130,7 +130,7 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + CERTCertificate *found_cert = NULL; + PK11SlotList *list = NULL; + PK11SlotListElement *le; +- SECItem *key_id = NULL; ++ const char *label; + char *key_id_str = NULL; + CERTCertList *valid_certs = NULL; + char *cert_b64 = NULL; +@@ -505,6 +505,17 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + goto done; + } + ++ /* The NSS nickname is typically token_name:label, so the label starts ++ * after the ':'. */ ++ if (found_cert->nickname != NULL) { ++ if ((label = strchr(found_cert->nickname, ':')) == NULL) { ++ label = found_cert->nickname; ++ } else { ++ label++; ++ } ++ } else { ++ label = "- no label found -"; ++ } + talloc_free(cert_b64); + cert_b64 = sss_base64_encode(mem_ctx, found_cert->derCert.data, + found_cert->derCert.len); +@@ -517,9 +528,9 @@ int do_work(TALLOC_CTX *mem_ctx, const char *nss_db, + DEBUG(SSSDBG_TRACE_ALL, "Found certificate has key id [%s].\n", + key_id_str); + +- multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n", ++ multi = talloc_asprintf_append(multi, "%s\n%s\n%s\n%s\n%s\n", + token_name, module_name, key_id_str, +- cert_b64); ++ label, cert_b64); + } + *_multi = multi; + +@@ -546,7 +557,6 @@ done: + CERT_DestroyCertList(cert_list); + } + +- SECITEM_FreeItem(key_id, PR_TRUE); + PORT_Free(key_id_str); + + PORT_Free(signed_random_value.data); +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 0bc229212844602ed461d1c7db48bf51ac2e2194..dfd982178446d6327e09afc652018886c08fd88a 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -93,6 +93,7 @@ const char *sss_cai_get_cert(struct cert_auth_info *i); + const char *sss_cai_get_token_name(struct cert_auth_info *i); + const char *sss_cai_get_module_name(struct cert_auth_info *i); + const char *sss_cai_get_key_id(struct cert_auth_info *i); ++const char *sss_cai_get_label(struct cert_auth_info *i); + struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i); + struct ldb_result *sss_cai_get_cert_user_objs(struct cert_auth_info *i); + void sss_cai_set_cert_user_objs(struct cert_auth_info *i, +diff --git a/src/responder/pam/pamsrv_p11.c b/src/responder/pam/pamsrv_p11.c +index ec52c5ae7163d41144fe082643a201b766a1e201..fa2435543ea305f7cdb1e18753525beb373eaf4c 100644 +--- a/src/responder/pam/pamsrv_p11.c ++++ b/src/responder/pam/pamsrv_p11.c +@@ -43,6 +43,7 @@ struct cert_auth_info { + char *token_name; + char *module_name; + char *key_id; ++ char *label; + struct ldb_result *cert_user_objs; + struct cert_auth_info *prev; + struct cert_auth_info *next; +@@ -68,6 +69,11 @@ const char *sss_cai_get_key_id(struct cert_auth_info *i) + return i != NULL ? i->key_id : NULL; + } + ++const char *sss_cai_get_label(struct cert_auth_info *i) ++{ ++ return i != NULL ? i->label : NULL; ++} ++ + struct cert_auth_info *sss_cai_get_next(struct cert_auth_info *i) + { + return i != NULL ? i->next : NULL; +@@ -438,6 +444,31 @@ static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, + goto done; + } + ++ if (pn == p) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing label in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ cert_auth_info->label = talloc_strndup(cert_auth_info, (char *) p, ++ (pn - p)); ++ if (cert_auth_info->label == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ DEBUG(SSSDBG_TRACE_ALL, "Found label [%s].\n", cert_auth_info->label); ++ ++ p = ++pn; ++ pn = memchr(p, '\n', buf_len - (p - buf)); ++ if (pn == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Missing new-line in p11_child response.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ + if (pn == p) { + DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n"); + ret = EINVAL; +@@ -816,7 +847,8 @@ errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + return EOK; + } + +-static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert) ++static char *get_cert_prompt(TALLOC_CTX *mem_ctx, ++ struct cert_auth_info *cert_info) + { + int ret; + struct sss_certmap_ctx *ctx = NULL; +@@ -839,7 +871,7 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert) + goto done; + } + +- der = sss_base64_decode(mem_ctx, cert, &der_size); ++ der = sss_base64_decode(mem_ctx, sss_cai_get_cert(cert_info), &der_size); + if (der == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "sss_base64_decode failed.\n"); + goto done; +@@ -851,7 +883,8 @@ static char *get_cert_prompt(TALLOC_CTX *mem_ctx, const char *cert) + goto done; + } + +- prompt = talloc_strdup(mem_ctx, filter); ++ prompt = talloc_asprintf(mem_ctx, "%s\n%s", sss_cai_get_label(cert_info), ++ filter); + if (prompt == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); + } +@@ -885,7 +918,7 @@ static errno_t pack_cert_data(TALLOC_CTX *mem_ctx, const char *sysdb_username, + username = sysdb_username; + } + +- prompt = get_cert_prompt(mem_ctx, sss_cai_get_cert(cert_info)); ++ prompt = get_cert_prompt(mem_ctx, cert_info); + if (prompt == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "get_cert_prompt failed.\n"); + return EIO; +diff --git a/src/tests/cmocka/test_pam_srv.c b/src/tests/cmocka/test_pam_srv.c +index f86719f4fb154524fc9620aa8cb583690ca597f3..d7b47507b75044793996bc5156163616a55e05f6 100644 +--- a/src/tests/cmocka/test_pam_srv.c ++++ b/src/tests/cmocka/test_pam_srv.c +@@ -53,7 +53,7 @@ + #define TEST_TOKEN_NAME "SSSD Test Token" + #define TEST_MODULE_NAME "NSS-Internal" + #define TEST_KEY_ID "A5EF7DEE625CA5996C8D1BA7D036708161FD49E7" +-#define TEST_SUBJECT_DN "CN=ipa-devel.ipa.devel,O=IPA.DEVEL" ++#define TEST_PROMPT "Server-Cert\nCN=ipa-devel.ipa.devel,O=IPA.DEVEL" + #define TEST_TOKEN_CERT \ + "MIIECTCCAvGgAwIBAgIBCTANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ + "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ +@@ -79,7 +79,7 @@ + "XyQBwOYRORlnfGyu+Yc9c3E0Wx8Tlznz0lqPR9g=" + + #define TEST2_KEY_ID "C8D60E009EB195D01A7083EE1D5419251AA87C2C" +-#define TEST2_SUBJECT_DN "CN=IPA RA,O=IPA.DEVEL" ++#define TEST2_PROMPT "ipaCert\nCN=IPA RA,O=IPA.DEVEL" + #define TEST_TOKEN_2ND_CERT \ + "MIIDazCCAlOgAwIBAgIBBzANBgkqhkiG9w0BAQsFADA0MRIwEAYDVQQKDAlJUEEu" \ + "REVWRUwxHjAcBgNVBAMMFUNlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNjA1MjMx" \ +@@ -837,7 +837,7 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) + + sizeof(TEST_KEY_ID) +- + sizeof(TEST_SUBJECT_DN))); ++ + sizeof(TEST_PROMPT))); + + assert_int_equal(*(body + rp + sizeof("pamuser@"TEST_DOM_NAME) - 1), 0); + assert_string_equal(body + rp, "pamuser@"TEST_DOM_NAME); +@@ -855,9 +855,9 @@ static int test_pam_cert_check_gdm_smartcard(uint32_t status, uint8_t *body, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + +- assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); +- assert_string_equal(body + rp, TEST_SUBJECT_DN); +- rp += sizeof(TEST_SUBJECT_DN); ++ assert_int_equal(*(body + rp + sizeof(TEST_PROMPT) - 1), 0); ++ assert_string_equal(body + rp, TEST_PROMPT); ++ rp += sizeof(TEST_PROMPT); + + assert_int_equal(rp, blen); + return EOK; +@@ -904,7 +904,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) + + sizeof(TEST_KEY_ID) +- + sizeof(TEST_SUBJECT_DN))); ++ + sizeof(TEST_PROMPT))); + + assert_int_equal(*(body + rp + strlen(name)), 0); + assert_string_equal(body + rp, name); +@@ -922,9 +922,9 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_string_equal(body + rp, TEST_KEY_ID); + rp += sizeof(TEST_KEY_ID); + +- assert_int_equal(*(body + rp + sizeof(TEST_SUBJECT_DN) - 1), 0); +- assert_string_equal(body + rp, TEST_SUBJECT_DN); +- rp += sizeof(TEST_SUBJECT_DN); ++ assert_int_equal(*(body + rp + sizeof(TEST_PROMPT) - 1), 0); ++ assert_string_equal(body + rp, TEST_PROMPT); ++ rp += sizeof(TEST_PROMPT); + + if (name2 != NULL && *name2 != '\0') { + SAFEALIGN_COPY_UINT32(&val, body + rp, &rp); +@@ -935,7 +935,7 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + + sizeof(TEST_TOKEN_NAME) + + sizeof(TEST_MODULE_NAME) + + sizeof(TEST2_KEY_ID) +- + sizeof(TEST2_SUBJECT_DN))); ++ + sizeof(TEST2_PROMPT))); + + assert_int_equal(*(body + rp + strlen(name)), 0); + assert_string_equal(body + rp, name); +@@ -953,9 +953,9 @@ static int test_pam_cert_check_ex(uint32_t status, uint8_t *body, size_t blen, + assert_string_equal(body + rp, TEST2_KEY_ID); + rp += sizeof(TEST2_KEY_ID); + +- assert_int_equal(*(body + rp + sizeof(TEST2_SUBJECT_DN) - 1), 0); +- assert_string_equal(body + rp, TEST2_SUBJECT_DN); +- rp += sizeof(TEST2_SUBJECT_DN); ++ assert_int_equal(*(body + rp + sizeof(TEST2_PROMPT) - 1), 0); ++ assert_string_equal(body + rp, TEST2_PROMPT); ++ rp += sizeof(TEST2_PROMPT); + } + + assert_int_equal(rp, blen); +-- +2.15.1 + diff --git a/0051-SYSDB-Remove-code-causing-a-covscan-warning.patch b/0051-SYSDB-Remove-code-causing-a-covscan-warning.patch new file mode 100644 index 0000000..678db0d --- /dev/null +++ b/0051-SYSDB-Remove-code-causing-a-covscan-warning.patch @@ -0,0 +1,127 @@ +From 38bc29c3475421d9e9ce62810739b6b8b10ad7c6 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Mon, 13 Nov 2017 08:29:53 +0100 +Subject: [PATCH 51/79] SYSDB: Remove code causing a covscan warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There's no reason to check for both ret != EOK and sanitized == NULL, as +the second should never ever happen. + +This check is causing a clang warning in our code: + + Defect type: CLANG_WARNING + 1. sssd-1.16.0/src/db/sysdb_ops.c:4223:9: warning: Dereference of undefined pointer value + # if (res->count > 1) { + # ^~~~~~~~~~ + 4. sssd-1.16.0/src/db/sysdb_ops.c:4199:5: note: 'res' declared without an initial value + # struct ldb_result *res; + # ^~~~~~~~~~~~~~~~~~~~~~ + 7. sssd-1.16.0/src/db/sysdb_ops.c:4202:9: note: Assuming 'sid_str' is non-null + # if (!sid_str) return EINVAL; + # ^~~~~~~~ + 10. sssd-1.16.0/src/db/sysdb_ops.c:4202:5: note: Taking false branch + # if (!sid_str) return EINVAL; + # ^ + 13. sssd-1.16.0/src/db/sysdb_ops.c:4205:9: note: Assuming 'tmp_ctx' is non-null + # if (!tmp_ctx) { + # ^~~~~~~~ + 16. sssd-1.16.0/src/db/sysdb_ops.c:4205:5: note: Taking false branch + # if (!tmp_ctx) { + # ^ + 19. sssd-1.16.0/src/db/sysdb_ops.c:4209:11: note: Calling 'sysdb_search_object_by_sid' + # ret = sysdb_search_object_by_sid(tmp_ctx, domain, sid_str, NULL, &res); + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 22. sssd-1.16.0/src/db/sysdb_ops.c:4960:12: note: Calling 'sysdb_search_object_by_str_attr' + # return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER, + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 25. sssd-1.16.0/src/db/sysdb_ops.c:4872:5: note: Taking false branch + # if (str == NULL) { + # ^ + 28. sssd-1.16.0/src/db/sysdb_ops.c:4877:9: note: Assuming 'ret' is equal to 0 + # if (ret != EOK || sanitized == NULL) { + # ^~~~~~~~~~ + 31. sssd-1.16.0/src/db/sysdb_ops.c:4877:9: note: Left side of '||' is false + 32. sssd-1.16.0/src/db/sysdb_ops.c:4877:23: note: Assuming 'sanitized' is equal to null + # if (ret != EOK || sanitized == NULL) { + # ^~~~~~~~~~~~~~~~~ + 35. sssd-1.16.0/src/db/sysdb_ops.c:4877:5: note: Taking true branch + # if (ret != EOK || sanitized == NULL) { + # ^ + 38. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Left side of '||' is false + # DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n"); + # ^ + 41. sssd-1.16.0/src/util/debug.h:123:9: note: expanded from macro 'DEBUG' + # if (DEBUG_IS_SET(__debug_macro_level)) { \ + # ^ + 44. sssd-1.16.0/src/util/debug.h:135:30: note: expanded from macro 'DEBUG_IS_SET' + # #define DEBUG_IS_SET(level) (debug_level & (level) || \ + # ^ + 47. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Assuming 'debug_level' is not equal to 0 + # DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n"); + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 50. sssd-1.16.0/src/util/debug.h:123:9: note: expanded from macro 'DEBUG' + # if (DEBUG_IS_SET(__debug_macro_level)) { \ + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 53. sssd-1.16.0/src/util/debug.h:136:30: note: expanded from macro 'DEBUG_IS_SET' + # (debug_level == SSSDBG_UNRESOLVED && \ + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 56. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Left side of '&&' is false + 57. sssd-1.16.0/src/util/debug.h:123:9: note: expanded from macro 'DEBUG' + # if (DEBUG_IS_SET(__debug_macro_level)) { \ + # ^ + 60. sssd-1.16.0/src/util/debug.h:136:63: note: expanded from macro 'DEBUG_IS_SET' + # (debug_level == SSSDBG_UNRESOLVED && \ + # ^ + 63. sssd-1.16.0/src/db/sysdb_ops.c:4878:9: note: Loop condition is false. Exiting loop + 64. sssd-1.16.0/src/util/debug.h:121:35: note: expanded from macro 'DEBUG' + # #define DEBUG(level, format, ...) do { \ + # ^ + 67. sssd-1.16.0/src/db/sysdb_ops.c:4879:9: note: Control jumps to line 4892 + # goto done; + # ^ + 70. sssd-1.16.0/src/db/sysdb_ops.c:4960:12: note: Returning from 'sysdb_search_object_by_str_attr' + # return sysdb_search_object_by_str_attr(mem_ctx, domain, SYSDB_SID_FILTER, + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 73. sssd-1.16.0/src/db/sysdb_ops.c:4209:11: note: Returning from 'sysdb_search_object_by_sid' + # ret = sysdb_search_object_by_sid(tmp_ctx, domain, sid_str, NULL, &res); + # ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 76. sssd-1.16.0/src/db/sysdb_ops.c:4211:5: note: Taking false branch + # if (ret == ENOENT) { + # ^ + 79. sssd-1.16.0/src/db/sysdb_ops.c:4217:12: note: Taking false branch + # } else if (ret != EOK) { + # ^ + 82. sssd-1.16.0/src/db/sysdb_ops.c:4223:9: note: Dereference of undefined pointer value + # if (res->count > 1) { + # ^~~~~~~~~~ + # 4221| } + # 4222| + # 4223|-> if (res->count > 1) { + # 4224| DEBUG(SSSDBG_FATAL_FAILURE, "getbysid call returned more than one " \ + # 4225| "result !?!\n"); + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +--- + src/db/sysdb_ops.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 2f8e36c6c9a2c2cefe4af5fb78957763304d989a..635c7db51f516e2217c93016409499e49289004c 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -4874,7 +4874,7 @@ static errno_t sysdb_search_object_by_str_attr(TALLOC_CTX *mem_ctx, + } + + ret = sss_filter_sanitize(NULL, str, &sanitized); +- if (ret != EOK || sanitized == NULL) { ++ if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_filter_sanitize failed.\n"); + goto done; + } +-- +2.15.1 + diff --git a/0052-SYSDB-Better-debugging-for-email-conflicts.patch b/0052-SYSDB-Better-debugging-for-email-conflicts.patch new file mode 100644 index 0000000..2a6fcda --- /dev/null +++ b/0052-SYSDB-Better-debugging-for-email-conflicts.patch @@ -0,0 +1,93 @@ +From e728796cde9a95fd4186ad2c30faadc62497472e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20=C5=BDidek?= +Date: Thu, 26 Oct 2017 18:38:42 +0200 +Subject: [PATCH 52/79] SYSDB: Better debugging for email conflicts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add DEBUG message when conflicts in FQ names or emails +are detected. + +Also improve man page to hint on how to work around issue +with conflicting emails. + +Note: We store emails in two different attributes in sysdb: +- SYSDB_USER_EMAIL +- SYSDB_NAME_ALIAS - this one is lowercased and used in getpwnam + searches. + +Resolves: +https://fedorahosted.org/sssd/ticket/3293 + +Reviewed-by: Fabiano Fidêncio +--- + src/db/sysdb_ops.c | 4 +++- + src/db/sysdb_search.c | 15 +++++++++++++++ + src/man/sssd-ldap.5.xml | 9 +++++++++ + 3 files changed, 27 insertions(+), 1 deletion(-) + +diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c +index 635c7db51f516e2217c93016409499e49289004c..1539c41c93e7d6ebd1e544abbb1707df5578cd72 100644 +--- a/src/db/sysdb_ops.c ++++ b/src/db/sysdb_ops.c +@@ -640,7 +640,9 @@ int sysdb_search_user_by_upn_res(TALLOC_CTX *mem_ctx, + goto done; + } else if (res->count > 1) { + DEBUG(SSSDBG_OP_FAILURE, +- "Search for upn [%s] returns more than one result.\n", upn); ++ "Search for upn [%s] returns more than one result. One of the " ++ "possible reasons can be that several users share the same " ++ "email address.\n", upn); + ret = EINVAL; + goto done; + } +diff --git a/src/db/sysdb_search.c b/src/db/sysdb_search.c +index f488442afcc6eef114437a7110722759f86fe19e..8083966900429b268a3b984f1cad3d47d1099198 100644 +--- a/src/db/sysdb_search.c ++++ b/src/db/sysdb_search.c +@@ -218,6 +218,21 @@ int sysdb_getpwnam(TALLOC_CTX *mem_ctx, + goto done; + } + ++ if (res->count > 1) { ++ /* We expected either 0 or 1 result for search with ++ * SYSDB_PWNAM_FILTER, but we got more. This error ++ * is handled individually depending on what function ++ * called sysdb_getpwnam, so we just print a message ++ * here and let the caller decide what error code to ++ * propagate based on res->count > 1. */ ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Search for [%s] returned multiple results. It can be an email " ++ "address shared among multiple users or an email address of a " ++ "user that conflicts with another user's fully qualified name. " ++ "SSSD will not be able to handle those users properly.\n", ++ sanitized_name); ++ } ++ + /* Merge in the timestamps from the fast ts db */ + ret = sysdb_merge_res_ts_attrs(domain->sysdb, res, attrs); + if (ret != EOK) { +diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml +index d38bac3607d294c53ea692130a6b93ced9b0ab82..de596f0da62be9eb61b880b6e1d4a0f33689e25a 100644 +--- a/src/man/sssd-ldap.5.xml ++++ b/src/man/sssd-ldap.5.xml +@@ -877,6 +877,15 @@ + Name of the LDAP attribute containing the email + address of the user. + ++ ++ Note: If an email address of a user conflicts with ++ an email address or fully qualified name of another ++ user, then SSSD will not be able to serve those ++ users properly. If for some reason several users ++ need to share the same email address then set ++ this option to a nonexistent attribute name in ++ order to disable user lookup/login by email. ++ + + Default: mail + +-- +2.15.1 + diff --git a/0053-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch b/0053-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch new file mode 100644 index 0000000..cf2b01c --- /dev/null +++ b/0053-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch @@ -0,0 +1,38 @@ +From 22cc09e379710b29520d5bbc6fdf6ad84473cd43 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 6 Nov 2017 17:03:19 +0100 +Subject: [PATCH 53/79] NSS: Use enum_ctx as memory_context in + _setnetgrent_set_timeout() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We've noticed some crashes that happened because enum_ctx is already +freed, but the timeout handler is still called. In order to avoid that, +let's remove the timeout handler when enum_ctx is freed at other places. + +Resolves: https://pagure.io/SSSD/sssd/issue/3523 + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Pavel Březina +--- + src/responder/nss/nss_enum.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/responder/nss/nss_enum.c b/src/responder/nss/nss_enum.c +index aa7d8428f37e943a6b5904495c40ad4b8011b767..da844fbced529f606a3e98669fb7b95e0696ce00 100644 +--- a/src/responder/nss/nss_enum.c ++++ b/src/responder/nss/nss_enum.c +@@ -283,7 +283,7 @@ nss_setnetgrent_set_timeout(struct tevent_context *ev, + timeout = enum_ctx->result[0]->domain->netgroup_timeout; + + tv = tevent_timeval_current_ofs(timeout, 0); +- te = tevent_add_timer(ev, nss_ctx, tv, nss_setnetgrent_timeout, enum_ctx); ++ te = tevent_add_timer(ev, enum_ctx, tv, nss_setnetgrent_timeout, enum_ctx); + if (te == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not set up life timer for enumeration object.\n"); +-- +2.15.1 + diff --git a/0054-cache_req-Correction-of-cache_req-debug-string-ID-fo.patch b/0054-cache_req-Correction-of-cache_req-debug-string-ID-fo.patch new file mode 100644 index 0000000..25b7305 --- /dev/null +++ b/0054-cache_req-Correction-of-cache_req-debug-string-ID-fo.patch @@ -0,0 +1,67 @@ +From 5fb2959852b53c6015cbf1cea653365708b379e9 Mon Sep 17 00:00:00 2001 +From: amitkuma +Date: Tue, 14 Nov 2017 13:59:12 +0530 +Subject: [PATCH 54/79] cache_req: Correction of cache_req debug string ID + format +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The cache-req debug string representation uses a wrong format +specifier for by-ID requests. +data->id (uint32_t) should be replaced with %"PRIu32" +in cache_req_group_by_id.c, cache_req_object_by_id.c & +cache_req_user_by_id.c. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3570 + +Reviewed-by: Lukáš Slebodník +--- + src/responder/common/cache_req/plugins/cache_req_group_by_id.c | 2 +- + src/responder/common/cache_req/plugins/cache_req_object_by_id.c | 2 +- + src/responder/common/cache_req/plugins/cache_req_user_by_id.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +index 5ca64283a781318bc4e4d6920fff989c3f3919b4..121f95abe86d2466aaea69f0fe68dfb33b1fee9e 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_group_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_group_by_id.c +@@ -31,7 +31,7 @@ cache_req_group_by_id_create_debug_name(TALLOC_CTX *mem_ctx, + struct cache_req_data *data, + struct sss_domain_info *domain) + { +- return talloc_asprintf(mem_ctx, "GID:%d@%s", data->id, domain->name); ++ return talloc_asprintf(mem_ctx, "GID:%"PRIu32"@%s", data->id, domain->name); + } + + static errno_t +diff --git a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +index 339bd4f5fef827acc1aa3c123d041e426d9e4782..4c88e1035b41969703c1c38d740e15516ac0d622 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_object_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_object_by_id.c +@@ -31,7 +31,7 @@ cache_req_object_by_id_create_debug_name(TALLOC_CTX *mem_ctx, + struct cache_req_data *data, + struct sss_domain_info *domain) + { +- return talloc_asprintf(mem_ctx, "ID:%d@%s", data->id, domain->name); ++ return talloc_asprintf(mem_ctx, "ID:%"PRIu32"@%s", data->id, domain->name); + } + + static errno_t +diff --git a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +index 913f9be5bcc2dfd074b52cb3b15fb6948826e831..3c25c7631b3da4a829ab577629334a7ee97980da 100644 +--- a/src/responder/common/cache_req/plugins/cache_req_user_by_id.c ++++ b/src/responder/common/cache_req/plugins/cache_req_user_by_id.c +@@ -31,7 +31,7 @@ cache_req_user_by_id_create_debug_name(TALLOC_CTX *mem_ctx, + struct cache_req_data *data, + struct sss_domain_info *domain) + { +- return talloc_asprintf(mem_ctx, "UID:%d@%s", data->id, domain->name); ++ return talloc_asprintf(mem_ctx, "UID:%"PRIu32"@%s", data->id, domain->name); + } + + static errno_t +-- +2.15.1 + diff --git a/0012-TESTS-Order-list-of-entries-in-some-lists.patch b/0055-TESTS-Order-list-of-entries-in-some-lists.patch similarity index 97% rename from 0012-TESTS-Order-list-of-entries-in-some-lists.patch rename to 0055-TESTS-Order-list-of-entries-in-some-lists.patch index 7011d24..b786019 100644 --- a/0012-TESTS-Order-list-of-entries-in-some-lists.patch +++ b/0055-TESTS-Order-list-of-entries-in-some-lists.patch @@ -1,7 +1,7 @@ -From caae0e53e6091806634943699f4398b6a20273b4 Mon Sep 17 00:00:00 2001 +From 0e73859e68b8dc348c2ee1e00a45646d9ac2c63c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=BDidek?= Date: Mon, 13 Nov 2017 16:15:21 +0100 -Subject: [PATCH] TESTS: Order list of entries in some lists +Subject: [PATCH 55/79] TESTS: Order list of entries in some lists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @@ -167,5 +167,5 @@ index 0378254b4440b29c3182faf2adde8c3db8a4ce97..dd3eb50f9310ff925734dcf51a669d08 "three", TEST_GID_OVERRIDE_BASE + 2); assert_group_attrs(res->msgs[1], test_ctx->domain, "two", -- -2.15.0 +2.15.1 diff --git a/0056-TOOLS-Add-a-new-sssctl-command-access-report.patch b/0056-TOOLS-Add-a-new-sssctl-command-access-report.patch new file mode 100644 index 0000000..4853377 --- /dev/null +++ b/0056-TOOLS-Add-a-new-sssctl-command-access-report.patch @@ -0,0 +1,503 @@ +From f4d860aa678d899fdcbcd8c991c99b3b85c5c8e0 Mon Sep 17 00:00:00 2001 +From: Jakub Hrozek +Date: Mon, 23 Oct 2017 18:08:12 +0200 +Subject: [PATCH 56/79] TOOLS: Add a new sssctl command access-report +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Pavel Březina +Reviewed-by: Fabiano Fidêncio +--- + Makefile.am | 1 + + src/tools/sssctl/sssctl.c | 1 + + src/tools/sssctl/sssctl.h | 5 + + src/tools/sssctl/sssctl_access_report.c | 435 ++++++++++++++++++++++++++++++++ + 4 files changed, 442 insertions(+) + create mode 100644 src/tools/sssctl/sssctl_access_report.c + +diff --git a/Makefile.am b/Makefile.am +index 04e7d59e9fb0fdbdd420573e7d737a9a465b66ea..4c8fe64c3e689c0d411277d58995a4c0fb008dc1 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1752,6 +1752,7 @@ sssctl_SOURCES = \ + src/tools/sssctl/sssctl_sifp.c \ + src/tools/sssctl/sssctl_config.c \ + src/tools/sssctl/sssctl_user_checks.c \ ++ src/tools/sssctl/sssctl_access_report.c \ + $(SSSD_TOOLS_OBJ) \ + $(NULL) + sssctl_LDADD = \ +diff --git a/src/tools/sssctl/sssctl.c b/src/tools/sssctl/sssctl.c +index d9bc897c1a32954bbdd2d4ae2b0a9fb6d2c34752..afaa84bc0b44a0fc91fe8b62c0c1fd36ac4e1e0b 100644 +--- a/src/tools/sssctl/sssctl.c ++++ b/src/tools/sssctl/sssctl.c +@@ -264,6 +264,7 @@ int main(int argc, const char **argv) + SSS_TOOL_COMMAND("domain-list", "List available domains", 0, sssctl_domain_list), + SSS_TOOL_COMMAND("domain-status", "Print information about domain", 0, sssctl_domain_status), + SSS_TOOL_COMMAND("user-checks", "Print information about a user and check authentication", 0, sssctl_user_checks), ++ SSS_TOOL_COMMAND("access-report", "Generate access report for a domain", 0, sssctl_access_report), + SSS_TOOL_DELIMITER("Information about cached content:"), + SSS_TOOL_COMMAND("user-show", "Information about cached user", 0, sssctl_user_show), + SSS_TOOL_COMMAND("group-show", "Information about cached group", 0, sssctl_group_show), +diff --git a/src/tools/sssctl/sssctl.h b/src/tools/sssctl/sssctl.h +index 22ca5d41e2c084e64b58bc5aa066414b002e7e8b..70fc19eff07317c264978a1ecb9159ae3acdfced 100644 +--- a/src/tools/sssctl/sssctl.h ++++ b/src/tools/sssctl/sssctl.h +@@ -133,4 +133,9 @@ errno_t sssctl_config_check(struct sss_cmdline *cmdline, + errno_t sssctl_user_checks(struct sss_cmdline *cmdline, + struct sss_tool_ctx *tool_ctx, + void *pvt); ++ ++errno_t sssctl_access_report(struct sss_cmdline *cmdline, ++ struct sss_tool_ctx *tool_ctx, ++ void *pvt); ++ + #endif /* _SSSCTL_H_ */ +diff --git a/src/tools/sssctl/sssctl_access_report.c b/src/tools/sssctl/sssctl_access_report.c +new file mode 100644 +index 0000000000000000000000000000000000000000..11172329817b4dedaca480ab8a4537149853c330 +--- /dev/null ++++ b/src/tools/sssctl/sssctl_access_report.c +@@ -0,0 +1,435 @@ ++/* ++ Copyright (C) 2017 Red Hat ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as published by ++ the Free Software Foundation; either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with this program. If not, see . ++*/ ++ ++#include ++ ++#include "util/util.h" ++#include "tools/common/sss_tools.h" ++#include "tools/sssctl/sssctl.h" ++ ++/* ++ * We're searching the cache directly.. ++ */ ++#include "providers/ipa/ipa_hbac_private.h" ++#include "providers/ipa/ipa_rules_common.h" ++ ++#ifdef HAVE_SECURITY_PAM_MISC_H ++# include ++#elif defined(HAVE_SECURITY_OPENPAM_H) ++# include ++#endif ++ ++#ifdef HAVE_SECURITY_PAM_MISC_H ++static struct pam_conv conv = { ++ misc_conv, ++ NULL ++}; ++#elif defined(HAVE_SECURITY_OPENPAM_H) ++static struct pam_conv conv = { ++ openpam_ttyconv, ++ NULL ++}; ++#else ++# error "Missing text based pam conversation function" ++#endif ++ ++#ifndef DEFAULT_SERVICE ++#define DEFAULT_SERVICE "system-auth" ++#endif /* DEFAULT_SERVICE */ ++ ++#ifndef DEFAULT_USER ++#define DEFAULT_USER "admin" ++#endif /* DEFAULT_USER */ ++ ++typedef errno_t (*sssctl_dom_access_reporter_fn)(struct sss_tool_ctx *tool_ctx, ++ const char *user, ++ const char *service, ++ struct sss_domain_info *domain); ++ ++static errno_t run_pam_acct(struct sss_tool_ctx *tool_ctx, ++ const char *user, ++ const char *service, ++ struct sss_domain_info *domain) ++{ ++ errno_t ret; ++ pam_handle_t *pamh; ++ ++ ret = pam_start(service, user, &conv, &pamh); ++ if (ret != PAM_SUCCESS) { ++ ERROR("pam_start failed: %s\n", pam_strerror(pamh, ret)); ++ return EIO; ++ } ++ ++ ret = pam_acct_mgmt(pamh, 0); ++ pam_end(pamh, ret); ++ return ret; ++} ++ ++static errno_t get_rdn_value(TALLOC_CTX *mem_ctx, ++ struct sss_domain_info *dom, ++ const char *dn_attr, ++ const char **_rdn_value) ++{ ++ errno_t ret; ++ TALLOC_CTX *tmp_ctx; ++ struct ldb_dn *dn = NULL; ++ const struct ldb_val *rdn_val; ++ const char *rdn_str; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(dom->sysdb), dn_attr); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ rdn_val = ldb_dn_get_rdn_val(dn); ++ if (rdn_val == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "No RDN value?\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ rdn_str = talloc_strndup(tmp_ctx, ++ (const char *)rdn_val->data, ++ rdn_val->length); ++ if (rdn_str == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = EOK; ++ *_rdn_value = talloc_steal(mem_ctx, rdn_str); ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++static errno_t is_member_group(struct sss_domain_info *dom, ++ const char *dn_attr, ++ const char *group_rdn, ++ bool *_is_group) ++{ ++ const char *comp_name; ++ const struct ldb_val *comp_val; ++ TALLOC_CTX *tmp_ctx; ++ bool is_group = false; ++ errno_t ret; ++ struct ldb_dn *dn = NULL; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new(tmp_ctx, sysdb_ctx_get_ldb(dom->sysdb), dn_attr); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ comp_name = ldb_dn_get_component_name(dn, 1); ++ comp_val = ldb_dn_get_component_val(dn, 1); ++ if (strcasecmp("cn", comp_name) == 0 ++ && strncasecmp(group_rdn, ++ (const char *) comp_val->data, ++ comp_val->length) == 0) { ++ is_group = true; ++ } ++ ++ ret = EOK; ++done: ++ *_is_group = is_group; ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++static void print_category(struct sss_domain_info *domain, ++ struct ldb_message *rule_msg, ++ const char *category_attr_name, ++ const char *category_label) ++{ ++ struct ldb_message_element *category_attr; ++ ++ category_attr = ldb_msg_find_element(rule_msg, category_attr_name); ++ if (category_attr == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find %s\n", category_attr_name); ++ return; ++ } ++ ++ if (category_attr->num_values > 0) { ++ PRINT("\t%s: ", category_label); ++ for (unsigned i = 0; i < category_attr->num_values; i++) { ++ PRINT("%s%s", ++ i > 0 ? ", " : "", ++ (const char *) category_attr->values[i].data); ++ } ++ PRINT("\n"); ++ } ++} ++ ++static void print_member_attr(struct sss_domain_info *domain, ++ struct ldb_message *rule_msg, ++ const char *member_attr_name, ++ const char *group_rdn, ++ const char *object_label, ++ const char *group_label) ++{ ++ errno_t ret; ++ TALLOC_CTX *tmp_ctx = NULL; ++ const char **member_names = NULL; ++ size_t name_count = 0; ++ const char **member_group_names = NULL; ++ size_t group_count = 0; ++ struct ldb_message_element *member_attr = NULL; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return; ++ } ++ ++ member_attr = ldb_msg_find_element(rule_msg, member_attr_name); ++ if (member_attr == NULL) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "Cannot find %s\n", member_attr_name); ++ goto done; ++ } ++ ++ member_names = talloc_zero_array(tmp_ctx, ++ const char *, ++ member_attr->num_values + 1); ++ member_group_names = talloc_zero_array(tmp_ctx, ++ const char *, ++ member_attr->num_values + 1); ++ if (member_names == NULL || member_group_names == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "OOM?\n"); ++ goto done; ++ } ++ ++ for (size_t i = 0; i < member_attr->num_values; i++) { ++ bool is_group; ++ const char *rdn_string; ++ const char *dn_attr; ++ ++ dn_attr = (const char *) member_attr->values[i].data; ++ ++ ret = is_member_group(domain, dn_attr, group_rdn, &is_group); ++ if (ret != EOK) { ++ continue; ++ } ++ ++ ret = get_rdn_value(tmp_ctx, domain, dn_attr, &rdn_string); ++ if (ret != EOK) { ++ continue; ++ } ++ ++ if (is_group == false) { ++ member_names[name_count] = talloc_steal(member_names, ++ rdn_string); ++ if (member_names[name_count] == NULL) { ++ goto done; ++ } ++ name_count++; ++ } else { ++ member_group_names[group_count] = talloc_strdup(member_group_names, ++ rdn_string); ++ if (member_group_names[group_count] == NULL) { ++ goto done; ++ } ++ group_count++; ++ } ++ } ++ ++ if (member_names[0] != NULL) { ++ PRINT("\t%s: ", object_label); ++ for (int i = 0; member_names[i]; i++) { ++ PRINT("%s%s", i > 0 ? ", " : "", member_names[i]); ++ } ++ PRINT("\n"); ++ } ++ ++ if (member_group_names[0] != NULL) { ++ PRINT("\t%s: ", group_label); ++ for (int i = 0; member_group_names[i]; i++) { ++ PRINT("%s%s", i > 0 ? ", " : "", member_group_names[i]); ++ } ++ PRINT("\n"); ++ } ++ ++done: ++ talloc_free(tmp_ctx); ++} ++ ++static void print_ipa_hbac_rule(struct sss_domain_info *domain, ++ struct ldb_message *rule_msg) ++{ ++ struct ldb_message_element *el; ++ ++ el = ldb_msg_find_element(rule_msg, IPA_CN); ++ if (el == NULL || el->num_values < 1) { ++ DEBUG(SSSDBG_MINOR_FAILURE, "A rule with no name\n"); ++ return; ++ } ++ ++ PRINT("Rule name: %1$s\n", el->values[0].data); ++ ++ print_member_attr(domain, ++ rule_msg, ++ IPA_MEMBER_USER, ++ "groups", ++ _("Member users"), ++ _("Member groups")); ++ print_category(domain, ++ rule_msg, ++ IPA_USER_CATEGORY, ++ _("User category")); ++ ++ print_member_attr(domain, ++ rule_msg, ++ IPA_MEMBER_SERVICE, ++ "hbacservicegroups", ++ _("Member services"), ++ _("Member service groups")); ++ print_category(domain, ++ rule_msg, ++ IPA_SERVICE_CATEGORY, ++ _("Service category")); ++ ++ PRINT("\n"); ++} ++ ++static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx, ++ const char *user, ++ const char *service, ++ struct sss_domain_info *domain) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ const char *filter = NULL; ++ errno_t ret; ++ const char *attrs[] = { ++ OBJECTCLASS, ++ IPA_CN, ++ IPA_MEMBER_USER, ++ IPA_USER_CATEGORY, ++ IPA_MEMBER_SERVICE, ++ IPA_SERVICE_CATEGORY, ++ IPA_MEMBER_HOST, ++ IPA_HOST_CATEGORY, ++ NULL, ++ }; ++ size_t rule_count; ++ struct ldb_message **msgs = NULL; ++ ++ /* Run the pam account phase to make sure the rules are fetched by SSSD */ ++ ret = run_pam_acct(tool_ctx, user, service, domain); ++ if (ret != PAM_SUCCESS && ret != PAM_PERM_DENIED) { ++ ERROR("Cannot run the PAM account phase, reporting stale rules\n"); ++ /* Non-fatal */ ++ } ++ ++ tmp_ctx = talloc_new(tool_ctx); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ filter = talloc_asprintf(tmp_ctx, "(objectClass=%s)", IPA_HBAC_RULE); ++ if (filter == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = sysdb_search_custom(tmp_ctx, domain, filter, ++ HBAC_RULES_SUBDIR, attrs, ++ &rule_count, &msgs); ++ if (ret != EOK && ret != ENOENT) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Error looking up HBAC rules\n"); ++ goto done; ++ } ++ ++ if (ret == ENOENT) { ++ PRINT("No cached rules. All users will be denied access\n"); ++ ret = EOK; ++ goto done; ++ } ++ ++ PRINT("%1$zu rules cached\n\n", rule_count); ++ ++ for (size_t i = 0; i < rule_count; i++) { ++ print_ipa_hbac_rule(domain, msgs[i]); ++ } ++ ++ ret = EOK; ++done: ++ talloc_zfree(tmp_ctx); ++ return ret; ++} ++ ++sssctl_dom_access_reporter_fn get_report_fn(const char *provider) ++{ ++ if (strcmp(provider, "ipa") == 0) { ++ return sssctl_ipa_access_report; ++ } ++ ++ return NULL; ++} ++ ++errno_t sssctl_access_report(struct sss_cmdline *cmdline, ++ struct sss_tool_ctx *tool_ctx, ++ void *pvt) ++{ ++ errno_t ret; ++ const char *domname = NULL; ++ sssctl_dom_access_reporter_fn reporter; ++ struct sss_domain_info *dom; ++ const char *user = DEFAULT_USER; ++ const char *service = DEFAULT_SERVICE; ++ ++ /* Parse command line. */ ++ struct poptOption options[] = { ++ { "user", 'u', POPT_ARG_STRING, &user, 0, ++ _("PAM user, default: " DEFAULT_USER), NULL }, ++ { "service", 's', POPT_ARG_STRING, &service, 0, ++ _("PAM service, default: " DEFAULT_SERVICE), NULL }, ++ POPT_TABLEEND ++ }; ++ ++ ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL, ++ NULL, NULL, "DOMAIN", _("Specify domain name."), ++ &domname, NULL); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to parse command arguments\n"); ++ return ret; ++ } ++ ++ dom = find_domain_by_name(tool_ctx->domains, domname, true); ++ if (dom == NULL) { ++ ERROR("Cannot find domain %1$s\n", domname); ++ return ERR_DOMAIN_NOT_FOUND; ++ } ++ ++ reporter = get_report_fn(dom->provider); ++ if (reporter == NULL) { ++ ERROR("Access report not implemented for domains of type %1$s\n", ++ dom->provider); ++ return ret; ++ } ++ ++ return reporter(tool_ctx, user, service, dom); ++} +-- +2.15.1 + diff --git a/0057-dp-use-void-to-express-empty-output-argument-list.patch b/0057-dp-use-void-to-express-empty-output-argument-list.patch new file mode 100644 index 0000000..5a000df --- /dev/null +++ b/0057-dp-use-void-to-express-empty-output-argument-list.patch @@ -0,0 +1,49 @@ +From 7130dad936c55ce0d3d895e9f216c3bc9fbd371b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 14:58:05 +0100 +Subject: [PATCH 57/79] dp: use void * to express empty output argument list +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since we cannot use plain void type is function definition. + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +--- + src/providers/data_provider/dp_private.h | 2 +- + src/providers/data_provider/dp_request_reply.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/providers/data_provider/dp_private.h b/src/providers/data_provider/dp_private.h +index 2e71a373fdc8886fccb23bfb8283dc5bc341b1b0..028070f7f1866854c145a148e44c2cb108d2fc58 100644 +--- a/src/providers/data_provider/dp_private.h ++++ b/src/providers/data_provider/dp_private.h +@@ -136,7 +136,7 @@ typedef void (*dp_req_reply_fn)(const char *req_name, + + void dp_req_reply_default(const char *req_name, + struct sbus_request *sbus_req, +- void *data); ++ void **data); + + /* Data provider request table. */ + +diff --git a/src/providers/data_provider/dp_request_reply.c b/src/providers/data_provider/dp_request_reply.c +index 27d9654bad76a099b004846463f035bf2e6d1243..34440fda7f28f0026d63af1af9958dcea3c6aaec 100644 +--- a/src/providers/data_provider/dp_request_reply.c ++++ b/src/providers/data_provider/dp_request_reply.c +@@ -31,7 +31,7 @@ + + void dp_req_reply_default(const char *req_name, + struct sbus_request *sbus_req, +- void *data) ++ void **data) + { + DP_REQ_DEBUG(SSSDBG_TRACE_FUNC, req_name, "Replying with empty message"); + +-- +2.15.1 + diff --git a/0058-dp-add-method-to-refresh-access-control-rules.patch b/0058-dp-add-method-to-refresh-access-control-rules.patch new file mode 100644 index 0000000..2acac86 --- /dev/null +++ b/0058-dp-add-method-to-refresh-access-control-rules.patch @@ -0,0 +1,191 @@ +From 78643d6c3b10c370cbefe0194a6b40f31aebe29b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 14:58:38 +0100 +Subject: [PATCH 58/79] dp: add method to refresh access control rules +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +--- + src/providers/data_provider/dp.h | 2 ++ + src/providers/data_provider/dp_iface.c | 6 ++++++ + src/providers/data_provider/dp_iface.h | 4 ++++ + src/providers/data_provider/dp_iface.xml | 6 ++++++ + src/providers/data_provider/dp_iface_generated.c | 27 ++++++++++++++++++++++++ + src/providers/data_provider/dp_iface_generated.h | 16 ++++++++++++++ + src/providers/data_provider/dp_target_auth.c | 14 ++++++++++++ + 7 files changed, 75 insertions(+) + +diff --git a/src/providers/data_provider/dp.h b/src/providers/data_provider/dp.h +index 9cdbe5b3a56ba159f9a10df6e010e616e4aefcac..aa5b781158c54545b26034602bb25db46b189e87 100644 +--- a/src/providers/data_provider/dp.h ++++ b/src/providers/data_provider/dp.h +@@ -83,6 +83,8 @@ enum dp_methods { + DPM_DOMAINS_HANDLER, + DPM_SESSION_HANDLER, + ++ DPM_REFRESH_ACCESS_RULES, ++ + DP_METHOD_SENTINEL + }; + +diff --git a/src/providers/data_provider/dp_iface.c b/src/providers/data_provider/dp_iface.c +index 4b2b0ddca68be8899f7285b4d881a91444b99362..28d70e686f63a3572ac595f493aa1d59436c563f 100644 +--- a/src/providers/data_provider/dp_iface.c ++++ b/src/providers/data_provider/dp_iface.c +@@ -48,10 +48,16 @@ struct iface_dp_failover iface_dp_failover = { + .ListServers = dp_failover_list_servers + }; + ++struct iface_dp_access_control iface_dp_access_control = { ++ { &iface_dp_access_control_meta, 0 }, ++ .RefreshRules = dp_access_control_refresh_rules_handler ++}; ++ + static struct sbus_iface_map dp_map[] = { + { DP_PATH, &iface_dp.vtable }, + { DP_PATH, &iface_dp_backend.vtable }, + { DP_PATH, &iface_dp_failover.vtable }, ++ { DP_PATH, &iface_dp_access_control.vtable }, + { NULL, NULL } + }; + +diff --git a/src/providers/data_provider/dp_iface.h b/src/providers/data_provider/dp_iface.h +index 8ae7a2ad7a61f82b000493f3309926cd932211f6..759b9e6c9eb7f53836ae0b641b34e6c31e65779f 100644 +--- a/src/providers/data_provider/dp_iface.h ++++ b/src/providers/data_provider/dp_iface.h +@@ -76,4 +76,8 @@ errno_t dp_failover_list_servers(struct sbus_request *sbus_req, + void *dp_cli, + const char *service_name); + ++/* org.freedesktop.sssd.DataProvider.AccessControl */ ++errno_t dp_access_control_refresh_rules_handler(struct sbus_request *sbus_req, ++ void *dp_cli); ++ + #endif /* DP_IFACE_H_ */ +diff --git a/src/providers/data_provider/dp_iface.xml b/src/providers/data_provider/dp_iface.xml +index a3969873ad1660c71ebdcae7a951757f5254c865..2bfa9dfa7e9d02d2d12c3358967f6969438a97a2 100644 +--- a/src/providers/data_provider/dp_iface.xml ++++ b/src/providers/data_provider/dp_iface.xml +@@ -32,6 +32,12 @@ + + + ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/providers/data_provider/dp_iface_generated.c b/src/providers/data_provider/dp_iface_generated.c +index e2e0216bd98c498b2b34c524ba615b70564420a2..11ee2e24a69cc8d4d19fdbeed613e76081aef15d 100644 +--- a/src/providers/data_provider/dp_iface_generated.c ++++ b/src/providers/data_provider/dp_iface_generated.c +@@ -187,6 +187,33 @@ const struct sbus_interface_meta iface_dp_failover_meta = { + sbus_invoke_get_all, /* GetAll invoker */ + }; + ++int iface_dp_access_control_RefreshRules_finish(struct sbus_request *req) ++{ ++ return sbus_request_return_and_finish(req, ++ DBUS_TYPE_INVALID); ++} ++ ++/* methods for org.freedesktop.sssd.DataProvider.AccessControl */ ++const struct sbus_method_meta iface_dp_access_control__methods[] = { ++ { ++ "RefreshRules", /* name */ ++ NULL, /* no in_args */ ++ NULL, /* no out_args */ ++ offsetof(struct iface_dp_access_control, RefreshRules), ++ NULL, /* no invoker */ ++ }, ++ { NULL, } ++}; ++ ++/* interface info for org.freedesktop.sssd.DataProvider.AccessControl */ ++const struct sbus_interface_meta iface_dp_access_control_meta = { ++ "org.freedesktop.sssd.DataProvider.AccessControl", /* name */ ++ iface_dp_access_control__methods, ++ NULL, /* no signals */ ++ NULL, /* no properties */ ++ sbus_invoke_get_all, /* GetAll invoker */ ++}; ++ + /* arguments for org.freedesktop.sssd.dataprovider.autofsHandler */ + const struct sbus_arg_meta iface_dp_autofsHandler__in[] = { + { "dp_flags", "u" }, +diff --git a/src/providers/data_provider/dp_iface_generated.h b/src/providers/data_provider/dp_iface_generated.h +index b7f63fb438d7b3024a0f66de0a5d15cc3d426f44..541a90b0b5a5bc0a346cbd04974d33c8bb0983c5 100644 +--- a/src/providers/data_provider/dp_iface_generated.h ++++ b/src/providers/data_provider/dp_iface_generated.h +@@ -26,6 +26,10 @@ + #define IFACE_DP_FAILOVER_ACTIVESERVER "ActiveServer" + #define IFACE_DP_FAILOVER_LISTSERVERS "ListServers" + ++/* constants for org.freedesktop.sssd.DataProvider.AccessControl */ ++#define IFACE_DP_ACCESS_CONTROL "org.freedesktop.sssd.DataProvider.AccessControl" ++#define IFACE_DP_ACCESS_CONTROL_REFRESHRULES "RefreshRules" ++ + /* constants for org.freedesktop.sssd.dataprovider */ + #define IFACE_DP "org.freedesktop.sssd.dataprovider" + #define IFACE_DP_PAMHANDLER "pamHandler" +@@ -88,6 +92,15 @@ int iface_dp_failover_ActiveServer_finish(struct sbus_request *req, const char * + /* finish function for ListServers */ + int iface_dp_failover_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers); + ++/* vtable for org.freedesktop.sssd.DataProvider.AccessControl */ ++struct iface_dp_access_control { ++ struct sbus_vtable vtable; /* derive from sbus_vtable */ ++ int (*RefreshRules)(struct sbus_request *req, void *data); ++}; ++ ++/* finish function for RefreshRules */ ++int iface_dp_access_control_RefreshRules_finish(struct sbus_request *req); ++ + /* vtable for org.freedesktop.sssd.dataprovider */ + struct iface_dp { + struct sbus_vtable vtable; /* derive from sbus_vtable */ +@@ -130,6 +143,9 @@ extern const struct sbus_interface_meta iface_dp_backend_meta; + /* interface info for org.freedesktop.sssd.DataProvider.Failover */ + extern const struct sbus_interface_meta iface_dp_failover_meta; + ++/* interface info for org.freedesktop.sssd.DataProvider.AccessControl */ ++extern const struct sbus_interface_meta iface_dp_access_control_meta; ++ + /* interface info for org.freedesktop.sssd.dataprovider */ + extern const struct sbus_interface_meta iface_dp_meta; + +diff --git a/src/providers/data_provider/dp_target_auth.c b/src/providers/data_provider/dp_target_auth.c +index 6bb3313b2de002466e5ca84464c962acd2412bfa..4b47975569a04a4d79aef4c16fcacf92c295de25 100644 +--- a/src/providers/data_provider/dp_target_auth.c ++++ b/src/providers/data_provider/dp_target_auth.c +@@ -306,3 +306,17 @@ void dp_pam_handler_selinux_done(struct tevent_req *req) + dp_pam_reply(state->sbus_req, state->request_name, pd); + return; + } ++ ++errno_t dp_access_control_refresh_rules_handler(struct sbus_request *sbus_req, ++ void *dp_cli) ++{ ++ const char *key; ++ ++ key = "RefreshRules"; ++ ++ dp_req_with_reply(dp_cli, NULL, "Refresh Access Control Rules", key, ++ sbus_req, DPT_ACCESS, DPM_REFRESH_ACCESS_RULES, 0, NULL, ++ dp_req_reply_default, void *); ++ ++ return EOK; ++} +-- +2.15.1 + diff --git a/0059-ipa-implement-method-to-refresh-HBAC-rules.patch b/0059-ipa-implement-method-to-refresh-HBAC-rules.patch new file mode 100644 index 0000000..398f7de --- /dev/null +++ b/0059-ipa-implement-method-to-refresh-HBAC-rules.patch @@ -0,0 +1,139 @@ +From 0b9d469b90b38b864134100de2a999152fe85507 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 14:59:19 +0100 +Subject: [PATCH 59/79] ipa: implement method to refresh HBAC rules +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +--- + src/providers/ipa/ipa_access.c | 68 ++++++++++++++++++++++++++++++++++++++++-- + src/providers/ipa/ipa_access.h | 10 +++++++ + src/providers/ipa/ipa_init.c | 4 +++ + 3 files changed, 80 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c +index 32ccf541c9436b633e7724b2c44ee545810a7fb8..de9f68170b6e9c38fd8b6d23f1d565250bbf78d2 100644 +--- a/src/providers/ipa/ipa_access.c ++++ b/src/providers/ipa/ipa_access.c +@@ -682,8 +682,8 @@ done: + + errno_t + ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx, +- struct tevent_req *req, +- struct pam_data **_data) ++ struct tevent_req *req, ++ struct pam_data **_data) + { + struct ipa_pam_access_handler_state *state = NULL; + +@@ -695,3 +695,67 @@ ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx, + + return EOK; + } ++ ++struct ipa_refresh_access_rules_state { ++ int dummy; ++}; ++ ++static void ipa_refresh_access_rules_done(struct tevent_req *subreq); ++ ++struct tevent_req * ++ipa_refresh_access_rules_send(TALLOC_CTX *mem_ctx, ++ struct ipa_access_ctx *access_ctx, ++ void *no_input_data, ++ struct dp_req_params *params) ++{ ++ struct ipa_refresh_access_rules_state *state; ++ struct tevent_req *subreq; ++ struct tevent_req *req; ++ ++ DEBUG(SSSDBG_TRACE_FUNC, "Refreshing HBAC rules\n"); ++ ++ req = tevent_req_create(mem_ctx, &state, ++ struct ipa_refresh_access_rules_state); ++ if (req == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n"); ++ return NULL; ++ } ++ ++ subreq = ipa_fetch_hbac_send(state, params->ev, params->be_ctx, access_ctx); ++ if (subreq == NULL) { ++ tevent_req_error(req, ENOMEM); ++ tevent_req_post(req, params->ev); ++ return req; ++ } ++ ++ tevent_req_set_callback(subreq, ipa_refresh_access_rules_done, req); ++ ++ return req; ++} ++ ++static void ipa_refresh_access_rules_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req; ++ errno_t ret; ++ ++ req = tevent_req_callback_data(subreq, struct tevent_req); ++ ++ ret = ipa_fetch_hbac_recv(subreq); ++ talloc_zfree(subreq); ++ if (ret != EOK) { ++ tevent_req_error(req, ret); ++ return; ++ } ++ ++ tevent_req_done(req); ++ return; ++} ++ ++errno_t ipa_refresh_access_rules_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ void **_no_output_data) ++{ ++ TEVENT_REQ_RETURN_ON_ERROR(req); ++ ++ return EOK; ++} +diff --git a/src/providers/ipa/ipa_access.h b/src/providers/ipa/ipa_access.h +index de690350218bd47165a2b48c10059b8de96b718a..9cec0d1063fd39380a77093526e3240523752075 100644 +--- a/src/providers/ipa/ipa_access.h ++++ b/src/providers/ipa/ipa_access.h +@@ -63,4 +63,14 @@ ipa_pam_access_handler_recv(TALLOC_CTX *mem_ctx, + struct tevent_req *req, + struct pam_data **_data); + ++struct tevent_req * ++ipa_refresh_access_rules_send(TALLOC_CTX *mem_ctx, ++ struct ipa_access_ctx *access_ctx, ++ void *no_input_data, ++ struct dp_req_params *params); ++ ++errno_t ipa_refresh_access_rules_recv(TALLOC_CTX *mem_ctx, ++ struct tevent_req *req, ++ void **_no_output_data); ++ + #endif /* _IPA_ACCESS_H_ */ +diff --git a/src/providers/ipa/ipa_init.c b/src/providers/ipa/ipa_init.c +index 5b7c8e1348f561901782c872078a0e7391d4ff75..f335d51fd65959d256c54a5d92c594a24e895b7c 100644 +--- a/src/providers/ipa/ipa_init.c ++++ b/src/providers/ipa/ipa_init.c +@@ -831,6 +831,10 @@ errno_t sssm_ipa_access_init(TALLOC_CTX *mem_ctx, + ipa_pam_access_handler_send, ipa_pam_access_handler_recv, access_ctx, + struct ipa_access_ctx, struct pam_data, struct pam_data *); + ++ dp_set_method(dp_methods, DPM_REFRESH_ACCESS_RULES, ++ ipa_refresh_access_rules_send, ipa_refresh_access_rules_recv, access_ctx, ++ struct ipa_access_ctx, void, void *); ++ + ret = EOK; + + done: +-- +2.15.1 + diff --git a/0060-ifp-add-method-to-refresh-access-control-rules-in-do.patch b/0060-ifp-add-method-to-refresh-access-control-rules-in-do.patch new file mode 100644 index 0000000..5f934ca --- /dev/null +++ b/0060-ifp-add-method-to-refresh-access-control-rules-in-do.patch @@ -0,0 +1,157 @@ +From 77ff1aa3fdb0231f649d5bb3e583bf8244ad23ba Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 14:59:57 +0100 +Subject: [PATCH 60/79] ifp: add method to refresh access control rules in + domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Fabiano Fidêncio +Reviewed-by: Jakub Hrozek +--- + src/responder/ifp/ifp_domains.c | 22 ++++++++++++++++++++++ + src/responder/ifp/ifp_domains.h | 3 +++ + src/responder/ifp/ifp_iface.c | 3 ++- + src/responder/ifp/ifp_iface.xml | 3 +++ + src/responder/ifp/ifp_iface_generated.c | 13 +++++++++++++ + src/responder/ifp/ifp_iface_generated.h | 5 +++++ + 6 files changed, 48 insertions(+), 1 deletion(-) + +diff --git a/src/responder/ifp/ifp_domains.c b/src/responder/ifp/ifp_domains.c +index 977bbfcbe818f08873ce072d34fdcf900cabf52f..cd7e2fc7aeff5467514269e5b078b0da88ab4f50 100644 +--- a/src/responder/ifp/ifp_domains.c ++++ b/src/responder/ifp/ifp_domains.c +@@ -630,3 +630,25 @@ int ifp_domains_domain_list_servers(struct sbus_request *sbus_req, + + return EOK; + } ++ ++int ifp_domains_domain_refresh_access_rules(struct sbus_request *sbus_req, ++ void *data) ++{ ++ struct ifp_ctx *ifp_ctx; ++ struct sss_domain_info *dom; ++ ++ ifp_ctx = talloc_get_type(data, struct ifp_ctx); ++ ++ dom = get_domain_info_from_req(sbus_req, data); ++ if (dom == NULL) { ++ sbus_request_reply_error(sbus_req, SBUS_ERROR_UNKNOWN_DOMAIN, ++ "Unknown domain"); ++ return EOK; ++ } ++ ++ rdp_message_send_and_reply(sbus_req, ifp_ctx->rctx, dom, DP_PATH, ++ IFACE_DP_ACCESS_CONTROL, ++ IFACE_DP_ACCESS_CONTROL_REFRESHRULES); ++ ++ return EOK; ++} +diff --git a/src/responder/ifp/ifp_domains.h b/src/responder/ifp/ifp_domains.h +index 621ba6158e285911cb8298cef212219dfd3afec8..d8cc9d34c92cd04b6db432c1fc0e179a717001da 100644 +--- a/src/responder/ifp/ifp_domains.h ++++ b/src/responder/ifp/ifp_domains.h +@@ -108,4 +108,7 @@ int ifp_domains_domain_list_servers(struct sbus_request *sbus_req, + void *data, + const char *service); + ++int ifp_domains_domain_refresh_access_rules(struct sbus_request *sbus_req, ++ void *data); ++ + #endif /* IFP_DOMAINS_H_ */ +diff --git a/src/responder/ifp/ifp_iface.c b/src/responder/ifp/ifp_iface.c +index 3293b92d750d33b2ecf77a03098c5169d052c924..f995e28f99f9489ca17fbc51fa6894d458f9e21f 100644 +--- a/src/responder/ifp/ifp_iface.c ++++ b/src/responder/ifp/ifp_iface.c +@@ -79,7 +79,8 @@ struct iface_ifp_domains_domain iface_ifp_domains_domain = { + .IsOnline = ifp_domains_domain_is_online, + .ListServices = ifp_domains_domain_list_services, + .ActiveServer = ifp_domains_domain_active_server, +- .ListServers = ifp_domains_domain_list_servers ++ .ListServers = ifp_domains_domain_list_servers, ++ .RefreshAccessRules = ifp_domains_domain_refresh_access_rules + }; + + struct iface_ifp_users iface_ifp_users = { +diff --git a/src/responder/ifp/ifp_iface.xml b/src/responder/ifp/ifp_iface.xml +index 39385e866f31131c7860001ae4d6e6b51105aa52..1aa7eac03f0a3dc86f1d25883ac37f2fabf6b9e8 100644 +--- a/src/responder/ifp/ifp_iface.xml ++++ b/src/responder/ifp/ifp_iface.xml +@@ -112,6 +112,9 @@ + + + ++ ++ ++ + + + +diff --git a/src/responder/ifp/ifp_iface_generated.c b/src/responder/ifp/ifp_iface_generated.c +index 6943e38e3b6d2fc9e09ade1a863905c8d81a39ba..c2cdbf5b0ef3d59068aeed7a8f45099c14c4a94a 100644 +--- a/src/responder/ifp/ifp_iface_generated.c ++++ b/src/responder/ifp/ifp_iface_generated.c +@@ -552,6 +552,12 @@ int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const + DBUS_TYPE_INVALID); + } + ++int iface_ifp_domains_domain_RefreshAccessRules_finish(struct sbus_request *req) ++{ ++ return sbus_request_return_and_finish(req, ++ DBUS_TYPE_INVALID); ++} ++ + /* methods for org.freedesktop.sssd.infopipe.Domains.Domain */ + const struct sbus_method_meta iface_ifp_domains_domain__methods[] = { + { +@@ -582,6 +588,13 @@ const struct sbus_method_meta iface_ifp_domains_domain__methods[] = { + offsetof(struct iface_ifp_domains_domain, ListServers), + invoke_s_method, + }, ++ { ++ "RefreshAccessRules", /* name */ ++ NULL, /* no in_args */ ++ NULL, /* no out_args */ ++ offsetof(struct iface_ifp_domains_domain, RefreshAccessRules), ++ NULL, /* no invoker */ ++ }, + { NULL, } + }; + +diff --git a/src/responder/ifp/ifp_iface_generated.h b/src/responder/ifp/ifp_iface_generated.h +index 30752bf063de1f2530c7451f01cc22ad3e863185..f1e6c80bab27d0ed581abc566a178e6857794805 100644 +--- a/src/responder/ifp/ifp_iface_generated.h ++++ b/src/responder/ifp/ifp_iface_generated.h +@@ -57,6 +57,7 @@ + #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVICES "ListServices" + #define IFACE_IFP_DOMAINS_DOMAIN_ACTIVESERVER "ActiveServer" + #define IFACE_IFP_DOMAINS_DOMAIN_LISTSERVERS "ListServers" ++#define IFACE_IFP_DOMAINS_DOMAIN_REFRESHACCESSRULES "RefreshAccessRules" + + /* constants for org.freedesktop.sssd.infopipe.Cache */ + #define IFACE_IFP_CACHE "org.freedesktop.sssd.infopipe.Cache" +@@ -209,6 +210,7 @@ struct iface_ifp_domains_domain { + int (*ListServices)(struct sbus_request *req, void *data); + int (*ActiveServer)(struct sbus_request *req, void *data, const char *arg_service); + int (*ListServers)(struct sbus_request *req, void *data, const char *arg_service_name); ++ int (*RefreshAccessRules)(struct sbus_request *req, void *data); + }; + + /* finish function for IsOnline */ +@@ -223,6 +225,9 @@ int iface_ifp_domains_domain_ActiveServer_finish(struct sbus_request *req, const + /* finish function for ListServers */ + int iface_ifp_domains_domain_ListServers_finish(struct sbus_request *req, const char *arg_servers[], int len_servers); + ++/* finish function for RefreshAccessRules */ ++int iface_ifp_domains_domain_RefreshAccessRules_finish(struct sbus_request *req); ++ + /* vtable for org.freedesktop.sssd.infopipe.Cache */ + struct iface_ifp_cache { + struct sbus_vtable vtable; /* derive from sbus_vtable */ +-- +2.15.1 + diff --git a/0061-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch b/0061-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch new file mode 100644 index 0000000..87fefaf --- /dev/null +++ b/0061-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch @@ -0,0 +1,199 @@ +From a5bf38afa217b8e22fe221977959f78a44f15843 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Pavel=20B=C5=99ezina?= +Date: Thu, 2 Nov 2017 15:00:17 +0100 +Subject: [PATCH 61/79] sssctl: call dbus instead of pam to refresh HBAC rules +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Related: +https://pagure.io/SSSD/sssd/issue/2840 + +Reviewed-by: Jakub Hrozek +Reviewed-by: Fabiano Fidêncio +--- + src/tools/sssctl/sssctl_access_report.c | 127 +++++++++++++++----------------- + 1 file changed, 58 insertions(+), 69 deletions(-) + +diff --git a/src/tools/sssctl/sssctl_access_report.c b/src/tools/sssctl/sssctl_access_report.c +index 11172329817b4dedaca480ab8a4537149853c330..8cf1a8a871b27827c317d658c0f93f34773c4841 100644 +--- a/src/tools/sssctl/sssctl_access_report.c ++++ b/src/tools/sssctl/sssctl_access_report.c +@@ -15,11 +15,11 @@ + along with this program. If not, see . + */ + +-#include +- + #include "util/util.h" + #include "tools/common/sss_tools.h" + #include "tools/sssctl/sssctl.h" ++#include "sbus/sssd_dbus.h" ++#include "responder/ifp/ifp_iface.h" + + /* + * We're searching the cache directly.. +@@ -27,58 +27,9 @@ + #include "providers/ipa/ipa_hbac_private.h" + #include "providers/ipa/ipa_rules_common.h" + +-#ifdef HAVE_SECURITY_PAM_MISC_H +-# include +-#elif defined(HAVE_SECURITY_OPENPAM_H) +-# include +-#endif +- +-#ifdef HAVE_SECURITY_PAM_MISC_H +-static struct pam_conv conv = { +- misc_conv, +- NULL +-}; +-#elif defined(HAVE_SECURITY_OPENPAM_H) +-static struct pam_conv conv = { +- openpam_ttyconv, +- NULL +-}; +-#else +-# error "Missing text based pam conversation function" +-#endif +- +-#ifndef DEFAULT_SERVICE +-#define DEFAULT_SERVICE "system-auth" +-#endif /* DEFAULT_SERVICE */ +- +-#ifndef DEFAULT_USER +-#define DEFAULT_USER "admin" +-#endif /* DEFAULT_USER */ +- + typedef errno_t (*sssctl_dom_access_reporter_fn)(struct sss_tool_ctx *tool_ctx, +- const char *user, +- const char *service, + struct sss_domain_info *domain); + +-static errno_t run_pam_acct(struct sss_tool_ctx *tool_ctx, +- const char *user, +- const char *service, +- struct sss_domain_info *domain) +-{ +- errno_t ret; +- pam_handle_t *pamh; +- +- ret = pam_start(service, user, &conv, &pamh); +- if (ret != PAM_SUCCESS) { +- ERROR("pam_start failed: %s\n", pam_strerror(pamh, ret)); +- return EIO; +- } +- +- ret = pam_acct_mgmt(pamh, 0); +- pam_end(pamh, ret); +- return ret; +-} +- + static errno_t get_rdn_value(TALLOC_CTX *mem_ctx, + struct sss_domain_info *dom, + const char *dn_attr, +@@ -315,9 +266,58 @@ static void print_ipa_hbac_rule(struct sss_domain_info *domain, + PRINT("\n"); + } + ++static errno_t refresh_hbac_rules(struct sss_tool_ctx *tool_ctx, ++ struct sss_domain_info *domain) ++{ ++ TALLOC_CTX *tmp_ctx; ++ sss_sifp_error error; ++ sss_sifp_ctx *sifp; ++ DBusMessage *reply; ++ const char *path; ++ errno_t ret; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n"); ++ return ENOMEM; ++ } ++ ++ path = sbus_opath_compose(tmp_ctx, IFP_PATH_DOMAINS, domain->name); ++ if (path == NULL) { ++ printf(_("Out of memory!\n")); ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ error = sssctl_sifp_init(tool_ctx, &sifp); ++ if (error != SSS_SIFP_OK) { ++ sssctl_sifp_error(sifp, error, "Unable to connect to the InfoPipe"); ++ ret = EIO; ++ goto done; ++ } ++ ++ error = sssctl_sifp_send(tmp_ctx, sifp, &reply, path, ++ IFACE_IFP_DOMAINS_DOMAIN, ++ IFACE_IFP_DOMAINS_DOMAIN_REFRESHACCESSRULES); ++ if (error != SSS_SIFP_OK) { ++ sssctl_sifp_error(sifp, error, "Unable to refresh HBAC rules"); ++ ret = EIO; ++ goto done; ++ } ++ ++ ret = sbus_parse_reply(reply); ++ if (ret != EOK) { ++ goto done; ++ } ++ ++ ret = EOK; ++ ++done: ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx, +- const char *user, +- const char *service, + struct sss_domain_info *domain) + { + TALLOC_CTX *tmp_ctx = NULL; +@@ -338,9 +338,9 @@ static errno_t sssctl_ipa_access_report(struct sss_tool_ctx *tool_ctx, + struct ldb_message **msgs = NULL; + + /* Run the pam account phase to make sure the rules are fetched by SSSD */ +- ret = run_pam_acct(tool_ctx, user, service, domain); +- if (ret != PAM_SUCCESS && ret != PAM_PERM_DENIED) { +- ERROR("Cannot run the PAM account phase, reporting stale rules\n"); ++ ret = refresh_hbac_rules(tool_ctx, domain); ++ if (ret != EOK) { ++ ERROR("Unable to refresh HBAC rules, using cached content\n"); + /* Non-fatal */ + } + +@@ -398,19 +398,8 @@ errno_t sssctl_access_report(struct sss_cmdline *cmdline, + const char *domname = NULL; + sssctl_dom_access_reporter_fn reporter; + struct sss_domain_info *dom; +- const char *user = DEFAULT_USER; +- const char *service = DEFAULT_SERVICE; + +- /* Parse command line. */ +- struct poptOption options[] = { +- { "user", 'u', POPT_ARG_STRING, &user, 0, +- _("PAM user, default: " DEFAULT_USER), NULL }, +- { "service", 's', POPT_ARG_STRING, &service, 0, +- _("PAM service, default: " DEFAULT_SERVICE), NULL }, +- POPT_TABLEEND +- }; +- +- ret = sss_tool_popt_ex(cmdline, options, SSS_TOOL_OPT_OPTIONAL, ++ ret = sss_tool_popt_ex(cmdline, NULL, SSS_TOOL_OPT_OPTIONAL, + NULL, NULL, "DOMAIN", _("Specify domain name."), + &domname, NULL); + if (ret != EOK) { +@@ -431,5 +420,5 @@ errno_t sssctl_access_report(struct sss_cmdline *cmdline, + return ret; + } + +- return reporter(tool_ctx, user, service, dom); ++ return reporter(tool_ctx, dom); + } +-- +2.15.1 + diff --git a/0062-SPEC-Reduce-build-time-dependencies.patch b/0062-SPEC-Reduce-build-time-dependencies.patch new file mode 100644 index 0000000..a6eeb69 --- /dev/null +++ b/0062-SPEC-Reduce-build-time-dependencies.patch @@ -0,0 +1,36 @@ +From cd36d84d4996ac768b13f43e00a7a219ea28bb99 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Thu, 16 Nov 2017 12:11:28 +0100 +Subject: [PATCH 62/79] SPEC: Reduce build time dependencies +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Total download size: 139 M +Installed size: 465 M + +vs + +Total size: 11 k + +Reviewed-by: Fabiano Fidêncio +--- + contrib/sssd.spec.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in +index c716efdce05ab7b9178be66f34d09124c78071b5..d1cd1965f6673be9a756f216dea187c88660e99d 100644 +--- a/contrib/sssd.spec.in ++++ b/contrib/sssd.spec.in +@@ -240,7 +240,7 @@ BuildRequires: jansson-devel + BuildRequires: libcurl-devel + %endif + %if (0%{?with_gdm_pam_extensions} == 1) +-BuildRequires: gdm-devel ++BuildRequires: gdm-pam-extensions-devel + %endif + + %description +-- +2.15.1 + diff --git a/0063-WATCHDOG-Restart-providers-with-SIGUSR2-after-time-d.patch b/0063-WATCHDOG-Restart-providers-with-SIGUSR2-after-time-d.patch new file mode 100644 index 0000000..882388c --- /dev/null +++ b/0063-WATCHDOG-Restart-providers-with-SIGUSR2-after-time-d.patch @@ -0,0 +1,42 @@ +From 97b56f1ec15a3270cc2e85c9b367e4d38f91ae1a Mon Sep 17 00:00:00 2001 +From: Victor Tapia +Date: Mon, 16 Oct 2017 09:45:24 +0200 +Subject: [PATCH 63/79] WATCHDOG: Restart providers with SIGUSR2 after time + drift +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Restarting the providers using the already implemented SIGUSR2 (for +method .resetOffline, used after netlink detects an interface change) +when a time drift is detected, ensures that affected connection retries +(e.g. LDAP) will be rescheduled immediately instead of having to wait +the time shifted to return to its normal execution. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3285 + +Reviewed-by: Lukáš Slebodník +Reviewed-by: Fabiano Fidêncio +--- + src/util/util_watchdog.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/util/util_watchdog.c b/src/util/util_watchdog.c +index 59293db60e4ffbe566f8b17f3f289503e8d9aee6..20a8b896791118c1ae9b5bfe101a539b213497a4 100644 +--- a/src/util/util_watchdog.c ++++ b/src/util/util_watchdog.c +@@ -160,6 +160,10 @@ static void watchdog_fd_read_handler(struct tevent_context *ev, + "[%d]: %s\n", ret, sss_strerror(ret)); + orderly_shutdown(1); + } ++ if (strncmp(debug_prg_name, "sssd[be[", sizeof("sssd[be[") - 1) == 0) { ++ kill(getpid(), SIGUSR2); ++ DEBUG(SSSDBG_IMPORTANT_INFO, "SIGUSR2 sent to %s\n", debug_prg_name); ++ } + } + + int setup_watchdog(struct tevent_context *ev, int interval) +-- +2.15.1 + diff --git a/0064-mmap_cache-make-checks-independent-of-input-size.patch b/0064-mmap_cache-make-checks-independent-of-input-size.patch new file mode 100644 index 0000000..61f443b --- /dev/null +++ b/0064-mmap_cache-make-checks-independent-of-input-size.patch @@ -0,0 +1,168 @@ +From b70b4099b049b6a2bd85e773dbd81974dee24e05 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 17 Nov 2017 10:51:44 +0100 +Subject: [PATCH 64/79] mmap_cache: make checks independent of input size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently the consistency checks for the mmap_cache payload data on the +client and the responder side include the length of the input string of +the current request. Since there might be hash collisions which other +much longer or much shorter names those checks might fail although there +is no data corruption. + +This patch removes the checks using the length of the input and adds a +check if the name found in the payload is zero-terminated inside of the +payload data. + +Resolves https://pagure.io/SSSD/sssd/issue/3571 + +Reviewed-by: Michal Židek +Reviewed-by: Lukáš Slebodník +--- + src/responder/nss/nsssrv_mmap_cache.c | 34 ++++++++++++++++++++++++---------- + src/sss_client/nss_mc_group.c | 12 ++++++------ + src/sss_client/nss_mc_initgr.c | 12 +++++++----- + src/sss_client/nss_mc_passwd.c | 12 ++++++------ + 4 files changed, 43 insertions(+), 27 deletions(-) + +diff --git a/src/responder/nss/nsssrv_mmap_cache.c b/src/responder/nss/nsssrv_mmap_cache.c +index a87ad646f9b741db3eb18680678697032fc420ba..ad5adbce15e50c065d4d16e626be97fd23d06643 100644 +--- a/src/responder/nss/nsssrv_mmap_cache.c ++++ b/src/responder/nss/nsssrv_mmap_cache.c +@@ -547,18 +547,32 @@ static struct sss_mc_rec *sss_mc_find_record(struct sss_mc_ctx *mcc, + return NULL; + } + ++ if (key->len > strs_len) { ++ /* The string cannot be in current record */ ++ slot = sss_mc_next_slot_with_hash(rec, hash); ++ continue; ++ } ++ + safealign_memcpy(&name_ptr, rec->data, sizeof(rel_ptr_t), NULL); +- if (key->len > strs_len +- || (name_ptr + key->len) > (strs_offset + strs_len) +- || (uint8_t *)rec->data + strs_offset + strs_len > max_addr) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "Corrupted fastcache. name_ptr value is %u.\n", name_ptr); +- sss_mc_save_corrupted(mcc); +- sss_mmap_cache_reset(mcc); +- return NULL; +- } +- + t_key = (char *)rec->data + name_ptr; ++ /* name_ptr must point to some data in the strs/gids area of the data ++ * payload. Since it is a pointer relative to rec->data it must larger ++ * equal strs_offset and must be smaller then strs_offset + strs_len. ++ * Additionally the area must not end outside of the data table and ++ * t_key must be a zero-terminates string. */ ++ if (name_ptr < strs_offset ++ || name_ptr >= strs_offset + strs_len ++ || (uint8_t *)rec->data > max_addr ++ || strs_offset > max_addr - (uint8_t *)rec->data ++ || strs_len > max_addr - (uint8_t *)rec->data - strs_offset) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Corrupted fastcache entry at slot %u. " ++ "name_ptr value is %u.\n", slot, name_ptr); ++ sss_mc_save_corrupted(mcc); ++ sss_mmap_cache_reset(mcc); ++ return NULL; ++ } ++ + if (strcmp(key->str, t_key) == 0) { + break; + } +diff --git a/src/sss_client/nss_mc_group.c b/src/sss_client/nss_mc_group.c +index ce88d42fdaf4f19e78fc43e187bc28651cdc3c4e..ba582fe55cf3abf90d8e016c82a0bee48608ce78 100644 +--- a/src/sss_client/nss_mc_group.c ++++ b/src/sss_client/nss_mc_group.c +@@ -148,20 +148,20 @@ errno_t sss_nss_mc_getgrnam(const char *name, size_t name_len, + } + + data = (struct sss_mc_grp_data *)rec->data; ++ rec_name = (char *)data + data->name; + /* Integrity check +- * - name_len cannot be longer than all strings + * - data->name cannot point outside strings + * - all strings must be within copy of record +- * - size of record must be lower that data table size */ +- if (name_len > data->strs_len +- || (data->name + name_len) > (strs_offset + data->strs_len) ++ * - record must not end outside data table ++ * - rec_name is a zero-terminated string */ ++ if (data->name < strs_offset ++ || data->name >= strs_offset + data->strs_len + || data->strs_len > rec->len +- || rec->len > data_size) { ++ || (uint8_t *) rec + rec->len > gr_mc_ctx.data_table + data_size ) { + ret = ENOENT; + goto done; + } + +- rec_name = (char *)data + data->name; + if (strcmp(name, rec_name) == 0) { + break; + } +diff --git a/src/sss_client/nss_mc_initgr.c b/src/sss_client/nss_mc_initgr.c +index a77088d849ad3601cb3edb55fc5ea4ae4c52fe38..606f1c7ee2526a15378831d4512e943bac214d0e 100644 +--- a/src/sss_client/nss_mc_initgr.c ++++ b/src/sss_client/nss_mc_initgr.c +@@ -131,15 +131,17 @@ errno_t sss_nss_mc_initgroups_dyn(const char *name, size_t name_len, + data = (struct sss_mc_initgr_data *)rec->data; + rec_name = (char *)data + data->name; + /* Integrity check +- * - name_len cannot be longer than all strings or data ++ * - data->name cannot point outside all strings or data + * - all data must be within copy of record + * - size of record must be lower that data table size +- * - data->strs cannot point outside strings */ +- if (name_len > data->strs_len ++ * - data->strs cannot point outside strings ++ * - rec_name is a zero-terminated string */ ++ if (data->name < data_offset ++ || data->name >= data_offset + data->data_len + || data->strs_len > data->data_len + || data->data_len > rec->len +- || rec->len > data_size +- || (data->strs + name_len) > (data_offset + data->data_len)) { ++ || (uint8_t *) rec + rec->len ++ > initgr_mc_ctx.data_table + data_size ) { + ret = ENOENT; + goto done; + } +diff --git a/src/sss_client/nss_mc_passwd.c b/src/sss_client/nss_mc_passwd.c +index 0da7ad0aeece7d38ca34bb3fde64adc898eaf0ae..0bc1237446d3691c8c83aa0fc0cf692d4b336f9e 100644 +--- a/src/sss_client/nss_mc_passwd.c ++++ b/src/sss_client/nss_mc_passwd.c +@@ -141,20 +141,20 @@ errno_t sss_nss_mc_getpwnam(const char *name, size_t name_len, + } + + data = (struct sss_mc_pwd_data *)rec->data; ++ rec_name = (char *)data + data->name; + /* Integrity check +- * - name_len cannot be longer than all strings + * - data->name cannot point outside strings + * - all strings must be within copy of record +- * - size of record must be lower that data table size */ +- if (name_len > data->strs_len +- || (data->name + name_len) > (strs_offset + data->strs_len) ++ * - record must not end outside data table ++ * - rec_name is a zero-terminated string */ ++ if (data->name < strs_offset ++ || data->name >= strs_offset + data->strs_len + || data->strs_len > rec->len +- || rec->len > data_size) { ++ || (uint8_t *) rec + rec->len > pw_mc_ctx.data_table + data_size ) { + ret = ENOENT; + goto done; + } + +- rec_name = (char *)data + data->name; + if (strcmp(name, rec_name) == 0) { + break; + } +-- +2.15.1 + diff --git a/0065-NSS-Fix-covscan-warning.patch b/0065-NSS-Fix-covscan-warning.patch new file mode 100644 index 0000000..30653ab --- /dev/null +++ b/0065-NSS-Fix-covscan-warning.patch @@ -0,0 +1,53 @@ +From 91d9cf1d38ffa4de06504c70b1f2af02da169b30 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= +Date: Tue, 21 Nov 2017 16:12:24 +0100 +Subject: [PATCH 65/79] NSS: Fix covscan warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + Error: NULL_RETURNS (CWE-476): [#def1] + sssd-1.16.1/src/responder/nss/nss_protocol.c:162: returned_null: "memchr" returns null (checked 7 out of 8 times). + sssd-1.16.1/src/responder/nss/nsssrv_mmap_cache.c:557: example_checked: Example 1: "memchr(t_key, 0, strs_offset + strs_len - name_ptr)" has its value checked in "memchr(t_key, 0, strs_offset + strs_len - name_ptr) == NULL". + sssd-1.16.1/src/sss_client/idmap/sss_nss_idmap.c:171: example_assign: Example 2: Assigning: "p" = return value from "memchr(p, 0, buf_len - (p - buf))". + sssd-1.16.1/src/sss_client/idmap/sss_nss_idmap.c:172: example_checked: Example 2 (cont.): "p" has its value checked in "p == NULL". + sssd-1.16.1/src/sss_client/nss_mc_group.c:157: example_checked: Example 3: "memchr(rec_name, 0, 16UL + data->strs_len - data->name)" has its value checked in "memchr(rec_name, 0, 16UL + data->strs_len - data->name) == NULL". + sssd-1.16.1/src/sss_client/nss_mc_initgr.c:139: example_checked: Example 4: "memchr(rec_name, 0, 24UL + data->data_len - data->name)" has its value checked in "memchr(rec_name, 0, 24UL + data->data_len - data->name) == NULL". + sssd-1.16.1/src/sss_client/nss_mc_passwd.c:150: example_checked: Example 5: "memchr(rec_name, 0, 16UL + data->strs_len - data->name)" has its value checked in "memchr(rec_name, 0, 16UL + data->strs_len - data->name) == NULL". + sssd-1.16.1/src/responder/nss/nss_protocol.c:162: var_assigned: Assigning: "p" = null return value from "memchr". + sssd-1.16.1/src/responder/nss/nss_protocol.c:176: dereference: Incrementing a pointer which might be null: "p". + # 174| } + # 175| + # 176|-> p++; + # 177| if ((p - body) + sizeof(uint32_t) != blen) { + # 178| DEBUG(SSSDBG_CRIT_FAILURE, "Body has unexpected size!\n"); + +Signed-off-by: Fabiano Fidêncio + +Reviewed-by: Lukáš Slebodník +Reviewed-by: Michal Židek +--- + src/responder/nss/nss_protocol.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/responder/nss/nss_protocol.c b/src/responder/nss/nss_protocol.c +index 2655386498754c46fbb363bdd1f976f9ded6a434..13f6d1541b79bf5494e1560841f027bf98bef72b 100644 +--- a/src/responder/nss/nss_protocol.c ++++ b/src/responder/nss/nss_protocol.c +@@ -160,6 +160,13 @@ nss_protocol_parse_name_ex(struct cli_ctx *cli_ctx, const char **_rawname, + } + + p = memchr(body, '\0', blen); ++ /* Although body for sure is null terminated, let's add this check here ++ * so static analyzers are happier. */ ++ if (p == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "memchr() returned NULL, body is not null terminated!\n"); ++ return EINVAL; ++ } + + /* If the body isn't valid UTF-8, fail */ + if (!sss_utf8_check(body, (p - body))) { +-- +2.15.1 + diff --git a/0066-krb5-show-error-message-for-krb5_init_context-failur.patch b/0066-krb5-show-error-message-for-krb5_init_context-failur.patch new file mode 100644 index 0000000..c8bea80 --- /dev/null +++ b/0066-krb5-show-error-message-for-krb5_init_context-failur.patch @@ -0,0 +1,187 @@ +From 209caaad9d545aeb601f64854a2ffb978b77c4b1 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 27 Nov 2017 13:45:14 +0100 +Subject: [PATCH 66/79] krb5: show error message for krb5_init_context() + failures +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If there are typos in /etc/krb5.conf (or one of the included config +snippets) krb5_init_context(), the initial call always needed to do any +other operation with libkrb5, fails because /etc/krb5.conf cannot be +parsed. + +Currently the related debug/syslog messages might be misleading, e.g. +failed to read keytab. This is because SSSD does not use a global krb5 +context but creates a fresh one for every new request or operation (to +always use the latest settings from /etc/krb5.conf) and typically there +is an error message indicating that the related operation failed but not +giving more details. + +Since krb5_init_context() is fundamental for Kerberos support this patch +tries to add as much details as libkrb5 provides in the logs if the call +fails. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3586 + +Reviewed-by: Lukáš Slebodník +Reviewed-by: Robbie Harwood +--- + src/providers/krb5/krb5_ccache.c | 6 +++--- + src/providers/krb5/krb5_common.c | 2 +- + src/providers/ldap/ldap_child.c | 2 +- + src/providers/ldap/ldap_common.c | 2 +- + src/responder/kcm/kcm.c | 3 ++- + src/util/sss_krb5.c | 25 ++++++++++++++++++++++--- + src/util/sss_krb5.h | 2 ++ + 7 files changed, 32 insertions(+), 10 deletions(-) + +diff --git a/src/providers/krb5/krb5_ccache.c b/src/providers/krb5/krb5_ccache.c +index f9bb25efd4ca3257845c3b157667d21d24299f4a..2e28276b72b6d5961de33c0ceb61774074a92d11 100644 +--- a/src/providers/krb5/krb5_ccache.c ++++ b/src/providers/krb5/krb5_ccache.c +@@ -299,7 +299,7 @@ static errno_t sss_open_ccache_as_user(TALLOC_CTX *mem_ctx, + goto done; + } + +- kerr = krb5_init_context(&cc->context); ++ kerr = sss_krb5_init_context(&cc->context); + if (kerr) { + ret = EIO; + goto done; +@@ -565,9 +565,9 @@ errno_t get_ccache_file_data(const char *ccache_file, const char *client_name, + const char *realm_name; + int realm_length; + +- kerr = krb5_init_context(&ctx); ++ kerr = sss_krb5_init_context(&ctx); + if (kerr != 0) { +- DEBUG(SSSDBG_CRIT_FAILURE, "krb5_init_context failed.\n"); ++ DEBUG(SSSDBG_CRIT_FAILURE, "sss_krb5_init_context failed.\n"); + goto done; + } + +diff --git a/src/providers/krb5/krb5_common.c b/src/providers/krb5/krb5_common.c +index 0b32da94dd8320d51708e2b7e827b94c472642a6..520e7591ce1b37b4a8dea357b6dd0ec7afd76f58 100644 +--- a/src/providers/krb5/krb5_common.c ++++ b/src/providers/krb5/krb5_common.c +@@ -106,7 +106,7 @@ static errno_t sss_get_system_ccname_template(TALLOC_CTX *mem_ctx, + + *ccname = NULL; + +- ret = krb5_init_context(&ctx); ++ ret = sss_krb5_init_context(&ctx); + if (ret) return ret; + + ret = krb5_get_profile(ctx, &p); +diff --git a/src/providers/ldap/ldap_child.c b/src/providers/ldap/ldap_child.c +index c0618d6d8828f102c32cf56731995e2b370590e7..4558fd7c42be03c4472dbf3092ce8044e8ae89d9 100644 +--- a/src/providers/ldap/ldap_child.c ++++ b/src/providers/ldap/ldap_child.c +@@ -574,7 +574,7 @@ static krb5_error_code privileged_krb5_setup(struct input_buffer *ibuf) + krb5_error_code kerr; + char *keytab_name; + +- kerr = krb5_init_context(&ibuf->context); ++ kerr = sss_krb5_init_context(&ibuf->context); + if (kerr != 0) { + DEBUG(SSSDBG_CRIT_FAILURE, "Failed to init kerberos context\n"); + return kerr; +diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c +index 0597e91f7fade47aeb34565597c730ac406e0cfc..4ec36584ad5acc52cf442b015caec80a6a8936da 100644 +--- a/src/providers/ldap/ldap_common.c ++++ b/src/providers/ldap/ldap_common.c +@@ -364,7 +364,7 @@ sdap_gssapi_get_default_realm(TALLOC_CTX *mem_ctx) + krb5_error_code krberr; + krb5_context context = NULL; + +- krberr = krb5_init_context(&context); ++ krberr = sss_krb5_init_context(&context); + if (krberr) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to init kerberos context\n"); + goto done; +diff --git a/src/responder/kcm/kcm.c b/src/responder/kcm/kcm.c +index 358fcc18165dec7b41a7389a3ef22660ac04b4a8..0fc09376888544570ca1bcf8c1ff1ba1d72d5906 100644 +--- a/src/responder/kcm/kcm.c ++++ b/src/responder/kcm/kcm.c +@@ -28,6 +28,7 @@ + #include "responder/kcm/kcmsrv_pvt.h" + #include "responder/common/responder.h" + #include "util/util.h" ++#include "util/sss_krb5.h" + + #define DEFAULT_KCM_FD_LIMIT 2048 + +@@ -183,7 +184,7 @@ static struct kcm_resp_ctx *kcm_data_setup(TALLOC_CTX *mem_ctx, + return NULL; + } + +- kret = krb5_init_context(&kcm_data->k5c); ++ kret = sss_krb5_init_context(&kcm_data->k5c); + if (kret != EOK) { + talloc_free(kcm_data); + return NULL; +diff --git a/src/util/sss_krb5.c b/src/util/sss_krb5.c +index a702a8b57c55bdb4215edf73731ddeaba156a84f..12660b0dd2e9170108afd54492e7ce30415741cb 100644 +--- a/src/util/sss_krb5.c ++++ b/src/util/sss_krb5.c +@@ -113,7 +113,7 @@ errno_t select_principal_from_keytab(TALLOC_CTX *mem_ctx, + return ENOMEM; + } + +- kerr = krb5_init_context(&krb_ctx); ++ kerr = sss_krb5_init_context(&krb_ctx); + if (kerr) { + DEBUG(SSSDBG_OP_FAILURE, "Failed to init kerberos context\n"); + ret = EFAULT; +@@ -1096,9 +1096,9 @@ bool sss_krb5_realm_has_proxy(const char *realm) + return false; + } + +- kerr = krb5_init_context(&context); ++ kerr = sss_krb5_init_context(&context); + if (kerr != 0) { +- DEBUG(SSSDBG_OP_FAILURE, "krb5_init_context failed.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, "sss_krb5_init_context failed.\n"); + return false; + } + +@@ -1330,3 +1330,22 @@ krb5_error_code sss_krb5_marshal_princ(krb5_principal princ, + } + return EOK; + } ++ ++krb5_error_code sss_krb5_init_context(krb5_context *context) ++{ ++ krb5_error_code kerr; ++ const char *msg; ++ ++ kerr = krb5_init_context(context); ++ if (kerr != 0) { ++ /* It is safe to call (sss_)krb5_get_error_message() with NULL as first ++ * argument. */ ++ msg = sss_krb5_get_error_message(NULL, kerr); ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Failed to init kerberos context [%s]\n", msg); ++ sss_log(SSS_LOG_CRIT, "Failed to init kerberos context [%s]\n", msg); ++ sss_krb5_free_error_message(NULL, msg); ++ } ++ ++ return kerr; ++} +diff --git a/src/util/sss_krb5.h b/src/util/sss_krb5.h +index 0d9043be98749b1a21a1b74c68f07298fa27f230..423951443c8c512211b1e894c41f1c8891be479f 100644 +--- a/src/util/sss_krb5.h ++++ b/src/util/sss_krb5.h +@@ -195,4 +195,6 @@ krb5_error_code sss_krb5_unmarshal_princ(TALLOC_CTX *mem_ctx, + struct sss_iobuf *iobuf, + krb5_principal *_princ); + ++krb5_error_code sss_krb5_init_context(krb5_context *context); ++ + #endif /* __SSS_KRB5_H__ */ +-- +2.15.1 + diff --git a/0067-responder-Fix-talloc-hierarchy-in-sized_output_name.patch b/0067-responder-Fix-talloc-hierarchy-in-sized_output_name.patch new file mode 100644 index 0000000..a819eb4 --- /dev/null +++ b/0067-responder-Fix-talloc-hierarchy-in-sized_output_name.patch @@ -0,0 +1,58 @@ +From ddff278e709a2aa882f2d8d64c263cddc3a93a2c Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 28 Nov 2017 12:19:54 +0100 +Subject: [PATCH 67/79] responder: Fix talloc hierarchy in sized_output_name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +sized_output_name was a called with NULL context in +memcache_delete_entry but returned data from sized_output_name +didn't have proper talloc hierarchy and we could not release all +all returned data. + +==00:01:01:29.871 10088== 934,414 bytes in 8,731 blocks are definitely lost in loss record 121 of 121 +==00:01:01:29.871 10088== at 0x4C29BE3: malloc (vg_replace_malloc.c:299) +==00:01:01:29.871 10088== by 0x8FF4EAB: talloc_strdup (in /usr/lib64/libtalloc.so.2.1.9) +==00:01:01:29.871 10088== by 0x52933B9: sss_output_name (usertools.c:808) +==00:01:01:29.871 10088== by 0x5293550: sss_output_fqname (usertools.c:863) +==00:01:01:29.871 10088== by 0x1211F9: sized_output_name (responder_common.c:1708) +==00:01:01:29.871 10088== by 0x1137E6: memcache_delete_entry (nss_get_object.c:112) +==00:01:01:29.871 10088== by 0x113BB6: nss_get_object_done (nss_get_object.c:245) +==00:01:01:29.871 10088== by 0x8DE5291: _tevent_req_error (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x1276CE: cache_req_done (cache_req.c:1047) +==00:01:01:29.871 10088== by 0x8DE5291: _tevent_req_error (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x126AF6: cache_req_search_domains_done (cache_req.c:607) +==00:01:01:29.871 10088== by 0x8DE4AB9: tevent_common_loop_immediate (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE9C9C: ??? (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE82A6: ??? (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE40CC: _tevent_loop_once (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE42FA: tevent_common_loop_wait (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x8DE8246: ??? (in /usr/lib64/libtevent.so.0.9.31) +==00:01:01:29.871 10088== by 0x5291B32: server_loop (server.c:718) +==00:01:01:29.871 10088== by 0x11004C: main (nsssrv.c:560) + +Resolves: +https://pagure.io/SSSD/sssd/issue/3588 + +Reviewed-by: Fabiano Fidêncio +--- + src/responder/common/responder_common.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c +index 6b4d2d9e5936c79944b6f883e9fe46fd03ff32f6..e1100ce4b1eaae8bc561246699dc9bacc96133c8 100644 +--- a/src/responder/common/responder_common.c ++++ b/src/responder/common/responder_common.c +@@ -1815,7 +1815,7 @@ int sized_output_name(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sss_output_fqname(mem_ctx, name_dom, orig_name, ++ ret = sss_output_fqname(name, name_dom, orig_name, + rctx->override_space, &name_str); + if (ret != EOK) { + goto done; +-- +2.15.1 + diff --git a/0068-test_responder-Check-memory-leak-in-sized_output_nam.patch b/0068-test_responder-Check-memory-leak-in-sized_output_nam.patch new file mode 100644 index 0000000..2b2ede3 --- /dev/null +++ b/0068-test_responder-Check-memory-leak-in-sized_output_nam.patch @@ -0,0 +1,57 @@ +From 878fa7d0d4a3c9de1e813a550c5968153faae0a9 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Tue, 28 Nov 2017 12:20:26 +0100 +Subject: [PATCH 68/79] test_responder: Check memory leak in sized_output_name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: +https://pagure.io/SSSD/sssd/issue/3588 + +Reviewed-by: Fabiano Fidêncio +--- + src/tests/cmocka/test_responder_common.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/src/tests/cmocka/test_responder_common.c b/src/tests/cmocka/test_responder_common.c +index fb7e4ee500570319999e6e85ee14a05cddea8de3..5441167caeb284982ee76926117da029966ec997 100644 +--- a/src/tests/cmocka/test_responder_common.c ++++ b/src/tests/cmocka/test_responder_common.c +@@ -316,6 +316,23 @@ void test_schedule_get_domains_task(void **state) + talloc_free(dummy_ncache_ptr); + } + ++void test_sss_output_fqname(void **state) ++{ ++ struct parse_inp_test_ctx *parse_inp_ctx = talloc_get_type(*state, ++ struct parse_inp_test_ctx); ++ errno_t ret; ++ struct sized_string *res = NULL; ++ ++ ret = sized_output_name(parse_inp_ctx, parse_inp_ctx->rctx, "dummy", ++ parse_inp_ctx->tctx->dom, &res); ++ assert_int_equal(ret, EOK); ++ assert_non_null(res); ++ assert_string_equal("dummy", res->str); ++ assert_int_equal(6, res->len); ++ ++ talloc_zfree(res); ++} ++ + int main(int argc, const char *argv[]) + { + int rv; +@@ -346,6 +363,9 @@ int main(int argc, const char *argv[]) + cmocka_unit_test_setup_teardown(test_schedule_get_domains_task, + parse_inp_test_setup, + parse_inp_test_teardown), ++ cmocka_unit_test_setup_teardown(test_sss_output_fqname, ++ parse_inp_test_setup, ++ parse_inp_test_teardown), + }; + + /* Set debug level to invalid value so we can deside if -d 0 was used. */ +-- +2.15.1 + diff --git a/0069-UTIL-add-find_domain_by_object_name_ex.patch b/0069-UTIL-add-find_domain_by_object_name_ex.patch new file mode 100644 index 0000000..e94d73a --- /dev/null +++ b/0069-UTIL-add-find_domain_by_object_name_ex.patch @@ -0,0 +1,81 @@ +From 8b98ab849993ddd2bddbe475f443fbee24081c1a Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 12:08:30 +0100 +Subject: [PATCH 69/79] UTIL: add find_domain_by_object_name_ex() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The _ex version of find_domain_by_object_name() has a additional option +'strict'. If set to 'true' NULL is return instead to domain from the +first argument. This way the caller can see if the provider object name +really contains a known domain. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +--- + src/util/domain_info_utils.c | 17 ++++++++++++++--- + src/util/util.h | 4 ++++ + 2 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c +index 3a3f5130a32e2c5fe4b81819bf2de697a4474111..66077092a40111967a98b0937506d9e4472f50d5 100644 +--- a/src/util/domain_info_utils.c ++++ b/src/util/domain_info_utils.c +@@ -174,8 +174,8 @@ sss_get_domain_by_sid_ldap_fallback(struct sss_domain_info *domain, + } + + struct sss_domain_info * +-find_domain_by_object_name(struct sss_domain_info *domain, +- const char *object_name) ++find_domain_by_object_name_ex(struct sss_domain_info *domain, ++ const char *object_name, bool strict) + { + TALLOC_CTX *tmp_ctx; + struct sss_domain_info *dom = NULL; +@@ -197,7 +197,11 @@ find_domain_by_object_name(struct sss_domain_info *domain, + } + + if (domainname == NULL) { +- dom = domain; ++ if (strict) { ++ dom = NULL; ++ } else { ++ dom = domain; ++ } + } else { + dom = find_domain_by_name(domain, domainname, true); + } +@@ -207,6 +211,13 @@ done: + return dom; + } + ++struct sss_domain_info * ++find_domain_by_object_name(struct sss_domain_info *domain, ++ const char *object_name) ++{ ++ return find_domain_by_object_name_ex(domain, object_name, false); ++} ++ + errno_t sssd_domain_init(TALLOC_CTX *mem_ctx, + struct confdb_ctx *cdb, + const char *domain_name, +diff --git a/src/util/util.h b/src/util/util.h +index 37383011763a9a2a3c2c066215e3ed94aca77308..2521b1789b0b8701b1fbcce33890eedb7fe18d5e 100644 +--- a/src/util/util.h ++++ b/src/util/util.h +@@ -551,6 +551,10 @@ struct sss_domain_info * + find_domain_by_object_name(struct sss_domain_info *domain, + const char *object_name); + ++struct sss_domain_info * ++find_domain_by_object_name_ex(struct sss_domain_info *domain, ++ const char *object_name, bool strict); ++ + bool subdomain_enumerates(struct sss_domain_info *parent, + const char *sd_name); + +-- +2.15.1 + diff --git a/0070-ipa-handle-users-from-different-domains-in-ipa_resol.patch b/0070-ipa-handle-users-from-different-domains-in-ipa_resol.patch new file mode 100644 index 0000000..e7b7f1c --- /dev/null +++ b/0070-ipa-handle-users-from-different-domains-in-ipa_resol.patch @@ -0,0 +1,75 @@ +From 2029b7b32c868dd5ad33dcc9b078d362ee9bb602 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 12:04:50 +0100 +Subject: [PATCH 70/79] ipa: handle users from different domains in + ipa_resolve_user_list_send() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Instead of assuming that all users in the list can be found in the +provided domain with this patch the domain name part of the user name is +preferred. The provided domain name is used as a fallback. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +--- + src/providers/ipa/ipa_id.c | 20 ++++++++++++++++---- + 1 file changed, 16 insertions(+), 4 deletions(-) + +diff --git a/src/providers/ipa/ipa_id.c b/src/providers/ipa/ipa_id.c +index 5044577f0faa95b19de9233240e92aa60f029774..9a092bc837f762af8d229ff5a7eb4c4ba4b78f2f 100644 +--- a/src/providers/ipa/ipa_id.c ++++ b/src/providers/ipa/ipa_id.c +@@ -63,6 +63,8 @@ struct ipa_resolve_user_list_state { + struct ipa_id_ctx *ipa_ctx; + struct ldb_message_element *users; + const char *domain_name; ++ struct sss_domain_info *domain; ++ struct sss_domain_info *user_domain; + size_t user_idx; + + int dp_error; +@@ -91,6 +93,8 @@ ipa_resolve_user_list_send(TALLOC_CTX *memctx, struct tevent_context *ev, + state->ev = ev; + state->ipa_ctx = ipa_ctx; + state->domain_name = domain_name; ++ state->domain = find_domain_by_name(state->ipa_ctx->sdap_id_ctx->be->domain, ++ state->domain_name, true); + state->users = users; + state->user_idx = 0; + state->dp_error = DP_ERR_FATAL; +@@ -132,8 +136,17 @@ static errno_t ipa_resolve_user_list_get_user_step(struct tevent_req *req) + + DEBUG(SSSDBG_TRACE_ALL, "Trying to resolve user [%s].\n", ar->filter_value); + +- if (strcasecmp(state->domain_name, +- state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) { ++ state->user_domain = find_domain_by_object_name_ex( ++ state->ipa_ctx->sdap_id_ctx->be->domain, ++ ar->filter_value, true); ++ /* Use provided domain as as fallback is no known domain was found in the ++ * user name. */ ++ if (state->user_domain == NULL) { ++ state->user_domain = state->domain; ++ } ++ ar->domain = state->user_domain->name; ++ ++ if (state->user_domain != state->ipa_ctx->sdap_id_ctx->be->domain) { + subreq = ipa_subdomain_account_send(state, state->ev, state->ipa_ctx, + ar); + } else { +@@ -158,8 +171,7 @@ static void ipa_resolve_user_list_get_user_done(struct tevent_req *subreq) + struct ipa_resolve_user_list_state); + int ret; + +- if (strcasecmp(state->domain_name, +- state->ipa_ctx->sdap_id_ctx->be->domain->name) != 0) { ++ if (state->user_domain != state->ipa_ctx->sdap_id_ctx->be->domain) { + ret = ipa_subdomain_account_recv(subreq, &state->dp_error); + } else { + ret = ipa_id_get_account_info_recv(subreq, &state->dp_error); +-- +2.15.1 + diff --git a/0071-overrides-fixes-for-sysdb_invalidate_overrides.patch b/0071-overrides-fixes-for-sysdb_invalidate_overrides.patch new file mode 100644 index 0000000..89fdaac --- /dev/null +++ b/0071-overrides-fixes-for-sysdb_invalidate_overrides.patch @@ -0,0 +1,202 @@ +From 3edca52d650154bcd784674d631a76512c6c4004 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 15:51:27 +0100 +Subject: [PATCH 71/79] overrides: fixes for sysdb_invalidate_overrides() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There were two issues in sysdb_invalidate_overrides(). + +First, SYSDB_CACHE_EXPIRE was only reset for the entry in the data cache +but not in the timestamp cache. + +Second, if one of the steps in the combined replace and delete operation +failed no change was committed to the cache. If, for whatever reasons, +a user or group object didn't had SYSDB_OVERRIDE_DN set the delete +failed and hence SYSDB_CACHE_EXPIRE wasn't reset as well. To make sure +the cache is in a consistent state after a view change the replace and +the delete operations are don in two steps. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +--- + src/db/sysdb_views.c | 111 +++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 80 insertions(+), 31 deletions(-) + +diff --git a/src/db/sysdb_views.c b/src/db/sysdb_views.c +index f640c813acf4deafe98eb15708d3a94790502dcb..bcd7dd46168aecdf808ad315175a12cef9ee03dd 100644 +--- a/src/db/sysdb_views.c ++++ b/src/db/sysdb_views.c +@@ -279,6 +279,45 @@ done: + return ret; + } + ++static errno_t invalidate_entry_override(struct sysdb_ctx *sysdb, ++ struct ldb_dn *dn, ++ struct ldb_message *msg_del, ++ struct ldb_message *msg_repl) ++{ ++ int ret; ++ ++ msg_del->dn = dn; ++ msg_repl->dn = dn; ++ ++ ret = ldb_modify(sysdb->ldb, msg_del); ++ if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_modify failed: [%s](%d)[%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); ++ return sysdb_error_to_errno(ret); ++ } ++ ++ ret = ldb_modify(sysdb->ldb, msg_repl); ++ if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_modify failed: [%s](%d)[%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); ++ return sysdb_error_to_errno(ret); ++ } ++ ++ if (sysdb->ldb_ts != NULL) { ++ ret = ldb_modify(sysdb->ldb_ts, msg_repl); ++ if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "ldb_modify failed: [%s](%d)[%s]\n", ++ ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb_ts)); ++ return sysdb_error_to_errno(ret); ++ } ++ } ++ ++ return EOK; ++} ++ + errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + { + int ret; +@@ -287,22 +326,23 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + bool in_transaction = false; + struct ldb_result *res; + size_t c; +- struct ldb_message *msg; ++ struct ldb_message *msg_del; ++ struct ldb_message *msg_repl; + struct ldb_dn *base_dn; + ++ if (sysdb->ldb_ts == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Timestamp cache context not available, cache might not be " ++ "invalidated completely. Please call 'sss_cache -E' or remove " ++ "the cache file if there are issues after a view name change.\n"); ++ } ++ + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + return ENOMEM; + } + +- msg = ldb_msg_new(tmp_ctx); +- if (msg == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- + base_dn = ldb_dn_new(tmp_ctx, sysdb->ldb, SYSDB_BASE); + if (base_dn == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed\n"); +@@ -310,27 +350,40 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + goto done; + } + +- ret = ldb_msg_add_empty(msg, SYSDB_CACHE_EXPIRE, LDB_FLAG_MOD_REPLACE, ++ msg_del = ldb_msg_new(tmp_ctx); ++ if (msg_del == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = ldb_msg_add_empty(msg_del, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_DELETE, + NULL); + if (ret != LDB_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n"); + ret = sysdb_error_to_errno(ret); + goto done; + } +- ret = ldb_msg_add_string(msg, SYSDB_CACHE_EXPIRE, "1"); ++ ++ msg_repl = ldb_msg_new(tmp_ctx); ++ if (msg_repl == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_new failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = ldb_msg_add_empty(msg_repl, SYSDB_CACHE_EXPIRE, ++ LDB_FLAG_MOD_REPLACE, NULL); ++ if (ret != LDB_SUCCESS) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n"); ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ret = ldb_msg_add_string(msg_repl, SYSDB_CACHE_EXPIRE, "1"); + if (ret != LDB_SUCCESS) { + DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_string failed.\n"); + ret = sysdb_error_to_errno(ret); + goto done; + } + +- ret = ldb_msg_add_empty(msg, SYSDB_OVERRIDE_DN, LDB_FLAG_MOD_DELETE, NULL); +- if (ret != LDB_SUCCESS) { +- DEBUG(SSSDBG_OP_FAILURE, "ldb_msg_add_empty failed.\n"); +- ret = sysdb_error_to_errno(ret); +- goto done; +- } +- + ret = sysdb_transaction_start(sysdb); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_transaction_start failed.\n"); +@@ -347,14 +400,12 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + } + + for (c = 0; c < res->count; c++) { +- msg->dn = res->msgs[c]->dn; +- +- ret = ldb_modify(sysdb->ldb, msg); +- if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ ret = invalidate_entry_override(sysdb, res->msgs[c]->dn, msg_del, ++ msg_repl); ++ if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- "ldb_modify failed: [%s](%d)[%s]\n", +- ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); +- ret = sysdb_error_to_errno(ret); ++ "invalidate_entry_override failed [%d][%s].\n", ++ ret, sss_strerror(ret)); + goto done; + } + } +@@ -370,14 +421,12 @@ errno_t sysdb_invalidate_overrides(struct sysdb_ctx *sysdb) + } + + for (c = 0; c < res->count; c++) { +- msg->dn = res->msgs[c]->dn; +- +- ret = ldb_modify(sysdb->ldb, msg); +- if (ret != LDB_SUCCESS && ret != LDB_ERR_NO_SUCH_ATTRIBUTE) { ++ ret = invalidate_entry_override(sysdb, res->msgs[c]->dn, msg_del, ++ msg_repl); ++ if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, +- "ldb_modify failed: [%s](%d)[%s]\n", +- ldb_strerror(ret), ret, ldb_errstring(sysdb->ldb)); +- ret = sysdb_error_to_errno(ret); ++ "invalidate_entry_override failed [%d][%s].\n", ++ ret, sss_strerror(ret)); + goto done; + } + } +-- +2.15.1 + diff --git a/0072-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch b/0072-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch new file mode 100644 index 0000000..2a94c0a --- /dev/null +++ b/0072-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch @@ -0,0 +1,253 @@ +From afa3e5d8401c529dad9fb6f2e3a3f4c2aa79a977 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 16:12:58 +0100 +Subject: [PATCH 72/79] ipa: check for SYSDB_OVERRIDE_DN in process_members and + get_group_dn_list +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +process_members() and get_group_dn_list() are used on an IPA client to +determine a list of users or groups which are missing in the cache and +are needed to properly add a group or user object to the cache +respectively. + +If a non-default view is assigned to the client the SYSDB_OVERRIDE_DN +must be set for all user and group objects to indicate that it was +already checked if there is an id-override defined for the object or +not. There a circumstances were SYSDB_OVERRIDE_DN is not set, e.g. after +a view name change. To make sure the cache is in a consistent state with +this patch user and group entries without SYSDB_OVERRIDE_DN are +considered as missing is a non-default view is assigned to the client. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +--- + src/providers/ipa/ipa_s2n_exop.c | 145 ++++++++++++++++++++++----------------- + 1 file changed, 83 insertions(+), 62 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 39ed17cbf0e8c523212084197e9f2963fed88dc8..c6132f509dcc8e7af84e03e8bfe20701107d1392 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -1523,6 +1523,7 @@ fail: + } + + static errno_t process_members(struct sss_domain_info *domain, ++ bool is_default_view, + struct sysdb_attrs *group_attrs, + char **members, + TALLOC_CTX *mem_ctx, char ***_missing_members) +@@ -1536,6 +1537,7 @@ static errno_t process_members(struct sss_domain_info *domain, + struct sss_domain_info *parent_domain; + char **missing_members = NULL; + size_t miss_count = 0; ++ const char *attrs[] = {SYSDB_NAME, SYSDB_OVERRIDE_DN, NULL}; + + if (members == NULL) { + DEBUG(SSSDBG_TRACE_INTERNAL, "No members\n"); +@@ -1572,53 +1574,59 @@ static errno_t process_members(struct sss_domain_info *domain, + goto done; + } + +- ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], NULL, ++ ret = sysdb_search_user_by_name(tmp_ctx, obj_domain, members[c], attrs, + &msg); +- if (ret == EOK) { +- if (group_attrs != NULL) { +- dn_str = ldb_dn_get_linearized(msg->dn); +- if (dn_str == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n"); +- ret = EINVAL; +- goto done; +- } +- +- DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n", +- members[c], dn_str); ++ if (ret == EOK || ret == ENOENT) { ++ if (ret == ENOENT ++ || (!is_default_view ++ && ldb_msg_find_attr_as_string(msg, SYSDB_OVERRIDE_DN, ++ NULL) == NULL)) { ++ /* only add ghost if the member is really missing */ ++ if (group_attrs != NULL && ret == ENOENT) { ++ DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n", ++ members[c]); + +- ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_MEMBER, +- dn_str); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "sysdb_attrs_add_string_safe failed.\n"); +- goto done; ++ /* There were cases where the server returned the same user ++ * multiple times */ ++ ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_GHOST, ++ members[c]); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_attrs_add_string failed.\n"); ++ goto done; ++ } + } +- } +- } else if (ret == ENOENT) { +- if (group_attrs != NULL) { +- DEBUG(SSSDBG_TRACE_ALL, "Adding ghost member [%s]\n", +- members[c]); + +- /* There were cases where the server returned the same user +- * multiple times */ +- ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_GHOST, +- members[c]); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "sysdb_attrs_add_string failed.\n"); +- goto done; ++ if (missing_members != NULL) { ++ missing_members[miss_count] = talloc_strdup(missing_members, ++ members[c]); ++ if (missing_members[miss_count] == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ miss_count++; + } +- } ++ } else { ++ if (group_attrs != NULL) { ++ dn_str = ldb_dn_get_linearized(msg->dn); ++ if (dn_str == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_get_linearized failed.\n"); ++ ret = EINVAL; ++ goto done; ++ } ++ ++ DEBUG(SSSDBG_TRACE_ALL, "Adding member [%s][%s]\n", ++ members[c], dn_str); + +- if (missing_members != NULL) { +- missing_members[miss_count] = talloc_strdup(missing_members, +- members[c]); +- if (missing_members[miss_count] == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); +- ret = ENOMEM; +- goto done; ++ ret = sysdb_attrs_add_string_safe(group_attrs, SYSDB_MEMBER, ++ dn_str); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "sysdb_attrs_add_string_safe failed.\n"); ++ goto done; ++ } + } +- miss_count++; + } + } else { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_user_by_name failed.\n"); +@@ -1649,6 +1657,7 @@ done: + } + + static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx, ++ bool is_default_view, + struct sss_domain_info *dom, + size_t ngroups, char **groups, + struct ldb_dn ***_dn_list, +@@ -1664,6 +1673,7 @@ static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx, + size_t n_missing = 0; + struct sss_domain_info *obj_domain; + struct sss_domain_info *parent_domain; ++ const char *attrs[] = {SYSDB_NAME, SYSDB_OVERRIDE_DN, NULL}; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { +@@ -1689,25 +1699,31 @@ static errno_t get_group_dn_list(TALLOC_CTX *mem_ctx, + goto done; + } + +- ret = sysdb_search_group_by_name(tmp_ctx, obj_domain, groups[c], NULL, ++ ret = sysdb_search_group_by_name(tmp_ctx, obj_domain, groups[c], attrs, + &msg); +- if (ret == EOK) { +- dn_list[n_dns] = ldb_dn_copy(dn_list, msg->dn); +- if (dn_list[n_dns] == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n"); +- ret = ENOMEM; +- goto done; ++ if (ret == EOK || ret == ENOENT) { ++ if (ret == ENOENT ++ || (!is_default_view ++ && ldb_msg_find_attr_as_string(msg, SYSDB_OVERRIDE_DN, ++ NULL) == NULL)) { ++ missing_groups[n_missing] = talloc_strdup(missing_groups, ++ groups[c]); ++ if (missing_groups[n_missing] == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ n_missing++; ++ ++ } else { ++ dn_list[n_dns] = ldb_dn_copy(dn_list, msg->dn); ++ if (dn_list[n_dns] == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n"); ++ ret = ENOMEM; ++ goto done; ++ } ++ n_dns++; + } +- n_dns++; +- } else if (ret == ENOENT) { +- missing_groups[n_missing] = talloc_strdup(missing_groups, +- groups[c]); +- if (missing_groups[n_missing] == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n"); +- ret = ENOMEM; +- goto done; +- } +- n_missing++; + } else { + DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_group_by_name failed.\n"); + goto done; +@@ -1803,7 +1819,9 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + } + + +- ret = get_group_dn_list(state, state->dom, ++ ret = get_group_dn_list(state, ++ is_default_view(state->ipa_ctx->view_name), ++ state->dom, + attrs->ngroups, attrs->groups, + &group_dn_list, &missing_list); + if (ret != EOK) { +@@ -1832,8 +1850,10 @@ static void ipa_s2n_get_user_done(struct tevent_req *subreq) + } + break; + } else if (attrs->response_type == RESP_GROUP_MEMBERS) { +- ret = process_members(state->dom, NULL, attrs->a.group.gr_mem, +- state, &missing_list); ++ ret = process_members(state->dom, ++ is_default_view(state->ipa_ctx->view_name), ++ NULL, attrs->a.group.gr_mem, state, ++ &missing_list); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n"); + goto done; +@@ -2572,8 +2592,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + } + } + +- ret = process_members(dom, attrs->sysdb_attrs, +- attrs->a.group.gr_mem, NULL, NULL); ++ ret = process_members(dom, is_default_view(view_name), ++ attrs->sysdb_attrs, attrs->a.group.gr_mem, ++ NULL, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "process_members failed.\n"); + goto done; +-- +2.15.1 + diff --git a/0073-IPA-use-cache-searches-in-get_groups_dns.patch b/0073-IPA-use-cache-searches-in-get_groups_dns.patch new file mode 100644 index 0000000..7cd8d7a --- /dev/null +++ b/0073-IPA-use-cache-searches-in-get_groups_dns.patch @@ -0,0 +1,69 @@ +From d1d62630e1d1c6a88fe4bf8612cb4f9a2fff7181 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 16:41:29 +0100 +Subject: [PATCH 73/79] IPA: use cache searches in get_groups_dns() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If the group name is overridden in the default view we have to search +for the name and cannot construct it because the extdom plugin will +return the overridden name but the DN of the related group object in the +cache will contain the original name. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +--- + src/providers/ipa/ipa_s2n_exop.c | 27 +++++++++++++++++++-------- + 1 file changed, 19 insertions(+), 8 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index c6132f509dcc8e7af84e03e8bfe20701107d1392..49c393e9a1eb19ab683949cf633a6838274bc0fe 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -2038,6 +2038,7 @@ static errno_t get_groups_dns(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + int c; + struct sss_domain_info *root_domain; + char **dn_list; ++ struct ldb_message *msg; + + if (name_list == NULL) { + *_dn_list = NULL; +@@ -2082,15 +2083,25 @@ static errno_t get_groups_dns(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom, + goto done; + } + +- /* This might fail if some unexpected cases are used. But current +- * sysdb code which handles group membership constructs DNs this way +- * as well, IPA names are lowercased and AD names by default will be +- * lowercased as well. If there are really use-cases which cause an +- * issue here, sysdb_group_strdn() has to be replaced by a proper +- * search. */ +- dn_list[c] = sysdb_group_strdn(dn_list, dom->name, name_list[c]); ++ /* If the group name is overridden in the default view we have to ++ * search for the name and cannot construct it because the extdom ++ * plugin will return the overridden name but the DN of the related ++ * group object in the cache will contain the original name. */ ++ ++ ret = sysdb_search_group_by_name(tmp_ctx, dom, name_list[c], NULL, ++ &msg); ++ if (ret == EOK) { ++ dn_list[c] = ldb_dn_alloc_linearized(dn_list, msg->dn); ++ } else { ++ /* best effort, try to construct the DN */ ++ DEBUG(SSSDBG_TRACE_FUNC, ++ "sysdb_search_group_by_name failed with [%d], " ++ "generating DN for [%s] in domain [%s].\n", ++ ret, name_list[c], dom->name); ++ dn_list[c] = sysdb_group_strdn(dn_list, dom->name, name_list[c]); ++ } + if (dn_list[c] == NULL) { +- DEBUG(SSSDBG_OP_FAILURE, "sysdb_group_strdn failed.\n"); ++ DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_alloc_linearized failed.\n"); + ret = ENOMEM; + goto done; + } +-- +2.15.1 + diff --git a/0074-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch b/0074-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch new file mode 100644 index 0000000..1f087be --- /dev/null +++ b/0074-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch @@ -0,0 +1,85 @@ +From 97becd502f5d8aa74b94eee78a949825222b6933 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 20 Nov 2017 16:45:45 +0100 +Subject: [PATCH 74/79] ipa: compare DNs instead of group names in + ipa_s2n_save_objects() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +If group names are used to compare the current list of group memberships +returned by the server with the one from the cache some groups might end +up in the wrong result list if group names are overridden. This +ambiguity can be resolved by using the DNs of the cached objects. + +Related to https://pagure.io/SSSD/sssd/issue/3579 + +Reviewed-by: Fabiano Fidêncio +--- + src/providers/ipa/ipa_s2n_exop.c | 31 ++++++++++++------------------- + 1 file changed, 12 insertions(+), 19 deletions(-) + +diff --git a/src/providers/ipa/ipa_s2n_exop.c b/src/providers/ipa/ipa_s2n_exop.c +index 49c393e9a1eb19ab683949cf633a6838274bc0fe..8b97f78620f19b0708e8a480cb72fd7f12d96dfb 100644 +--- a/src/providers/ipa/ipa_s2n_exop.c ++++ b/src/providers/ipa/ipa_s2n_exop.c +@@ -2185,10 +2185,9 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + struct ldb_result *res; + enum sysdb_member_type type; + char **sysdb_grouplist; +- char **add_groups; + char **add_groups_dns; +- char **del_groups; + char **del_groups_dns; ++ char **groups_dns; + bool in_transaction = false; + int tret; + struct sysdb_attrs *gid_override_attrs = NULL; +@@ -2514,33 +2513,27 @@ static errno_t ipa_s2n_save_objects(struct sss_domain_info *dom, + } + + if (attrs->response_type == RESP_USER_GROUPLIST) { +- ret = get_sysdb_grouplist(tmp_ctx, dom->sysdb, dom, name, +- &sysdb_grouplist); ++ ret = get_sysdb_grouplist_dn(tmp_ctx, dom->sysdb, dom, name, ++ &sysdb_grouplist); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "get_sysdb_grouplist failed.\n"); + goto done; + } + +- ret = diff_string_lists(tmp_ctx, attrs->groups, +- sysdb_grouplist, &add_groups, +- &del_groups, NULL); ++ ret = get_groups_dns(tmp_ctx, dom, attrs->groups, &groups_dns); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n"); ++ goto done; ++ } ++ ++ ret = diff_string_lists(tmp_ctx, groups_dns, ++ sysdb_grouplist, &add_groups_dns, ++ &del_groups_dns, NULL); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "diff_string_lists failed.\n"); + goto done; + } + +- ret = get_groups_dns(tmp_ctx, dom, add_groups, &add_groups_dns); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n"); +- goto done; +- } +- +- ret = get_groups_dns(tmp_ctx, dom, del_groups, &del_groups_dns); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "get_groups_dns failed.\n"); +- goto done; +- } +- + DEBUG(SSSDBG_TRACE_INTERNAL, "Updating memberships for %s\n", + name); + ret = sysdb_update_members_dn(dom, name, SYSDB_MEMBER_USER, +-- +2.15.1 + diff --git a/0075-nss-Fix-invalid-enum-nss_status-return-values.patch b/0075-nss-Fix-invalid-enum-nss_status-return-values.patch new file mode 100644 index 0000000..c7ea5de --- /dev/null +++ b/0075-nss-Fix-invalid-enum-nss_status-return-values.patch @@ -0,0 +1,150 @@ +From fd0fb14e613f15a7d1fbde86bf371a72d8dfe3b8 Mon Sep 17 00:00:00 2001 +From: Carlos O'Donell +Date: Wed, 29 Nov 2017 22:36:39 -0800 +Subject: [PATCH 75/79] nss: Fix invalid enum nss_status return values. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The upstream glibc test nss/bug17079 covers several cases where the +NSS infrastructure passes invalid pointers to NSS plugins. The plugins +should return correct results for the invalid values e.g. ERANGE, +but it should do so by setting *errnop to the error and returning +NSS_STATUS_TRYAGAIN. This commit fixes the group, netgroup, passwd +and service handling code to correctly return ERANGE in *errnop +and NSS_TATUS_TRYAGAIN in the case of invalid buffer (NULL) or +zero sized buffer length. This fixes the nss/bug17079 regression test +when run in a test configuration with sss enabled for any of the +above mentioned services. + +Upstream glibc bug: +Bug 22530 - FAIL: nss/bug17079 due to _nss_sss_getpwuid_r +https://sourceware.org/bugzilla/show_bug.cgi?id=22530 + +Merges: https://pagure.io/SSSD/sssd/pull-request/3561 + +Signed-off-by: Carlos O'Donell +Reviewed-by: Florian Weimer +Reviewed-by: Lukáš Slebodník +--- + src/sss_client/nss_group.c | 10 ++++++++-- + src/sss_client/nss_netgroup.c | 5 ++++- + src/sss_client/nss_passwd.c | 10 ++++++++-- + src/sss_client/nss_services.c | 15 ++++++++++++--- + 4 files changed, 32 insertions(+), 8 deletions(-) + +diff --git a/src/sss_client/nss_group.c b/src/sss_client/nss_group.c +index 42fba6242d23fc1d52cfd7be10cf10383010f091..054f30e13f8d5f8300a3e63c9035b98d30473c0e 100644 +--- a/src/sss_client/nss_group.c ++++ b/src/sss_client/nss_group.c +@@ -522,7 +522,10 @@ enum nss_status _nss_sss_getgrgid_r(gid_t gid, struct group *result, + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ +- if (!buffer || !buflen) return ERANGE; ++ if (!buffer || !buflen) { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } + + ret = sss_nss_mc_getgrgid(gid, result, buffer, buflen); + switch (ret) { +@@ -655,7 +658,10 @@ static enum nss_status internal_getgrent_r(struct group *result, + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ +- if (!buffer || !buflen) return ERANGE; ++ if (!buffer || !buflen) { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } + + /* if there are leftovers return the next one */ + if (sss_nss_getgrent_data.data != NULL && +diff --git a/src/sss_client/nss_netgroup.c b/src/sss_client/nss_netgroup.c +index 8594fc460514d6f92e786605168fa7d15c7ee913..3a1834a311e6658c6160b5f95a01434fed69ad1c 100644 +--- a/src/sss_client/nss_netgroup.c ++++ b/src/sss_client/nss_netgroup.c +@@ -231,7 +231,10 @@ static enum nss_status internal_getnetgrent_r(struct __netgrent *result, + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ +- if (!buffer || !buflen) return ERANGE; ++ if (!buffer || !buflen) { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } + + /* If we're already processing result data, continue to + * return it. +diff --git a/src/sss_client/nss_passwd.c b/src/sss_client/nss_passwd.c +index 61e2a567e684fbc7664b5d425e81cfa28a98e845..5b1c2ce66b0954bc304dfb458f509defa8eed889 100644 +--- a/src/sss_client/nss_passwd.c ++++ b/src/sss_client/nss_passwd.c +@@ -251,7 +251,10 @@ enum nss_status _nss_sss_getpwuid_r(uid_t uid, struct passwd *result, + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ +- if (!buffer || !buflen) return ERANGE; ++ if (!buffer || !buflen) { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } + + ret = sss_nss_mc_getpwuid(uid, result, buffer, buflen); + switch (ret) { +@@ -376,7 +379,10 @@ static enum nss_status internal_getpwent_r(struct passwd *result, + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ +- if (!buffer || !buflen) return ERANGE; ++ if (!buffer || !buflen) { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } + + /* if there are leftovers return the next one */ + if (sss_nss_getpwent_data.data != NULL && +diff --git a/src/sss_client/nss_services.c b/src/sss_client/nss_services.c +index 64e0b43e1643e4e76d2381a6b062335c3d513a21..161dad9ae27f822b40af8368e5af38b020d6549a 100644 +--- a/src/sss_client/nss_services.c ++++ b/src/sss_client/nss_services.c +@@ -177,7 +177,10 @@ _nss_sss_getservbyname_r(const char *name, + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ +- if (!buffer || !buflen) return ERANGE; ++ if (!buffer || !buflen) { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } + + ret = sss_strnlen(name, SSS_NAME_MAX, &name_len); + if (ret != 0) { +@@ -278,7 +281,10 @@ _nss_sss_getservbyport_r(int port, const char *protocol, + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ +- if (!buffer || !buflen) return ERANGE; ++ if (!buffer || !buflen) { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } + + if (protocol) { + ret = sss_strnlen(protocol, SSS_NAME_MAX, &proto_len); +@@ -411,7 +417,10 @@ static enum nss_status internal_getservent_r(struct servent *result, + int ret; + + /* Caught once glibc passing in buffer == 0x0 */ +- if (!buffer || !buflen) return ERANGE; ++ if (!buffer || !buflen) { ++ *errnop = ERANGE; ++ return NSS_STATUS_TRYAGAIN; ++ } + + /* if there are leftovers return the next one */ + if (sss_nss_getservent_data.data != NULL && +-- +2.15.1 + diff --git a/0076-confdb-Move-detection-files-to-separate-function.patch b/0076-confdb-Move-detection-files-to-separate-function.patch new file mode 100644 index 0000000..70da307 --- /dev/null +++ b/0076-confdb-Move-detection-files-to-separate-function.patch @@ -0,0 +1,110 @@ +From 5af7dcbba7a54c9a017a7d317f74453254125eb7 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 29 Nov 2017 17:57:56 +0100 +Subject: [PATCH 76/79] confdb: Move detection files to separate function + +--- + src/confdb/confdb.c | 73 ++++++++++++++++++++++++++++++----------------------- + 1 file changed, 41 insertions(+), 32 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index a028224817f12ace2a0c4165d7b9cb0bb80ce5a1..c41bd5087592ba15d8956e0279aaf72ba86936ed 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1718,52 +1718,61 @@ done: + return ret; + } + +-static int confdb_has_files_domain(struct confdb_ctx *cdb) ++static bool need_implicit_files_domain(TALLOC_CTX *tmp_ctx, ++ struct ldb_result *doms) + { +- TALLOC_CTX *tmp_ctx = NULL; +- struct ldb_dn *dn = NULL; +- struct ldb_result *res = NULL; +- static const char *attrs[] = { CONFDB_DOMAIN_ID_PROVIDER, NULL }; + const char *id_provider = NULL; +- int ret; + unsigned int i; + +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- return ENOMEM; +- } +- +- dn = ldb_dn_new(tmp_ctx, cdb->ldb, CONFDB_DOMAIN_BASEDN); +- if (dn == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL, +- attrs, NULL); +- if (ret != LDB_SUCCESS) { +- ret = EIO; +- goto done; +- } +- +- for (i = 0; i < res->count; i++) { +- id_provider = ldb_msg_find_attr_as_string(res->msgs[i], ++ for (i = 0; i < doms->count; i++) { ++ id_provider = ldb_msg_find_attr_as_string(doms->msgs[i], + CONFDB_DOMAIN_ID_PROVIDER, + NULL); + if (id_provider == NULL) { +- DEBUG(SSSDBG_CRIT_FAILURE, ++ DEBUG(SSSDBG_OP_FAILURE, + "The object [%s] doesn't have a id_provider\n", +- ldb_dn_get_linearized(res->msgs[i]->dn)); +- ret = EINVAL; +- goto done; ++ ldb_dn_get_linearized(doms->msgs[i]->dn)); ++ continue; + } + + if (strcasecmp(id_provider, "files") == 0) { +- break; ++ return false; + } + } + +- ret = i < res->count ? EOK : ENOENT; ++ return true; ++} ++ ++static int confdb_has_files_domain(struct confdb_ctx *cdb) ++{ ++ TALLOC_CTX *tmp_ctx = NULL; ++ struct ldb_dn *dn = NULL; ++ struct ldb_result *res = NULL; ++ static const char *attrs[] = { CONFDB_DOMAIN_ID_PROVIDER, NULL }; ++ int ret; ++ bool need_files_dom; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return ENOMEM; ++ } ++ ++ dn = ldb_dn_new(tmp_ctx, cdb->ldb, CONFDB_DOMAIN_BASEDN); ++ if (dn == NULL) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_search(cdb->ldb, tmp_ctx, &res, dn, LDB_SCOPE_ONELEVEL, ++ attrs, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = EIO; ++ goto done; ++ } ++ ++ need_files_dom = need_implicit_files_domain(tmp_ctx, res); ++ ++ ret = need_files_dom ? ENOENT : EOK; + done: + talloc_free(tmp_ctx); + return ret; +-- +2.15.1 + diff --git a/0077-confdb-Fix-starting-of-implicit-files-domain.patch b/0077-confdb-Fix-starting-of-implicit-files-domain.patch new file mode 100644 index 0000000..de3d873 --- /dev/null +++ b/0077-confdb-Fix-starting-of-implicit-files-domain.patch @@ -0,0 +1,96 @@ +From 57720f0d0945262a13d9ab7d1ec8220837ab618f Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Wed, 29 Nov 2017 20:02:35 +0100 +Subject: [PATCH 77/79] confdb: Fix starting of implicit files domain + +We did not start implicit_files domain when sssd configuration +contains files domain which was disabled. +--- + src/confdb/confdb.c | 36 +++++++++++++++++++++++++++++++++-- + src/tests/intg/test_files_provider.py | 3 +++ + 2 files changed, 37 insertions(+), 2 deletions(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index c41bd5087592ba15d8956e0279aaf72ba86936ed..ef1be4a6e6daee2644d535e561fac7735eb6a0b2 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1719,12 +1719,43 @@ done: + } + + static bool need_implicit_files_domain(TALLOC_CTX *tmp_ctx, ++ struct confdb_ctx *cdb, + struct ldb_result *doms) + { + const char *id_provider = NULL; + unsigned int i; ++ errno_t ret; ++ char **domlist; ++ const char *val; ++ ++ ret = confdb_get_string_as_list(cdb, tmp_ctx, ++ CONFDB_MONITOR_CONF_ENTRY, ++ CONFDB_MONITOR_ACTIVE_DOMAINS, ++ &domlist); ++ if (ret == ENOENT) { ++ return true; ++ } else if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "Cannot get active domains %d[%s]\n", ++ ret, sss_strerror(ret)); ++ return false; ++ } + + for (i = 0; i < doms->count; i++) { ++ val = ldb_msg_find_attr_as_string(doms->msgs[i], CONFDB_DOMAIN_ATTR, ++ NULL); ++ if (val == NULL) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "The object [%s] doesn't have a name\n", ++ ldb_dn_get_linearized(doms->msgs[i]->dn)); ++ continue; ++ } ++ ++ /* skip disabled domain */ ++ if (!string_in_list(val, domlist, false)) { ++ continue; ++ } ++ + id_provider = ldb_msg_find_attr_as_string(doms->msgs[i], + CONFDB_DOMAIN_ID_PROVIDER, + NULL); +@@ -1748,7 +1779,8 @@ static int confdb_has_files_domain(struct confdb_ctx *cdb) + TALLOC_CTX *tmp_ctx = NULL; + struct ldb_dn *dn = NULL; + struct ldb_result *res = NULL; +- static const char *attrs[] = { CONFDB_DOMAIN_ID_PROVIDER, NULL }; ++ static const char *attrs[] = { CONFDB_DOMAIN_ID_PROVIDER, ++ CONFDB_DOMAIN_ATTR, NULL }; + int ret; + bool need_files_dom; + +@@ -1770,7 +1802,7 @@ static int confdb_has_files_domain(struct confdb_ctx *cdb) + goto done; + } + +- need_files_dom = need_implicit_files_domain(tmp_ctx, res); ++ need_files_dom = need_implicit_files_domain(tmp_ctx, cdb, res); + + ret = need_files_dom ? ENOENT : EOK; + done: +diff --git a/src/tests/intg/test_files_provider.py b/src/tests/intg/test_files_provider.py +index e507ea10d78b9b35ee57178e78f4621372d0c2e5..169da713767b6495e117d805b29d8d6346237ebc 100644 +--- a/src/tests/intg/test_files_provider.py ++++ b/src/tests/intg/test_files_provider.py +@@ -167,6 +167,9 @@ def no_files_domain(request): + + [domain/local] + id_provider = local ++ ++ [domain/disabled.files] ++ id_provider = files + """).format(**locals()) + create_conf_fixture(request, conf) + create_sssd_fixture(request) +-- +2.15.1 + diff --git a/0078-confdb-Do-not-start-implicit_files-with-proxy-domain.patch b/0078-confdb-Do-not-start-implicit_files-with-proxy-domain.patch new file mode 100644 index 0000000..1115366 --- /dev/null +++ b/0078-confdb-Do-not-start-implicit_files-with-proxy-domain.patch @@ -0,0 +1,59 @@ +From 8cf5e390b38f0be4f88b0ebbbd1b14f52d35cd02 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Thu, 30 Nov 2017 07:59:33 +0100 +Subject: [PATCH 78/79] confdb: Do not start implicit_files with proxy domain + +id_provider = proxy + proxy_lib_name = files is equivalent +to id_provider = files. But requests to user hit implicit_files +domain instead of proxy domain and therefore it broke usage +of proxy domain with auth_provider = krb5. + +Resolves: +https://pagure.io/SSSD/sssd/issue/3590 +--- + src/confdb/confdb.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/src/confdb/confdb.c b/src/confdb/confdb.c +index ef1be4a6e6daee2644d535e561fac7735eb6a0b2..0a4be57e08791f8a9eb5fc143a56352cd4ef4b5e 100644 +--- a/src/confdb/confdb.c ++++ b/src/confdb/confdb.c +@@ -1769,6 +1769,25 @@ static bool need_implicit_files_domain(TALLOC_CTX *tmp_ctx, + if (strcasecmp(id_provider, "files") == 0) { + return false; + } ++ ++ if (strcasecmp(id_provider, "proxy") == 0) { ++ val = ldb_msg_find_attr_as_string(doms->msgs[i], ++ CONFDB_PROXY_LIBNAME, NULL); ++ if (val == NULL) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "The object [%s] doesn't have proxy_lib_name with " ++ "id_provider proxy\n", ++ ldb_dn_get_linearized(doms->msgs[i]->dn)); ++ continue; ++ } ++ ++ /* id_provider = proxy + proxy_lib_name = files is equivalent ++ * to id_provider = files ++ */ ++ if (strcmp(val, "files") == 0) { ++ return false; ++ } ++ } + } + + return true; +@@ -1780,7 +1799,8 @@ static int confdb_has_files_domain(struct confdb_ctx *cdb) + struct ldb_dn *dn = NULL; + struct ldb_result *res = NULL; + static const char *attrs[] = { CONFDB_DOMAIN_ID_PROVIDER, +- CONFDB_DOMAIN_ATTR, NULL }; ++ CONFDB_DOMAIN_ATTR, ++ CONFDB_PROXY_LIBNAME, NULL }; + int ret; + bool need_files_dom; + +-- +2.15.1 + diff --git a/0079-test_files_provider-Regression-test-for-implicit_fil.patch b/0079-test_files_provider-Regression-test-for-implicit_fil.patch new file mode 100644 index 0000000..eda6524 --- /dev/null +++ b/0079-test_files_provider-Regression-test-for-implicit_fil.patch @@ -0,0 +1,73 @@ +From f9518dce861a1fe9a3a5c5c63ac45f67fdbc5e68 Mon Sep 17 00:00:00 2001 +From: Lukas Slebodnik +Date: Thu, 30 Nov 2017 10:21:17 +0100 +Subject: [PATCH 79/79] test_files_provider: Regression test for implicit_files + + proxy + +Related to: +https://pagure.io/SSSD/sssd/issue/3590 +--- + src/tests/intg/test_files_provider.py | 40 +++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/src/tests/intg/test_files_provider.py b/src/tests/intg/test_files_provider.py +index 169da713767b6495e117d805b29d8d6346237ebc..ea4e5b70a3626cb43217b59488cf186e3325ae8d 100644 +--- a/src/tests/intg/test_files_provider.py ++++ b/src/tests/intg/test_files_provider.py +@@ -145,6 +145,26 @@ def files_domain_only(request): + return None + + ++@pytest.fixture ++def proxy_to_files_domain_only(request): ++ conf = unindent("""\ ++ [sssd] ++ domains = proxy, local ++ services = nss ++ ++ [domain/local] ++ id_provider = local ++ ++ [domain/proxy] ++ id_provider = proxy ++ proxy_lib_name = files ++ auth_provider = none ++ """).format(**locals()) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ return None ++ ++ + @pytest.fixture + def no_sssd_domain(request): + conf = unindent("""\ +@@ -980,6 +1000,26 @@ def test_no_sssd_domain(add_user_with_canary, no_sssd_domain): + assert user == USER1 + + ++def test_proxy_to_files_domain_only(add_user_with_canary, ++ proxy_to_files_domain_only): ++ """ ++ Test that implicit_files domain is not started together with proxy to files ++ """ ++ local_user1 = dict(name='user1', passwd='*', uid=10009, gid=10009, ++ gecos='user1', dir='/home/user1', shell='/bin/bash') ++ ++ # Add a user with a different UID than the one in files ++ subprocess.check_call( ++ ["sss_useradd", "-u", "10009", "-M", USER1["name"]]) ++ ++ res, user = call_sssd_getpwnam(USER1["name"]) ++ assert res == NssReturnCode.SUCCESS ++ assert user == local_user1 ++ ++ res, _ = call_sssd_getpwnam("{0}@implicit_files".format(USER1["name"])) ++ assert res == NssReturnCode.NOTFOUND ++ ++ + def test_no_files_domain(add_user_with_canary, no_files_domain): + """ + Test that if no files domain is configured, sssd will add the implicit one +-- +2.15.1 + diff --git a/0502-SYSTEMD-Use-capabilities.patch b/0502-SYSTEMD-Use-capabilities.patch index 9d35c85..cfc1827 100644 --- a/0502-SYSTEMD-Use-capabilities.patch +++ b/0502-SYSTEMD-Use-capabilities.patch @@ -1,4 +1,4 @@ -From 5381ad1bd7693a6681f00bef093241f13e3a2c4f Mon Sep 17 00:00:00 2001 +From 565ef3ffcaaef69a768b6a341777c339217bbbab Mon Sep 17 00:00:00 2001 From: Lukas Slebodnik Date: Mon, 12 Dec 2016 21:56:16 +0100 Subject: [PATCH] SYSTEMD: Use capabilities @@ -9,17 +9,17 @@ copied from selinux policy 1 file changed, 1 insertion(+) diff --git a/src/sysv/systemd/sssd.service.in b/src/sysv/systemd/sssd.service.in -index 05cfd3705084dbff8b46fb07e736612612c58b70..e7bbbdb5093f52e4b71e3c85a9082192013385e8 100644 +index 0c515d34caaa3ea397c4c7e95eef0188df170840..252889dbb2b7b1e651966258e7b76eab38357e76 100644 --- a/src/sysv/systemd/sssd.service.in +++ b/src/sysv/systemd/sssd.service.in -@@ -9,6 +9,7 @@ EnvironmentFile=-@environment_file@ - ExecStart=@sbindir@/sssd -i -f +@@ -11,6 +11,7 @@ ExecStart=@sbindir@/sssd -i ${DEBUG_LOGGER} Type=notify NotifyAccess=main + PIDFile=@localstatedir@/run/sssd.pid +CapabilityBoundingSet=CAP_IPC_LOCK CAP_CHOWN CAP_DAC_READ_SEARCH CAP_KILL CAP_NET_ADMIN CAP_SYS_NICE CAP_FOWNER CAP_SETGID CAP_SETUID CAP_SYS_ADMIN CAP_SYS_RESOURCE CAP_BLOCK_SUSPEND [Install] WantedBy=multi-user.target -- -2.11.0 +2.15.1 diff --git a/sssd.spec b/sssd.spec index 6d1cbdd..3cc88c2 100644 --- a/sssd.spec +++ b/sssd.spec @@ -20,6 +20,8 @@ %global with_kcm 1 + %global with_gdm_pam_extensions 1 + %global libwbc_alternatives_version 0.14 %global libwbc_lib_version %{libwbc_alternatives_version}.0 %global libwbc_alternatives_suffix %nil @@ -29,7 +31,7 @@ Name: sssd Version: 1.16.0 -Release: 4%{?dist} +Release: 5%{?dist} Group: Applications/System Summary: System Security Services Daemon License: GPLv3+ @@ -38,19 +40,84 @@ Source0: https://releases.pagure.org/SSSD/sssd/%{name}-%{version}.tar.gz BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) ### Patches ### -Patch0001: 0001-KCM-Fix-restart-during-after-upgrade.patch -Patch0002: 0002-sss_client-create-nss_common.h.patch -Patch0003: 0003-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch -Patch0004: 0004-NSS-add-_EX-version-of-some-requests.patch -Patch0005: 0005-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch -Patch0006: 0006-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch -Patch0007: 0007-nss-make-memcache_delete_entry-public.patch -Patch0008: 0008-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch -Patch0009: 0009-NSS-TESTS-add-unit-tests-for-_EX-requests.patch -Patch0010: 0010-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch -Patch0011: 0011-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch -Patch0012: 0012-TESTS-Order-list-of-entries-in-some-lists.patch -Patch0013: 0013-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch +Patch0001: 0001-KCM-Fix-typo-in-comments.patch +Patch0002: 0002-Fix-minor-spelling-mistakes.patch +Patch0003: 0003-CONFIG-Add-a-new-option-auto_private_groups.patch +Patch0004: 0004-CONFDB-Remove-the-obsolete-option-magic_private_grou.patch +Patch0005: 0005-SDAP-Allow-the-mpg-flag-for-the-main-domain.patch +Patch0006: 0006-LDAP-Turn-group-request-into-user-request-for-MPG-do.patch +Patch0007: 0007-SYSDB-Prevent-users-and-groups-ID-collision-in-MPG-d.patch +Patch0008: 0008-TESTS-Add-integration-tests-for-the-auto_private_gro.patch +Patch0009: 0009-CACHE_REQ-Copy-the-cr_domain-list-for-each-request.patch +Patch0010: 0010-sudo-document-background-activity.patch +Patch0011: 0011-MAN-GPO-Security-Filtering-limitation.patch +Patch0012: 0012-CI-Ignore-source-file-generated-by-systemtap.patch +Patch0013: 0013-sudo-always-use-srv_opts-from-id-context.patch +Patch0014: 0014-AD-Remember-last-site-discovered.patch +Patch0015: 0015-sysdb-add-functions-to-get-set-client-site.patch +Patch0016: 0016-AD-Remember-last-site-discovered-in-sysdb.patch +Patch0017: 0017-UTIL-Add-wrapper-function-to-configure-logger.patch +Patch0018: 0018-Add-parameter-logger-to-daemons.patch +Patch0019: 0019-SYSTEMD-Replace-parameter-debug-to-files-with-DEBUG_.patch +Patch0020: 0020-SYSTEMD-Add-environment-file-to-responder-service-fi.patch +Patch0021: 0021-UTIL-Hide-and-deprecate-parameter-debug-to-files.patch +Patch0023: 0023-LDAP-Bind-to-the-LDAP-server-also-in-the-auth.patch +Patch0024: 0024-KCM-Fix-restart-during-after-upgrade.patch +Patch0025: 0025-sss_client-create-nss_common.h.patch +Patch0026: 0026-nss-idmap-add-nss-like-calls-with-timeout-and-flags.patch +Patch0027: 0027-NSS-add-_EX-version-of-some-requests.patch +Patch0028: 0028-NSS-add-support-for-SSS_NSS_EX_FLAG_NO_CACHE.patch +Patch0029: 0029-CACHE_REQ-Add-cache_req_data_set_bypass_dp.patch +Patch0030: 0030-nss-make-memcache_delete_entry-public.patch +Patch0031: 0031-NSS-add-support-for-SSS_NSS_EX_FLAG_INVALIDATE_CACHE.patch +Patch0032: 0032-NSS-TESTS-add-unit-tests-for-_EX-requests.patch +Patch0033: 0033-nss-idmap-add-timeout-version-of-old-sss_nss_-calls.patch +Patch0034: 0034-nss-idmap-allow-empty-buffer-with-SSS_NSS_EX_FLAG_IN.patch +Patch0035: 0035-RESP-Add-some-missing-NULL-checks.patch +Patch0036: 0036-BUILD-Properly-expand-variables-in-sssd-ifp.service.patch +Patch0037: 0037-SYSTEMD-Clean-pid-file-in-corner-cases.patch +Patch0038: 0038-CHILD-Pass-information-about-logger-to-children.patch +Patch0039: 0039-TOOLS-Double-quote-array-expansions-in-sss_debugleve.patch +Patch0040: 0040-TOOLS-Call-exec-for-sss_debuglevel.patch +Patch0041: 0041-LDAP-Improve-error-treatment-from-sdap_cli_connect-i.patch +Patch0042: 0042-p11_child-return-multiple-certs.patch +Patch0043: 0043-PAM-handled-multiple-certs-in-the-responder.patch +Patch0044: 0044-pam_sss-refactoring-use-struct-cert_auth_info.patch +Patch0045: 0045-p11_child-use-options-to-select-certificate-for-auth.patch +Patch0046: 0046-pam-add-prompt-string-for-certificate-authentication.patch +Patch0047: 0047-PAM-allow-missing-logon_name-during-certificate-auth.patch +Patch0048: 0048-p11_child-add-descriptions-for-error-codes-to-debug-.patch +Patch0049: 0049-pam-filter-certificates-in-the-responder-not-in-the-.patch +Patch0050: 0050-PAM-add-certificate-s-label-to-the-selection-prompt.patch +Patch0051: 0051-SYSDB-Remove-code-causing-a-covscan-warning.patch +Patch0052: 0052-SYSDB-Better-debugging-for-email-conflicts.patch +Patch0053: 0053-NSS-Use-enum_ctx-as-memory_context-in-_setnetgrent_s.patch +Patch0054: 0054-cache_req-Correction-of-cache_req-debug-string-ID-fo.patch +Patch0055: 0055-TESTS-Order-list-of-entries-in-some-lists.patch +Patch0056: 0056-TOOLS-Add-a-new-sssctl-command-access-report.patch +Patch0057: 0057-dp-use-void-to-express-empty-output-argument-list.patch +Patch0058: 0058-dp-add-method-to-refresh-access-control-rules.patch +Patch0059: 0059-ipa-implement-method-to-refresh-HBAC-rules.patch +Patch0060: 0060-ifp-add-method-to-refresh-access-control-rules-in-do.patch +Patch0061: 0061-sssctl-call-dbus-instead-of-pam-to-refresh-HBAC-rule.patch +Patch0062: 0062-SPEC-Reduce-build-time-dependencies.patch +Patch0063: 0063-WATCHDOG-Restart-providers-with-SIGUSR2-after-time-d.patch +Patch0064: 0064-mmap_cache-make-checks-independent-of-input-size.patch +Patch0065: 0065-NSS-Fix-covscan-warning.patch +Patch0066: 0066-krb5-show-error-message-for-krb5_init_context-failur.patch +Patch0067: 0067-responder-Fix-talloc-hierarchy-in-sized_output_name.patch +Patch0068: 0068-test_responder-Check-memory-leak-in-sized_output_nam.patch +Patch0069: 0069-UTIL-add-find_domain_by_object_name_ex.patch +Patch0070: 0070-ipa-handle-users-from-different-domains-in-ipa_resol.patch +Patch0071: 0071-overrides-fixes-for-sysdb_invalidate_overrides.patch +Patch0072: 0072-ipa-check-for-SYSDB_OVERRIDE_DN-in-process_members-a.patch +Patch0073: 0073-IPA-use-cache-searches-in-get_groups_dns.patch +Patch0074: 0074-ipa-compare-DNs-instead-of-group-names-in-ipa_s2n_sa.patch +Patch0075: 0075-nss-Fix-invalid-enum-nss_status-return-values.patch +Patch0076: 0076-confdb-Move-detection-files-to-separate-function.patch +Patch0077: 0077-confdb-Fix-starting-of-implicit-files-domain.patch +Patch0078: 0078-confdb-Do-not-start-implicit_files-with-proxy-domain.patch +Patch0079: 0079-test_files_provider-Regression-test-for-implicit_fil.patch Patch0502: 0502-SYSTEMD-Use-capabilities.patch Patch0503: 0503-Disable-stopping-idle-socket-activated-responders.patch @@ -132,6 +199,7 @@ BuildRequires: http-parser-devel BuildRequires: libuuid-devel BuildRequires: jansson-devel BuildRequires: libcurl-devel +BuildRequires: gdm-pam-extensions-devel %description Provides a set of daemons to manage access to remote directories and @@ -852,8 +920,6 @@ done %attr(700,root,root) %dir %{_sysconfdir}/sssd %attr(711,root,root) %dir %{_sysconfdir}/sssd/conf.d %ghost %attr(0600,root,root) %config(noreplace) %{_sysconfdir}/sssd/sssd.conf -%attr(755,root,root) %dir %{_sysconfdir}/systemd/system/sssd.service.d -%config(noreplace) %{_sysconfdir}/systemd/system/sssd.service.d/journal.conf %dir %{_sysconfdir}/logrotate.d %config(noreplace) %{_sysconfdir}/logrotate.d/sssd %dir %{_sysconfdir}/rwtab.d @@ -1253,6 +1319,24 @@ fi %{_libdir}/%{name}/modules/libwbclient.so %changelog +* Mon Dec 04 2017 Lukas Slebodnik - 1.16.0-5 +- Resolves: upstream#3523 - ABRT crash - /usr/libexec/sssd/sssd_nss in + setnetgrent_result_timeout +- 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 + * Tue Nov 21 2017 Lukas Slebodnik - 1.16.0-4 - Resolves: rhbz#1494002 - sssd_nss crashed in cache_req_search_domains_next