35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher Stephen Gallagher <sgallagh@redhat.com>
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher Copyright (C) 2010 Red Hat
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher This program is free software; you can redistribute it and/or modify
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher it under the terms of the GNU General Public License as published by
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher the Free Software Foundation; either version 3 of the License, or
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher (at your option) any later version.
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher This program is distributed in the hope that it will be useful,
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher but WITHOUT ANY WARRANTY; without even the implied warranty of
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher GNU General Public License for more details.
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher You should have received a copy of the GNU General Public License
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher along with this program. If not, see <http://www.gnu.org/licenses/>.
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl#define PERMANENTLY_LOCKED_ACCOUNT "000001010000Z"
46ebf4415306454e1d062b61a2495b7cdb821c0fPavel Reichl#define MALFORMED_FILTER "Malformed access control filter [%s]\n"
c9b0071bfcb8eb8c71e40248de46d23aceecc0f3Pavel Reichlstatic errno_t perform_pwexpire_policy(TALLOC_CTX *mem_ctx,
4c38ed71727a9668cec4d3bd1bf8f7e77ac5e6c0Pavel Reichlstatic errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
719985a9e2aeaf2cba960f1525325ff125b7e19bPavel Reichlstatic errno_t sdap_get_basedn_user_entry(struct ldb_message *user_entry,
719985a9e2aeaf2cba960f1525325ff125b7e19bPavel Reichl const char **_basedn);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichlstatic struct tevent_req *
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bosestatic struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorcestatic errno_t sdap_access_filter_recv(struct tevent_req *req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic errno_t sdap_access_ppolicy_recv(struct tevent_req *req);
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorcestatic errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorcestatic errno_t sdap_access_service(struct pam_data *pd,
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorcestatic errno_t sdap_access_host(struct ldb_message *user_entry);
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiyerrno_t sdap_access_rhost(struct ldb_message *user_entry, char *rhost);
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichlstatic errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state,
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichlstatic void sdap_access_done(struct tevent_req *subreq);
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher req = tevent_req_create(mem_ctx, &state, struct sdap_access_req_ctx);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Performing access check for user [%s]\n", pd->user);
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose if (access_ctx->access_rule[0] == LDAP_ACCESS_EMPTY) {
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "No access rules defined, access denied.\n");
443eb8217741df57d9f58f2098487b91e3404e71Jakub Hrozek /* Get original user DN, domain already points to the right (sub)domain */
b3292840ebaa747a9fd596ff47cc5d18198361d0Michal Zidek ret = sysdb_get_user_attr(state, domain, pd->user, attrs, &res);
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorce /* If we can't find the user, return access denied */
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorce /* If we can't find the user, return access denied */
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Invalid response from sysdb_get_user_attr\n");
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichlstatic errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state,
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorce switch (state->access_ctx->access_rule[state->current_rule]) {
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorce /* we are done with no errors */
108a49f0e816d95cf75a1e964f63b397e53c8b56Pavel Reichl /* This option is deprecated by LDAP_ACCESS_PPOLICY */
108a49f0e816d95cf75a1e964f63b397e53c8b56Pavel Reichl "WARNING: %s option is deprecated and might be removed in "
108a49f0e816d95cf75a1e964f63b397e53c8b56Pavel Reichl "a future release. Please migrate to %s option instead.\n",
108a49f0e816d95cf75a1e964f63b397e53c8b56Pavel Reichl LDAP_ACCESS_LOCK_NAME, LDAP_ACCESS_PPOLICY_NAME);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl subreq = sdap_access_ppolicy_send(state, state->ev, state->be_ctx,
108a49f0e816d95cf75a1e964f63b397e53c8b56Pavel Reichl "sdap_access_ppolicy_send failed.\n");
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl state->ac_type = SDAP_ACCESS_CONTROL_PPOLICY_LOCK;
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl tevent_req_set_callback(subreq, sdap_access_done, req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl subreq = sdap_access_ppolicy_send(state, state->ev, state->be_ctx,
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "sdap_access_ppolicy_send failed.\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl state->ac_type = SDAP_ACCESS_CONTROL_PPOLICY_LOCK;
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl tevent_req_set_callback(subreq, sdap_access_done, req);
249a28dbf31e11794c7f35d709c5561c1555898dSimo Sorce subreq = sdap_access_filter_send(state, state->ev, state->be_ctx,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "sdap_access_filter_send failed.\n");
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichl tevent_req_set_callback(subreq, sdap_access_done, req);
c9b0071bfcb8eb8c71e40248de46d23aceecc0f3Pavel Reichl ret = perform_pwexpire_policy(state, state->domain, state->pd,
c9b0071bfcb8eb8c71e40248de46d23aceecc0f3Pavel Reichl ret = perform_pwexpire_policy(state, state->domain, state->pd,
c9b0071bfcb8eb8c71e40248de46d23aceecc0f3Pavel Reichl ret = perform_pwexpire_policy(state, state->domain, state->pd,
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorce ret = sdap_access_service( state->pd, state->user_entry);
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy ret = sdap_access_rhost(state->user_entry, state->pd->rhost);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Unexpected access rule type. Access denied.\n");
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichlstatic void sdap_access_done(struct tevent_req *subreq)
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichl req = tevent_req_callback_data(subreq, struct tevent_req);
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichl state = tevent_req_data(req, struct sdap_access_req_ctx);
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichl /* process subrequest */
b07a3b729892d2bc2ffa73d93de95e19003cc6c8Pavel Reichl DEBUG(SSSDBG_MINOR_FAILURE, "Unknown access control type: %d.\n",
9956e720e7f055afdb6ada141b4ab892bfa0930bPavel Reichl DEBUG(SSSDBG_TRACE_FUNC, "Access was denied.\n");
9956e720e7f055afdb6ada141b4ab892bfa0930bPavel Reichl "Error retrieving access check result.\n");
6742203fd84e97822cdddc4065402c15f3c5703fSumit Bose#define SHADOW_EXPIRE_MSG "Account expired according to shadow attributes"
6742203fd84e97822cdddc4065402c15f3c5703fSumit Bosestatic errno_t sdap_account_expired_shadow(struct pam_data *pd,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Performing access shadow check for user [%s]\n", pd->user);
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose val = ldb_msg_find_attr_as_string(user_entry, SYSDB_SHADOWPW_EXPIRE, NULL);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_MINOR_FAILURE, "Shadow expire attribute not found. "
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Access will be granted.\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failed to retrieve shadow expire date.\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose#define AD_DISABLE_MESSAGE "The user account is disabled on the AD server"
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose#define AD_EXPIRED_MESSAGE "The user account is expired on the AD server"
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bosestatic bool ad_account_expired(uint64_t expiration_time)
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose if (expiration_time == 0 || expiration_time == AD_NEVER_EXP) {
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose return false;
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "time failed [%d][%s].\n", err, strerror(err));
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose return true;
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose /* NT timestamps start at 1601-01-01 and use a 100ns base */
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose nt_now = (now + AD_TO_UNIX_TIME_CONST) * 1000 * 1000 * 10;
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose return true;
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose return false;
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bosestatic errno_t sdap_account_expired_ad(struct pam_data *pd,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Performing AD access check for user [%s]\n", pd->user);
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose uac = ldb_msg_find_attr_as_uint(user_entry, SYSDB_AD_USER_ACCOUNT_CONTROL,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_ALL, "User account control for user [%s] is [%X].\n",
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose expiration_time = ldb_msg_find_attr_as_uint64(user_entry,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Expiration time for user [%s] is [%"PRIu64"].\n",
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose } else if (ad_account_expired(expiration_time)) {
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
d73fcc5183a676aed4fd040714b87274248b784cSumit Bose#define RHDS_LOCK_MSG "The user account is locked on the server"
d73fcc5183a676aed4fd040714b87274248b784cSumit Bosestatic errno_t sdap_account_expired_rhds(struct pam_data *pd,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Performing RHDS access check for user [%s]\n", pd->user);
d73fcc5183a676aed4fd040714b87274248b784cSumit Bose locked = ldb_msg_find_attr_as_bool(user_entry, SYSDB_NS_ACCOUNT_LOCK, false);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_ALL, "Account for user [%s] is%s locked.\n", pd->user,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose#define NDS_DISABLE_MSG "The user account is disabled on the server"
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose#define NDS_EXPIRED_MSG "The user account is expired"
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose#define NDS_TIME_MAP_MSG "The user account is not allowed at this time"
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichlbool nds_check_expired(const char *exp_time_str)
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "ndsLoginExpirationTime is not set, access granted.\n");
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return false;
08f83281cf4b0f35e8569851fae7364e140371f9Pavel Reichl ret = sss_utc_to_time_t(exp_time_str, "%Y%m%d%H%M%SZ",
08f83281cf4b0f35e8569851fae7364e140371f9Pavel Reichl DEBUG(SSSDBG_MINOR_FAILURE, "sss_utc_to_time_t failed with %d:%s.\n",
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return true;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Time info: tzname[0] [%s] tzname[1] [%s] timezone [%ld] "
937928d1161a4f7bd894cb365ada97569ab0f78fLukas Slebodnik "daylight [%d] now [%ld] expire_time [%ld].\n", tzname[0],
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov tzname[1], timezone, daylight, now, expire_time);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "NDS account expired.\n");
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return true;
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return false;
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose/* There is no real documentation of the byte string value of
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose * loginAllowedTimeMap, but some good example code in
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose * http://http://developer.novell.com/documentation/samplecode/extjndi_sample/CheckBind.java.html
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bosestatic bool nds_check_time_map(const struct ldb_val *time_map)
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "loginAllowedTimeMap is missing, access granted.\n");
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return false;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Allowed time map has the wrong size, "
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "got [%zu], expected 42.\n", time_map->length);
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return true;
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose map_index = tm_now->tm_wday * 48 + tm_now->tm_hour * 2 +
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Unexpected index value [%zu] for time map.\n", map_index);
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return true;
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose if (q.quot > 41 || q.quot < 0 || q.rem > 7 || q.rem < 0) {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Unexpected result of div(), [%zu][%d][%d].\n",
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return true;
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose if (q.rem > 0) {
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "Access allowed by time map.\n");
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return false;
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose return true;
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bosestatic errno_t sdap_account_expired_nds(struct pam_data *pd,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Performing NDS access check for user [%s]\n", pd->user);
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose locked = ldb_msg_find_attr_as_bool(user_entry, SYSDB_NDS_LOGIN_DISABLED,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_ALL, "Account for user [%s] is%s disabled.\n", pd->user,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose exp_time_str = ldb_msg_find_attr_as_string(user_entry,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Account for user [%s] is%s expired.\n", pd->user,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Account for user [%s] is%s locked at this time.\n",
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorcestatic errno_t sdap_account_expired(struct sdap_access_ctx *access_ctx,
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose expire = dp_opt_get_cstring(access_ctx->id_ctx->opts->basic,
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Missing account expire policy. Access denied\n");
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_SHADOW) == 0) {
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorce ret = sdap_account_expired_shadow(pd, user_entry);
c820e6db26426c9f74a0e8f8ff9d9cf79d57406aPavel Reichl "sdap_account_expired_shadow: %s.\n", sss_strerror(ret));
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "sdap_account_expired_shadow failed.\n");
22f4c1b86dcf5589e63f2ae043dc65a8f72f6f18Sumit Bose } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_AD) == 0) {
c820e6db26426c9f74a0e8f8ff9d9cf79d57406aPavel Reichl if (ret == ERR_ACCOUNT_EXPIRED || ret == ERR_ACCESS_DENIED) {
c820e6db26426c9f74a0e8f8ff9d9cf79d57406aPavel Reichl "sdap_account_expired_ad: %s.\n", sss_strerror(ret));
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "sdap_account_expired_ad failed.\n");
d73fcc5183a676aed4fd040714b87274248b784cSumit Bose } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_RHDS) == 0 ||
d73fcc5183a676aed4fd040714b87274248b784cSumit Bose strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_IPA) == 0 ||
d73fcc5183a676aed4fd040714b87274248b784cSumit Bose strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_389DS) == 0) {
c820e6db26426c9f74a0e8f8ff9d9cf79d57406aPavel Reichl "sdap_account_expired_rhds: %s.\n", sss_strerror(ret));
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "sdap_account_expired_rhds failed.\n");
eedfc2cced329731c90317a5be3cd82a3749eb8aJakub Hrozek strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_IPA) == 0) {
eedfc2cced329731c90317a5be3cd82a3749eb8aJakub Hrozek "IPA access control succeeded, checking AD "
eedfc2cced329731c90317a5be3cd82a3749eb8aJakub Hrozek "access control\n");
eedfc2cced329731c90317a5be3cd82a3749eb8aJakub Hrozek if (ret == ERR_ACCOUNT_EXPIRED || ret == ERR_ACCESS_DENIED) {
eedfc2cced329731c90317a5be3cd82a3749eb8aJakub Hrozek "sdap_account_expired_ad: %s.\n", sss_strerror(ret));
eedfc2cced329731c90317a5be3cd82a3749eb8aJakub Hrozek "sdap_account_expired_ad failed.\n");
37e7e93f1996cf50677cf59fd8af6938dd5d85b2Sumit Bose } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_NDS) == 0) {
c820e6db26426c9f74a0e8f8ff9d9cf79d57406aPavel Reichl "sdap_account_expired_nds: %s.\n", sss_strerror(ret));
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "sdap_account_expired_nds failed.\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Unsupported LDAP account expire policy [%s]. "
c9b0071bfcb8eb8c71e40248de46d23aceecc0f3Pavel Reichlstatic errno_t perform_pwexpire_policy(TALLOC_CTX *mem_ctx,
c9b0071bfcb8eb8c71e40248de46d23aceecc0f3Pavel Reichl ret = get_user_dn(mem_ctx, domain, opts, pd->user, &dn, &pw_expire_type,
c9b0071bfcb8eb8c71e40248de46d23aceecc0f3Pavel Reichl DEBUG(SSSDBG_MINOR_FAILURE, "get_user_dn returned %d:[%s].\n",
c9b0071bfcb8eb8c71e40248de46d23aceecc0f3Pavel Reichl ret = check_pwexpire_policy(pw_expire_type, pw_expire_data, pd,
c9b0071bfcb8eb8c71e40248de46d23aceecc0f3Pavel Reichl "check_pwexpire_policy returned %d:[%s].\n",
1a357c873baa79c0b82ab1d084f942cfcc8ba1c0Pavel Reichl /* cached result of access control checks */
1a357c873baa79c0b82ab1d084f942cfcc8ba1c0Pavel Reichlstatic errno_t sdap_access_decide_offline(bool cached_ac);
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bosestatic int sdap_access_filter_retry(struct tevent_req *req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic void sdap_access_ppolicy_connect_done(struct tevent_req *subreq);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic errno_t sdap_access_ppolicy_get_lockout_step(struct tevent_req *req);
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bosestatic void sdap_access_filter_connect_done(struct tevent_req *subreq);
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichlstatic void sdap_access_filter_done(struct tevent_req *req);
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bosestatic struct tevent_req *sdap_access_filter_send(TALLOC_CTX *mem_ctx,
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose req = tevent_req_create(mem_ctx, &state, struct sdap_access_filter_req_ctx);
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose if (access_ctx->filter == NULL || *access_ctx->filter == '\0') {
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose /* If no filter is set, default to restrictive */
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_FUNC, "No filter set. Access is denied.\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Performing access filter check for user [%s]\n", username);
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose state->cached_access = ldb_msg_find_attr_as_bool(user_entry,
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher /* Ok, we have one result, check if we are online or offline */
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher /* Ok, we're offline. Return from the cache */
1a357c873baa79c0b82ab1d084f942cfcc8ba1c0Pavel Reichl ret = sdap_access_decide_offline(state->cached_access);
719985a9e2aeaf2cba960f1525325ff125b7e19bPavel Reichl ret = sdap_get_basedn_user_entry(user_entry, state->username,
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher /* Construct the filter */
7a9f3fc59a2041e868fa9524d8351ec48ec8c158Jakub Hrozek ret = sss_parse_internal_fqname(state, username, &name, NULL);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Could not parse [%s] into name and "
7a9f3fc59a2041e868fa9524d8351ec48ec8c158Jakub Hrozek "domain components, access might fail\n", username);
dd2f33603228005a44675f1484c294ea647dbce3Jakub Hrozek ret = sss_filter_sanitize(state, name, &clean_username);
a6dbe52dc824f8338d209ef5c56f9e345aeeb2feStephen Gallagher "(&(%s=%s)(objectclass=%s)%s)",
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_FATAL_FAILURE, "Could not construct access filter\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_FUNC, "Checking filter against LDAP\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
1a357c873baa79c0b82ab1d084f942cfcc8ba1c0Pavel Reichl/* Helper function,
1a357c873baa79c0b82ab1d084f942cfcc8ba1c0Pavel Reichl * cached_ac => access granted
1a357c873baa79c0b82ab1d084f942cfcc8ba1c0Pavel Reichl * !cached_ac => access denied
1a357c873baa79c0b82ab1d084f942cfcc8ba1c0Pavel Reichlstatic errno_t sdap_access_decide_offline(bool cached_ac)
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_FUNC, "Access granted by cached credentials\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_FUNC, "Access denied by cached credentials\n");
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bosestatic int sdap_access_filter_retry(struct tevent_req *req)
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose tevent_req_data(req, struct sdap_access_filter_req_ctx);
ee3b4d1d0a6a438626e2dbbae3bf96d2d6faaf18eindenbom subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "sdap_id_op_connect_send failed: %d (%s)\n", ret, strerror(ret));
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose tevent_req_set_callback(subreq, sdap_access_filter_connect_done, req);
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bosestatic void sdap_access_filter_connect_done(struct tevent_req *subreq)
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher struct tevent_req *req = tevent_req_callback_data(subreq,
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose tevent_req_data(req, struct sdap_access_filter_req_ctx);
1a357c873baa79c0b82ab1d084f942cfcc8ba1c0Pavel Reichl ret = sdap_access_decide_offline(state->cached_access);
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher /* Connection to LDAP succeeded
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher * Send filter request
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Could not start LDAP communication\n");
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichl tevent_req_set_callback(subreq, sdap_access_filter_done, req);
ed2136eebe3fbffccb8a5c548afdb815a46d5d39Pavel Reichlstatic void sdap_access_filter_done(struct tevent_req *subreq)
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher tevent_req_callback_data(subreq, struct tevent_req);
32266b2c1c6b8bf95f3ba8fd7f3ff2ef63d8fb9aSumit Bose tevent_req_data(req, struct sdap_access_filter_req_ctx);
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher ret = sdap_get_generic_recv(subreq, state,
ee3b4d1d0a6a438626e2dbbae3bf96d2d6faaf18eindenbom ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
1a357c873baa79c0b82ab1d084f942cfcc8ba1c0Pavel Reichl ret = sdap_access_decide_offline(state->cached_access);
46ebf4415306454e1d062b61a2495b7cdb821c0fPavel Reichl sss_log(SSS_LOG_ERR, MALFORMED_FILTER, state->filter);
46ebf4415306454e1d062b61a2495b7cdb821c0fPavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, MALFORMED_FILTER, state->filter);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "sdap_get_generic_send() returned error [%d][%s]\n",
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher /* Check the number of responses we got
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher * If it's exactly 1, we passed the check
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher * If it's < 1, we failed the check
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher * Anything else is an error
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "User [%s] was not found with the specified filter. "
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher /* It should not be possible to get more than one reply
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher * here, since we're doing a base-scoped search
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher else { /* Ok, we got a single reply */
46ebf4415306454e1d062b61a2495b7cdb821c0fPavel Reichl /* Save "allow" to the cache for future offline access checks. */
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_FUNC, "Access granted by online lookup\n");
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher /* Save "disallow" to the cache for future offline
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher * access checks.
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_TRACE_FUNC, "Access denied by online lookup\n");
4c38ed71727a9668cec4d3bd1bf8f7e77ac5e6c0Pavel Reichl tret = sdap_save_user_cache_bool(state->domain, state->username,
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher /* Failing to save to the cache is non-fatal.
35480afaefafb77b28d35b29039989ab888aafe9Stephen Gallagher * Just return the result.
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user access attribute\n");
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorcestatic errno_t sdap_access_filter_recv(struct tevent_req *req)
e1522a568dac91499f5f2039ef978a0a4ceeb3b3Sumit Bose#define AUTHR_SRV_MISSING_MSG "Authorized service attribute missing, " \
e1522a568dac91499f5f2039ef978a0a4ceeb3b3Sumit Bose "access denied"
e1522a568dac91499f5f2039ef978a0a4ceeb3b3Sumit Bose#define AUTHR_SRV_DENY_MSG "Access denied by authorized service attribute"
e1522a568dac91499f5f2039ef978a0a4ceeb3b3Sumit Bose#define AUTHR_SRV_NO_MATCH_MSG "Authorized service attribute has " \
e1522a568dac91499f5f2039ef978a0a4ceeb3b3Sumit Bose "no matching rule, access denied"
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorcestatic errno_t sdap_access_service(struct pam_data *pd,
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher unsigned int i;
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_SERVICE);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Missing authorized services. Access denied\n");
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher strcasecmp(pd->service, service+1) == 0) {
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher /* This service is explicitly denied */
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "Access denied by [%s]\n", service);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher /* A denial trumps all. Break here */
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher } else if (strcasecmp(pd->service, service) == 0) {
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher /* This service is explicitly allowed */
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "Access granted for [%s]\n", service);
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher /* We still need to loop through to make sure
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher * that it's not also explicitly denied
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher /* This user has access to all services */
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "Access granted to all services\n");
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher /* We still need to loop through to make sure
2a2f642aae37e3f41cbbda162a74c2b946a4521fStephen Gallagher * that it's not also explicitly denied
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "No matching service rule found\n");
586793c2f95b574695c5520cf6f3ef019fb58519Stephen Gallagher (const uint8_t *) AUTHR_SRV_NO_MATCH_MSG);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
4c38ed71727a9668cec4d3bd1bf8f7e77ac5e6c0Pavel Reichlstatic errno_t sdap_save_user_cache_bool(struct sss_domain_info *domain,
4c38ed71727a9668cec4d3bd1bf8f7e77ac5e6c0Pavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
4c38ed71727a9668cec4d3bd1bf8f7e77ac5e6c0Pavel Reichl ret = sysdb_attrs_add_bool(attrs, attr_name, value);
4c38ed71727a9668cec4d3bd1bf8f7e77ac5e6c0Pavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "Could not set up attrs\n");
4c38ed71727a9668cec4d3bd1bf8f7e77ac5e6c0Pavel Reichl ret = sysdb_set_user_attr(domain, username, attrs, SYSDB_MOD_REP);
4c38ed71727a9668cec4d3bd1bf8f7e77ac5e6c0Pavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user access attribute\n");
dfd71fc92db940b2892cc996911cec03d7b6c52bSimo Sorcestatic errno_t sdap_access_host(struct ldb_message *user_entry)
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman unsigned int i;
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_HOST);
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CRIT_FAILURE, "Missing hosts. Access denied\n");
bf6f1b3d49e17b1adf0448c0b06e94b1e52ddffdLukas Slebodnik if (gethostname(hostname, HOST_NAME_MAX) == -1) {
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov "Unable to get system hostname. Access denied\n");
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman /* FIXME: PADL's pam_ldap also calls gethostbyname() on the hostname
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman * in some attempt to get aliases and/or FQDN for the machine.
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman * Not sure this is a good idea, but we might want to add it in
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman * order to be compatible...
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman /* This host is explicitly denied */
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "Access denied by [%s]\n", host);
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman /* A denial trumps all. Break here */
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman /* This host is explicitly allowed */
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "Access granted for [%s]\n", host);
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman /* We still need to loop through to make sure
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman * that it's not also explicitly denied
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman /* This user has access to all hosts */
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "Access granted to all hosts\n");
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman /* We still need to loop through to make sure
3612c73e7957721bcbf31d0118e2ac210eb46b88Pierre Ossman * that it's not also explicitly denied
83bf46f4066e3d5e838a32357c201de9bd6ecdfdNikolai Kondrashov DEBUG(SSSDBG_CONF_SETTINGS, "No matching host rule found\n");
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiyerrno_t sdap_access_rhost(struct ldb_message *user_entry, char *pam_rhost)
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy unsigned int i;
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* If user_entry is NULL do not perform any checks */
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy "user_entry is NULL, that is not possible, "
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy "so we just reject access\n");
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* If pam_rhost is NULL do not perform any checks */
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy "pam_rhost is NULL, no rhost check is possible\n");
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* When the access is local we get empty string as pam_rhost
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy in which case we should not evaluate rhost access rules */
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* FIXME: I think ideally should have LDAP to define what to do in
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy * this case */
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy "pam_rhost is empty, possible local access, "
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy "no rhost check possible\n");
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* If rhost validation is enabled and entry has no relevant attribute -
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy * deny access */
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_RHOST);
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy DEBUG(SSSDBG_CONF_SETTINGS, "Missing rhost entries. Access denied\n");
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy be_rhost_rule = (char *)el->values[i].data;
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy && strcasecmp(pam_rhost, be_rhost_rule+1) == 0) {
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* This rhost is explicitly denied */
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy "Access from [%s] denied by [%s]\n",
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* A denial trumps all. Break here */
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy } else if (strcasecmp(pam_rhost, be_rhost_rule) == 0) {
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* This rhost is explicitly allowed */
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy "Access from [%s] granted by [%s]\n",
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* We still need to loop through to make sure
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy * that it's not also explicitly denied
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy } else if (strcmp("*", be_rhost_rule) == 0) {
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* This user has access from anywhere */
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy "Access from [%s] granted by [*]\n", pam_rhost);
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy /* We still need to loop through to make sure
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy * that it's not also explicitly denied
f34a8330c1615511795847b0a1454249d782db2aAlexey Kamenskiy "No matching rhost rules found\n");
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic void sdap_access_ppolicy_get_lockout_done(struct tevent_req *subreq);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic int sdap_access_ppolicy_retry(struct tevent_req *req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic errno_t sdap_access_ppolicy_step(struct tevent_req *req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic void sdap_access_ppolicy_step_done(struct tevent_req *subreq);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* cached results of access control checks */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* default DNs to ppolicy */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichlstatic struct tevent_req *
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "Performing access ppolicy check for user [%s]\n", username);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl state->cached_access = ldb_msg_find_attr_as_bool(
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl user_entry, SYSDB_LDAP_ACCESS_CACHED_LOCKOUT, false);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Ok, we have one result, check if we are online or offline */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Ok, we're offline. Return from the cache */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sdap_access_decide_offline(state->cached_access);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sdap_get_basedn_user_entry(user_entry, state->username,
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl DEBUG(SSSDBG_TRACE_FUNC, "Checking ppolicy against LDAP\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic int sdap_access_ppolicy_retry(struct tevent_req *req)
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "sdap_id_op_connect_send failed: %d (%s)\n",
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl tevent_req_set_callback(subreq, sdap_access_ppolicy_connect_done, req);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichlstatic const char**
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichlget_default_ppolicy_dns(TALLOC_CTX *mem_ctx, struct sdap_domain *sdom)
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* +1 to have space for final NULL */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ppolicy_dns = talloc_array(mem_ctx, const char*, count + 1);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl for(i = 0; i < count; i++) {
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ppolicy_dns[i] = talloc_asprintf(mem_ctx, "cn=ppolicy,ou=policies,%s",
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic void sdap_access_ppolicy_connect_done(struct tevent_req *subreq)
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl req = tevent_req_callback_data(subreq, struct tevent_req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sdap_id_op_connect_recv(subreq, &dp_error);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sdap_access_decide_offline(state->cached_access);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ppolicy_dn = dp_opt_get_string(state->opts->basic,
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* option was configured */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl state->ppolicy_dns = talloc_array(state, const char*, 2);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "Could not allocate ppolicy_dns.\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* try to determine default value */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "ldap_pwdlockout_dn was not defined in configuration file.\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl state->ppolicy_dns = get_default_ppolicy_dns(state, state->opts->sdom);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Connection to LDAP succeeded
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * Send 'pwdLockout' request
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl ret = sdap_access_ppolicy_get_lockout_step(req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "sdap_access_ppolicy_get_lockout_step failed: [%d][%s]\n",
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlsdap_access_ppolicy_get_lockout_step(struct tevent_req *req)
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKOUT, NULL };
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* no more DNs to try */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl if (state->ppolicy_dns[state->ppolicy_dns_index] == NULL) {
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl DEBUG(SSSDBG_TRACE_FUNC, "No more DNs to try.\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "Trying to find out if ppolicy is enabled using the DN: %s\n",
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "Could not start LDAP communication\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* try next basedn */
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl tevent_req_set_callback(subreq, sdap_access_ppolicy_get_lockout_done, req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic void sdap_access_ppolicy_get_lockout_done(struct tevent_req *subreq)
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl req = tevent_req_callback_data(subreq, struct tevent_req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
d80412010e18d1f48aa402bf7e31a909008edb24Jakub Hrozek DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve ppolicy\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Check the number of responses we got
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * If it's exactly 1, we passed the check
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * If it's < 1, we failed the check
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * Anything else is an error
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Didn't find ppolicy attribute */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Try using next $search_base */
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl ret = sdap_access_ppolicy_get_lockout_step(req);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* No more search bases to try */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "[%s] was not found. Granting access.\n",
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "sdap_access_ppolicy_get_lockout_step failed: "
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "[%d][%s]\n",
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* It should not be possible to get more than one reply
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * here, since we're doing a base-scoped search
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl } else { /* Ok, we got a single reply */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sysdb_attrs_get_bool(results[0], SYSDB_LDAP_ACCESS_LOCKOUT,
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "Error reading %s: [%s]\n", SYSDB_LDAP_ACCESS_LOCKOUT,
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "Password policy is enabled on LDAP server.\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* ppolicy is enabled => find out if account is locked */
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "sdap_access_ppolicy_step failed: [%d][%s].\n",
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "Password policy is disabled on LDAP server "
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "- storing 'access granted' in sysdb.\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl tret = sdap_save_user_cache_bool(state->domain, state->username,
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Failing to save to the cache is non-fatal.
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * Just return the result.
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "Failed to set user locked attribute\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* release connection */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl tret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "sdap_get_generic_send() returned error [%d][%s]\n",
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlerrno_t sdap_access_ppolicy_step(struct tevent_req *req)
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl const char *attrs[] = { SYSDB_LDAP_ACCESS_LOCKED_TIME,
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "sdap_access_ppolicy_send failed.\n");
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl tevent_req_set_callback(subreq, sdap_access_ppolicy_step_done, req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlis_account_locked(const char *pwdAccountLockedTime,
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl /* Default action is to consider account to be locked. */
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl /* account is permanently locked */
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl /* We do *not* care about exact value of account locked time, we
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl * only *do* care if the value is equal to
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl * PERMANENTLY_LOCKED_ACCOUNT, which means that account is locked
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl * permanently.
871f340834f25ca92a481718939164e708a70e29Pavel Reichl "Account of: %s is being blocked by password policy, "
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "but value: [%s] value is ignored by SSSD.\n",
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl /* Account may be locked out from natural reasons (too many attempts,
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl * expired password). In this case, pwdAccountLockedTime is also set,
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl * to the time of lock out.
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl ret = sss_utc_to_time_t(pwdAccountLockedTime, "%Y%m%d%H%M%SZ",
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl DEBUG(SSSDBG_TRACE_FUNC, "sss_utc_to_time_t failed with %d:%s.\n",
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl /* Account was NOT locked in past. */
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl } else if (pwdAccountLockedDurationTime != NULL) {
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl duration = strtouint32(pwdAccountLockedDurationTime, NULL, 0);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl /* Lockout has expired */
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl if (duration != 0 && difftime(now, lock_time) > duration) {
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "Unexpected value of password policy mode: %d.\n", pwpol_mode);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic void sdap_access_ppolicy_step_done(struct tevent_req *subreq)
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl req = tevent_req_callback_data(subreq, struct tevent_req);
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl state = tevent_req_data(req, struct sdap_access_ppolicy_req_ctx);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sdap_id_op_done(state->sdap_op, ret, &dp_error);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sdap_access_decide_offline(state->cached_access);
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "sdap_get_generic_send() returned error [%d][%s]\n",
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Check the number of responses we got
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * If it's exactly 1, we passed the check
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * If it's < 1, we failed the check
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * Anything else is an error
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "User [%s] was not found with the specified filter. "
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "num_results > 0, but results is NULL\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* It should not be possible to get more than one reply
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * here, since we're doing a base-scoped search
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "Received multiple replies\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl } else { /* Ok, we got a single reply */
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl ret = sysdb_attrs_get_string(results[0], SYSDB_LDAP_ACESS_LOCKOUT_DURATION,
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl /* This attribute might not be set even if account is locked */
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl ret = sysdb_attrs_get_string(results[0], SYSDB_LDAP_ACCESS_LOCKED_TIME,
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "timezone specifier in ppolicy is not supported\n");
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "is_account_locked failed: %d:[%s].\n",
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichl "Account will be considered to be locked.\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Attribute SYSDB_LDAP_ACCESS_LOCKED_TIME in not be present unless
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * user's account is blocked by password policy.
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "Attribute %s failed to be obtained - [%d][%s].\n",
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl SYSDB_LDAP_ACCESS_LOCKED_TIME, ret, strerror(ret));
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "Access denied by online lookup - account is locked.\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl "Access granted by online lookup - account is not locked.\n");
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Save '!locked' to the cache for future offline access checks.
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * Locked == true => access denied,
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * Locked == false => access granted
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl tret = sdap_save_user_cache_bool(state->domain, state->username,
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl /* Failing to save to the cache is non-fatal.
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl * Just return the result.
2a91d3dd0ce4387332db27bd1a0c0005c74f870ePavel Reichl DEBUG(SSSDBG_CRIT_FAILURE, "Failed to set user locked attribute\n");
13ec767e6ca3e435e119f1f07bda10eb213383f6Pavel Reichlstatic errno_t sdap_access_ppolicy_recv(struct tevent_req *req)
719985a9e2aeaf2cba960f1525325ff125b7e19bPavel Reichlstatic errno_t sdap_get_basedn_user_entry(struct ldb_message *user_entry,
719985a9e2aeaf2cba960f1525325ff125b7e19bPavel Reichl const char **_basedn)
719985a9e2aeaf2cba960f1525325ff125b7e19bPavel Reichl basedn = ldb_msg_find_attr_as_string(user_entry, SYSDB_ORIG_DN, NULL);
719985a9e2aeaf2cba960f1525325ff125b7e19bPavel Reichl DEBUG(SSSDBG_CRIT_FAILURE,"Could not find originalDN for user [%s]\n",