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...).
> 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(a)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(a)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(a)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(a)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(a)lists.fedorahosted.org
>
https://lists.fedorahosted.org/mailman/listinfo/sssd-devel
_______________________________________________
sssd-devel mailing list
sssd-devel(a)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?
--
Thank you,
Dmitri Pal
Director of Engineering for IdM portfolio
Red Hat, Inc.