URL: https://github.com/SSSD/sssd/pull/269
Author: NWilson
 Title: #269: Add support for ActiveDirectory's logonHours restrictions
Action: opened

PR body:
"""
This is a straightforward patch for denying access to a user when the user is 
not permitted to access their account due to logonHours restrictions.

This matches the default behaviour for domain-joined Windows machines. When 
outside the logonHours, all types of authentication are denied 
(password/Kerberos/certificate) - so it is appropriate to put this check inside 
the PAM "account" rules.
"""

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/269/head:pr269
git checkout pr269
From a1fb09cd1a7dd6df285e27850917e9437d166764 Mon Sep 17 00:00:00 2001
From: Nicholas Wilson <nicholas.wil...@realvnc.com>
Date: Thu, 11 May 2017 13:38:24 +0100
Subject: [PATCH] Add support for ActiveDirectory's logonHours restrictions

---
 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                  | 14 +++++++++
 src/providers/ad/ad_opts.c               |  1 +
 src/providers/ipa/ipa_opts.c             |  1 +
 src/providers/ldap/ldap_opts.c           |  3 ++
 src/providers/ldap/sdap.h                |  1 +
 src/providers/ldap/sdap_access.c         | 50 ++++++++++++++++++++++++++++++++
 src/responder/nss/nss_cmd.c              |  1 +
 src/responder/nss/nss_protocol_sid.c     |  1 +
 12 files changed, 76 insertions(+)

diff --git a/src/config/SSSDConfig/__init__.py.in b/src/config/SSSDConfig/__init__.py.in
index 5ca31cf..bd41d7a 100644
--- a/src/config/SSSDConfig/__init__.py.in
+++ b/src/config/SSSDConfig/__init__.py.in
@@ -347,6 +347,7 @@ option_strings = {
     'ldap_pwd_attribute' : _('Attribute indicating that server side password policies are active'),
     'ldap_user_ad_account_expires' : _('accountExpires attribute of AD'),
     'ldap_user_ad_user_account_control' : _('userAccountControl attribute of AD'),
+    'ldap_user_ad_logon_hours' : _('logonHours attribute of AD'),
     'ldap_ns_account_lock' : _('nsAccountLock attribute'),
     'ldap_user_nds_login_disabled' : _('loginDisabled attribute of NDS'),
     'ldap_user_nds_login_expiration_time' : _('loginExpirationTime attribute of NDS'),
diff --git a/src/config/cfg_rules.ini b/src/config/cfg_rules.ini
index 64cb147..7ae7c26 100644
--- a/src/config/cfg_rules.ini
+++ b/src/config/cfg_rules.ini
@@ -654,6 +654,7 @@ option = ldap_tls_reqcert
 option = ldap_uri
 option = ldap_user_ad_account_expires
 option = ldap_user_ad_user_account_control
+option = ldap_user_ad_logon_hours
 option = ldap_user_authorized_host
 option = ldap_user_authorized_service
 option = ldap_user_auth_type
diff --git a/src/config/etc/sssd.api.d/sssd-ldap.conf b/src/config/etc/sssd.api.d/sssd-ldap.conf
index c2ad346..67ea7cc 100644
--- a/src/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/src/config/etc/sssd.api.d/sssd-ldap.conf
@@ -79,6 +79,7 @@ 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
+ldap_user_ad_logon_hours = str, None, false
 ldap_ns_account_lock = str, None, false
 ldap_user_nds_login_disabled = str, None, false
 ldap_user_nds_login_expiration_time = str, None, false
diff --git a/src/db/sysdb.h b/src/db/sysdb.h
index 62c561b..ff803d6 100644
--- a/src/db/sysdb.h
+++ b/src/db/sysdb.h
@@ -173,6 +173,7 @@
 
 #define SYSDB_AD_ACCOUNT_EXPIRES "adAccountExpires"
 #define SYSDB_AD_USER_ACCOUNT_CONTROL "adUserAccountControl"
+#define SYSDB_AD_LOGON_HOURS "adLogonHours"
 
 #define SYSDB_DEFAULT_VIEW_NAME "default"
 #define SYSDB_LOCAL_VIEW_NAME "LOCAL" /* reserved for client-side overrides */
diff --git a/src/man/sssd-ldap.5.xml b/src/man/sssd-ldap.5.xml
index 739ae15..b0094f4 100644
--- a/src/man/sssd-ldap.5.xml
+++ b/src/man/sssd-ldap.5.xml
@@ -566,6 +566,20 @@
                 </varlistentry>
 
                 <varlistentry>
+                    <term>ldap_user_ad_logon_hours (string)</term>
+                    <listitem>
+                        <para>
+                            When using ldap_account_expire_policy=ad, this
+                            parameter contains the name of an LDAP attribute
+                            storing the user's permitted logon hours.
+                        </para>
+                        <para>
+                            Default: logonHours
+                        </para>
+                    </listitem>
+                </varlistentry>
+
+                <varlistentry>
                     <term>ldap_ns_account_lock (string)</term>
                     <listitem>
                         <para>
diff --git a/src/providers/ad/ad_opts.c b/src/providers/ad/ad_opts.c
index fc1dc67..2ebddfc 100644
--- a/src/providers/ad/ad_opts.c
+++ b/src/providers/ad/ad_opts.c
@@ -211,6 +211,7 @@ struct sdap_attr_map ad_2008r2_user_map[] = {
     { "ldap_user_authorized_service", NULL, 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_user_ad_logon_hours", "logonHours", SYSDB_AD_LOGON_HOURS, NULL},
     { "ldap_ns_account_lock", NULL, SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", NULL, SYSDB_AUTHORIZED_HOST, NULL },
     { "ldap_user_nds_login_disabled", NULL, SYSDB_NDS_LOGIN_DISABLED, NULL },
diff --git a/src/providers/ipa/ipa_opts.c b/src/providers/ipa/ipa_opts.c
index f9f3a2a..88b402c 100644
--- a/src/providers/ipa/ipa_opts.c
+++ b/src/providers/ipa/ipa_opts.c
@@ -196,6 +196,7 @@ 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_user_ad_logon_hours", "logonHours", SYSDB_AD_LOGON_HOURS, NULL},
     { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL },
     { "ldap_user_nds_login_disabled", "loginDisabled", SYSDB_NDS_LOGIN_DISABLED, NULL },
diff --git a/src/providers/ldap/ldap_opts.c b/src/providers/ldap/ldap_opts.c
index c6efe33..01a3687 100644
--- a/src/providers/ldap/ldap_opts.c
+++ b/src/providers/ldap/ldap_opts.c
@@ -172,6 +172,7 @@ 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_user_ad_logon_hours", "logonHours", SYSDB_AD_LOGON_HOURS, NULL},
     { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL },
     { "ldap_user_nds_login_disabled", "loginDisabled", SYSDB_NDS_LOGIN_DISABLED, NULL },
@@ -230,6 +231,7 @@ 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_user_ad_logon_hours", "logonHours", SYSDB_AD_LOGON_HOURS, NULL},
     { "ldap_ns_account_lock", "nsAccountLock", SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL },
     { "ldap_user_nds_login_disabled", "loginDisabled", SYSDB_NDS_LOGIN_DISABLED, NULL },
@@ -288,6 +290,7 @@ struct sdap_attr_map gen_ad2008r2_user_map[] = {
     { "ldap_user_authorized_service", NULL, 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_user_ad_logon_hours", "logonHours", SYSDB_AD_LOGON_HOURS, NULL},
     { "ldap_ns_account_lock", NULL, SYSDB_NS_ACCOUNT_LOCK, NULL},
     { "ldap_user_authorized_host", NULL, SYSDB_AUTHORIZED_HOST, NULL },
     { "ldap_user_nds_login_disabled", NULL, SYSDB_NDS_LOGIN_DISABLED, NULL },
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index afdc019..2e57ad5 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -277,6 +277,7 @@ enum sdap_user_attrs {
     SDAP_AT_AUTH_SVC,
     SDAP_AT_AD_ACCOUNT_EXPIRES,
     SDAP_AT_AD_USER_ACCOUNT_CONTROL,
+    SDAP_AT_AD_LOGON_HOURS,
     SDAP_AT_NS_ACCOUNT_LOCK,
     SDAP_AT_AUTHORIZED_HOST,
     SDAP_AT_NDS_LOGIN_DISABLED,
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index 6e8af73..475a9f7 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -426,6 +426,8 @@ static errno_t sdap_account_expired_shadow(struct pam_data *pd,
 #define AD_TO_UNIX_TIME_CONST 11644473600LL
 #define AD_DISABLE_MESSAGE "The user account is disabled on the AD server"
 #define AD_EXPIRED_MESSAGE "The user account is expired on the AD server"
+#define AD_OUTSIDE_LOGONHOURS_MESSAGE \
+    "Outside of the user's login hours on the AD server"
 
 static bool ad_account_expired(uint64_t expiration_time)
 {
@@ -455,11 +457,41 @@ static bool ad_account_expired(uint64_t expiration_time)
     return false;
 }
 
+static bool ad_account_outside_logonhours(const uint8_t *data)
+{
+    time_t now;
+    struct tm tm;
+    int hour_of_week, err;
+
+    if (data == NULL) {
+        return false;
+    }
+
+    now = time(NULL);
+    if (now == ((time_t) -1)) {
+        err = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "time failed [%d][%s].\n", err, strerror(err));
+        return true;
+    }
+
+    if (gmtime_r(&now, &tm) == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "gmtime_r failed.\n");
+        return true;
+    }
+
+    hour_of_week = tm.tm_wday * 24 + tm.tm_hour;
+    hour_of_week = MAX(0, MIN(hour_of_week, 167));
+
+    return !(data[hour_of_week / 8] & (1 << (hour_of_week % 8)));
+}
+
 static errno_t sdap_account_expired_ad(struct pam_data *pd,
                                        struct ldb_message *user_entry)
 {
     uint32_t uac;
     uint64_t expiration_time;
+    const struct ldb_val *logon_hours;
     int ret;
 
     DEBUG(SSSDBG_TRACE_FUNC,
@@ -476,6 +508,13 @@ static errno_t sdap_account_expired_ad(struct pam_data *pd,
           "Expiration time for user [%s] is [%"PRIu64"].\n",
            pd->user, expiration_time);
 
+    logon_hours = ldb_msg_find_ldb_val(user_entry, SYSDB_AD_LOGON_HOURS);
+    if (logon_hours != NULL && logon_hours->length != 21) {
+        logon_hours = NULL;
+    }
+    DEBUG(SSSDBG_TRACE_ALL, "Logon hours for user [%s] are %s.\n",
+          pd->user, logon_hours ? "set" : "unset");
+
     if (uac & UAC_ACCOUNTDISABLE) {
 
         ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
@@ -497,6 +536,17 @@ static errno_t sdap_account_expired_ad(struct pam_data *pd,
         }
 
         return ERR_ACCOUNT_EXPIRED;
+
+    } else if (ad_account_outside_logonhours(logon_hours->data)) {
+
+        ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
+                               sizeof(AD_OUTSIDE_LOGONHOURS_MESSAGE),
+                               (const uint8_t *) AD_OUTSIDE_LOGONHOURS_MESSAGE);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
+        }
+
+        return ERR_ACCESS_DENIED;
     }
 
     return EOK;
diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
index a4727c1..c613ab4 100644
--- a/src/responder/nss/nss_cmd.c
+++ b/src/responder/nss/nss_cmd.c
@@ -984,6 +984,7 @@ static errno_t nss_cmd_getorigbyname(struct cli_ctx *cli_ctx)
                                       SYSDB_DEFAULT_OVERRIDE_NAME,
                                       SYSDB_AD_ACCOUNT_EXPIRES,
                                       SYSDB_AD_USER_ACCOUNT_CONTROL,
+                                      SYSDB_AD_LOGON_HOURS,
                                       SYSDB_SSH_PUBKEY,
                                       SYSDB_USER_CERT,
                                       SYSDB_USER_EMAIL,
diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c
index 61357c2..531c214 100644
--- a/src/responder/nss/nss_protocol_sid.c
+++ b/src/responder/nss/nss_protocol_sid.c
@@ -233,6 +233,7 @@ nss_protocol_fill_orig(struct nss_ctx *nss_ctx,
                                  SYSDB_DEFAULT_OVERRIDE_NAME,
                                  SYSDB_AD_ACCOUNT_EXPIRES,
                                  SYSDB_AD_USER_ACCOUNT_CONTROL,
+                                 SYSDB_AD_LOGON_HOURS,
                                  SYSDB_SSH_PUBKEY,
                                  SYSDB_USER_CERT,
                                  SYSDB_USER_EMAIL,
_______________________________________________
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