Hi,
If you're a member of the FreeIPA-devel mailing list, you may already know me. I am currently trying to re-introduce the time-based policies for FreeIPA HBAC Rules to both FreeIPA and SSSD. For some more information, see the design at http://www.freeipa.org/page/V4/Time-Based_Account_Policies or read the whole paper at http://www.fit.vutbr.cz/study/DP/DP.php.cs?id=17185&file=t.
At the moment, I have a prototype solution which is able to decide whether an HBAC rule should or should not apply based on the time rules supplied with HBAC rule objects from FreeIPA. See the source code attached to this mail, if you will. The biggest problem of this solution is that it is not thread-safe.
It seems to be quite a problem to convert time from a certain time zone to a different time zone in C and keep it thread-safe. A very simple and also very ugly solution would be to have a mutex to guard each localtime() call as well as it should wrap the body of the time_to_timezone() function from the second patch. This seems rather unacceptable. The other solution would be to find another way to convert the time. Currently, there seems to be a C++ Boost solution based on a .csv file but it is not accepted well (https://github.com/boostorg/date_time/blob/master/data/date_time_zonespec.cs...). I was also thinking on using the glibc tzfile parsers (http://code.woboq.org/userspace/glibc/time/tzfile.c.html#__tzfile_read) but they too seem rather thread-unsafe and trying to rework it in a thread-safe manner might be a painful thing to do.
I welcome any suggestions and ideas on the topic as I seem to be quite stuck here.
Cheers, Stanislav Laznicka
On (14/07/15 09:11), Stanislav Laznicka wrote:
Hi,
If you're a member of the FreeIPA-devel mailing list, you may already know me. I am currently trying to re-introduce the time-based policies for FreeIPA HBAC Rules to both FreeIPA and SSSD. For some more information, see the design at http://www.freeipa.org/page/V4/Time-Based_Account_Policies or read the whole paper at http://www.fit.vutbr.cz/study/DP/DP.php.cs?id=17185&file=t.
At the moment, I have a prototype solution which is able to decide whether an HBAC rule should or should not apply based on the time rules supplied with HBAC rule objects from FreeIPA. See the source code attached to this mail, if you will. The biggest problem of this solution is that it is not thread-safe.
It seems to be quite a problem to convert time from a certain time zone to a different time zone in C and keep it thread-safe. A very simple and also very ugly solution would be to have a mutex to guard each localtime() call as well as it should wrap the body of the time_to_timezone() function from the second patch. This seems rather unacceptable. The other solution would be to find another way to convert the time. Currently, there seems to be a C++ Boost solution based on a .csv file but it is not accepted well (https://github.com/boostorg/date_time/blob/master/data/date_time_zonespec.cs...). I was also thinking on using the glibc tzfile parsers (http://code.woboq.org/userspace/glibc/time/tzfile.c.html#__tzfile_read) but they too seem rather thread-unsafe and trying to rework it in a thread-safe manner might be a painful thing to do.
I welcome any suggestions and ideas on the topic as I seem to be quite stuck here.
Cheers, Stanislav Laznicka
I did a very brief review of Makefile changes I have a few questions.
From 428db72ca0a07c7dba1a6959696b3dc2df7d77ec Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka slaznick@redhat.com Date: Mon, 13 Jul 2015 09:53:10 +0200 Subject: [PATCH 1/2] Added caching of time policies for IPA HBAC rules.
The time policies which are part of the FreeIPA HBAC Rule object are now being cached along with other HBAC Rule objects' attributes. Also, the cached time policies are transformed into hbac_time_rules structure representation.
https://fedorahosted.org/freeipa/ticket/547 https://fedorahosted.org/freeipa/ticket/548
Makefile.am | 4 -- src/providers/ipa/hbac_evaluator.c | 7 -- src/providers/ipa/ipa_access.c | 3 + src/providers/ipa/ipa_hbac.h | 6 +- src/providers/ipa/ipa_hbac_common.c | 120 +++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_hbac_private.h | 10 +++ src/providers/ipa/ipa_hbac_rules.c | 7 +- src/tests/ipa_hbac-tests.c | 6 ++ 8 files changed, 149 insertions(+), 14 deletions(-)
diff --git a/Makefile.am b/Makefile.am index b8cbc6df23ded1edb945a709b6dbe1c44eb54017..8665a0560cc3cd57f148325640c2e709a05f4c2a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -264,14 +264,10 @@ PYTHON_TESTS =
if BUILD_PYTHON2_BINDINGS PYTHON_TESTS += src/config/SSSDConfigTest.py2.sh \
src/tests/pyhbac-test.py2.sh \src/tests/pysss_murmur-test.py2.sh \ $(NULL)endif if BUILD_PYTHON3_BINDINGS PYTHON_TESTS += src/config/SSSDConfigTest.py3.sh \
src/tests/pyhbac-test.py3.sh \src/tests/pysss_murmur-test.py3.sh \ $(NULL)
Could you explain why did you remove pysss_murmur-test? How is it related to hbac?
BTW I would prefer to temporary disable pyhbac-test test or fix it rather that removing it.
From 856dc04c7bd9b4f46637c7c598dfff0bb8b95105 Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka slaznick@redhat.com Date: Mon, 13 Jul 2015 10:00:42 +0200 Subject: [PATCH 2/2] Added evaluation of time-policies in HBAC objects.
The time-policies in FreeIPA HBAC objects are now evaluated in the libipa_hbac module.
FIXME: The evaluation is not thread-safe. See the time_to_timezone function in ipa_timerules.c
https://fedorahosted.org/freeipa/ticket/547 https://fedorahosted.org/freeipa/ticket/548
Makefile.am | 2 + src/providers/ipa/hbac_evaluator.c | 17 +- src/providers/ipa/ipa_timerules.c | 488 +++++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_timerules.h | 40 +++ 4 files changed, 545 insertions(+), 2 deletions(-) create mode 100644 src/providers/ipa/ipa_timerules.c create mode 100644 src/providers/ipa/ipa_timerules.h
diff --git a/Makefile.am b/Makefile.am index 8665a0560cc3cd57f148325640c2e709a05f4c2a..937cc99757b501f953c91aef40a13e69fb4c4f4e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -600,6 +600,7 @@ dist_noinst_HEADERS = \ src/providers/ldap/sdap_dyndns.h \ src/providers/ldap/sdap_async_enum.h \ src/providers/ipa/ipa_common.h \
- src/providers/ipa/ipa_timerules.h \
^^ '\t' used instead of spaces.
src/providers/ipa/ipa_config.h \ src/providers/ipa/ipa_access.h \ src/providers/ipa/ipa_selinux.h \@@ -877,6 +878,7 @@ lib_LTLIBRARIES = libipa_hbac.la \ pkgconfig_DATA += src/providers/ipa/ipa_hbac.pc libipa_hbac_la_DEPENDENCIES = src/providers/ipa/ipa_hbac.exports libipa_hbac_la_SOURCES = \
- src/providers/ipa/ipa_timerules.c \ src/providers/ipa/hbac_evaluator.c \ src/util/sss_utf8.c
libipa_hbac_la_LIBADD = \ diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c index 64af36aae2855d0fb5a737989cc3ee8959e1b5b6..5d9bdaf29e6352f7835ee316b00790f8a739fae3 100644 --- a/src/providers/ipa/hbac_evaluator.c +++ b/src/providers/ipa/hbac_evaluator.c @@ -27,6 +27,7 @@ #include <string.h> #include <errno.h> #include "providers/ipa/ipa_hbac.h" +#include "providers/ipa/ipa_timerules.h" #include "util/sss_utf8.h"
#ifndef HAVE_ERRNO_T @@ -106,7 +107,6 @@ enum hbac_eval_result hbac_evaluate(struct hbac_rule **rules, enum hbac_error_code ret; enum hbac_eval_result result = HBAC_EVAL_DENY; enum hbac_eval_result_int intermediate_result;
Code is more readable if there is emty line after declarations. Plese do not remove it.
if (info) { *info = malloc(sizeof(struct hbac_info)); if (!*info) {@@ -176,7 +176,8 @@ enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, if (!rule->users || !rule->services || !rule->targethosts
|| !rule->srchosts) {
|| !rule->srchosts }|| !rule->timerules) { *error = HBAC_ERROR_UNPARSEABLE_RULE; return HBAC_EVAL_MATCH_ERROR;@@ -224,6 +225,18 @@ enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, } else if (!matched) { return HBAC_EVAL_UNMATCHED; }
- /* Check time policies */
- ret = hbac_evaluate_time_rules(rule->timerules,
hbac_req->request_time,&matched);- if(ret != EOK) {
*error = HBAC_ERROR_UNPARSEABLE_RULE;return HBAC_EVAL_MATCH_ERROR;- } else if (!matched) {
return HBAC_EVAL_UNMATCHED;- }
- return HBAC_EVAL_MATCHED;
}
On 07/14/2015 09:32 AM, Lukas Slebodnik wrote:
On (14/07/15 09:11), Stanislav Laznicka wrote:
Hi,
If you're a member of the FreeIPA-devel mailing list, you may already know me. I am currently trying to re-introduce the time-based policies for FreeIPA HBAC Rules to both FreeIPA and SSSD. For some more information, see the design athttp://www.freeipa.org/page/V4/Time-Based_Account_Policies or read the whole paper at http://www.fit.vutbr.cz/study/DP/DP.php.cs?id=17185&file=t.
At the moment, I have a prototype solution which is able to decide whether an HBAC rule should or should not apply based on the time rules supplied with HBAC rule objects from FreeIPA. See the source code attached to this mail, if you will. The biggest problem of this solution is that it is not thread-safe.
It seems to be quite a problem to convert time from a certain time zone to a different time zone in C and keep it thread-safe. A very simple and also very ugly solution would be to have a mutex to guard each localtime() call as well as it should wrap the body of the time_to_timezone() function from the second patch. This seems rather unacceptable. The other solution would be to find another way to convert the time. Currently, there seems to be a C++ Boost solution based on a .csv file but it is not accepted well (https://github.com/boostorg/date_time/blob/master/data/date_time_zonespec.cs...). I was also thinking on using the glibc tzfile parsers (http://code.woboq.org/userspace/glibc/time/tzfile.c.html#__tzfile_read) but they too seem rather thread-unsafe and trying to rework it in a thread-safe manner might be a painful thing to do.
I welcome any suggestions and ideas on the topic as I seem to be quite stuck here.
Cheers, Stanislav Laznicka
I did a very brief review of Makefile changes I have a few questions.
From 428db72ca0a07c7dba1a6959696b3dc2df7d77ec Mon Sep 17 00:00:00 2001 From: Stanislav Laznickaslaznick@redhat.com Date: Mon, 13 Jul 2015 09:53:10 +0200 Subject: [PATCH 1/2] Added caching of time policies for IPA HBAC rules.
The time policies which are part of the FreeIPA HBAC Rule object are now being cached along with other HBAC Rule objects' attributes. Also, the cached time policies are transformed into hbac_time_rules structure representation.
https://fedorahosted.org/freeipa/ticket/547 https://fedorahosted.org/freeipa/ticket/548
Makefile.am | 4 -- src/providers/ipa/hbac_evaluator.c | 7 -- src/providers/ipa/ipa_access.c | 3 + src/providers/ipa/ipa_hbac.h | 6 +- src/providers/ipa/ipa_hbac_common.c | 120 +++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_hbac_private.h | 10 +++ src/providers/ipa/ipa_hbac_rules.c | 7 +- src/tests/ipa_hbac-tests.c | 6 ++ 8 files changed, 149 insertions(+), 14 deletions(-)
diff --git a/Makefile.am b/Makefile.am index b8cbc6df23ded1edb945a709b6dbe1c44eb54017..8665a0560cc3cd57f148325640c2e709a05f4c2a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -264,14 +264,10 @@ PYTHON_TESTS =
if BUILD_PYTHON2_BINDINGS PYTHON_TESTS += src/config/SSSDConfigTest.py2.sh \
src/tests/pyhbac-test.py2.sh \src/tests/pysss_murmur-test.py2.sh \ $(NULL)endif if BUILD_PYTHON3_BINDINGS PYTHON_TESTS += src/config/SSSDConfigTest.py3.sh \
src/tests/pyhbac-test.py3.sh \src/tests/pysss_murmur-test.py3.sh \ $(NULL)Could you explain why did you remove pysss_murmur-test? How is it related to hbac?
It was probably just a mistake.
BTW I would prefer to temporary disable pyhbac-test test or fix it rather that removing it.
I made a brief try to fix it but at the time I was writing the code, it was not my main goal so I decided just to remove it. I will fix it and add the python tests back once the issues with the solution itself are resolved.
From 856dc04c7bd9b4f46637c7c598dfff0bb8b95105 Mon Sep 17 00:00:00 2001 From: Stanislav Laznickaslaznick@redhat.com Date: Mon, 13 Jul 2015 10:00:42 +0200 Subject: [PATCH 2/2] Added evaluation of time-policies in HBAC objects.
The time-policies in FreeIPA HBAC objects are now evaluated in the libipa_hbac module.
FIXME: The evaluation is not thread-safe. See the time_to_timezone function in ipa_timerules.c
https://fedorahosted.org/freeipa/ticket/547 https://fedorahosted.org/freeipa/ticket/548
Makefile.am | 2 + src/providers/ipa/hbac_evaluator.c | 17 +- src/providers/ipa/ipa_timerules.c | 488 +++++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_timerules.h | 40 +++ 4 files changed, 545 insertions(+), 2 deletions(-) create mode 100644 src/providers/ipa/ipa_timerules.c create mode 100644 src/providers/ipa/ipa_timerules.h
diff --git a/Makefile.am b/Makefile.am index 8665a0560cc3cd57f148325640c2e709a05f4c2a..937cc99757b501f953c91aef40a13e69fb4c4f4e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -600,6 +600,7 @@ dist_noinst_HEADERS = \ src/providers/ldap/sdap_dyndns.h \ src/providers/ldap/sdap_async_enum.h \ src/providers/ipa/ipa_common.h \
- src/providers/ipa/ipa_timerules.h \
^^ '\t' used instead of spaces.
src/providers/ipa/ipa_config.h \ src/providers/ipa/ipa_access.h \ src/providers/ipa/ipa_selinux.h \@@ -877,6 +878,7 @@ lib_LTLIBRARIES = libipa_hbac.la \ pkgconfig_DATA += src/providers/ipa/ipa_hbac.pc libipa_hbac_la_DEPENDENCIES = src/providers/ipa/ipa_hbac.exports libipa_hbac_la_SOURCES = \
- src/providers/ipa/ipa_timerules.c \ src/providers/ipa/hbac_evaluator.c \ src/util/sss_utf8.c
libipa_hbac_la_LIBADD = \ diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c index 64af36aae2855d0fb5a737989cc3ee8959e1b5b6..5d9bdaf29e6352f7835ee316b00790f8a739fae3 100644 --- a/src/providers/ipa/hbac_evaluator.c +++ b/src/providers/ipa/hbac_evaluator.c @@ -27,6 +27,7 @@ #include <string.h> #include <errno.h> #include "providers/ipa/ipa_hbac.h" +#include "providers/ipa/ipa_timerules.h" #include "util/sss_utf8.h"
#ifndef HAVE_ERRNO_T @@ -106,7 +107,6 @@ enum hbac_eval_result hbac_evaluate(struct hbac_rule **rules, enum hbac_error_code ret; enum hbac_eval_result result = HBAC_EVAL_DENY; enum hbac_eval_result_int intermediate_result;
Code is more readable if there is emty line after declarations. Plese do not remove it.
if (info) { *info = malloc(sizeof(struct hbac_info)); if (!*info) {@@ -176,7 +176,8 @@ enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, if (!rule->users || !rule->services || !rule->targethosts
|| !rule->srchosts) {
|| !rule->srchosts }|| !rule->timerules) { *error = HBAC_ERROR_UNPARSEABLE_RULE; return HBAC_EVAL_MATCH_ERROR;@@ -224,6 +225,18 @@ enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, } else if (!matched) { return HBAC_EVAL_UNMATCHED; }
- /* Check time policies */
- ret = hbac_evaluate_time_rules(rule->timerules,
hbac_req->request_time,&matched);- if(ret != EOK) {
*error = HBAC_ERROR_UNPARSEABLE_RULE;return HBAC_EVAL_MATCH_ERROR;- } else if (!matched) {
return HBAC_EVAL_UNMATCHED;- }
- return HBAC_EVAL_MATCHED;
}
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
On Tue, Jul 14, 2015 at 09:11:28AM +0200, Stanislav Laznicka wrote:
Hi,
If you're a member of the FreeIPA-devel mailing list, you may already know me. I am currently trying to re-introduce the time-based policies for FreeIPA HBAC Rules to both FreeIPA and SSSD. For some more information, see the design at http://www.freeipa.org/page/V4/Time-Based_Account_Policies or read the whole paper at http://www.fit.vutbr.cz/study/DP/DP.php.cs?id=17185&file=t.
At the moment, I have a prototype solution which is able to decide whether an HBAC rule should or should not apply based on the time rules supplied with HBAC rule objects from FreeIPA. See the source code attached to this mail, if you will. The biggest problem of this solution is that it is not thread-safe.
I have not look in detain at you patches but I think thread safety is not an issue here. The HBAC evaluation is done in a single process without using threads. To handle concurrent task we use the tevent library and asynchronous request (see https://tevent.samba.org/tevent_request.html for details). This means whatever you do will change the state of the whole process but as long as you do it in a single function and make sure to restore the original state it might be safe. I say it might because tevent handles signals as well so we have to make sure the state can be recovered even if a single handler runs in between.
bye, Sumit
It seems to be quite a problem to convert time from a certain time zone to a different time zone in C and keep it thread-safe. A very simple and also very ugly solution would be to have a mutex to guard each localtime() call as well as it should wrap the body of the time_to_timezone() function from the second patch. This seems rather unacceptable. The other solution would be to find another way to convert the time. Currently, there seems to be a C++ Boost solution based on a .csv file but it is not accepted well (https://github.com/boostorg/date_time/blob/master/data/date_time_zonespec.cs...). I was also thinking on using the glibc tzfile parsers (http://code.woboq.org/userspace/glibc/time/tzfile.c.html#__tzfile_read) but they too seem rather thread-unsafe and trying to rework it in a thread-safe manner might be a painful thing to do.
I welcome any suggestions and ideas on the topic as I seem to be quite stuck here.
Cheers, Stanislav Laznicka
From 428db72ca0a07c7dba1a6959696b3dc2df7d77ec Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka slaznick@redhat.com Date: Mon, 13 Jul 2015 09:53:10 +0200 Subject: [PATCH 1/2] Added caching of time policies for IPA HBAC rules.
The time policies which are part of the FreeIPA HBAC Rule object are now being cached along with other HBAC Rule objects' attributes. Also, the cached time policies are transformed into hbac_time_rules structure representation.
https://fedorahosted.org/freeipa/ticket/547 https://fedorahosted.org/freeipa/ticket/548
Makefile.am | 4 -- src/providers/ipa/hbac_evaluator.c | 7 -- src/providers/ipa/ipa_access.c | 3 + src/providers/ipa/ipa_hbac.h | 6 +- src/providers/ipa/ipa_hbac_common.c | 120 +++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_hbac_private.h | 10 +++ src/providers/ipa/ipa_hbac_rules.c | 7 +- src/tests/ipa_hbac-tests.c | 6 ++ 8 files changed, 149 insertions(+), 14 deletions(-)
diff --git a/Makefile.am b/Makefile.am index b8cbc6df23ded1edb945a709b6dbe1c44eb54017..8665a0560cc3cd57f148325640c2e709a05f4c2a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -264,14 +264,10 @@ PYTHON_TESTS =
if BUILD_PYTHON2_BINDINGS PYTHON_TESTS += src/config/SSSDConfigTest.py2.sh \
src/tests/pyhbac-test.py2.sh \src/tests/pysss_murmur-test.py2.sh \ $(NULL)endif if BUILD_PYTHON3_BINDINGS PYTHON_TESTS += src/config/SSSDConfigTest.py3.sh \
src/tests/pyhbac-test.py3.sh \src/tests/pysss_murmur-test.py3.sh \ $(NULL)endif
diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c index f40f9e0a7f16f5e012079c637b89c8e49ec5d15b..64af36aae2855d0fb5a737989cc3ee8959e1b5b6 100644 --- a/src/providers/ipa/hbac_evaluator.c +++ b/src/providers/ipa/hbac_evaluator.c @@ -38,13 +38,6 @@ typedef int errno_t; #define EOK 0 #endif
-/* Placeholder structure for future HBAC time-based
- evaluation rules
- */
-struct hbac_time_rules {
- int not_yet_implemented;
-};
enum hbac_eval_result_int { HBAC_EVAL_MATCH_ERROR = -1, HBAC_EVAL_MATCHED, diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c index 3198e2bd2a4c8355eeccc129c85ae3d7d67f61b0..c60775fd01f816c19b3617caa04088a8052d35ed 100644 --- a/src/providers/ipa/ipa_access.c +++ b/src/providers/ipa/ipa_access.c @@ -686,6 +686,9 @@ errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx, IPA_EXTERNAL_HOST, IPA_MEMBER_HOST, IPA_HOST_CATEGORY,
IPA_TIMEZONE,IPA_ACCESSTIME,IPA_ACCESSTIME_EXCLUDE, NULL };tmp_ctx = talloc_new(NULL);
diff --git a/src/providers/ipa/ipa_hbac.h b/src/providers/ipa/ipa_hbac.h index f43611351c8a5dfb20ca3d075f0bcd7bb71798c9..7f8d4ecf78aced49c5523f0487269f03aa9e6569 100644 --- a/src/providers/ipa/ipa_hbac.h +++ b/src/providers/ipa/ipa_hbac.h @@ -73,7 +73,11 @@ enum hbac_eval_result { /**
- Opaque type contained in hbac_evaluator.c
*/ -struct hbac_time_rules;
- struct hbac_time_rules {
const char *timezone;const char **accesstimes;const char **exceptions;- };
/**
- Component of an HBAC rule
diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c index 72a620ef0971a8bc657bd7bda3f61b4abdd614ee..4d9e5a1d0e135ec057608b1e748ea1c1183645a3 100644 --- a/src/providers/ipa/ipa_hbac_common.c +++ b/src/providers/ipa/ipa_hbac_common.c @@ -354,6 +354,16 @@ hbac_attrs_to_rule(TALLOC_CTX *mem_ctx, goto done; }
- ret = hbac_time_attrs_to_rule(new_rule, new_rule->name,
hbac_ctx->rules[idx],&new_rule->timerules);- if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,"Could not parse time rules for rule [%s]\n",new_rule->name);goto done;- }
- *rule = new_rule; ret = EOK;
@@ -363,6 +373,116 @@ done: }
errno_t +hbac_time_attrs_to_rule(TALLOC_CTX *mem_ctx,
const char *rule_name,struct sysdb_attrs *rule_attrs,struct hbac_time_rules **times)+{
- errno_t ret;
- TALLOC_CTX *tmp_ctx = NULL;
- struct ldb_message_element *el;
- struct hbac_time_rules *new_times = NULL;
- int i;
- tmp_ctx = talloc_new(mem_ctx);
- if (tmp_ctx == NULL) return ENOMEM;
- new_times = talloc_zero(tmp_ctx, struct hbac_time_rules);
- if (new_times == NULL) {
ret = ENOMEM;goto done;- }
- DEBUG(SSSDBG_TRACE_LIBS, "Processing time policies for rule [%s]\n",
rule_name);- ret = sysdb_attrs_get_el(rule_attrs, IPA_TIMEZONE, &el);
- if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed.\n");goto done;- }
- if (ret == ENOENT || el->num_values == 0) {
/* No value = default behavior (utc) */el->num_values = 0;new_times->timezone = talloc_strdup(new_times, "utc");- }
- else {
new_times->timezone = talloc_strndup(new_times,(const char*) el->values[0].data,el->values[0].length);- }
- ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESSTIME, &el);
- if(ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed");goto done;- }
- if(ret == ENOENT || el->num_values == 0) {
el->num_values = 0;DEBUG(SSSDBG_CONF_SETTINGS,"No access time specified.\n");- }
- new_times->accesstimes = talloc_array(new_times,
const char *,el->num_values + 1);- if (new_times->accesstimes == NULL) {
ret = ENOMEM;goto done;- }
- for(i = 0; i < el->num_values; i++) {
new_times->accesstimes[i] = talloc_strdup(new_times->accesstimes,(const char *)el->values[i].data);if(new_times->accesstimes[i] == NULL) {ret = ENOMEM;goto done;}- }
- new_times->accesstimes[i] = NULL;
- ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESSTIME_EXCLUDE, &el);
- if(ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed");goto done;- }
- if(ret == ENOENT || el->num_values == 0) {
el->num_values = 0;DEBUG(SSSDBG_CONF_SETTINGS,"No access time exceptions specified.\n");- }
- new_times->exceptions = talloc_array(new_times,
const char *,el->num_values + 1);- if (new_times->exceptions == NULL) {
ret = ENOMEM;goto done;- }
- for(i = 0; i < el->num_values; i++) {
new_times->exceptions[i] = talloc_strdup(new_times->exceptions,(const char *)el->values[i].data);if(new_times->exceptions[i] == NULL) {ret = ENOMEM;goto done;}- }
- new_times->exceptions[i] = NULL;
- ret = EOK;
+done:
- if (ret == EOK) {
*times = talloc_steal(mem_ctx, new_times);- }
- talloc_free(tmp_ctx);
- return ret;
+}
+errno_t hbac_get_category(struct sysdb_attrs *attrs, const char *category_attr, uint32_t *_categories) diff --git a/src/providers/ipa/ipa_hbac_private.h b/src/providers/ipa/ipa_hbac_private.h index c831cd5c6dd2ed1ff2bc0d649a25ae1212548dda..2f009626569547202ae46105a5d2d4e4e62f36f4 100644 --- a/src/providers/ipa/ipa_hbac_private.h +++ b/src/providers/ipa/ipa_hbac_private.h @@ -53,6 +53,9 @@ #define IPA_CN "cn" #define IPA_MEMBER_SERVICE "memberService" #define IPA_SERVICE_CATEGORY "serviceCategory" +#define IPA_TIMEZONE "timezone" +#define IPA_ACCESSTIME "accesstime" +#define IPA_ACCESSTIME_EXCLUDE "accesstimeexclude" #define IPA_TRUE_VALUE "TRUE"
#define IPA_HBAC_BASE_TMPL "cn=hbac,%s" @@ -129,6 +132,13 @@ hbac_service_attrs_to_rule(TALLOC_CTX *mem_ctx, const char *rule_name, struct sysdb_attrs *rule_attrs, struct hbac_rule_element **services);
+errno_t +hbac_time_attrs_to_rule(TALLOC_CTX *mem_ctx,
const char *rule_name,struct sysdb_attrs *rule_attrs,struct hbac_time_rules **times);errno_t get_ipa_servicegroupname(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c index ffef6dc4ce4229f2063d1b00308892bd3765f398..08dbaed5caa10b39ca7a8458335d57457ffc5255 100644 --- a/src/providers/ipa/ipa_hbac_rules.c +++ b/src/providers/ipa/ipa_hbac_rules.c @@ -94,7 +94,7 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, state->opts = opts; state->search_bases = search_bases; state->search_base_iter = 0;
- state->attrs = talloc_zero_array(state, const char *, 15);
- state->attrs = talloc_zero_array(state, const char *, 18); if (state->attrs == NULL) { ret = ENOMEM; goto immediate;
@@ -113,7 +113,10 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, state->attrs[11] = IPA_EXTERNAL_HOST; state->attrs[12] = IPA_MEMBER_HOST; state->attrs[13] = IPA_HOST_CATEGORY;
- state->attrs[14] = NULL;
state->attrs[14] = IPA_TIMEZONE;
state->attrs[15] = IPA_ACCESSTIME;
state->attrs[16] = IPA_ACCESSTIME_EXCLUDE;
state->attrs[17] = NULL;
rule_filter = talloc_asprintf(tmp_ctx, "(&(objectclass=%s)"
diff --git a/src/tests/ipa_hbac-tests.c b/src/tests/ipa_hbac-tests.c index bd56c8f107b05f07b1ba8913fc14a03419d679f7..46f1e3e1e648a8a53f35857ba7752b81ef2425be 100644 --- a/src/tests/ipa_hbac-tests.c +++ b/src/tests/ipa_hbac-tests.c @@ -103,6 +103,12 @@ static void get_allow_all_rule(TALLOC_CTX *mem_ctx, rule->srchosts->names = NULL; rule->srchosts->groups = NULL;
- rule->timerules = talloc_zero(rule, struct hbac_time_rules);
- fail_if(rule->timerules == NULL);
- rule->timerules->timezone = NULL;
- rule->timerules->accesstimes = NULL;
- rule->timerules->exceptions = NULL;
- *allow_rule = rule;
}
-- 2.4.3
From 856dc04c7bd9b4f46637c7c598dfff0bb8b95105 Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka slaznick@redhat.com Date: Mon, 13 Jul 2015 10:00:42 +0200 Subject: [PATCH 2/2] Added evaluation of time-policies in HBAC objects.
The time-policies in FreeIPA HBAC objects are now evaluated in the libipa_hbac module.
FIXME: The evaluation is not thread-safe. See the time_to_timezone function in ipa_timerules.c
https://fedorahosted.org/freeipa/ticket/547 https://fedorahosted.org/freeipa/ticket/548
Makefile.am | 2 + src/providers/ipa/hbac_evaluator.c | 17 +- src/providers/ipa/ipa_timerules.c | 488 +++++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_timerules.h | 40 +++ 4 files changed, 545 insertions(+), 2 deletions(-) create mode 100644 src/providers/ipa/ipa_timerules.c create mode 100644 src/providers/ipa/ipa_timerules.h
diff --git a/Makefile.am b/Makefile.am index 8665a0560cc3cd57f148325640c2e709a05f4c2a..937cc99757b501f953c91aef40a13e69fb4c4f4e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -600,6 +600,7 @@ dist_noinst_HEADERS = \ src/providers/ldap/sdap_dyndns.h \ src/providers/ldap/sdap_async_enum.h \ src/providers/ipa/ipa_common.h \
- src/providers/ipa/ipa_timerules.h \ src/providers/ipa/ipa_config.h \ src/providers/ipa/ipa_access.h \ src/providers/ipa/ipa_selinux.h \
@@ -877,6 +878,7 @@ lib_LTLIBRARIES = libipa_hbac.la \ pkgconfig_DATA += src/providers/ipa/ipa_hbac.pc libipa_hbac_la_DEPENDENCIES = src/providers/ipa/ipa_hbac.exports libipa_hbac_la_SOURCES = \
- src/providers/ipa/ipa_timerules.c \ src/providers/ipa/hbac_evaluator.c \ src/util/sss_utf8.c
libipa_hbac_la_LIBADD = \ diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c index 64af36aae2855d0fb5a737989cc3ee8959e1b5b6..5d9bdaf29e6352f7835ee316b00790f8a739fae3 100644 --- a/src/providers/ipa/hbac_evaluator.c +++ b/src/providers/ipa/hbac_evaluator.c @@ -27,6 +27,7 @@ #include <string.h> #include <errno.h> #include "providers/ipa/ipa_hbac.h" +#include "providers/ipa/ipa_timerules.h" #include "util/sss_utf8.h"
#ifndef HAVE_ERRNO_T @@ -106,7 +107,6 @@ enum hbac_eval_result hbac_evaluate(struct hbac_rule **rules, enum hbac_error_code ret; enum hbac_eval_result result = HBAC_EVAL_DENY; enum hbac_eval_result_int intermediate_result;
- if (info) { *info = malloc(sizeof(struct hbac_info)); if (!*info) {
@@ -176,7 +176,8 @@ enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, if (!rule->users || !rule->services || !rule->targethosts
|| !rule->srchosts) {
|| !rule->srchosts }|| !rule->timerules) { *error = HBAC_ERROR_UNPARSEABLE_RULE; return HBAC_EVAL_MATCH_ERROR;@@ -224,6 +225,18 @@ enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, } else if (!matched) { return HBAC_EVAL_UNMATCHED; }
- /* Check time policies */
- ret = hbac_evaluate_time_rules(rule->timerules,
hbac_req->request_time,&matched);- if(ret != EOK) {
*error = HBAC_ERROR_UNPARSEABLE_RULE;return HBAC_EVAL_MATCH_ERROR;- } else if (!matched) {
return HBAC_EVAL_UNMATCHED;- }
- return HBAC_EVAL_MATCHED;
}
diff --git a/src/providers/ipa/ipa_timerules.c b/src/providers/ipa/ipa_timerules.c new file mode 100644 index 0000000000000000000000000000000000000000..9c406402c8c14429a8f67a8e0ff319908dc85aeb --- /dev/null +++ b/src/providers/ipa/ipa_timerules.c @@ -0,0 +1,488 @@ +/*
- SSSD
- IPA Provider - Time Rules Parsing
- Authors:
Stanislav Laznicka <slaz@seznam.cz>- Copyright (C) 2015 Red Hat
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
+*/
+#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "util/sss_utf8.h" +#include "providers/ipa/ipa_hbac_private.h" +#include "providers/ipa/ipa_hbac.h" +#include "providers/ipa/ipa_common.h"
+#define NORANGE -10001
+#define TOD_STR "timeofday" +#define DOW_STR "dayofweek" +#define DOM_STR "dayofmonth" +#define WOM_STR "weekofmonth" +#define MOY_STR "monthofyear" +#define YEAR_STR "year"
+typedef int errno_t;
+enum time_types {
- TOD = 0,
- DOW,
- DOM,
- WOM,
- MOY,
- YEAR,
- START,
- END,
- VAL_ERR,
- MEM_ERR
+};
+struct time_token {
- enum time_types type;
- int value_low;
- int value_high;
- int pos;
+};
+errno_t +eval_time_rule(const char *rule,
struct tm* cmp_time,bool *matched);+struct tm *time_to_timezone(time_t t, const char *tz);
+errno_t +hbac_evaluate_time_rules(struct hbac_time_rules *rule,
time_t req_time,bool *matched)+{
- errno_t ret;
- struct tm *cmp_time;
- int i;
- /* No access time policies = always match */
- if((!rule->accesstimes && !rule->exceptions)
|| (!rule->accesstimes[0] && !rule->exceptions[0])) {*matched = true;return EOK;- }
- if(!rule->timezone || strcasecmp(rule->timezone, "utc") == 0)
cmp_time = gmtime(&req_time);- else if(strcasecmp(rule->timezone, "host") == 0)
cmp_time = localtime(&req_time);- else cmp_time = time_to_timezone(req_time, rule->timezone);
- if(cmp_time == NULL) return ENOMATCH;
- /* conversion to our language */
- if(cmp_time->tm_wday == 0)
cmp_time->tm_wday = 7;- cmp_time->tm_mon += 1;
- cmp_time->tm_year += 1900;
- if(rule->exceptions) {
for(i = 0; rule->exceptions[i]; i++) {ret = eval_time_rule(rule->exceptions[i], cmp_time, matched);if(ret != EOK) {/*DEBUG(SSSDBG_CONF_SETTINGS,"Invalid value found in accessTimeExclude rule [%s]\n",rule->exceptions[i]);*/*matched = false;return ENOMATCH;}/* exception matched, rule can't be applied */if(*matched == true) {*matched = false;return EOK;}}- }
- if(!rule->accesstimes[0]) {
/* No match in exceptions and no accessTimes set -> the rule should apply */*matched = true;return EOK;- }
- if(rule->accesstimes) {
for(i = 0; rule->accesstimes[i]; i++) {ret = eval_time_rule(rule->accesstimes[i], cmp_time, matched);if(ret != EOK) {*matched = false;return ENOMATCH;}else if(*matched == true) {return EOK;}}- }
- return ret;
+}
+struct tm *time_to_timezone(time_t t, const char *tz) +{
- struct tm *ret;
- char *env_backup = NULL;
- char *tz_toenv;
- char *tmp = NULL;
- int tzlen;
- tzlen = strlen(tz);
- /* + 2 because - prepending string with ':'; end is a null sign */
- tz_toenv = malloc((tzlen + 2) * sizeof(char));
- if(tz_toenv == NULL)
return NULL;- /* TZ variable is set */
- if((tmp = getenv("TZ")) != NULL)
env_backup = strdup(tmp);- tz_toenv[0] = ':';
- tz_toenv[tzlen+1] = '\0';
- memcpy(&tz_toenv[1], tz, tzlen*sizeof(char));
- if(setenv("TZ", tz_toenv, 1) != 0)
return NULL;- tzset();
- ret = localtime(&t);
- if(env_backup != NULL)
setenv("TZ", env_backup, 1);- else unsetenv("TZ");
- free(tz_toenv);
- return ret;
+}
+void get_token(const char *input, struct time_token *tok); +errno_t check_range(int val, int low, int high); +int get_week_of_month(struct tm *t);
+errno_t +eval_time_rule(const char *rule,
struct tm* cmp_time,bool *matched)+{
- struct time_token tok;
- enum time_types prev;
- errno_t ret;
- int checked_val;
- prev = START;
- tok.type = START;
- tok.pos = 0;
- *matched = true;
- do {
get_token(rule, &tok);switch(tok.type) {case TOD:if((tok.value_low % 100) > 60 || tok.value_low > 2359)return EINVAL;if(tok.value_high != NORANGE) {if((tok.value_high % 100) > 60 || tok.value_low > 2359)return EINVAL;}checked_val = cmp_time->tm_hour*100 + cmp_time->tm_min;break;case DOW:if(tok.value_low > 7 || tok.value_high > 7)return EINVAL;checked_val = cmp_time->tm_wday;break;case DOM:if(tok.value_low > 31 || tok.value_high > 31)return EINVAL;if(tok.value_low == 0 || tok.value_high == 0)return EINVAL;checked_val = cmp_time->tm_mday;break;case WOM:if(tok.value_low > 6 || tok.value_high > 6)return EINVAL;if(tok.value_low == 0 || tok.value_high == 0)return EINVAL;checked_val = get_week_of_month(cmp_time);break;case MOY:if(tok.value_low > 12 || tok.value_high > 12)return EINVAL;if(tok.value_low == 0 || tok.value_high == 0)return EINVAL;checked_val = cmp_time->tm_mon;break;case YEAR:if(tok.value_low < 1970)return EINVAL;if(tok.value_high != NORANGE && tok.value_high < 1970)return EINVAL;checked_val = cmp_time->tm_year;break;case END:return EOK;case MEM_ERR:return ENOMEM;default:return EINVAL;}ret = check_range(checked_val, tok.value_low, tok.value_high);/* invalid range */if (ret == EINVAL)return ret;if(prev == tok.type) {/* if val in range, set matched to true, else keep matched same */if(ret == EOK)*matched = true;}else {/* a new attribute */if(*matched == true) {prev = tok.type;*matched = (ret == EOK);}else {/* previous attribute did not match */*matched = false;return EOK;}}- } while (tok.type < END);
- return EOK;
+}
+int get_week_of_month(struct tm *t) {
- int sun; /* first sunday */
- int week = 1;
- /* mod 7 turns mday into 0-6 interval, -curr_day gets a sunday */
- sun = (t->tm_mday % 7) - t->tm_wday;
- if(sun <= 0)
sun +=7;- if(t->tm_mday <= sun) return 1;
- while(t->tm_mday > sun) {
sun+=7;week++;- }
- return week;
+}
+void get_token(const char *input, struct time_token *tok) +{
- int idx = tok->pos;
- int cmplen;
- char c;
- char *part = NULL;
- char *err = NULL;
- int i;
- int j;
- while(((c = input[idx]) != '\0') && isspace(c))
idx++;- if(c != ',') {
switch(c) {case 't':cmplen = strlen(TOD_STR);if(strncasecmp(&input[idx], TOD_STR, cmplen) != 0) {goto error;}tok->type=TOD;idx += cmplen;break;case 'd':cmplen = strlen(DOW_STR);if(strncasecmp(&input[idx], DOW_STR, cmplen) != 0) {cmplen = strlen(DOM_STR);if(strncasecmp(&input[idx], DOM_STR, cmplen) != 0) {goto error;}tok->type = DOM;idx += cmplen;break;}tok->type = DOW;idx += cmplen;break;case 'w':cmplen = strlen(WOM_STR);if(strncasecmp(&input[idx], WOM_STR, cmplen) != 0) {goto error;}tok->type = WOM;idx += cmplen;break;case 'm':cmplen = strlen(MOY_STR);if(strncasecmp(&input[idx], MOY_STR, cmplen) != 0) {goto error;}tok->type = MOY;idx += cmplen;break;case 'y':cmplen = strlen(YEAR_STR);if(strncasecmp(&input[idx], YEAR_STR, cmplen) != 0) {goto error;}tok->type = YEAR;idx += cmplen;break;case '\0':tok->type = END;return;default:goto error;} /* switch(c) */while(((c = input[idx]) != '\0') && isspace(c))idx++;if(c != '=') {goto error;}- } /* if (c != ',') */
- else {
if(tok->type == START) {goto error;}- }
- idx++; /* either after '=' or ',' */
- while(((c = input[idx]) != '\0') && isspace(c))
idx++;- /* 4 is the number of max chars to read in a number + 1 for \0 */
- if((part = calloc(5, sizeof(char))) == NULL) {
tok->type = MEM_ERR;return;- }
- for(j = 0; j < 2; j++) {
switch(tok->type) {case TOD:case YEAR:for(i = 0; i < 4; i++) {if(input[idx] == '\0') {goto error;}part[i] = input[idx];idx++;}break;case DOW:case WOM:/* No need to check for \0, strtol will do that*/part[0] = input[idx];idx++;break;case DOM:case MOY:for(i = 0; i < 2; i++) {if(isdigit(input[idx])) {part[i] = input[idx];idx++;}else if(i == 0) /* not even a one-digit number */goto error;}break;default:goto error;}if(j == 0) {tok->value_low = (int)strtol(part, &err, 10);if(*err != '\0') {goto error;}/* if it's not a range */if(input[idx] != '-') {tok->value_high = NORANGE;free(part);tok->pos = idx++;return;}else idx++;}else {tok->value_high = (int)strtol(part, &err, 10);if(*err != '\0') {goto error;}}- } /* endfor */
- tok->pos = idx;
- free(part);
- return;
+error:
- tok->type = VAL_ERR;
- if(part != NULL)
free(part);- return;
+}
+errno_t check_range(int val, int low, int high) +{
- /* not a range */
- if (high == NORANGE) {
if (val != low)return ERANGE;return EOK;- }
- else if (high < 0) {
return EINVAL;- }
- if(low < 0)
return EINVAL;- if (low > high)
return EINVAL;- if (val < low)
return ERANGE;- if (val > high)
return ERANGE;- return EOK;
+} diff --git a/src/providers/ipa/ipa_timerules.h b/src/providers/ipa/ipa_timerules.h new file mode 100644 index 0000000000000000000000000000000000000000..291c48ec73d1745032edea653ed02d7eb43d4bbe --- /dev/null +++ b/src/providers/ipa/ipa_timerules.h @@ -0,0 +1,40 @@ +/*
- SSSD
- IPA Provider - Time Rules Parsing
- Authors:
Stanislav Laznicka <slaz@seznam.cz>- Copyright (C) 2015 Red Hat
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
+*/
+#ifndef __IPA_TIMERULES_H_ +#define __IPA_TIMERULES_H_
+#include "providers/ipa/ipa_hbac.h"
+#ifndef HAVE_ERRNO_T +#define HAVE_ERRNO_T +typedef int errno_t; +#endif
+errno_t +hbac_evaluate_time_rules(struct hbac_time_rules *rule,
time_t req_time,bool *matched);+#endif /* __IPA_TIMERULES_H_ */
2.4.3
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
On 07/14/2015 04:50 AM, Sumit Bose wrote:
On Tue, Jul 14, 2015 at 09:11:28AM +0200, Stanislav Laznicka wrote:
Hi,
If you're a member of the FreeIPA-devel mailing list, you may already know me. I am currently trying to re-introduce the time-based policies for FreeIPA HBAC Rules to both FreeIPA and SSSD. For some more information, see the design at http://www.freeipa.org/page/V4/Time-Based_Account_Policies or read the whole paper at http://www.fit.vutbr.cz/study/DP/DP.php.cs?id=17185&file=t.
At the moment, I have a prototype solution which is able to decide whether an HBAC rule should or should not apply based on the time rules supplied with HBAC rule objects from FreeIPA. See the source code attached to this mail, if you will. The biggest problem of this solution is that it is not thread-safe.
I have not look in detain at you patches but I think thread safety is not an issue here. The HBAC evaluation is done in a single process without using threads. To handle concurrent task we use the tevent library and asynchronous request (see https://tevent.samba.org/tevent_request.html for details). This means whatever you do will change the state of the whole process but as long as you do it in a single function and make sure to restore the original state it might be safe. I say it might because tevent handles signals as well so we have to make sure the state can be recovered even if a single handler runs in between.
bye, Sumit
It seems to be quite a problem to convert time from a certain time zone to a different time zone in C and keep it thread-safe. A very simple and also very ugly solution would be to have a mutex to guard each localtime() call as well as it should wrap the body of the time_to_timezone() function from the second patch. This seems rather unacceptable. The other solution would be to find another way to convert the time. Currently, there seems to be a C++ Boost solution based on a .csv file but it is not accepted well (https://github.com/boostorg/date_time/blob/master/data/date_time_zonespec.cs...). I was also thinking on using the glibc tzfile parsers (http://code.woboq.org/userspace/glibc/time/tzfile.c.html#__tzfile_read) but they too seem rather thread-unsafe and trying to rework it in a thread-safe manner might be a painful thing to do.
I welcome any suggestions and ideas on the topic as I seem to be quite stuck here.
Cheers, Stanislav Laznicka From 428db72ca0a07c7dba1a6959696b3dc2df7d77ec Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka slaznick@redhat.com Date: Mon, 13 Jul 2015 09:53:10 +0200 Subject: [PATCH 1/2] Added caching of time policies for IPA HBAC rules.
The time policies which are part of the FreeIPA HBAC Rule object are now being cached along with other HBAC Rule objects' attributes. Also, the cached time policies are transformed into hbac_time_rules structure representation.
https://fedorahosted.org/freeipa/ticket/547 https://fedorahosted.org/freeipa/ticket/548
Makefile.am | 4 -- src/providers/ipa/hbac_evaluator.c | 7 -- src/providers/ipa/ipa_access.c | 3 + src/providers/ipa/ipa_hbac.h | 6 +- src/providers/ipa/ipa_hbac_common.c | 120 +++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_hbac_private.h | 10 +++ src/providers/ipa/ipa_hbac_rules.c | 7 +- src/tests/ipa_hbac-tests.c | 6 ++ 8 files changed, 149 insertions(+), 14 deletions(-)
diff --git a/Makefile.am b/Makefile.am index b8cbc6df23ded1edb945a709b6dbe1c44eb54017..8665a0560cc3cd57f148325640c2e709a05f4c2a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -264,14 +264,10 @@ PYTHON_TESTS =
if BUILD_PYTHON2_BINDINGS PYTHON_TESTS += src/config/SSSDConfigTest.py2.sh \
src/tests/pyhbac-test.py2.sh \ endif if BUILD_PYTHON3_BINDINGS PYTHON_TESTS += src/config/SSSDConfigTest.py3.sh \src/tests/pysss_murmur-test.py2.sh \ $(NULL)src/tests/pyhbac-test.py3.sh \ endifsrc/tests/pysss_murmur-test.py3.sh \ $(NULL)diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c index f40f9e0a7f16f5e012079c637b89c8e49ec5d15b..64af36aae2855d0fb5a737989cc3ee8959e1b5b6 100644 --- a/src/providers/ipa/hbac_evaluator.c +++ b/src/providers/ipa/hbac_evaluator.c @@ -38,13 +38,6 @@ typedef int errno_t; #define EOK 0 #endif
-/* Placeholder structure for future HBAC time-based
- evaluation rules
- */
-struct hbac_time_rules {
- int not_yet_implemented;
-};
- enum hbac_eval_result_int { HBAC_EVAL_MATCH_ERROR = -1, HBAC_EVAL_MATCHED,
diff --git a/src/providers/ipa/ipa_access.c b/src/providers/ipa/ipa_access.c index 3198e2bd2a4c8355eeccc129c85ae3d7d67f61b0..c60775fd01f816c19b3617caa04088a8052d35ed 100644 --- a/src/providers/ipa/ipa_access.c +++ b/src/providers/ipa/ipa_access.c @@ -686,6 +686,9 @@ errno_t hbac_get_cached_rules(TALLOC_CTX *mem_ctx, IPA_EXTERNAL_HOST, IPA_MEMBER_HOST, IPA_HOST_CATEGORY,
IPA_TIMEZONE,IPA_ACCESSTIME,IPA_ACCESSTIME_EXCLUDE, NULL }; tmp_ctx = talloc_new(NULL);diff --git a/src/providers/ipa/ipa_hbac.h b/src/providers/ipa/ipa_hbac.h index f43611351c8a5dfb20ca3d075f0bcd7bb71798c9..7f8d4ecf78aced49c5523f0487269f03aa9e6569 100644 --- a/src/providers/ipa/ipa_hbac.h +++ b/src/providers/ipa/ipa_hbac.h @@ -73,7 +73,11 @@ enum hbac_eval_result { /**
- Opaque type contained in hbac_evaluator.c
*/ -struct hbac_time_rules;
struct hbac_time_rules {
const char *timezone;const char **accesstimes;const char **exceptions;};
/**
- Component of an HBAC rule
diff --git a/src/providers/ipa/ipa_hbac_common.c b/src/providers/ipa/ipa_hbac_common.c index 72a620ef0971a8bc657bd7bda3f61b4abdd614ee..4d9e5a1d0e135ec057608b1e748ea1c1183645a3 100644 --- a/src/providers/ipa/ipa_hbac_common.c +++ b/src/providers/ipa/ipa_hbac_common.c @@ -354,6 +354,16 @@ hbac_attrs_to_rule(TALLOC_CTX *mem_ctx, goto done; }
- ret = hbac_time_attrs_to_rule(new_rule, new_rule->name,
hbac_ctx->rules[idx],&new_rule->timerules);- if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE,"Could not parse time rules for rule [%s]\n",new_rule->name);goto done;- }
*rule = new_rule; ret = EOK;@@ -363,6 +373,116 @@ done: }
errno_t +hbac_time_attrs_to_rule(TALLOC_CTX *mem_ctx,
const char *rule_name,struct sysdb_attrs *rule_attrs,struct hbac_time_rules **times)+{
- errno_t ret;
- TALLOC_CTX *tmp_ctx = NULL;
- struct ldb_message_element *el;
- struct hbac_time_rules *new_times = NULL;
- int i;
- tmp_ctx = talloc_new(mem_ctx);
- if (tmp_ctx == NULL) return ENOMEM;
- new_times = talloc_zero(tmp_ctx, struct hbac_time_rules);
- if (new_times == NULL) {
ret = ENOMEM;goto done;- }
- DEBUG(SSSDBG_TRACE_LIBS, "Processing time policies for rule [%s]\n",
rule_name);- ret = sysdb_attrs_get_el(rule_attrs, IPA_TIMEZONE, &el);
- if (ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed.\n");goto done;- }
- if (ret == ENOENT || el->num_values == 0) {
/* No value = default behavior (utc) */el->num_values = 0;new_times->timezone = talloc_strdup(new_times, "utc");- }
- else {
new_times->timezone = talloc_strndup(new_times,(const char*) el->values[0].data,el->values[0].length);- }
- ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESSTIME, &el);
- if(ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed");goto done;- }
- if(ret == ENOENT || el->num_values == 0) {
el->num_values = 0;DEBUG(SSSDBG_CONF_SETTINGS,"No access time specified.\n");- }
- new_times->accesstimes = talloc_array(new_times,
const char *,el->num_values + 1);- if (new_times->accesstimes == NULL) {
ret = ENOMEM;goto done;- }
- for(i = 0; i < el->num_values; i++) {
new_times->accesstimes[i] = talloc_strdup(new_times->accesstimes,(const char *)el->values[i].data);if(new_times->accesstimes[i] == NULL) {ret = ENOMEM;goto done;}- }
- new_times->accesstimes[i] = NULL;
- ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESSTIME_EXCLUDE, &el);
- if(ret != EOK && ret != ENOENT) {
DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_attrs_get_el failed");goto done;- }
- if(ret == ENOENT || el->num_values == 0) {
el->num_values = 0;DEBUG(SSSDBG_CONF_SETTINGS,"No access time exceptions specified.\n");- }
- new_times->exceptions = talloc_array(new_times,
const char *,el->num_values + 1);- if (new_times->exceptions == NULL) {
ret = ENOMEM;goto done;- }
- for(i = 0; i < el->num_values; i++) {
new_times->exceptions[i] = talloc_strdup(new_times->exceptions,(const char *)el->values[i].data);if(new_times->exceptions[i] == NULL) {ret = ENOMEM;goto done;}- }
- new_times->exceptions[i] = NULL;
- ret = EOK;
+done:
- if (ret == EOK) {
*times = talloc_steal(mem_ctx, new_times);- }
- talloc_free(tmp_ctx);
- return ret;
+}
+errno_t hbac_get_category(struct sysdb_attrs *attrs, const char *category_attr, uint32_t *_categories) diff --git a/src/providers/ipa/ipa_hbac_private.h b/src/providers/ipa/ipa_hbac_private.h index c831cd5c6dd2ed1ff2bc0d649a25ae1212548dda..2f009626569547202ae46105a5d2d4e4e62f36f4 100644 --- a/src/providers/ipa/ipa_hbac_private.h +++ b/src/providers/ipa/ipa_hbac_private.h @@ -53,6 +53,9 @@ #define IPA_CN "cn" #define IPA_MEMBER_SERVICE "memberService" #define IPA_SERVICE_CATEGORY "serviceCategory" +#define IPA_TIMEZONE "timezone" +#define IPA_ACCESSTIME "accesstime" +#define IPA_ACCESSTIME_EXCLUDE "accesstimeexclude" #define IPA_TRUE_VALUE "TRUE"
#define IPA_HBAC_BASE_TMPL "cn=hbac,%s" @@ -129,6 +132,13 @@ hbac_service_attrs_to_rule(TALLOC_CTX *mem_ctx, const char *rule_name, struct sysdb_attrs *rule_attrs, struct hbac_rule_element **services);
+errno_t +hbac_time_attrs_to_rule(TALLOC_CTX *mem_ctx,
const char *rule_name,struct sysdb_attrs *rule_attrs,struct hbac_time_rules **times);- errno_t get_ipa_servicegroupname(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb,
diff --git a/src/providers/ipa/ipa_hbac_rules.c b/src/providers/ipa/ipa_hbac_rules.c index ffef6dc4ce4229f2063d1b00308892bd3765f398..08dbaed5caa10b39ca7a8458335d57457ffc5255 100644 --- a/src/providers/ipa/ipa_hbac_rules.c +++ b/src/providers/ipa/ipa_hbac_rules.c @@ -94,7 +94,7 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, state->opts = opts; state->search_bases = search_bases; state->search_base_iter = 0;
- state->attrs = talloc_zero_array(state, const char *, 15);
- state->attrs = talloc_zero_array(state, const char *, 18); if (state->attrs == NULL) { ret = ENOMEM; goto immediate;
@@ -113,7 +113,10 @@ ipa_hbac_rule_info_send(TALLOC_CTX *mem_ctx, state->attrs[11] = IPA_EXTERNAL_HOST; state->attrs[12] = IPA_MEMBER_HOST; state->attrs[13] = IPA_HOST_CATEGORY;
- state->attrs[14] = NULL;
state->attrs[14] = IPA_TIMEZONE;
state->attrs[15] = IPA_ACCESSTIME;
state->attrs[16] = IPA_ACCESSTIME_EXCLUDE;
state->attrs[17] = NULL;
rule_filter = talloc_asprintf(tmp_ctx, "(&(objectclass=%s)"
diff --git a/src/tests/ipa_hbac-tests.c b/src/tests/ipa_hbac-tests.c index bd56c8f107b05f07b1ba8913fc14a03419d679f7..46f1e3e1e648a8a53f35857ba7752b81ef2425be 100644 --- a/src/tests/ipa_hbac-tests.c +++ b/src/tests/ipa_hbac-tests.c @@ -103,6 +103,12 @@ static void get_allow_all_rule(TALLOC_CTX *mem_ctx, rule->srchosts->names = NULL; rule->srchosts->groups = NULL;
- rule->timerules = talloc_zero(rule, struct hbac_time_rules);
- fail_if(rule->timerules == NULL);
- rule->timerules->timezone = NULL;
- rule->timerules->accesstimes = NULL;
- rule->timerules->exceptions = NULL;
}*allow_rule = rule;-- 2.4.3
From 856dc04c7bd9b4f46637c7c598dfff0bb8b95105 Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka slaznick@redhat.com Date: Mon, 13 Jul 2015 10:00:42 +0200 Subject: [PATCH 2/2] Added evaluation of time-policies in HBAC objects.
The time-policies in FreeIPA HBAC objects are now evaluated in the libipa_hbac module.
FIXME: The evaluation is not thread-safe. See the time_to_timezone function in ipa_timerules.c
https://fedorahosted.org/freeipa/ticket/547 https://fedorahosted.org/freeipa/ticket/548
Makefile.am | 2 + src/providers/ipa/hbac_evaluator.c | 17 +- src/providers/ipa/ipa_timerules.c | 488 +++++++++++++++++++++++++++++++++++++ src/providers/ipa/ipa_timerules.h | 40 +++ 4 files changed, 545 insertions(+), 2 deletions(-) create mode 100644 src/providers/ipa/ipa_timerules.c create mode 100644 src/providers/ipa/ipa_timerules.h
diff --git a/Makefile.am b/Makefile.am index 8665a0560cc3cd57f148325640c2e709a05f4c2a..937cc99757b501f953c91aef40a13e69fb4c4f4e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -600,6 +600,7 @@ dist_noinst_HEADERS = \ src/providers/ldap/sdap_dyndns.h \ src/providers/ldap/sdap_async_enum.h \ src/providers/ipa/ipa_common.h \
- src/providers/ipa/ipa_timerules.h \ src/providers/ipa/ipa_config.h \ src/providers/ipa/ipa_access.h \ src/providers/ipa/ipa_selinux.h \
@@ -877,6 +878,7 @@ lib_LTLIBRARIES = libipa_hbac.la \ pkgconfig_DATA += src/providers/ipa/ipa_hbac.pc libipa_hbac_la_DEPENDENCIES = src/providers/ipa/ipa_hbac.exports libipa_hbac_la_SOURCES = \
- src/providers/ipa/ipa_timerules.c \ src/providers/ipa/hbac_evaluator.c \ src/util/sss_utf8.c libipa_hbac_la_LIBADD = \
diff --git a/src/providers/ipa/hbac_evaluator.c b/src/providers/ipa/hbac_evaluator.c index 64af36aae2855d0fb5a737989cc3ee8959e1b5b6..5d9bdaf29e6352f7835ee316b00790f8a739fae3 100644 --- a/src/providers/ipa/hbac_evaluator.c +++ b/src/providers/ipa/hbac_evaluator.c @@ -27,6 +27,7 @@ #include <string.h> #include <errno.h> #include "providers/ipa/ipa_hbac.h" +#include "providers/ipa/ipa_timerules.h" #include "util/sss_utf8.h"
#ifndef HAVE_ERRNO_T @@ -106,7 +107,6 @@ enum hbac_eval_result hbac_evaluate(struct hbac_rule **rules, enum hbac_error_code ret; enum hbac_eval_result result = HBAC_EVAL_DENY; enum hbac_eval_result_int intermediate_result;
if (info) { *info = malloc(sizeof(struct hbac_info)); if (!*info) {@@ -176,7 +176,8 @@ enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, if (!rule->users || !rule->services || !rule->targethosts
|| !rule->srchosts) {
|| !rule->srchosts|| !rule->timerules) { *error = HBAC_ERROR_UNPARSEABLE_RULE; return HBAC_EVAL_MATCH_ERROR; }@@ -224,6 +225,18 @@ enum hbac_eval_result_int hbac_evaluate_rule(struct hbac_rule *rule, } else if (!matched) { return HBAC_EVAL_UNMATCHED; }
- /* Check time policies */
- ret = hbac_evaluate_time_rules(rule->timerules,
hbac_req->request_time,&matched);- if(ret != EOK) {
*error = HBAC_ERROR_UNPARSEABLE_RULE;return HBAC_EVAL_MATCH_ERROR;- } else if (!matched) {
return HBAC_EVAL_UNMATCHED;- }
}return HBAC_EVAL_MATCHED;diff --git a/src/providers/ipa/ipa_timerules.c b/src/providers/ipa/ipa_timerules.c new file mode 100644 index 0000000000000000000000000000000000000000..9c406402c8c14429a8f67a8e0ff319908dc85aeb --- /dev/null +++ b/src/providers/ipa/ipa_timerules.c @@ -0,0 +1,488 @@ +/*
- SSSD
- IPA Provider - Time Rules Parsing
- Authors:
Stanislav Laznicka <slaz@seznam.cz>- Copyright (C) 2015 Red Hat
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
+*/
+#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include "util/sss_utf8.h" +#include "providers/ipa/ipa_hbac_private.h" +#include "providers/ipa/ipa_hbac.h" +#include "providers/ipa/ipa_common.h"
+#define NORANGE -10001
+#define TOD_STR "timeofday" +#define DOW_STR "dayofweek" +#define DOM_STR "dayofmonth" +#define WOM_STR "weekofmonth" +#define MOY_STR "monthofyear" +#define YEAR_STR "year"
+typedef int errno_t;
+enum time_types {
- TOD = 0,
- DOW,
- DOM,
- WOM,
- MOY,
- YEAR,
- START,
- END,
- VAL_ERR,
- MEM_ERR
+};
+struct time_token {
- enum time_types type;
- int value_low;
- int value_high;
- int pos;
+};
+errno_t +eval_time_rule(const char *rule,
struct tm* cmp_time,bool *matched);+struct tm *time_to_timezone(time_t t, const char *tz);
+errno_t +hbac_evaluate_time_rules(struct hbac_time_rules *rule,
time_t req_time,bool *matched)+{
- errno_t ret;
- struct tm *cmp_time;
- int i;
- /* No access time policies = always match */
- if((!rule->accesstimes && !rule->exceptions)
|| (!rule->accesstimes[0] && !rule->exceptions[0])) {*matched = true;return EOK;- }
- if(!rule->timezone || strcasecmp(rule->timezone, "utc") == 0)
cmp_time = gmtime(&req_time);- else if(strcasecmp(rule->timezone, "host") == 0)
cmp_time = localtime(&req_time);- else cmp_time = time_to_timezone(req_time, rule->timezone);
- if(cmp_time == NULL) return ENOMATCH;
- /* conversion to our language */
- if(cmp_time->tm_wday == 0)
cmp_time->tm_wday = 7;- cmp_time->tm_mon += 1;
- cmp_time->tm_year += 1900;
- if(rule->exceptions) {
for(i = 0; rule->exceptions[i]; i++) {ret = eval_time_rule(rule->exceptions[i], cmp_time, matched);if(ret != EOK) {/*DEBUG(SSSDBG_CONF_SETTINGS,"Invalid value found in accessTimeExclude rule [%s]\n",rule->exceptions[i]);*/*matched = false;return ENOMATCH;}/* exception matched, rule can't be applied */if(*matched == true) {*matched = false;return EOK;}}- }
- if(!rule->accesstimes[0]) {
/* No match in exceptions and no accessTimes set -> the rule should apply */*matched = true;return EOK;- }
- if(rule->accesstimes) {
for(i = 0; rule->accesstimes[i]; i++) {ret = eval_time_rule(rule->accesstimes[i], cmp_time, matched);if(ret != EOK) {*matched = false;return ENOMATCH;}else if(*matched == true) {return EOK;}}- }
- return ret;
+}
+struct tm *time_to_timezone(time_t t, const char *tz) +{
- struct tm *ret;
- char *env_backup = NULL;
- char *tz_toenv;
- char *tmp = NULL;
- int tzlen;
- tzlen = strlen(tz);
- /* + 2 because - prepending string with ':'; end is a null sign */
- tz_toenv = malloc((tzlen + 2) * sizeof(char));
- if(tz_toenv == NULL)
return NULL;- /* TZ variable is set */
- if((tmp = getenv("TZ")) != NULL)
env_backup = strdup(tmp);- tz_toenv[0] = ':';
- tz_toenv[tzlen+1] = '\0';
- memcpy(&tz_toenv[1], tz, tzlen*sizeof(char));
- if(setenv("TZ", tz_toenv, 1) != 0)
return NULL;- tzset();
- ret = localtime(&t);
- if(env_backup != NULL)
setenv("TZ", env_backup, 1);- else unsetenv("TZ");
- free(tz_toenv);
- return ret;
+}
+void get_token(const char *input, struct time_token *tok); +errno_t check_range(int val, int low, int high); +int get_week_of_month(struct tm *t);
+errno_t +eval_time_rule(const char *rule,
struct tm* cmp_time,bool *matched)+{
- struct time_token tok;
- enum time_types prev;
- errno_t ret;
- int checked_val;
- prev = START;
- tok.type = START;
- tok.pos = 0;
- *matched = true;
- do {
get_token(rule, &tok);switch(tok.type) {case TOD:if((tok.value_low % 100) > 60 || tok.value_low > 2359)return EINVAL;if(tok.value_high != NORANGE) {if((tok.value_high % 100) > 60 || tok.value_low > 2359)return EINVAL;}checked_val = cmp_time->tm_hour*100 + cmp_time->tm_min;break;case DOW:if(tok.value_low > 7 || tok.value_high > 7)return EINVAL;checked_val = cmp_time->tm_wday;break;case DOM:if(tok.value_low > 31 || tok.value_high > 31)return EINVAL;if(tok.value_low == 0 || tok.value_high == 0)return EINVAL;checked_val = cmp_time->tm_mday;break;case WOM:if(tok.value_low > 6 || tok.value_high > 6)return EINVAL;if(tok.value_low == 0 || tok.value_high == 0)return EINVAL;checked_val = get_week_of_month(cmp_time);break;case MOY:if(tok.value_low > 12 || tok.value_high > 12)return EINVAL;if(tok.value_low == 0 || tok.value_high == 0)return EINVAL;checked_val = cmp_time->tm_mon;break;case YEAR:if(tok.value_low < 1970)return EINVAL;if(tok.value_high != NORANGE && tok.value_high < 1970)return EINVAL;checked_val = cmp_time->tm_year;break;case END:return EOK;case MEM_ERR:return ENOMEM;default:return EINVAL;}ret = check_range(checked_val, tok.value_low, tok.value_high);/* invalid range */if (ret == EINVAL)return ret;if(prev == tok.type) {/* if val in range, set matched to true, else keep matched same */if(ret == EOK)*matched = true;}else {/* a new attribute */if(*matched == true) {prev = tok.type;*matched = (ret == EOK);}else {/* previous attribute did not match */*matched = false;return EOK;}}- } while (tok.type < END);
- return EOK;
+}
+int get_week_of_month(struct tm *t) {
- int sun; /* first sunday */
- int week = 1;
- /* mod 7 turns mday into 0-6 interval, -curr_day gets a sunday */
- sun = (t->tm_mday % 7) - t->tm_wday;
- if(sun <= 0)
sun +=7;- if(t->tm_mday <= sun) return 1;
- while(t->tm_mday > sun) {
sun+=7;week++;- }
- return week;
+}
+void get_token(const char *input, struct time_token *tok) +{
- int idx = tok->pos;
- int cmplen;
- char c;
- char *part = NULL;
- char *err = NULL;
- int i;
- int j;
- while(((c = input[idx]) != '\0') && isspace(c))
idx++;- if(c != ',') {
switch(c) {case 't':cmplen = strlen(TOD_STR);if(strncasecmp(&input[idx], TOD_STR, cmplen) != 0) {goto error;}tok->type=TOD;idx += cmplen;break;case 'd':cmplen = strlen(DOW_STR);if(strncasecmp(&input[idx], DOW_STR, cmplen) != 0) {cmplen = strlen(DOM_STR);if(strncasecmp(&input[idx], DOM_STR, cmplen) != 0) {goto error;}tok->type = DOM;idx += cmplen;break;}tok->type = DOW;idx += cmplen;break;case 'w':cmplen = strlen(WOM_STR);if(strncasecmp(&input[idx], WOM_STR, cmplen) != 0) {goto error;}tok->type = WOM;idx += cmplen;break;case 'm':cmplen = strlen(MOY_STR);if(strncasecmp(&input[idx], MOY_STR, cmplen) != 0) {goto error;}tok->type = MOY;idx += cmplen;break;case 'y':cmplen = strlen(YEAR_STR);if(strncasecmp(&input[idx], YEAR_STR, cmplen) != 0) {goto error;}tok->type = YEAR;idx += cmplen;break;case '\0':tok->type = END;return;default:goto error;} /* switch(c) */while(((c = input[idx]) != '\0') && isspace(c))idx++;if(c != '=') {goto error;}- } /* if (c != ',') */
- else {
if(tok->type == START) {goto error;}- }
- idx++; /* either after '=' or ',' */
- while(((c = input[idx]) != '\0') && isspace(c))
idx++;- /* 4 is the number of max chars to read in a number + 1 for \0 */
- if((part = calloc(5, sizeof(char))) == NULL) {
tok->type = MEM_ERR;return;- }
- for(j = 0; j < 2; j++) {
switch(tok->type) {case TOD:case YEAR:for(i = 0; i < 4; i++) {if(input[idx] == '\0') {goto error;}part[i] = input[idx];idx++;}break;case DOW:case WOM:/* No need to check for \0, strtol will do that*/part[0] = input[idx];idx++;break;case DOM:case MOY:for(i = 0; i < 2; i++) {if(isdigit(input[idx])) {part[i] = input[idx];idx++;}else if(i == 0) /* not even a one-digit number */goto error;}break;default:goto error;}if(j == 0) {tok->value_low = (int)strtol(part, &err, 10);if(*err != '\0') {goto error;}/* if it's not a range */if(input[idx] != '-') {tok->value_high = NORANGE;free(part);tok->pos = idx++;return;}else idx++;}else {tok->value_high = (int)strtol(part, &err, 10);if(*err != '\0') {goto error;}}- } /* endfor */
- tok->pos = idx;
- free(part);
- return;
+error:
- tok->type = VAL_ERR;
- if(part != NULL)
free(part);- return;
+}
+errno_t check_range(int val, int low, int high) +{
- /* not a range */
- if (high == NORANGE) {
if (val != low)return ERANGE;return EOK;- }
- else if (high < 0) {
return EINVAL;- }
- if(low < 0)
return EINVAL;- if (low > high)
return EINVAL;- if (val < low)
return ERANGE;- if (val > high)
return ERANGE;- return EOK;
+} diff --git a/src/providers/ipa/ipa_timerules.h b/src/providers/ipa/ipa_timerules.h new file mode 100644 index 0000000000000000000000000000000000000000..291c48ec73d1745032edea653ed02d7eb43d4bbe --- /dev/null +++ b/src/providers/ipa/ipa_timerules.h @@ -0,0 +1,40 @@ +/*
- SSSD
- IPA Provider - Time Rules Parsing
- Authors:
Stanislav Laznicka <slaz@seznam.cz>- Copyright (C) 2015 Red Hat
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see http://www.gnu.org/licenses/.
+*/
+#ifndef __IPA_TIMERULES_H_ +#define __IPA_TIMERULES_H_
+#include "providers/ipa/ipa_hbac.h"
+#ifndef HAVE_ERRNO_T +#define HAVE_ERRNO_T +typedef int errno_t; +#endif
+errno_t +hbac_evaluate_time_rules(struct hbac_time_rules *rule,
time_t req_time,bool *matched);+#endif /* __IPA_TIMERULES_H_ */
2.4.3
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
sssd-devel mailing list sssd-devel@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
What about hbac test library? AFAIU the same library is used on client - SSSD and server - HBAC test (via python) to process HBAC rules. What are the expectations regarding the library? Is the code going inside the library? How this affects API?
On 07/14/2015 08:24 PM, Dmitri Pal wrote:
On 07/14/2015 04:50 AM, Sumit Bose wrote:
On Tue, Jul 14, 2015 at 09:11:28AM +0200, Stanislav Laznicka wrote:
Hi,
If you're a member of the FreeIPA-devel mailing list, you may already know me. I am currently trying to re-introduce the time-based policies for FreeIPA HBAC Rules to both FreeIPA and SSSD. For some more information, see the design at http://www.freeipa.org/page/V4/Time-Based_Account_Policies or read the whole paper at http://www.fit.vutbr.cz/study/DP/DP.php.cs?id=17185&file=t.
At the moment, I have a prototype solution which is able to decide whether an HBAC rule should or should not apply based on the time rules supplied with HBAC rule objects from FreeIPA. See the source code attached to this mail, if you will. The biggest problem of this solution is that it is not thread-safe.
I have not look in detain at you patches but I think thread safety is not an issue here. The HBAC evaluation is done in a single process without using threads. To handle concurrent task we use the tevent library and asynchronous request (see https://tevent.samba.org/tevent_request.html for details). This means whatever you do will change the state of the whole process but as long as you do it in a single function and make sure to restore the original state it might be safe. I say it might because tevent handles signals as well so we have to make sure the state can be recovered even if a single handler runs in between.
bye, Sumit
[...]
What about hbac test library? AFAIU the same library is used on client - SSSD and server - HBAC test (via python) to process HBAC rules. What are the expectations regarding the library? Is the code going inside the library? How this affects API?
This is very embarrassing, but I have completely overlooked your email. I'm so sorry.
I hope some of the questions were answered in the last update I posted a week ago. I have made some progress on the pyhbac library regarding the time policies which is indeed used as you describe. As for the Python API, a new class was added to support time-based rules in HBAC - HbacTimeRules - and its instances are now part of the HbacRule objects. Also, the HbacRequest objects will need to contain the information about the time of the request.
I expect the library to be able to allow testing the time aspect of HBAC rules based on a time zone that needs to be handed to the time rules object in an HBAC rule object (and, of course, based on the time rules in the time rules object in that HBAC rule).
sssd-devel@lists.fedorahosted.org