From 2a2f642aae37e3f41cbbda162a74c2b946a4521f Mon Sep 17 00:00:00 2001 From: Stephen Gallagher Date: Mon, 20 Dec 2010 16:05:14 -0500 Subject: Add authorizedService support https://fedorahosted.org/sssd/ticket/670 --- src/config/SSSDConfig.py | 1 + src/config/etc/sssd.api.d/sssd-ldap.conf | 1 + src/db/sysdb.h | 2 + src/man/sssd-ldap.5.xml | 26 ++++++ 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 | 135 +++++++++++++++++++++++++++++++ src/providers/ldap/sdap_access.h | 2 + 10 files changed, 176 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/config/SSSDConfig.py b/src/config/SSSDConfig.py index de7f66a6..b1177178 100644 --- a/src/config/SSSDConfig.py +++ b/src/config/SSSDConfig.py @@ -166,6 +166,7 @@ option_strings = { 'ldap_user_shadow_inactive' : _('shadowInactive attribute'), 'ldap_user_shadow_expire' : _('shadowExpire attribute'), 'ldap_user_shadow_flag' : _('shadowFlag attribute'), + 'ldap_user_authorized_service' : _('Attribute listing authorized PAM services'), '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 c41ff7cc..c2179f2d 100644 --- a/src/config/etc/sssd.api.d/sssd-ldap.conf +++ b/src/config/etc/sssd.api.d/sssd-ldap.conf @@ -55,6 +55,7 @@ ldap_user_shadow_expire = str, None, false 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_pwd_attribute = str, None, false ldap_group_search_base = str, None, false ldap_group_search_scope = str, None, false diff --git a/src/db/sysdb.h b/src/db/sysdb.h index b5eed49b..3fefdf21 100644 --- a/src/db/sysdb.h +++ b/src/db/sysdb.h @@ -78,6 +78,8 @@ #define SYSDB_CACHE_EXPIRE "dataExpireTimestamp" #define SYSDB_INITGR_EXPIRE "initgrExpireTimestamp" +#define SYSDB_AUTHORIZED_SERVICE "authorizedService" + #define SYSDB_NETGROUP_TRIPLE "netgroupTriple" #define SYSDB_ORIG_NETGROUP_MEMBER "originalMemberNisNetgroup" #define SYSDB_NETGROUP_MEMBER "memberNisNetgroup" diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml index 3406dc46..7a733462 100644 --- a/src/man/sssd-ldap.5.xml +++ b/src/man/sssd-ldap.5.xml @@ -523,6 +523,27 @@ + + ldap_user_authorized_service (string) + + + If access_provider=ldap and + ldap_access_order=authorized_service, SSSD will + use the presence of the authorizedService + attribute in the user's LDAP entry to determine + access privilege. + + + An explicit deny (!svc) is resolved first. Second, + SSSD searches for explicit allow (svc) and finally + for allow_all (*). + + + Default: authorizedService + + + + ldap_group_object_class (string) @@ -1108,6 +1129,11 @@ ldap_access_filter = memberOf=cn=allowedusers,ou=Groups,dc=example,dc=com expire: use ldap_account_expire_policy + + authorized_service: use + the authorizedService attribute to determine + access + Default: filter diff --git a/src/providers/ipa/ipa_common.c b/src/providers/ipa/ipa_common.c index 2e7724a6..a42cc3b4 100644 --- a/src/providers/ipa/ipa_common.c +++ b/src/providers/ipa/ipa_common.c @@ -113,7 +113,8 @@ struct sdap_attr_map ipa_user_map[] = { { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL }, { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL }, { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL }, - { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL } + { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL }, + { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, 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 a38d5cc2..f0db53f2 100644 --- a/src/providers/ldap/ldap_common.c +++ b/src/providers/ldap/ldap_common.c @@ -118,7 +118,8 @@ struct sdap_attr_map rfc2307_user_map[] = { { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL }, { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL }, { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL }, - { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL } + { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL }, + { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, NULL } }; struct sdap_attr_map rfc2307_group_map[] = { @@ -157,7 +158,8 @@ struct sdap_attr_map rfc2307bis_user_map[] = { { "ldap_user_shadow_flag", "shadowFlag", SYSDB_SHADOWPW_FLAG, NULL }, { "ldap_user_krb_last_pwd_change", "krbLastPwdChange", SYSDB_KRBPW_LASTCHANGE, NULL }, { "ldap_user_krb_password_expiration", "krbPasswordExpiration", SYSDB_KRBPW_EXPIRATION, NULL }, - { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL } + { "ldap_pwd_attribute", "pwdAttribute", SYSDB_PWD_ATTRIBUTE, NULL }, + { "ldap_user_authorized_service", "authorizedService", SYSDB_AUTHORIZED_SERVICE, 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 a1d8f05d..d5dad360 100644 --- a/src/providers/ldap/ldap_init.c +++ b/src/providers/ldap/ldap_init.c @@ -352,6 +352,8 @@ int sssm_ldap_access_init(struct be_ctx *bectx, goto done; } } + } else if (strcasecmp(order_list[c], LDAP_ACCESS_SERVICE_NAME) == 0) { + access_ctx->access_rule[c] = LDAP_ACCESS_SERVICE; } 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 8c629a3b..57865fe0 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -229,6 +229,7 @@ enum sdap_user_attrs { SDAP_AT_KP_LASTCHANGE, SDAP_AT_KP_EXPIRATION, SDAP_AT_PWD_ATTRIBUTE, + SDAP_AT_AUTH_SVC, SDAP_OPTS_USER /* attrs counter */ }; diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c index fa3f522a..4767812c 100644 --- a/src/providers/ldap/sdap_access.c +++ b/src/providers/ldap/sdap_access.c @@ -72,6 +72,17 @@ static struct tevent_req *sdap_account_expired_send(TALLOC_CTX *mem_ctx, struct sdap_access_ctx *access_ctx, const char *username, struct ldb_message *user_entry); +static errno_t sdap_access_service_recv(struct tevent_req *req, + int *pam_status); +static void sdap_access_service_done(struct tevent_req *subreq); + +static struct tevent_req *sdap_access_service_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_account_expired_done(struct tevent_req *subreq); static void sdap_access_done(struct tevent_req *req); @@ -235,6 +246,19 @@ static errno_t select_next_rule(struct tevent_req *req) tevent_req_set_callback(subreq, sdap_account_expired_done, req); return EOK; + + case LDAP_ACCESS_SERVICE: + subreq = sdap_access_service_send(state, state->ev, + state->access_ctx, + state->pd, + state->user_entry); + if (subreq == NULL) { + DEBUG(1, ("sdap_access_service_send failed.\n")); + return ENOMEM; + } + tevent_req_set_callback(subreq, sdap_access_service_done, req); + return EOK; + default: DEBUG(1, ("Unexpected access rule type. Access denied.\n")); } @@ -759,6 +783,117 @@ static void sdap_access_filter_done(struct tevent_req *subreq) return; } + +struct sdap_access_service_ctx { + int pam_status; +}; + +static struct tevent_req *sdap_access_service_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_service_ctx *state; + struct ldb_message_element *el; + unsigned int i; + char *service; + + req = tevent_req_create(mem_ctx, &state, struct sdap_access_service_ctx); + if (!req) { + return NULL; + } + + state->pam_status = PAM_PERM_DENIED; + + el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_SERVICE); + if (!el || el->num_values == 0) { + DEBUG(1, ("Missing authorized services. Access denied\n")); + ret = EOK; + goto done; + } + + for (i = 0; i < el->num_values; i++) { + service = (char *)el->values[i].data; + if (service[0] == '!' && + strcasecmp(pd->service, service+1) == 0) { + /* This service is explicitly denied */ + state->pam_status = PAM_PERM_DENIED; + DEBUG(4, ("Access denied by [%s]\n", service)); + /* A denial trumps all. Break here */ + break; + + } else if (strcasecmp(pd->service, service) == 0) { + /* This service is explicitly allowed */ + state->pam_status = PAM_SUCCESS; + DEBUG(4, ("Access granted for [%s]\n", service)); + /* We still need to loop through to make sure + * that it's not also explicitly denied + */ + } else if (strcmp("*", service) == 0) { + /* This user has access to all services */ + state->pam_status = PAM_SUCCESS; + DEBUG(4, ("Access granted to all services\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 service 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_service_recv(struct tevent_req *req, + int *pam_status) +{ + struct sdap_access_service_ctx *state = + tevent_req_data(req, struct sdap_access_service_ctx); + + TEVENT_REQ_RETURN_ON_ERROR(req); + + *pam_status = state->pam_status; + + return EOK; +} + +static void sdap_access_service_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_service_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 9b8e45bd..66193a6d 100644 --- a/src/providers/ldap/sdap_access.h +++ b/src/providers/ldap/sdap_access.h @@ -31,6 +31,7 @@ #define LDAP_ACCESS_FILTER_NAME "filter" #define LDAP_ACCESS_EXPIRE_NAME "expire" +#define LDAP_ACCESS_SERVICE_NAME "authorized_service" #define LDAP_ACCOUNT_EXPIRE_SHADOW "shadow" @@ -38,6 +39,7 @@ enum ldap_access_rule { LDAP_ACCESS_EMPTY = -1, LDAP_ACCESS_FILTER = 0, LDAP_ACCESS_EXPIRE, + LDAP_ACCESS_SERVICE, LDAP_ACCESS_LAST }; -- cgit