mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-30 11:39:34 -05:00
531 lines
9.9 KiB
C
531 lines
9.9 KiB
C
/* 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] );
|
|
}
|
|
}
|