summaryrefslogtreecommitdiffstats
path: root/src/providers/ldap
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2010-12-21 15:45:37 +0100
committerStephen Gallagher <sgallagh@redhat.com>2011-07-08 15:20:38 -0400
commit37e7e93f1996cf50677cf59fd8af6938dd5d85b2 (patch)
tree0c7c2facfde01680e1f362fa8ec281c4ab3a6ac3 /src/providers/ldap
parentf7cfc227904771bccfda4f03f552923794dbb0c0 (diff)
downloadsssd-37e7e93f1996cf50677cf59fd8af6938dd5d85b2.tar.gz
sssd-37e7e93f1996cf50677cf59fd8af6938dd5d85b2.tar.xz
sssd-37e7e93f1996cf50677cf59fd8af6938dd5d85b2.zip
Add LDAP access control based on NDS attributes
Diffstat (limited to 'src/providers/ldap')
-rw-r--r--src/providers/ldap/ldap_common.c10
-rw-r--r--src/providers/ldap/ldap_init.c1
-rw-r--r--src/providers/ldap/sdap.h6
-rw-r--r--src/providers/ldap/sdap_access.c177
-rw-r--r--src/providers/ldap/sdap_access.h1
5 files changed, 193 insertions, 2 deletions
diff --git a/src/providers/ldap/ldap_common.c b/src/providers/ldap/ldap_common.c
index 5b75cf285..b28a348f1 100644
--- a/src/providers/ldap/ldap_common.c
+++ b/src/providers/ldap/ldap_common.c
@@ -135,7 +135,10 @@ struct sdap_attr_map rfc2307_user_map[] = {
{ "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_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL }
+ { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, 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 }
};
struct sdap_attr_map rfc2307_group_map[] = {
@@ -179,7 +182,10 @@ struct sdap_attr_map rfc2307bis_user_map[] = {
{ "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_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, NULL }
+ { "ldap_user_authorized_host", "host", SYSDB_AUTHORIZED_HOST, 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 }
};
struct sdap_attr_map rfc2307bis_group_map[] = {
diff --git a/src/providers/ldap/ldap_init.c b/src/providers/ldap/ldap_init.c
index 62588b776..c00c0a9d8 100644
--- a/src/providers/ldap/ldap_init.c
+++ b/src/providers/ldap/ldap_init.c
@@ -347,6 +347,7 @@ int sssm_ldap_access_init(struct be_ctx *bectx,
} else {
if (strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_SHADOW) != 0 &&
strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_AD) != 0 &&
+ strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_NDS) != 0 &&
strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_RHDS) != 0 &&
strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_IPA) != 0 &&
strcasecmp(dummy, LDAP_ACCOUNT_EXPIRE_389DS) != 0) {
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index 9184090e6..baac956be 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -123,6 +123,9 @@ struct sdap_ppolicy_data {
#define SYSDB_AD_ACCOUNT_EXPIRES "adAccountExpires"
#define SYSDB_AD_USER_ACCOUNT_CONTROL "adUserAccountControl"
+#define SYSDB_NDS_LOGIN_DISABLED "ndsLoginDisabled"
+#define SYSDB_NDS_LOGIN_EXPIRATION_TIME "ndsLoginExpirationTime"
+#define SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP "ndsLoginAllowedTimeMap"
#define SDAP_ROOTDSE_ATTR_NAMING_CONTEXTS "namingContexts"
#define SDAP_ROOTDSE_ATTR_DEFAULT_NAMING_CONTEXT "defaultNamingContext"
@@ -239,6 +242,9 @@ enum sdap_user_attrs {
SDAP_AT_AD_USER_ACCOUNT_CONTROL,
SDAP_AT_NS_ACCOUNT_LOCK,
SDAP_AT_AUTHORIZED_HOST,
+ SDAP_AT_NDS_LOGIN_DISABLED,
+ SDAP_AT_NDS_LOGIN_EXPIRATION_TIME,
+ SDAP_AT_NDS_LOGIN_ALLOWED_TIME_MAP,
SDAP_OPTS_USER /* attrs counter */
};
diff --git a/src/providers/ldap/sdap_access.c b/src/providers/ldap/sdap_access.c
index 9b598bc54..9bb2f2ef3 100644
--- a/src/providers/ldap/sdap_access.c
+++ b/src/providers/ldap/sdap_access.c
@@ -22,6 +22,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define _XOPEN_SOURCE 500 /* for strptime() */
+#include <time.h>
+#undef _XOPEN_SOURCE
#include <sys/param.h>
#include <security/pam_modules.h>
#include <talloc.h>
@@ -470,6 +473,174 @@ static errno_t sdap_account_expired_rhds(struct pam_data *pd,
return EOK;
}
+#define NDS_DISABLE_MSG "The user account is disabled on the server"
+#define NDS_EXPIRED_MSG "The user account is expired"
+#define NDS_TIME_MAP_MSG "The user account is not allowed at this time"
+
+static bool nds_check_expired(const char *exp_time_str)
+{
+ char *end;
+ struct tm tm;
+ time_t expire_time;
+ time_t now;
+
+ if (exp_time_str == NULL) {
+ DEBUG(9, ("ndsLoginExpirationTime is not set, access granted.\n"));
+ return false;
+ }
+
+ memset(&tm, 0, sizeof(tm));
+
+ end = strptime(exp_time_str, "%Y%m%d%H%M%SZ", &tm);
+ if (end == NULL) {
+ DEBUG(1, ("NDS expire date [%s] invalid.\n", exp_time_str));
+ return true;
+ }
+ if (*end != '\0') {
+ DEBUG(1, ("NDS expire date [%s] contains extra characters.\n",
+ exp_time_str));
+ return true;
+ }
+
+ expire_time = mktime(&tm);
+ if (expire_time == -1) {
+ DEBUG(1, ("mktime failed to convert [%s].\n", exp_time_str));
+ return true;
+ }
+
+ tzset();
+ expire_time -= timezone;
+ now = time(NULL);
+ DEBUG(9, ("Time info: tzname[0] [%s] tzname[1] [%s] timezone [%d] "
+ "daylight [%d] now [%d] expire_time [%d].\n", tzname[0],
+ tzname[1], timezone, daylight, now, expire_time));
+
+ if (difftime(now, expire_time) > 0.0) {
+ DEBUG(4, ("NDS account expired.\n"));
+ return true;
+ }
+
+ return false;
+}
+
+/* There is no real documentation of the byte string value of
+ * loginAllowedTimeMap, but some good example code in
+ * http://http://developer.novell.com/documentation/samplecode/extjndi_sample/CheckBind.java.html
+ */
+static bool nds_check_time_map(const struct ldb_val *time_map)
+{
+ time_t now;
+ struct tm *tm_now;
+ size_t map_index;
+ div_t q;
+ uint8_t mask = 0;
+
+ if (time_map == NULL) {
+ DEBUG(9, ("loginAllowedTimeMap is missing, access granted.\n"));
+ return false;
+ }
+
+ if (time_map->length != 42) {
+ DEBUG(4, ("Allowed time map has the wrong size, "
+ "got [%d], expected 42.\n", time_map->length));
+ return true;
+ }
+
+ now = time(NULL);
+ tm_now = gmtime(&now);
+
+ map_index = tm_now->tm_wday * 48 + tm_now->tm_hour * 2 +
+ (tm_now->tm_min < 30 ? 0 : 1);
+
+ if (map_index > 335) {
+ DEBUG(1, ("Unexpected index value [%d] for time map.\n", index));
+ return true;
+ }
+
+ q = div(map_index, 8);
+
+ if (q.quot > 41 || q.quot < 0 || q.rem > 7 || q.rem < 0) {
+ DEBUG(1, ("Unexpected result of div(), [%d][%d][%d].\n",
+ index, q.quot, q.rem));
+ return true;
+ }
+
+ if (q.rem > 0) {
+ mask = 1 << q.rem;
+ }
+
+ if (time_map->data[q.quot] & mask) {
+ DEBUG(4, ("Access allowed by time map.\n"));
+ return false;
+ }
+
+ return true;
+}
+
+static errno_t sdap_account_expired_nds(struct pam_data *pd,
+ struct ldb_message *user_entry,
+ int *pam_status)
+{
+ bool locked = true;
+ int ret;
+ const char *exp_time_str;
+ const struct ldb_val *time_map;
+
+ DEBUG(6, ("Performing NDS access check for user [%s]\n", pd->user));
+
+ locked = ldb_msg_find_attr_as_bool(user_entry, SYSDB_NDS_LOGIN_DISABLED,
+ false);
+ DEBUG(9, ("Account for user [%s] is%s disabled.\n", pd->user,
+ locked ? "" : " not"));
+
+ if (locked) {
+ ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
+ sizeof(NDS_DISABLE_MSG),
+ (const uint8_t *) NDS_DISABLE_MSG);
+ if (ret != EOK) {
+ DEBUG(1, ("pam_add_response failed.\n"));
+ }
+ } else {
+ exp_time_str = ldb_msg_find_attr_as_string(user_entry,
+ SYSDB_NDS_LOGIN_EXPIRATION_TIME,
+ NULL);
+ locked = nds_check_expired(exp_time_str);
+
+ DEBUG(9, ("Account for user [%s] is%s expired.\n", pd->user,
+ locked ? "" : " not"));
+
+ if (locked) {
+ ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
+ sizeof(NDS_EXPIRED_MSG),
+ (const uint8_t *) NDS_EXPIRED_MSG);
+ if (ret != EOK) {
+ DEBUG(1, ("pam_add_response failed.\n"));
+ }
+ } else {
+ time_map = ldb_msg_find_ldb_val(user_entry,
+ SYSDB_NDS_LOGIN_ALLOWED_TIME_MAP);
+
+ locked = nds_check_time_map(time_map);
+
+ DEBUG(9, ("Account for user [%s] is%s locked at this time.\n",
+ pd->user, locked ? "" : " not"));
+
+ if (locked) {
+ ret = pam_add_response(pd, SSS_PAM_SYSTEM_INFO,
+ sizeof(NDS_TIME_MAP_MSG),
+ (const uint8_t *) NDS_TIME_MAP_MSG);
+ if (ret != EOK) {
+ DEBUG(1, ("pam_add_response failed.\n"));
+ }
+ }
+ }
+ }
+
+ *pam_status = locked ? PAM_PERM_DENIED : PAM_SUCCESS;
+
+ return EOK;
+}
+
struct sdap_account_expired_req_ctx {
int pam_status;
};
@@ -525,6 +696,12 @@ static struct tevent_req *sdap_account_expired_send(TALLOC_CTX *mem_ctx,
DEBUG(1, ("sdap_account_expired_rhds failed.\n"));
goto done;
}
+ } else if (strcasecmp(expire, LDAP_ACCOUNT_EXPIRE_NDS) == 0) {
+ ret = sdap_account_expired_nds(pd, user_entry, &state->pam_status);
+ if (ret != EOK) {
+ DEBUG(1, ("sdap_account_expired_nds failed.\n"));
+ goto done;
+ }
} else {
DEBUG(1, ("Unsupported LDAP account expire policy [%s]. "
"Access denied.\n", expire));
diff --git a/src/providers/ldap/sdap_access.h b/src/providers/ldap/sdap_access.h
index d78fdb1ed..6263e25d8 100644
--- a/src/providers/ldap/sdap_access.h
+++ b/src/providers/ldap/sdap_access.h
@@ -39,6 +39,7 @@
#define LDAP_ACCOUNT_EXPIRE_RHDS "rhds"
#define LDAP_ACCOUNT_EXPIRE_IPA "ipa"
#define LDAP_ACCOUNT_EXPIRE_389DS "389ds"
+#define LDAP_ACCOUNT_EXPIRE_NDS "nds"
enum ldap_access_rule {
LDAP_ACCESS_EMPTY = -1,