From 3612c73e7957721bcbf31d0118e2ac210eb46b88 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Wed, 22 Dec 2010 22:29:03 +0100 Subject: Add host access control support https://fedorahosted.org/sssd/ticket/746 --- src/config/SSSDConfig.py | 1 + src/config/etc/sssd.api.d/sssd-ldap.conf | 1 + src/db/sysdb.h | 1 + src/man/sssd-ldap.5.xml | 24 +++++ src/providers/ipa/ipa_common.c | 3 +- src/providers/ldap/ldap_common.c | 6 +- src/providers/ldap/ldap_init.c | 2 + src/providers/ldap/sdap.h | 1 + src/providers/ldap/sdap_access.c | 146 +++++++++++++++++++++++++++++++ src/providers/ldap/sdap_access.h | 2 + 10 files changed, 184 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py index 9c61f06f5..5135174a8 100644 --- a/src/config/SSSDConfig.py +++ b/src/config/SSSDConfig.py @@ -174,6 +174,7 @@ option_strings = { 'ldap_user_shadow_expire' : _('shadowExpire attribute'), 'ldap_user_shadow_flag' : _('shadowFlag attribute'), 'ldap_user_authorized_service' : _('Attribute listing authorized PAM services'), + 'ldap_user_authorized_host' : _('Attribute listing authorized server hosts'), 'ldap_user_krb_last_pwd_change' : _('krbLastPwdChange attribute'), 'ldap_user_krb_password_expiration' : _('krbPasswordExpiration attribute'), 'ldap_pwd_attribute' : _('Attribute indicating that server side password policies are active'), diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf index 0e1b2ca55..5fd0cfb58 100644 --- a/src/config/etc/sssd.api.d/sssd-ldap.conf +++ b/src/config/etc/sssd.api.d/sssd-ldap.conf @@ -60,6 +60,7 @@ ldap_user_shadow_flag = str, None, false ldap_user_krb_last_pwd_change = str, None, false ldap_user_krb_password_expiration = str, None, false ldap_user_authorized_service = str, None, false +ldap_user_authorized_host = str, None, false ldap_pwd_attribute = str, None, false ldap_user_ad_account_expires = str, None, false ldap_user_ad_user_account_control = str, None, false diff --git a/src/db/sysdb.h b/src/db/sysdb.h index b7256911a..e6f9b4a7c 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -79,6 +79,7 @@ #define SYSDB_INITGR_EXPIRE "initgrExpireTimestamp" #define SYSDB_AUTHORIZED_SERVICE "authorizedService" +#define SYSDB_AUTHORIZED_HOST "authorizedHost" #define SYSDB_NETGROUP_TRIPLE "netgroupTriple" #define SYSDB_ORIG_NETGROUP_MEMBER "originalMemberNisNetgroup" diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml index 58665eb4e..2a39732b6 100644 --- a/src/man/sssd-ldap.5.xml +++ b/src/man/sssd-ldap.5.xml @@ -586,6 +586,26 @@ + + ldap_user_authorized_host (string) + + + If access_provider=ldap and + ldap_access_order=host, SSSD will use the presence + of the host attribute in the user's LDAP entry to + determine access privilege. + + + An explicit deny (!host) is resolved first. Second, + SSSD searches for explicit allow (host) and finally + for allow_all (*). + + + Default: host + + + + ldap_group_object_class (string) @@ -1248,6 +1268,10 @@ ldap_access_filter = memberOf=cn=allowedusers,ou=Groups,dc=example,dc=com the authorizedService attribute to determine access + + host: use the host attribute + to determine access + Default: filter diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c index 579b8b60e..067f2ee85 100644 --- a/src/providers/ipa/ipa_common.c +++ b/src/providers/ipa/ipa_common.c @@ -127,7 +127,8 @@ struct sdap_attr_map ipa_user_map[] = { { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL }, { "ldap_user_ad_account_expires", "accountExpires", SYSDB_AD_ACCOUNT_EXPIRES, NULL}, { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL}, - { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL} + { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL}, + { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL } }; struct sdap_attr_map ipa_group_map[] = { diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c index ce6d41d58..9eb9cc379 100644 --- a/src/providers/ldap/ldap_common.c +++ b/src/providers/ldap/ldap_common.c @@ -131,7 +131,8 @@ struct sdap_attr_map rfc2307_user_map[] = { { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL }, { "ldap_user_ad_account_expires", "accountExpires", SYSDB_AD_ACCOUNT_EXPIRES, NULL}, { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL}, - { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL} + { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL}, + { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL } }; struct sdap_attr_map rfc2307_group_map[] = { @@ -174,7 +175,8 @@ struct sdap_attr_map rfc2307bis_user_map[] = { { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL }, { "ldap_user_ad_account_expires", "accountExpires", SYSDB_AD_ACCOUNT_EXPIRES, NULL}, { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL}, - { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL} + { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL}, + { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL } }; struct sdap_attr_map rfc2307bis_group_map[] = { diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c index 6b05690ed..62588b776 100644 --- a/src/providers/ldap/ldap_init.c +++ b/src/providers/ldap/ldap_init.c @@ -358,6 +358,8 @@ int sssm_ldap_access_init(struct be_ctx *bectx, } } else if (strcasecmp(order_list[c], LDAP_ACCESS_SERVICE_NAME) == 0) { access_ctx->access_rule[c] = LDAP_ACCESS_SERVICE; + } else if (strcasecmp(order_list[c], LDAP_ACCESS_HOST_NAME) == 0) { + access_ctx->access_rule[c] = LDAP_ACCESS_HOST; } else { DEBUG(1, ("Unexpected access rule name [%s].\n", order_list[c])); ret = EINVAL; diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index 31e72cd5b..32dc34448 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -243,6 +243,7 @@ enum sdap_user_attrs { SDAP_AT_AD_ACCOUNT_EXPIRES, SDAP_AT_AD_USER_ACCOUNT_CONTROL, SDAP_AT_NS_ACCOUNT_LOCK, + SDAP_AT_AUTHORIZED_HOST, SDAP_OPTS_USER /* attrs counter */ }; diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c index 5a6b4a5d3..9b598bc54 100644 --- a/src/providers/ldap/sdap_access.c +++ b/src/providers/ldap/sdap_access.c @@ -85,6 +85,17 @@ static struct tevent_req *sdap_access_service_send( static void sdap_account_expired_done(struct tevent_req *subreq); +static errno_t sdap_access_host_recv(struct tevent_req *req, + int *pam_status); +static void sdap_access_host_done(struct tevent_req *subreq); + +static struct tevent_req *sdap_access_host_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_access_ctx *access_ctx, + struct pam_data *pd, + struct ldb_message *user_entry); + static void sdap_access_done(struct tevent_req *req); void sdap_pam_access_handler(struct be_req *breq) { @@ -259,6 +270,18 @@ static errno_t select_next_rule(struct tevent_req *req) tevent_req_set_callback(subreq, sdap_access_service_done, req); return EOK; + case LDAP_ACCESS_HOST: + subreq = sdap_access_host_send(state, state->ev, + state->access_ctx, + state->pd, + state->user_entry); + if (subreq == NULL) { + DEBUG(1, ("sdap_access_host_send failed.\n")); + return ENOMEM; + } + tevent_req_set_callback(subreq, sdap_access_host_done, req); + return EOK; + default: DEBUG(1, ("Unexpected access rule type. Access denied.\n")); } @@ -1057,6 +1080,129 @@ static void sdap_access_service_done(struct tevent_req *subreq) return; } +struct sdap_access_host_ctx { + int pam_status; +}; + +static struct tevent_req *sdap_access_host_send( + TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct sdap_access_ctx *access_ctx, + struct pam_data *pd, + struct ldb_message *user_entry) +{ + errno_t ret; + struct tevent_req *req; + struct sdap_access_host_ctx *state; + struct ldb_message_element *el; + unsigned int i; + char *host; + char hostname[HOST_NAME_MAX+1]; + + req = tevent_req_create(mem_ctx, &state, struct sdap_access_host_ctx); + if (!req) { + return NULL; + } + + state->pam_status = PAM_PERM_DENIED; + + el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_HOST); + if (!el || el->num_values == 0) { + DEBUG(1, ("Missing hosts. Access denied\n")); + ret = EOK; + goto done; + } + + if (gethostname(hostname, sizeof(hostname)) == -1) { + DEBUG(1, ("Unable to get system hostname. Access denied\n")); + ret = EOK; + goto done; + } + + /* FIXME: PADL's pam_ldap also calls gethostbyname() on the hostname + * in some attempt to get aliases and/or FQDN for the machine. + * Not sure this is a good idea, but we might want to add it in + * order to be compatible... + */ + + for (i = 0; i < el->num_values; i++) { + host = (char *)el->values[i].data; + if (host[0] == '!' && + strcasecmp(hostname, host+1) == 0) { + /* This host is explicitly denied */ + state->pam_status = PAM_PERM_DENIED; + DEBUG(4, ("Access denied by [%s]\n", host)); + /* A denial trumps all. Break here */ + break; + + } else if (strcasecmp(hostname, host) == 0) { + /* This host is explicitly allowed */ + state->pam_status = PAM_SUCCESS; + DEBUG(4, ("Access granted for [%s]\n", host)); + /* We still need to loop through to make sure + * that it's not also explicitly denied + */ + } else if (strcmp("*", host) == 0) { + /* This user has access to all hosts */ + state->pam_status = PAM_SUCCESS; + DEBUG(4, ("Access granted to all hosts\n")); + /* We still need to loop through to make sure + * that it's not also explicitly denied + */ + } + } + + if (state->pam_status != PAM_SUCCESS) { + DEBUG(4, ("No matching host rule found\n")); + } + + ret = EOK; + +done: + if (ret == EOK) { + tevent_req_done(req); + } else { + tevent_req_error(req, ret); + } + tevent_req_post(req, ev); + + return req; +} + +static errno_t sdap_access_host_recv(struct tevent_req *req, + int *pam_status) +{ + struct sdap_access_host_ctx *state = + tevent_req_data(req, struct sdap_access_host_ctx); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *pam_status = state->pam_status; + + return EOK; +} + +static void sdap_access_host_done(struct tevent_req *subreq) +{ + errno_t ret; + struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); + struct sdap_access_req_ctx *state = + tevent_req_data(req, struct sdap_access_req_ctx); + + ret = sdap_access_host_recv(subreq, &state->pam_status); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(1, ("Error retrieving access check result.\n")); + state->pam_status = PAM_SYSTEM_ERR; + tevent_req_error(req, ret); + return; + } + + next_access_rule(req); + + return; +} + static errno_t sdap_access_recv(struct tevent_req *req, int *pam_status) { struct sdap_access_req_ctx *state = diff --git a/src/providers/ldap/sdap_access.h b/src/providers/ldap/sdap_access.h index 32c45b817..d78fdb1ed 100644 --- a/src/providers/ldap/sdap_access.h +++ b/src/providers/ldap/sdap_access.h @@ -32,6 +32,7 @@ #define LDAP_ACCESS_FILTER_NAME "filter" #define LDAP_ACCESS_EXPIRE_NAME "expire" #define LDAP_ACCESS_SERVICE_NAME "authorized_service" +#define LDAP_ACCESS_HOST_NAME "host" #define LDAP_ACCOUNT_EXPIRE_SHADOW "shadow" #define LDAP_ACCOUNT_EXPIRE_AD "ad" @@ -44,6 +45,7 @@ enum ldap_access_rule { LDAP_ACCESS_FILTER = 0, LDAP_ACCESS_EXPIRE, LDAP_ACCESS_SERVICE, + LDAP_ACCESS_HOST, LDAP_ACCESS_LAST }; -- cgit