diff options
Diffstat (limited to 'contrib/slapd-modules/rbac/util.c')
-rw-r--r-- | contrib/slapd-modules/rbac/util.c | 531 |
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, ×tamp); + 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] ); + } +} |