URL: https://github.com/SSSD/sssd/pull/275
Author: akamensky
 Title: #275: Implement access verification by rhost using ldap_access_order 
rhost option
Action: synchronized

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/275/head:pr275
git checkout pr275
From dfad3dddc0ea9a14faf7cc66527f9c875937792d Mon Sep 17 00:00:00 2001
From: Alexey Kamenskiy <alexey.kamens...@chinanetcloud.com>
Date: Fri, 22 Sep 2017 16:42:41 +0800
Subject: [PATCH] Patch for issue #3458

This patch implements verification of pam_rhost against
rules stored in LDAP entry of a user.

2017-09-22: Fixed potential issue with pam_rhost being NULL
            and when pam_rhost is empty (local access)
---
 src/config/SSSDConfig/__init__.py.in     |  1 +
 src/config/cfg_rules.ini                 |  1 +
 src/config/etc/sssd.api.d/sssd-ldap.conf |  1 +
 src/db/sysdb.h                           |  1 +
 src/man/sssd-ldap.5.xml                  | 32 +++++++++++++++
 src/providers/ad/ad_opts.c               |  1 +
 src/providers/ipa/ipa_opts.c             |  1 +
 src/providers/ldap/ldap_init.c           |  2 +
 src/providers/ldap/ldap_opts.c           |  3 ++
 src/providers/ldap/sdap.h                |  1 +
 src/providers/ldap/sdap_access.c         | 68 ++++++++++++++++++++++++++++++++
 src/providers/ldap/sdap_access.h         |  2 +
 12 files changed, 114 insertions(+)

diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index cd844ce2b..72e554549 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -343,6 +343,7 @@ option_strings = {
     '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_authorized_rhost' : _('Attribute listing authorized server rhosts'),
     '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/cfg_rules.ini b/src/config/cfg_rules.ini
index 464346771..19e8c6678 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -658,6 +658,7 @@ option = ldap_uri
 option = ldap_user_ad_account_expires
 option = ldap_user_ad_user_account_control
 option = ldap_user_authorized_host
+option = ldap_user_authorized_rhost
 option = ldap_user_authorized_service
 option = ldap_user_auth_type
 option = ldap_user_certificate
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
index c2ad3463d..65b6407f6 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -76,6 +76,7 @@ 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_user_authorized_rhost = 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 21d6cf4fc..aa6146423 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -102,6 +102,7 @@
 
 #define SYSDB_AUTHORIZED_SERVICE "authorizedService"
 #define SYSDB_AUTHORIZED_HOST "authorizedHost"
+#define SYSDB_AUTHORIZED_RHOST "authorizedRHost"
 
 #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 739ae15c3..8f6f90895 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -830,6 +830,34 @@
                 </varlistentry>
 
                 <varlistentry>
+                    <term>ldap_user_authorized_rhost (string)</term>
+                    <listitem>
+                        <para>
+                            If access_provider=ldap and
+                            ldap_access_order=rhost, SSSD will use the presence
+                            of the rhost attribute in the user's LDAP entry to
+                            determine access privilege. Similarly to host
+                            verification process.
+                        </para>
+                        <para>
+                            An explicit deny (!rhost) is resolved first. Second,
+                            SSSD searches for explicit allow (rhost) and finally
+                            for allow_all (*).
+                        </para>
+                        <para>
+                            Please note that the ldap_access_order
+                            configuration option <emphasis>must</emphasis>
+                            include <quote>rhost</quote> in order for the
+                            ldap_user_authorized_rhost option
+                            to work.
+                        </para>
+                        <para>
+                            Default: rhost
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
                     <term>ldap_user_certificate (string)</term>
                     <listitem>
                         <para>
@@ -2089,6 +2117,10 @@ ldap_access_filter = (employeeType=admin)
                             to determine access
                         </para>
                         <para>
+                            <emphasis>rhost</emphasis>: use the rhost attribute
+                            to determine whether remote host can access
+                        </para>
+                        <para>
                             Default: filter
                         </para>
                         <para>
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index fc1dc6733..ac7163d56 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -213,6 +213,7 @@ struct sdap_attr_map ad_2008r2_user_map[] = {
     { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL},
     { "ldap_ns_account_lock", NULL, SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", NULL, SYSDB_AUTHORIZED_HOST, NULL },
+    { "ldap_user_authorized_rhost", NULL, SYSDB_AUTHORIZED_RHOST, NULL },
     { "ldap_user_nds_login_disabled", NULL, SYSDB_NDS_LOGIN_DISABLED, NULL },
     { "ldap_user_nds_login_expiration_time", NULL, SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", NULL, SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
index f9f3a2a69..43f4a85a8 100644
--- a/src/providers/ipa/ipa_opts.c
+++ b/src/providers/ipa/ipa_opts.c
@@ -198,6 +198,7 @@ struct sdap_attr_map ipa_user_map[] = {
     { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL},
     { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL },
+    { "ldap_user_authorized_rhost", NULL, SYSDB_AUTHORIZED_RHOST, NULL },
     { "ldap_user_nds_login_disabled", "loginDisabled", SYSDB_NDS_LOGIN_DISABLED, NULL },
     { "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index b7102adb8..43d905893 100644
--- a/src/providers/ldap/ldap_init.c
+++ b/src/providers/ldap/ldap_init.c
@@ -286,6 +286,8 @@ static errno_t set_access_rules(TALLOC_CTX *mem_ctx,
             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 if (strcasecmp(order_list[c], LDAP_ACCESS_RHOST_NAME) == 0) {
+            access_ctx->access_rule[c] = LDAP_ACCESS_RHOST;
         } else if (strcasecmp(order_list[c], LDAP_ACCESS_LOCK_NAME) == 0) {
             access_ctx->access_rule[c] = LDAP_ACCESS_LOCKOUT;
         } else if (strcasecmp(order_list[c],
diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
index c6efe332f..2236f2005 100644
--- a/src/providers/ldap/ldap_opts.c
+++ b/src/providers/ldap/ldap_opts.c
@@ -174,6 +174,7 @@ struct sdap_attr_map rfc2307_user_map[] = {
     { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL},
     { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL },
+    { "ldap_user_authorized_rhost", "rhost", SYSDB_AUTHORIZED_RHOST, NULL },
     { "ldap_user_nds_login_disabled", "loginDisabled", SYSDB_NDS_LOGIN_DISABLED, NULL },
     { "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
@@ -232,6 +233,7 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
     { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL},
     { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL },
+    { "ldap_user_authorized_rhost", "rhost", SYSDB_AUTHORIZED_RHOST, NULL },
     { "ldap_user_nds_login_disabled", "loginDisabled", SYSDB_NDS_LOGIN_DISABLED, NULL },
     { "ldap_user_nds_login_expiration_time", "loginExpirationTime", SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", "loginAllowedTimeMap", SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
@@ -290,6 +292,7 @@ struct sdap_attr_map gen_ad2008r2_user_map[] = {
     { "ldap_user_ad_user_account_control", "userAccountControl", SYSDB_AD_USER_ACCOUNT_CONTROL, NULL},
     { "ldap_ns_account_lock", NULL, SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", NULL, SYSDB_AUTHORIZED_HOST, NULL },
+    { "ldap_user_authorized_rhost", NULL, SYSDB_AUTHORIZED_RHOST, NULL },
     { "ldap_user_nds_login_disabled", NULL, SYSDB_NDS_LOGIN_DISABLED, NULL },
     { "ldap_user_nds_login_expiration_time", NULL, SYSDB_NDS_LOGIN_EXPIRATION_TIME, NULL },
     { "ldap_user_nds_login_allowed_time_map", NULL, SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP, NULL },
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index afdc01948..3a5505311 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -279,6 +279,7 @@ enum sdap_user_attrs {
     SDAP_AT_AD_USER_ACCOUNT_CONTROL,
     SDAP_AT_NS_ACCOUNT_LOCK,
     SDAP_AT_AUTHORIZED_HOST,
+    SDAP_AT_AUTHORIZED_RHOST,
     SDAP_AT_NDS_LOGIN_DISABLED,
     SDAP_AT_NDS_LOGIN_EXPIRATION_TIME,
     SDAP_AT_NDS_LOGIN_ALLOWED_TIME_MAP,
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index 4f3357a79..24d3f8742 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -97,6 +97,8 @@ static  errno_t sdap_access_service(struct pam_data *pd,
 
 static errno_t sdap_access_host(struct ldb_message *user_entry);
 
+static errno_t sdap_access_rhost(struct ldb_message *user_entry, char *rhost);
+
 enum sdap_access_control_type {
     SDAP_ACCESS_CONTROL_FILTER,
     SDAP_ACCESS_CONTROL_PPOLICY_LOCK,
@@ -309,6 +311,10 @@ static errno_t sdap_access_check_next_rule(struct sdap_access_req_ctx *state,
             ret = sdap_access_host(state->user_entry);
             break;
 
+        case LDAP_ACCESS_RHOST:
+            ret = sdap_access_rhost(state->user_entry, state->pd->rhost);
+            break;
+
         default:
             DEBUG(SSSDBG_CRIT_FAILURE,
                   "Unexpected access rule type. Access denied.\n");
@@ -1298,6 +1304,68 @@ static errno_t sdap_access_host(struct ldb_message *user_entry)
     return ret;
 }
 
+static errno_t sdap_access_rhost(struct ldb_message *user_entry, char *pam_rhost)
+{
+    errno_t ret;
+    struct ldb_message_element *el;
+    char *be_rhost_rule;
+    unsigned int i;
+
+    /* If pam_rhost is NULL do not perform any checks */
+    if (pam_rhost == NULL) {
+        DEBUG(SSSDBG_CONF_SETTINGS, "pam_rhost is NULL, no rhost check is possible\n");
+        return EOK;
+    }
+
+    /* When the access is local we get empty string as pam_rhost
+       in which case we should not evaluate rhost access rules */
+    /* FIXME: I think ideally should have LDAP to define what to do in this case */
+    if (pam_rhost[0] == '\0') {
+        DEBUG(SSSDBG_CONF_SETTINGS, "pam_rhost is empty, possible local access, no rhost check possible\n");
+        return EOK;
+    }
+
+    /* If rhost validation is enabled and entry has no relevant attribute - deny access */
+    el = ldb_msg_find_element(user_entry, SYSDB_AUTHORIZED_RHOST);
+    if (!el || el->num_values == 0) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "Missing rhost entries. Access denied\n");
+        return ERR_ACCESS_DENIED;
+    }
+
+    ret = ENOENT;
+
+    for (i = 0; i < el->num_values; i++) {
+        be_rhost_rule = (char *)el->values[i].data;
+        if (be_rhost_rule[0] == '!' && strcasecmp(pam_rhost, be_rhost_rule+1) == 0) {
+            /* This rhost is explicitly denied */
+            DEBUG(SSSDBG_CONF_SETTINGS, "Access from [%s] denied by [%s]\n", pam_rhost, be_rhost_rule);
+            /* A denial trumps all. Break here */
+            return ERR_ACCESS_DENIED;
+        } else if (strcasecmp(pam_rhost, be_rhost_rule) == 0) {
+            /* This rhost is explicitly allowed */
+            DEBUG(SSSDBG_CONF_SETTINGS, "Access from [%s] granted by [%s]\n", pam_rhost, be_rhost_rule);
+            /* We still need to loop through to make sure
+             * that it's not also explicitly denied
+             */
+            ret = EOK;
+        } else if (strcmp("*", be_rhost_rule) == 0) {
+            /* This user has access from anywhere */
+            DEBUG(SSSDBG_CONF_SETTINGS, "Access from [%s] granted by [*]\n", pam_rhost);
+            /* We still need to loop through to make sure
+             * that it's not also explicitly denied
+             */
+            ret = EOK;
+        }
+    }
+
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_CONF_SETTINGS, "No matching rhost rules found\n");
+        ret = ERR_ACCESS_DENIED;
+    }
+
+    return ret;
+}
+
 static void sdap_access_ppolicy_get_lockout_done(struct tevent_req *subreq);
 static int sdap_access_ppolicy_retry(struct tevent_req *req);
 static errno_t sdap_access_ppolicy_step(struct tevent_req *req);
diff --git a/src/providers/ldap/sdap_access.h b/src/providers/ldap/sdap_access.h
index 049daced6..86969d442 100644
--- a/src/providers/ldap/sdap_access.h
+++ b/src/providers/ldap/sdap_access.h
@@ -45,6 +45,7 @@
 #define LDAP_ACCESS_EXPIRE_POLICY_RENEW_NAME "pwd_expire_policy_renew"
 #define LDAP_ACCESS_SERVICE_NAME "authorized_service"
 #define LDAP_ACCESS_HOST_NAME "host"
+#define LDAP_ACCESS_RHOST_NAME "rhost"
 #define LDAP_ACCESS_LOCK_NAME "lockout"
 #define LDAP_ACCESS_PPOLICY_NAME "ppolicy"
 
@@ -61,6 +62,7 @@ enum ldap_access_rule {
     LDAP_ACCESS_EXPIRE,
     LDAP_ACCESS_SERVICE,
     LDAP_ACCESS_HOST,
+    LDAP_ACCESS_RHOST,
     LDAP_ACCESS_LOCKOUT,
     LDAP_ACCESS_EXPIRE_POLICY_REJECT,
     LDAP_ACCESS_EXPIRE_POLICY_WARN,
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org

Reply via email to