/* util.c - RBAC utility */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * * 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 * . */ /* ACKNOWLEDGEMENTS: */ #include "portable.h" #include #include #include #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] ); } }