summaryrefslogtreecommitdiffstats
path: root/contrib/slapd-modules/rbac/util.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/slapd-modules/rbac/util.c531
1 files changed, 531 insertions, 0 deletions
diff --git a/contrib/slapd-modules/rbac/util.c b/contrib/slapd-modules/rbac/util.c
new file mode 100644
index 0000000..11a5e54
--- /dev/null
+++ b/contrib/slapd-modules/rbac/util.c
@@ -0,0 +1,531 @@
+/* util.c - RBAC utility */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+/* ACKNOWLEDGEMENTS:
+ */
+
+#include "portable.h"
+
+#include <stdio.h>
+
+#include <ac/ctype.h>
+#include <ac/string.h>
+
+#include "slap.h"
+#include "slap-config.h"
+#include "lutil.h"
+
+#include "rbac.h"
+
+#define DELIMITER '$'
+
+#define SUNDAY 0x01
+#define MONDAY 0x02
+#define TUESDAY 0x04
+#define WEDNESDAY 0x08
+#define THURSDAY 0x10
+#define FRIDAY 0x20
+#define SATURDAY 0x40
+
+#define ALL_WEEK "all"
+
+void
+rbac_free_constraint( rbac_constraint_t *cp )
+{
+ if ( !cp ) return;
+
+ if ( !BER_BVISNULL( &cp->name ) ) {
+ ch_free( cp->name.bv_val );
+ }
+
+ ch_free( cp );
+}
+
+void
+rbac_free_constraints( rbac_constraint_t *constraints )
+{
+ rbac_constraint_t *cp, *tmp;
+
+ if ( !constraints ) return;
+
+ tmp = constraints;
+ while ( tmp ) {
+ cp = tmp->next;
+ rbac_free_constraint( tmp );
+ tmp = cp;
+ }
+
+ return;
+}
+
+rbac_constraint_t *
+rbac_alloc_constraint()
+{
+ rbac_constraint_t *cp = NULL;
+
+ cp = ch_calloc( 1, sizeof(rbac_constraint_t) );
+ return cp;
+}
+
+static int
+is_well_formed_constraint( struct berval *bv )
+{
+ int rc = LDAP_SUCCESS;
+
+ /* assume well-formed role/user-constraints, for the moment */
+
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY, "is_well_formed_constraint: "
+ "rbac role/user constraint not well-formed: %s\n",
+ bv->bv_val );
+ }
+
+ return rc;
+}
+
+/* input contains 4 digits, representing time */
+/* in hhmm format */
+static int
+constraint_parse_time( char *input )
+{
+ int btime;
+ char *ptr = input;
+
+ btime = ( *ptr++ - '0' ) * 12;
+ btime += ( *ptr++ - '0' );
+ btime *= 60; /* turning into mins */
+ btime += ( *ptr++ - '0' ) * 10;
+ btime += ( *ptr++ - '0' );
+ btime *= 60; /* turning into secs */
+
+ return btime;
+}
+
+/* input contains 4 digits, representing year */
+/* in yyyy format */
+static int
+constraint_parse_year( char *input )
+{
+ int i;
+ int year = 0;
+ char *ptr = input;
+
+ for ( i = 0; i <= 3; i++, ptr++ ) {
+ year = year * 10 + *ptr - '0';
+ }
+
+ return year;
+}
+
+/* input contains 2 digits, representing month */
+/* in mm format */
+static int
+constraint_parse_month( char *input )
+{
+ int i;
+ int month = 0;
+ char *ptr = input;
+
+ for ( i = 0; i < 2; i++, ptr++ ) {
+ month = month * 10 + *ptr - '0';
+ }
+
+ return month;
+}
+
+/* input contains 2 digits, representing day in month */
+/* in dd format */
+static int
+constraint_parse_day_in_month( char *input )
+{
+ int i;
+ int day_in_month = 0;
+ char *ptr = input;
+
+ for ( i = 0; i < 2; i++, ptr++ ) {
+ day_in_month = day_in_month * 10 + *ptr - '0';
+ }
+
+ return day_in_month;
+}
+
+rbac_constraint_t *
+rbac_bv2constraint( struct berval *bv )
+{
+ rbac_constraint_t *cp = NULL;
+ int rc = LDAP_SUCCESS;
+ char *ptr, *endp = NULL;
+ int len = 0;
+ int year, month, mday;
+
+ if ( !bv || BER_BVISNULL( bv ) ) goto done;
+
+ rc = is_well_formed_constraint( bv );
+ if ( rc != LDAP_SUCCESS ) {
+ goto done;
+ }
+
+ cp = rbac_alloc_constraint();
+ if ( !cp ) {
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+
+ /* constraint name */
+ ptr = bv->bv_val;
+ endp = ptr;
+ while ( *endp != DELIMITER ) {
+ endp++;
+ len++;
+ }
+
+ if ( len > 0 ) {
+ cp->name.bv_val = ch_malloc( len + 1 );
+ strncpy( cp->name.bv_val, ptr, len );
+ cp->name.bv_val[len] = '\0';
+ cp->name.bv_len = len;
+ } else {
+ rc = LDAP_OTHER;
+ goto done;
+ }
+
+ /* allowed inactivity period */
+ ptr = endp;
+ endp++;
+ if ( isdigit( *endp ) ) {
+ int secs = 0;
+ while ( isdigit( *endp ) ) {
+ secs = secs * 10 + *endp - '0';
+ endp++;
+ }
+ cp->allowed_inactivity = secs;
+ } else if ( *endp != DELIMITER ) {
+ rc = LDAP_OTHER;
+ goto done;
+ }
+
+ ptr = endp;
+ endp = ptr + 1;
+
+ /* begin time */
+ if ( isdigit( *endp ) ) {
+ cp->begin_time = constraint_parse_time( endp );
+ while ( isdigit( *endp ) )
+ endp++;
+ }
+
+ ptr = endp;
+ while ( *ptr != DELIMITER )
+ ptr++;
+ endp = ptr + 1;
+
+ /* end time */
+ if ( isdigit( *endp ) ) {
+ cp->end_time = constraint_parse_time( endp );
+ while ( isdigit( *endp ) )
+ endp++;
+ }
+
+ ptr = endp;
+ while ( *ptr != DELIMITER )
+ ptr++;
+ endp = ptr + 1;
+
+ /* begin year/month/day_in_month */
+ if ( isdigit( *endp ) ) {
+ lutil_tm tm;
+ year = constraint_parse_year( endp );
+ endp += 4;
+ month = constraint_parse_month( endp );
+ endp += 2;
+ mday = constraint_parse_day_in_month( endp );
+ endp += 2;
+
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = mday;
+ tm.tm_sec = 0;
+ tm.tm_min = 0;
+ tm.tm_hour = 0;
+
+ lutil_tm2time( &tm, &cp->begin_date );
+ }
+
+ ptr = endp;
+ while ( *ptr != DELIMITER )
+ ptr++;
+ endp = ptr + 1;
+
+ /* end year/month/day_in_month */
+ if ( isdigit( *endp ) ) {
+ lutil_tm tm;
+ year = constraint_parse_year( endp );
+ endp += 4;
+ month = constraint_parse_month( endp );
+ endp += 2;
+ mday = constraint_parse_day_in_month( endp );
+ endp += 2;
+
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = mday;
+ tm.tm_sec = 0;
+ tm.tm_min = 0;
+ tm.tm_hour = 0;
+
+ lutil_tm2time( &tm, &cp->end_date );
+ }
+
+ ptr = endp;
+ while ( *ptr != DELIMITER )
+ ptr++;
+ endp = ptr + 1;
+
+ /* begin lock year/month/day_in_month */
+ if ( isdigit( *endp ) ) {
+ lutil_tm tm;
+ year = constraint_parse_year( endp );
+ endp += 4;
+ month = constraint_parse_month( endp );
+ endp += 2;
+ mday = constraint_parse_day_in_month( endp );
+ endp += 2;
+
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = mday;
+ tm.tm_sec = 0;
+ tm.tm_min = 0;
+ tm.tm_hour = 0;
+
+ lutil_tm2time( &tm, &cp->begin_lock_date );
+ }
+
+ ptr = endp;
+ while ( *ptr != DELIMITER )
+ ptr++;
+ endp = ptr + 1;
+
+ /* end lock year/month/day_in_month */
+ if ( isdigit( *endp ) ) {
+ lutil_tm tm;
+
+ year = constraint_parse_year( endp );
+ endp += 4;
+ month = constraint_parse_month( endp );
+ endp += 2;
+ mday = constraint_parse_day_in_month( endp );
+ endp += 2;
+
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = mday;
+ tm.tm_sec = 0;
+ tm.tm_min = 0;
+ tm.tm_hour = 0;
+
+ lutil_tm2time( &tm, &cp->end_lock_date );
+ }
+
+ ptr = endp;
+ while ( *ptr != DELIMITER )
+ ptr++;
+ endp = ptr + 1;
+
+ /* dayMask */
+
+ /* allow "all" to mean the entire week */
+ if ( strncasecmp( endp, ALL_WEEK, strlen( ALL_WEEK ) ) == 0 ) {
+ cp->day_mask = SUNDAY | MONDAY | TUESDAY | WEDNESDAY | THURSDAY |
+ FRIDAY | SATURDAY;
+ }
+
+ while ( *endp && isdigit( *endp ) ) {
+ switch ( *endp - '0' ) {
+ case 1:
+ cp->day_mask |= SUNDAY;
+ break;
+ case 2:
+ cp->day_mask |= MONDAY;
+ break;
+ case 3:
+ cp->day_mask |= TUESDAY;
+ break;
+ case 4:
+ cp->day_mask |= WEDNESDAY;
+ break;
+ case 5:
+ cp->day_mask |= THURSDAY;
+ break;
+ case 6:
+ cp->day_mask |= FRIDAY;
+ break;
+ case 7:
+ cp->day_mask |= SATURDAY;
+ break;
+ default:
+ /* should not be here */
+ rc = LDAP_OTHER;
+ goto done;
+ }
+ endp++;
+ }
+
+done:;
+ if ( rc != LDAP_SUCCESS ) {
+ rbac_free_constraint( cp );
+ cp = NULL;
+ }
+
+ return cp;
+}
+
+static int
+constraint_day_of_week( rbac_constraint_t *cp, int wday )
+{
+ int rc = LDAP_UNWILLING_TO_PERFORM;
+
+ /* assumption: Monday is 1st day of a week */
+ switch ( wday ) {
+ case 1:
+ if ( !(cp->day_mask & MONDAY) ) goto done;
+ break;
+ case 2:
+ if ( !(cp->day_mask & TUESDAY) ) goto done;
+ break;
+ case 3:
+ if ( !(cp->day_mask & WEDNESDAY) ) goto done;
+ break;
+ case 4:
+ if ( !(cp->day_mask & THURSDAY) ) goto done;
+ break;
+ case 5:
+ if ( !(cp->day_mask & FRIDAY) ) goto done;
+ break;
+ case 6:
+ if ( !(cp->day_mask & SATURDAY) ) goto done;
+ break;
+ case 0:
+ case 7:
+ if ( !(cp->day_mask & SUNDAY) ) goto done;
+ break;
+ default:
+ /* should not be here */
+ goto done;
+ }
+
+ rc = LDAP_SUCCESS;
+
+done:;
+ return rc;
+}
+
+int
+rbac_check_time_constraint( rbac_constraint_t *cp )
+{
+ int rc = LDAP_UNWILLING_TO_PERFORM;
+ time_t now;
+ struct tm result, *resultp;
+
+ now = slap_get_time();
+
+ /*
+ * does slapd support day-of-week (wday)?
+ * using native routine for now.
+ * Win32's gmtime call is already thread-safe, to the _r
+ * decorator is unneeded.
+ */
+#ifdef _WIN32
+ resultp = gmtime( &now );
+#else
+ resultp = gmtime_r( &now, &result );
+#endif
+ if ( !resultp ) goto done;
+#if 0
+ timestamp.bv_val = timebuf;
+ timestamp.bv_len = sizeof(timebuf);
+ slap_timestamp(&now, &timestamp);
+ lutil_parsetime(timestamp.bv_val, &now_tm);
+ lutil_tm2time(&now_tm, &now_tt);
+#endif
+
+ if ( ( cp->begin_date.tt_sec > 0 && cp->begin_date.tt_sec > now ) ||
+ ( cp->end_date.tt_sec > 0 && cp->end_date.tt_sec < now ) ) {
+ /* not within allowed time period */
+ goto done;
+ }
+
+ /* allowed time period during a day */
+ if ( cp->begin_time > 0 && cp->end_time > 0 ) {
+ int timeofday = ( resultp->tm_hour * 60 + resultp->tm_min ) * 60 +
+ resultp->tm_sec;
+ if ( timeofday < cp->begin_time || timeofday > cp->end_time ) {
+ /* not within allowed time period in a day */
+ goto done;
+ }
+ }
+
+ /* allowed day in a week */
+ if ( cp->day_mask > 0 ) {
+ rc = constraint_day_of_week( cp, resultp->tm_wday );
+ if ( rc != LDAP_SUCCESS ) goto done;
+ }
+
+ /* during lock-out period? */
+ if ( ( cp->begin_lock_date.tt_sec > 0 &&
+ cp->begin_lock_date.tt_sec < now ) &&
+ ( cp->end_lock_date.tt_sec > 0 &&
+ cp->end_lock_date.tt_sec > now ) ) {
+ /* within locked out period */
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+
+ /* passed all tests */
+ rc = LDAP_SUCCESS;
+
+done:;
+ return rc;
+}
+
+rbac_constraint_t *
+rbac_role2constraint( struct berval *role, rbac_constraint_t *role_constraints )
+{
+ rbac_constraint_t *cp = NULL;
+
+ if ( !role_constraints || !role ) goto done;
+
+ cp = role_constraints;
+ while ( cp ) {
+ if ( ber_bvstrcasecmp( role, &cp->name ) == 0 ) {
+ /* found the role constraint */
+ goto done;
+ }
+ cp = cp->next;
+ }
+
+done:;
+ return cp;
+}
+
+void
+rbac_to_lower( struct berval *bv )
+{
+ // convert the berval to lower case:
+ int i;
+ for ( i = 0; i < bv->bv_len; i++ ) {
+ bv->bv_val[i] = tolower( bv->bv_val[i] );
+ }
+}