ITS#9471 Add RBAC overlay to contrib

This commit is contained in:
Ondřej Kuzník 2021-03-15 15:41:00 +00:00 committed by Quanah Gibson-Mount
parent fd39b726d8
commit d594ffe902
14 changed files with 6097 additions and 0 deletions

View file

@ -0,0 +1,50 @@
# $OpenLDAP$
LDAP_SRC = ../../..
LDAP_BUILD = $(LDAP_SRC)
LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd
LDAP_LIB = $(LDAP_BUILD)/libraries/libldap/libldap.la \
$(LDAP_BUILD)/libraries/liblber/liblber.la
LIBTOOL = $(LDAP_BUILD)/libtool
CC = gcc
OPT = -g -O2 -Wall
DEFS = -DSLAPD_OVER_RBAC=SLAPD_MOD_DYNAMIC
INCS = $(LDAP_INC)
LIBS = $(LDAP_LIB)
PROGRAMS = rbac.la
LTVER = 0:0:0
prefix=/usr/local
exec_prefix=$(prefix)
ldap_subdir=/openldap
libdir=$(exec_prefix)/lib
libexecdir=$(exec_prefix)/libexec
moduledir = $(libexecdir)$(ldap_subdir)
SRCS = rbac.c rbacperm.c rbacsess.c rbacuser.c rbacreq.c rbacaudit.c init.c rbacacl.c util.c jts.c
OBJS = $(patsubst %.c,%.o,$(SRCS))
LOBJS = $(patsubst %.c,%.lo,$(SRCS))
.SUFFIXES: .c .lo
%.lo: %.c rbac.h
$(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $<
all: $(PROGRAMS)
rbac.la: $(LOBJS)
$(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \
-rpath $(moduledir) -module -o $@ $^ $(LIBS)
clean:
rm -rf *.o *.lo *.la .libs
install: $(PROGRAMS)
mkdir -p $(DESTDIR)$(moduledir)
for p in $(PROGRAMS) ; do \
$(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \
done

View file

@ -0,0 +1,324 @@
/* init.c - RBAC initialization */
/* $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/string.h>
#include "slap.h"
#include "slap-config.h"
#include "lutil.h"
#include "rbac.h"
static slap_callback nullsc = { NULL, NULL, NULL, NULL };
struct slap_rbac_internal_schema slap_rbac_schema;
extern rbac_tenant_t rbac_tenants;
extern int initialize_jts( void );
rbac_ad_t rbac_session_ads[] = {
{ RBAC_SESSION_ID,
BER_BVC("rbacSessid"), &slap_rbac_schema.ad_session_id },
{ RBAC_USER_DN,
BER_BVC("rbacUserDN"), &slap_rbac_schema.ad_session_user_dn },
{ RBAC_ROLES,
BER_BVC("rbacRoles"), &slap_rbac_schema.ad_session_roles },
{ RBAC_ROLE_CONSTRAINTS,
BER_BVC("rbacRoleConstraints"),
&slap_rbac_schema.ad_session_role_constraints },
{ RBAC_UID,
BER_BVC("uid"), &slap_rbac_schema.ad_uid},
{ RBAC_TENANT_ID,
BER_BVC("tenantid"), &slap_rbac_schema.ad_tenant_id },
{ RBAC_NONE, BER_BVNULL, NULL }
};
rbac_ad_t rbac_session_permission_ads[] = {
{ RBAC_OP_NAME,
BER_BVC("rbacOpName"), &slap_rbac_schema.ad_permission_opname },
{ RBAC_OBJ_NAME,
BER_BVC("rbacObjName"), &slap_rbac_schema.ad_permission_objname },
{ RBAC_ROLE_NAME,
BER_BVC("rbacRoleName"), &slap_rbac_schema.ad_permission_rolename },
{ RBAC_NONE, BER_BVNULL, NULL }
};
rbac_ad_t audit_ads[] = {
{ RBAC_AUDIT_OP,
BER_BVC("rbacAuditOp"), &slap_rbac_schema.ad_audit_op },
{ RBAC_AUDIT_ID,
BER_BVC("rbacAuditId"), &slap_rbac_schema.ad_audit_id },
{ RBAC_AUDIT_ROLES,
BER_BVC("rbacAuditRoles"), &slap_rbac_schema.ad_audit_roles },
{ RBAC_AUDIT_REQUESTED_ROLES,
BER_BVC("rbacAuditRequestedRoles"),
&slap_rbac_schema.ad_audit_requested_roles
},
{ RBAC_AUDIT_TIMESTAMP,
BER_BVC("rbacAuditTimestamp"), &slap_rbac_schema.ad_audit_timestamp },
{ RBAC_AUDIT_RESOURCES,
BER_BVC("rbacAuditResources"), &slap_rbac_schema.ad_audit_resources },
{ RBAC_AUDIT_OBJS,
BER_BVC("rbacAuditObjects"), &slap_rbac_schema.ad_audit_objects },
{ RBAC_AUDIT_OPS,
BER_BVC("rbacAuditOperations"), &slap_rbac_schema.ad_audit_operations },
{ RBAC_AUDIT_RESULT,
BER_BVC("rbacAuditResult"), &slap_rbac_schema.ad_audit_result },
{ RBAC_AUDIT_PROPERTIES,
BER_BVC("rbacAuditProperties"), &slap_rbac_schema.ad_audit_properties },
{ RBAC_AUDIT_MSGS,
BER_BVC("rbacAuditMessages"), &slap_rbac_schema.ad_audit_messages },
{ RBAC_NONE, BER_BVNULL, NULL }
};
/* initialize repository attribute descriptions */
static int
initialize_sessions()
{
int i, nattrs, rc = LDAP_SUCCESS;
const char *text;
for ( nattrs = 0; !BER_BVISNULL( &rbac_session_ads[nattrs].attr );
nattrs++ )
; /* count the number of attrs */
slap_rbac_schema.session_attrs =
slap_sl_calloc( sizeof(AttributeName), nattrs + 1, NULL );
for ( i = 0; !BER_BVISNULL( &rbac_session_ads[i].attr ); i++ ) {
rc = slap_bv2ad(
&rbac_session_ads[i].attr, rbac_session_ads[i].ad, &text );
if ( rc != LDAP_SUCCESS ) {
goto done;
}
slap_rbac_schema.session_attrs[i].an_name = rbac_session_ads[i].attr;
slap_rbac_schema.session_attrs[i].an_desc = *rbac_session_ads[i].ad;
}
BER_BVZERO( &slap_rbac_schema.session_attrs[nattrs].an_name );
done:;
return rc;
}
static int
initialize_audit()
{
int i, rc = LDAP_SUCCESS;
const char *text;
/* for audit */
for ( i = 0; !BER_BVISNULL( &audit_ads[i].attr ); i++ ) {
rc = slap_bv2ad( &audit_ads[i].attr, audit_ads[i].ad, &text );
if ( rc != LDAP_SUCCESS ) {
goto done;
}
}
done:;
return rc;
}
static int
initialize_tenant(
BackendDB *be,
ConfigReply *cr,
tenant_info_t *tenantp,
int init_op )
{
int rc = LDAP_SUCCESS;
Entry *e = NULL;
OperationBuffer opbuf;
Operation *op2;
SlapReply rs2 = { REP_RESULT };
Connection conn = { 0 };
struct berval rbac_container_oc = BER_BVC("rbacContainer");
struct berval rbac_audit_container = BER_BVC("audit");
struct berval rbac_session_container = BER_BVC("rbac");
void *thrctx = ldap_pvt_thread_pool_context();
e = entry_alloc();
switch ( init_op ) {
case INIT_AUDIT_CONTAINER:
ber_dupbv( &e->e_name, &tenantp->audit_basedn );
ber_dupbv( &e->e_nname, &tenantp->audit_basedn );
/* container cn */
attr_merge_one(
e, slap_schema.si_ad_cn, &rbac_audit_container, NULL );
break;
case INIT_SESSION_CONTAINER:
ber_dupbv( &e->e_name, &tenantp->sessions_basedn );
ber_dupbv( &e->e_nname, &tenantp->sessions_basedn );
/* rendered dynmaicObject for session */
attr_merge_one( e, slap_schema.si_ad_objectClass,
&slap_schema.si_oc_dynamicObject->soc_cname, NULL );
/* container cn */
attr_merge_one(
e, slap_schema.si_ad_cn, &rbac_session_container, NULL );
break;
default:
break;
}
attr_merge_one(
e, slap_schema.si_ad_objectClass, &rbac_container_oc, NULL );
attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
&rbac_container_oc, NULL );
/* store RBAC session */
connection_fake_init2( &conn, &opbuf, thrctx, 0 );
op2 = &opbuf.ob_op;
op2->o_callback = &nullsc;
op2->o_tag = LDAP_REQ_ADD;
op2->o_protocol = LDAP_VERSION3;
op2->o_req_dn = e->e_name;
op2->o_req_ndn = e->e_nname;
op2->ora_e = e;
op2->o_bd = select_backend( &op2->o_req_ndn, 0 );
op2->o_dn = op2->o_bd->be_rootdn;
op2->o_ndn = op2->o_bd->be_rootndn;
rc = op2->o_bd->be_add( op2, &rs2 );
if ( e ) entry_free( e );
return rc;
}
int
rbac_initialize_tenants( BackendDB *be, ConfigReply *cr )
{
int rc = LDAP_SUCCESS;
rbac_tenant_t *tenantp = NULL;
for ( tenantp = &rbac_tenants; tenantp; tenantp = tenantp->next ) {
rc = initialize_tenant(
be, cr, &tenantp->tenant_info, INIT_AUDIT_CONTAINER );
if ( rc != LDAP_SUCCESS ) {
if ( rc == LDAP_ALREADY_EXISTS ) {
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
"audit container exists, tenant (%s)\n",
tenantp->tenant_info.tid.bv_val ?
tenantp->tenant_info.tid.bv_val :
"NULL" );
rc = LDAP_SUCCESS;
} else {
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
"failed to initialize (%s): rc (%d)\n",
tenantp->tenant_info.tid.bv_val ?
tenantp->tenant_info.tid.bv_val :
"NULL",
rc );
goto done;
}
} else {
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
"created audit container for tenant (%s):\n",
tenantp->tenant_info.tid.bv_val ?
tenantp->tenant_info.tid.bv_val :
"NULL" );
}
rc = initialize_tenant(
be, cr, &tenantp->tenant_info, INIT_SESSION_CONTAINER );
if ( rc != LDAP_SUCCESS ) {
if ( rc == LDAP_ALREADY_EXISTS ) {
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
"session container exists, tenant (%s)\n",
tenantp->tenant_info.tid.bv_val ?
tenantp->tenant_info.tid.bv_val :
"NULL" );
rc = LDAP_SUCCESS;
} else {
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
"failed to initialize (%s): rc (%d)\n",
tenantp->tenant_info.tid.bv_val ?
tenantp->tenant_info.tid.bv_val :
"NULL",
rc );
goto done;
}
} else {
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
"created session container for tenant (%s):\n",
tenantp->tenant_info.tid.bv_val ?
tenantp->tenant_info.tid.bv_val :
"NULL" );
}
}
done:;
return rc;
}
static int
initialize_rbac_session_permissions()
{
int i, rc = LDAP_SUCCESS;
const char *text;
for ( i = 0; !BER_BVISNULL( &rbac_session_permission_ads[i].attr ); i++ ) {
rc = slap_bv2ad( &rbac_session_permission_ads[i].attr,
rbac_session_permission_ads[i].ad, &text );
if ( rc != LDAP_SUCCESS ) {
goto done;
}
}
done:;
return rc;
}
int
rbac_initialize_repository()
{
int rc = LDAP_SUCCESS;
rc = initialize_jts();
if ( rc != LDAP_SUCCESS ) {
return rc;
}
rc = initialize_rbac_session_permissions();
if ( rc != LDAP_SUCCESS ) {
return rc;
}
rc = initialize_sessions();
if ( rc != LDAP_SUCCESS ) {
return rc;
}
rc = initialize_audit();
if ( rc != LDAP_SUCCESS ) {
return rc;
}
return rc;
}

View file

@ -0,0 +1,198 @@
/* jts.c - RBAC JTS initialization */
/* $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/string.h>
#include "slap.h"
#include "slap-config.h"
#include "lutil.h"
#include "rbac.h"
struct slap_rbac_tenant_schema slap_rbac_jts_schema;
/* to replace all JTS schema initialization */
rbac_ad_t ft_ads[] = {
{ RBAC_ROLE_ASSIGNMENT,
BER_BVC("ftRA"), &slap_rbac_jts_schema.ad_role },
{ RBAC_ROLE_CONSTRAINTS,
BER_BVC("ftRC"), &slap_rbac_jts_schema.ad_role_constraint },
{ RBAC_USER_CONSTRAINTS,
BER_BVC("ftCstr"), &slap_rbac_jts_schema.ad_user_constraint },
{ RBAC_UID,
BER_BVC("uid"), &slap_rbac_jts_schema.ad_uid },
{ RBAC_USERS,
BER_BVC("ftUsers"), &slap_rbac_jts_schema.ad_permission_users },
{ RBAC_ROLES,
BER_BVC("ftRoles"), &slap_rbac_jts_schema.ad_permission_roles },
{ RBAC_OBJ_NAME,
BER_BVC("ftObjNm"), &slap_rbac_jts_schema.ad_permission_objname },
{ RBAC_OP_NAME,
BER_BVC("ftOpNm"), &slap_rbac_jts_schema.ad_permission_opname },
{ RBAC_NONE, BER_BVNULL, NULL }
};
rbac_ad_t ft_user_ads[] = {
{ RBAC_ROLE_ASSIGNMENT,
BER_BVC("ftRA"), &slap_rbac_jts_schema.ad_role },
{ RBAC_ROLE_CONSTRAINTS,
BER_BVC("ftRC"), &slap_rbac_jts_schema.ad_role_constraint },
{ RBAC_USER_CONSTRAINTS,
BER_BVC("ftCstr"), &slap_rbac_jts_schema.ad_user_constraint },
{ RBAC_UID,
BER_BVC("uid"), &slap_rbac_jts_schema.ad_uid },
{ RBAC_NONE, BER_BVNULL, NULL }
};
rbac_ad_t ft_perm_ads[] = {
{ RBAC_USERS,
BER_BVC("ftUsers"), &slap_rbac_jts_schema.ad_permission_users },
{ RBAC_ROLES,
BER_BVC("ftRoles"), &slap_rbac_jts_schema.ad_permission_roles },
{ RBAC_NONE, BER_BVNULL, NULL }
};
rbac_ad_t ft_session_perm_ads[] = {
{ RBAC_USERS,
BER_BVC("ftUsers"), &slap_rbac_jts_schema.ad_permission_users },
{ RBAC_ROLES,
BER_BVC("ftRoles"), &slap_rbac_jts_schema.ad_permission_roles },
{ RBAC_OBJ_NAME,
BER_BVC("ftObjNm"), &slap_rbac_jts_schema.ad_permission_objname },
{ RBAC_OP_NAME,
BER_BVC("ftOpNm"), &slap_rbac_jts_schema.ad_permission_opname },
{ RBAC_NONE, BER_BVNULL, NULL }
};
static int
initialize_jts_session_permission_ads()
{
int i, nattrs, rc = LDAP_SUCCESS;
for ( nattrs = 0; !BER_BVISNULL( &ft_session_perm_ads[nattrs].attr );
nattrs++ )
; /* count the number of attrs */
slap_rbac_jts_schema.session_perm_attrs =
slap_sl_calloc( sizeof(AttributeName), nattrs + 1, NULL );
for ( i = 0; !BER_BVISNULL( &ft_session_perm_ads[i].attr ); i++ ) {
slap_rbac_jts_schema.session_perm_attrs[i].an_name =
ft_session_perm_ads[i].attr;
slap_rbac_jts_schema.session_perm_attrs[i].an_desc =
*ft_session_perm_ads[i].ad;
}
BER_BVZERO( &slap_rbac_jts_schema.session_perm_attrs[nattrs].an_name );
slap_rbac_jts_schema.session_permissions_ads = ft_session_perm_ads;
return rc;
}
static int
initialize_jts_permission_ads()
{
int i, nattrs, rc = LDAP_SUCCESS;
/* jts permissions configuration */
for ( nattrs = 0; !BER_BVISNULL( &ft_perm_ads[nattrs].attr ); nattrs++ )
; /* count the number of attrs */
slap_rbac_jts_schema.perm_attrs =
slap_sl_calloc( sizeof(AttributeName), nattrs + 1, NULL );
for ( i = 0; !BER_BVISNULL( &ft_perm_ads[i].attr ); i++ ) {
slap_rbac_jts_schema.perm_attrs[i].an_name = ft_perm_ads[i].attr;
slap_rbac_jts_schema.perm_attrs[i].an_desc = *ft_perm_ads[i].ad;
}
BER_BVZERO( &slap_rbac_jts_schema.perm_attrs[nattrs].an_name );
slap_rbac_jts_schema.permission_ads = ft_perm_ads;
return rc;
}
static int
initialize_jts_user_ads()
{
int i, nattrs, rc = LDAP_SUCCESS;
/* jts user attribute descriptions */
/* jts user attributes */
for ( nattrs = 0; !BER_BVISNULL( &ft_user_ads[nattrs].attr ); nattrs++ )
; /* count the number of attrs */
slap_rbac_jts_schema.user_attrs =
slap_sl_calloc( sizeof(AttributeName), nattrs + 1, NULL );
for ( i = 0; !BER_BVISNULL( &ft_user_ads[i].attr ); i++ ) {
slap_rbac_jts_schema.user_attrs[i].an_name = ft_user_ads[i].attr;
slap_rbac_jts_schema.user_attrs[i].an_desc = *ft_user_ads[i].ad;
}
BER_BVZERO( &slap_rbac_jts_schema.user_attrs[nattrs].an_name );
slap_rbac_jts_schema.user_ads = ft_user_ads;
return rc;
}
int
initialize_jts()
{
int i, rc;
const char *text;
/* jts attributes */
for ( i = 0; !BER_BVISNULL( &ft_ads[i].attr ); i++ ) {
rc = slap_bv2ad( &ft_ads[i].attr, ft_ads[i].ad, &text );
if ( rc != LDAP_SUCCESS ) {
goto done;
}
}
rc = initialize_jts_user_ads();
if ( rc != LDAP_SUCCESS ) {
return rc;
}
rc = initialize_jts_permission_ads();
if ( rc != LDAP_SUCCESS ) {
return rc;
}
rc = initialize_jts_session_permission_ads();
if ( rc != LDAP_SUCCESS ) {
return rc;
}
done:;
return rc;
}

View file

@ -0,0 +1,55 @@
#ifndef LDAP_RBAC_H
#define LDAP_RBAC_H
/* extended operations for RBAC */
#define LDAP_RBAC_EXOP_CREATE_SESSION "1.3.6.1.4.1.4203.555.1" /* RFC xxxx */
#define LDAP_RBAC_EXOP_CHECK_ACCESS "1.3.6.1.4.1.4203.555.2"
#define LDAP_RBAC_EXOP_ADD_ACTIVE_ROLE "1.3.6.1.4.1.4203.555.3"
#define LDAP_RBAC_EXOP_DROP_ACTIVE_ROLE "1.3.6.1.4.1.4203.555.4"
#define LDAP_RBAC_EXOP_DELETE_SESSION "1.3.6.1.4.1.4203.555.5"
#define LDAP_RBAC_EXOP_SESSION_ROLES "1.3.6.1.4.1.4203.555.6"
#define LDAP_RBAC_EXOP_SESSION_PERMISSIONS "1.3.6.1.4.1.4203.555.7"
#define LDAP_TAG_EXOP_RBAC_SESSION_ID ((ber_tag_t)0x80U)
#define LDAP_TAG_EXOP_RBAC_TENANT_ID ((ber_tag_t)0x81U)
#define LDAP_TAG_EXOP_RBAC_USER_ID ((ber_tag_t)0x82U)
#define LDAP_TAG_EXOP_RBAC_USER ((ber_tag_t)0x80U)
#define LDAP_TAG_EXOP_RBAC_AUTHTOK ((ber_tag_t)0x83U)
#define LDAP_TAG_EXOP_RBAC_ACTIVE_ROLE ((ber_tag_t)0xA4U)
#define LDAP_TAG_EXOP_RBAC_OPNAME ((ber_tag_t)0x81U)
#define LDAP_TAG_EXOP_RBAC_OBJNAME ((ber_tag_t)0x82U)
#define LDAP_TAG_EXOP_RBAC_OBJID ((ber_tag_t)0x83U)
#define LDAP_TAG_EXOP_RBAC_PWPOLICY_STATE ((ber_tag_t)0x85U)
#define LDAP_TAG_EXOP_RBAC_PWPOLICY_VALUE ((ber_tag_t)0x86U)
#define LDAP_TAG_EXOP_RBAC_ROLES ((ber_tag_t)0x04U)
#define LDAP_TAG_EXOP_RBAC_USER_ID_SESS ((ber_tag_t)0x80U)
#define LDAP_TAG_EXOP_RBAC_SESSION_ID_SESS ((ber_tag_t)0x81U)
#define LDAP_TAG_EXOP_RBAC_ROLE_NM_SESS ((ber_tag_t)0x82U)
#define RBAC_REQ_CREATE_SESSION 0
#define RBAC_REQ_CHECK_ACCESS 1
#define RBAC_REQ_ADD_ACTIVE_ROLE 2
#define RBAC_REQ_DROP_ACTIVE_ROLE 3
#define RBAC_REQ_DELETE_SESSION 4
#define RBAC_REQ_SESSION_PERMISSIONS 5
#define RBAC_REQ_SESSION_ROLES 6
/* defines for password policy */
#define RBAC_BIND_NEW_AUTHTOK_REQD 1
#define RBAC_PASSWORD_GOOD 0
#define RBAC_PASSWORD_EXPIRATION_WARNING 11
#define RBAC_PASSWORD_GRACE_WARNING 12
#define RBAC_PASSWORD_HAS_EXPIRED 100
#define RBAC_ACCOUNT_LOCKED 101
#define RBAC_CHANGE_AFTER_RESET 102
#define RBAC_NO_MODIFICATIONS 103
#define RBAC_MUST_SUPPLY_OLD 104
#define RBAC_INSUFFICIENT_QUALITY 105
#define RBAC_PASSWORD_TOO_SHORT 106
#define RBAC_PASSWORD_TOO_YOUNG 107
#define RBAC_HISTORY_VIOLATION 108
#define RBAC_ACCOUNT_LOCKED_CONSTRAINTS 109
#endif /* LDAP_RBAC_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,402 @@
/* rbac.h - */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
* Copyright 1999-2021 The OpenLDAP Foundation.
* 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:
*
*/
#ifndef RBAC_H
#define RBAC_H
LDAP_BEGIN_DECL
#include "ldap_rbac.h"
#define USE_NEW_THREAD_CONTEXT 1
#define RBAC_BUFLEN 1024
/* tenant initialization op */
#define INIT_AUDIT_CONTAINER 0x01
#define INIT_SESSION_CONTAINER 0x02
typedef struct rbac_ad {
int type;
struct berval attr;
AttributeDescription **ad;
} rbac_ad_t;
/* RBAC AttributeDescriptions */
struct slap_rbac_internal_schema {
/* slapd schema */
AttributeDescription *ad_uid;
/* RBAC tenant */
AttributeDescription *ad_tenant_id;
/* RBAC sessions */
AttributeDescription *ad_session_id;
AttributeDescription *ad_session_user_dn;
AttributeDescription *ad_session_roles;
AttributeDescription *ad_session_role_constraints;
/* RBAC session permissions */
AttributeDescription *ad_permission_opname;
AttributeDescription *ad_permission_objname;
AttributeDescription *ad_permission_rolename;
/* RBAC audit */
AttributeDescription *ad_audit_op; /* rbac op: create_session */
AttributeDescription *ad_audit_id;
AttributeDescription *ad_audit_roles;
AttributeDescription *ad_audit_requested_roles;
AttributeDescription *ad_audit_timestamp;
AttributeDescription *ad_audit_resources;
AttributeDescription *ad_audit_objects;
AttributeDescription *ad_audit_operations; /* resource ops */
AttributeDescription *ad_audit_result;
AttributeDescription *ad_audit_properties;
AttributeDescription *ad_audit_messages;
/* RBAC session attributes */
AttributeName *session_attrs;
};
extern struct slap_rbac_internal_schema slap_rbac_schema;
/* attributes in tenant repository */
struct slap_rbac_tenant_schema {
/* user role assignments, role constraints, and user constraint */
AttributeDescription *ad_role;
AttributeDescription *ad_role_constraint;
AttributeDescription *ad_user_constraint;
AttributeDescription *ad_uid;
/* session permission */
AttributeDescription *ad_permission_users;
AttributeDescription *ad_permission_roles;
AttributeDescription *ad_permission_objname;
AttributeDescription *ad_permission_opname;
/* the list of attributes when doing searches in the jts repo */
AttributeName *user_attrs;
AttributeName *perm_attrs; /* attrs to retrieve for check access */
AttributeName *session_perm_attrs; /* attrs for session permissions */
/* the corresponding list of attribute description mapping */
rbac_ad_t *user_ads;
rbac_ad_t *permission_ads;
rbac_ad_t *session_permissions_ads;
};
extern struct slap_rbac_tenant_schema slap_rbac_jts_schema;
/* types of RBAC requests */
typedef struct rbac_request {
int req_type;
struct berval sessid;
struct berval tenantid;
/* session creation */
struct berval uid;
struct berval authtok;
BerVarray roles;
struct berval role;
/* check access */
struct berval opname;
struct berval objname;
struct berval objid;
} rbac_req_t;
typedef struct rbac_constraint {
struct berval name; /* user name or role name */
int allowed_inactivity; /* secs */
int begin_time; /* secs */
int end_time; /* secs */
lutil_timet begin_date;
lutil_timet end_date;
lutil_timet begin_lock_date;
lutil_timet end_lock_date;
int day_mask;
struct rbac_constraint *next;
} rbac_constraint_t;
/* holds RBAC info */
typedef struct tenant_info {
struct berval tid; /* tenant id */
struct berval admin;
struct berval pwd;
struct berval users_basedn;
struct berval roles_basedn;
struct berval audit_basedn;
struct berval permissions_basedn;
struct berval sessions_basedn;
struct berval session_admin;
struct berval session_admin_pwd;
struct slap_rbac_tenant_schema *schema;
} tenant_info_t;
typedef struct rbac_tenant {
tenant_info_t tenant_info;
struct rbac_tenant *next;
} rbac_tenant_t;
/* for RBAC callback */
typedef struct rbac_callback_info {
tenant_info_t *tenantp;
void *private;
} rbac_callback_info_t;
/* RBAC user */
typedef struct rbac_user {
struct berval tenantid;
struct berval uid;
struct berval dn;
struct berval constraints;
struct berval password;
struct berval msg;
int authz; /* flag for bind (pwd policy) info */
BerVarray roles;
BerVarray role_constraints;
#if 0 /* additional parameters from Fortress */
private String userId;
@XmlElement(nillable = true)
private char[] password;
@XmlElement(nillable = true)
private char[] newPassword;
private String internalId;
@XmlElement(nillable = true)
private List<UserRole> roles;
@XmlElement(nillable = true)
private List<UserAdminRole> adminRoles;
private String pwPolicy;
private String cn;
private String sn;
private String dn;
private String ou;
private String description;
private String beginTime;
private String endTime;
private String beginDate;
private String endDate;
private String beginLockDate;
private String endLockDate;
private String dayMask;
private String name;
private int timeout;
private boolean reset;
private boolean locked;
private Boolean system;
@XmlElement(nillable = true)
private Props props = new Props();
@XmlElement(nillable = true)
private Address address;
@XmlElement(nillable = true)
private List<String> phones;
@XmlElement(nillable = true)
private List<String> mobiles;
@XmlElement(nillable = true)
private List<String> emails;
#endif /* 0 */
} rbac_user_t;
enum {
RBAC_NONE = 0,
RBAC_TENANT,
RBAC_TENANT_ID,
RBAC_USERS_BASE_DN,
RBAC_ROLES_BASE_DN,
RBAC_PERMISSIONS_BASE_DN,
RBAC_ADMIN_DN,
RBAC_ADMIN_PWD,
RBAC_SESSIONS_BASE_DN,
RBAC_SESSION_ADMIN_DN,
RBAC_SESSION_ADMIN_PWD,
RBAC_ROLE_ASSIGNMENT,
RBAC_ROLE_CONSTRAINTS,
RBAC_USER_CONSTRAINTS,
RBAC_UID,
RBAC_USERS,
RBAC_ROLES,
RBAC_OBJ_NAME,
RBAC_OP_NAME,
RBAC_ROLE_NAME,
RBAC_SESSION_ID,
RBAC_USER_DN,
RBAC_AUDIT_ROLES,
RBAC_AUDIT_RESOURCES,
RBAC_AUDIT_RESULT,
RBAC_AUDIT_TIMESTAMP,
RBAC_AUDIT_PROPERTIES,
RBAC_AUDIT_OP,
RBAC_AUDIT_ID,
RBAC_AUDIT_REQUESTED_ROLES,
RBAC_AUDIT_OBJS,
RBAC_AUDIT_OPS,
RBAC_AUDIT_MSGS,
RBAC_LAST
};
enum {
RBAC_DEFAULT_TENANT_ID = RBAC_LAST,
RBAC_DEFAULT_USERS_BASE_DN,
RBAC_DEFAULT_PERMISSIONS_BASE_DN,
RBAC_DEFAULT_ROLES_BASE_DN,
RBAC_DEFAULT_SESSIONS_BASE_DN,
RBAC_DEFAULT_AUDIT_BASE_DN
};
typedef struct rbac_user_idlist {
char *user_id;
struct rbac_user_idlist *next;
} rbac_user_idlist_t;
/* RBAC sessions */
#define RBAC_SESSION_RDN_EQ "rbacSessid="
#define RBAC_AUDIT_RDN_EQ "rbacAuditId="
typedef struct rbac_session {
rbac_user_t *user;
struct berval tenantid;
struct berval sessid;
struct berval uid;
struct berval userdn;
char uuidbuf[ LDAP_LUTIL_UUIDSTR_BUFSIZE ];
struct berval sessdn;
long last_access;
int timeout;
int warning_id;
int error_id;
int grace_logins;
int expiration_secs;
int is_authenticated; /* boolean */
struct berval message;
BerVarray roles;
BerVarray role_constraints;
} rbac_session_t;
/* RBAC roles */
typedef struct rbac_role {
char *name;
char *description;
struct rbac_role *parent;
struct rbac_role *next;
} rbac_role_t;
typedef struct rbac_role_list {
char *name;
struct rbac_role_list *next;
} rbac_role_list_t;
/* RBAC permissions */
typedef struct rbac_permission {
struct berval dn;
int admin; /* boolean */
struct berval internalId;
BerVarray opName;
BerVarray objName;
struct berval objectId;
struct berval abstractName;
struct berval type;
BerVarray roles;
BerVarray uids;
struct rbac_permission *next;
} rbac_permission_t;
/* RBAC Audit */
typedef enum {
CreateSession = 0,
CheckAccess,
AddActiveRole,
DropActiveRole,
SessionPermissions,
DeleteSession,
SessionRoles
} audit_op_t;
/* function prototypes */
int rbac_initialize_repository( void );
int rbac_initialize_tenants( BackendDB *be, ConfigReply *cr );
/* RBAC tenant information */
tenant_info_t *rbac_tid2tenant( struct berval *tid );
rbac_req_t *rbac_alloc_req( int type );
void rbac_free_req( rbac_req_t *reqp );
rbac_user_t *rbac_read_user( Operation *op, rbac_req_t *rabc_reqp );
int rbac_authenticate_user( Operation *op, rbac_user_t *user );
int rbac_user_temporal_constraint( rbac_user_t *userp );
void rbac_free_user( rbac_user_t *user );
rbac_session_t *rbac_alloc_session( void );
int rbac_is_valid_session_id( struct berval *sessid );
rbac_session_t *rbac_session_byid( Operation *op, rbac_req_t *reqp );
int rbac_is_session_owner( rbac_session_t *sessp, rbac_req_t *reqp );
int rbac_register_session( Operation *op, SlapReply *rs, rbac_session_t *sess );
int rbac_int_delete_session( Operation *op, rbac_session_t *sessp );
int rbac_session_add_role(
Operation *op,
rbac_session_t *sessp,
rbac_req_t *reqp );
int rbac_session_drop_role(
Operation *op,
rbac_session_t *sessp,
rbac_req_t *reqp );
int rbac_int_session_permissions(
Operation *op,
SlapReply *rs,
rbac_req_t *reqp,
rbac_session_t *sessp );
int activate_session_roles(
rbac_session_t *sessp,
rbac_req_t *reqp,
rbac_user_t *userp );
void rbac_free_session( rbac_session_t *sessp );
rbac_constraint_t *rbac_user_role_constraints( BerVarray values );
rbac_constraint_t *rbac_role2constraint(
struct berval *role,
rbac_constraint_t *role_constraints );
rbac_constraint_t *rbac_bv2constraint( struct berval *bv );
int rbac_check_time_constraint( rbac_constraint_t *cp );
void rbac_free_constraint( rbac_constraint_t *cp );
void rbac_free_constraints( rbac_constraint_t *constraints );
rbac_permission_t *rbac_read_permission( Operation *op, rbac_req_t *rbac_reqp );
int rbac_check_session_permission(
rbac_session_t *sessp,
rbac_permission_t *permp,
rbac_constraint_t *role_constraints );
void rbac_free_permission( rbac_permission_t *permp );
/* audit functions */
void rbac_audit(
Operation *op,
audit_op_t rbac_op,
rbac_session_t *sessp,
rbac_req_t *reqp,
int result,
char *msg );
/* acl functions */
int rbac_create_session_acl_check( struct berval *sessid, rbac_user_t *userp );
void rbac_to_lower( struct berval *bv );
LDAP_END_DECL
#endif /* RBAC_H */

View file

@ -0,0 +1,37 @@
/* rbacacl.c - RBAC ACL */
/* $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/string.h>
#include "slap.h"
#include "slap-config.h"
#include "lutil.h"
#include "rbac.h"
int
rbac_create_session_acl_check( struct berval *sessid, rbac_user_t *userp )
{
int rc = LDAP_SUCCESS;
return rc;
}

View file

@ -0,0 +1,233 @@
/* rbacaudit.c - RBAC Audit */
/* $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/string.h>
#include "slap.h"
#include "slap-config.h"
#include "lutil.h"
#include "rbac.h"
static struct rbac_audit_op {
audit_op_t op;
struct berval op_bv;
} rbac_audit_ops[] = {
{ CreateSession, BER_BVC("CreateSession") },
{ CheckAccess, BER_BVC("CheckAccess") },
{ AddActiveRole, BER_BVC("AddActiveRole") },
{ DropActiveRole, BER_BVC("DropActiveRole") },
{ SessionPermissions, BER_BVC("SessionPermissions") },
{ DeleteSession, BER_BVC("DeleteSession") },
{ SessionRoles, BER_BVC("SessionRoles") },
{ -1, BER_BVNULL }
};
static int
rbac_audit_fake_cb( Operation *op, SlapReply *rs )
{
Debug( LDAP_DEBUG_ANY, "rbac_audit_fake_cb\n" );
return 0;
}
void
rbac_audit(
Operation *op,
audit_op_t rbac_op,
rbac_session_t *sessp,
rbac_req_t *reqp,
int result,
char *msg )
{
int op_idx, rc = LDAP_SUCCESS;
int found = 0;
struct berval timestamp;
tenant_info_t *tenantp = rbac_tid2tenant( &sessp->tenantid );
slap_callback cb = { 0 };
SlapReply rs2 = { REP_RESULT };
Entry *e = NULL;
struct berval auditObjectClass = BER_BVC("rbacAudit");
struct berval auditResultSuccess = BER_BVC("success");
struct berval auditResultFailed = BER_BVC("failed");
struct berval bv, rdn, nrdn;
char rdnbuf[RBAC_BUFLEN];
time_t now;
char nowstr[LDAP_LUTIL_GENTIME_BUFSIZE];
for ( op_idx = 0; rbac_audit_ops[op_idx].op != -1; op_idx++ ) {
if ( rbac_op == rbac_audit_ops[op_idx].op ) {
/* legit audit op */
found = 1;
break;
}
}
if ( !found ) goto done;
e = entry_alloc();
/* audit timestamp */
now = slap_get_time(); /* stored for later consideration */
timestamp.bv_val = nowstr;
timestamp.bv_len = sizeof(nowstr);
slap_timestamp( &now, &timestamp );
/* construct audit record DN; FIXME: random() call */
sprintf( rdnbuf, "%s%d", RBAC_AUDIT_RDN_EQ, (int)op->o_tid );
strcat( rdnbuf, "-" );
strncat( rdnbuf, timestamp.bv_val, timestamp.bv_len );
bv.bv_val = &rdnbuf[0];
bv.bv_len = strlen( &rdnbuf[0] );
rc = dnPrettyNormal( NULL, &bv, &rdn, &nrdn, NULL );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "rbac_audit: "
"unable to normalize audit rDN (rc=%d)\n", rc );
goto done;
}
/* FIXME: audit_basedn should have been normalized */
build_new_dn( &e->e_name, &tenantp->audit_basedn, &rdn, NULL );
build_new_dn( &e->e_nname, &tenantp->audit_basedn, &nrdn, NULL );
ch_free( rdn.bv_val );
ch_free( nrdn.bv_val );
/* add timestamp */
attr_merge_one( e, slap_rbac_schema.ad_audit_timestamp, &timestamp, NULL );
/* add rbac audit objectClass */
attr_merge_one( e, slap_schema.si_ad_objectClass, &auditObjectClass, NULL );
attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
&auditObjectClass, NULL );
/* audit op */
attr_merge_one( e, slap_rbac_schema.ad_audit_op,
&rbac_audit_ops[op_idx].op_bv, NULL );
/* userid */
if ( sessp && !BER_BVISNULL( &sessp->uid ) ) {
attr_merge_one( e, slap_schema.si_ad_uid, &sessp->uid, NULL );
}
/* session id */
if ( sessp && !BER_BVISNULL( &sessp->sessid ) ) {
AttributeDescription *ad = NULL;
const char *text = NULL;
struct berval sessid = BER_BVC("rbacSessid");
rc = slap_bv2ad( &sessid, &ad, &text );
if ( rc != LDAP_SUCCESS ) {
goto done;
}
attr_merge_one( e, ad, &sessp->sessid, NULL );
}
/* audit result */
attr_merge_one( e, slap_rbac_schema.ad_audit_result,
result == LDAP_SUCCESS ? &auditResultSuccess : &auditResultFailed,
NULL );
switch ( rbac_op ) {
case CreateSession:
/* audit roles */
if ( sessp && sessp->roles ) {
attr_merge( e, slap_rbac_schema.ad_audit_roles, sessp->roles,
NULL );
}
if ( reqp && reqp->roles ) {
attr_merge( e, slap_rbac_schema.ad_audit_requested_roles,
reqp->roles, NULL );
}
break;
case CheckAccess:
if ( sessp && sessp->roles ) {
attr_merge( e, slap_rbac_schema.ad_audit_roles, sessp->roles,
NULL );
}
if ( reqp && !BER_BVISEMPTY( &reqp->opname ) ) {
attr_merge_one( e, slap_rbac_schema.ad_audit_operations,
&reqp->opname, NULL );
}
if ( reqp && !BER_BVISEMPTY( &reqp->objname ) ) {
attr_merge_one( e, slap_rbac_schema.ad_audit_objects,
&reqp->objname, NULL );
}
break;
case AddActiveRole:
if ( reqp && reqp->roles ) {
attr_merge( e, slap_rbac_schema.ad_audit_requested_roles,
reqp->roles, NULL );
}
break;
case DropActiveRole:
/* audit roles */
if ( reqp && reqp->roles ) {
attr_merge( e, slap_rbac_schema.ad_audit_requested_roles,
reqp->roles, NULL );
}
break;
case SessionPermissions:
if ( sessp && sessp->roles ) {
attr_merge( e, slap_rbac_schema.ad_audit_roles, sessp->roles,
NULL );
}
break;
case DeleteSession:
case SessionRoles:
default:
break;
}
/* record the audit record */
Operation op2 = *op;
rbac_callback_info_t rbac_cb;
cb.sc_private = &rbac_cb;
cb.sc_response = rbac_audit_fake_cb;
op2.o_callback = &cb;
op2.o_tag = LDAP_REQ_ADD;
op2.o_protocol = LDAP_VERSION3;
op2.o_req_dn = e->e_name;
op2.o_req_ndn = e->e_nname;
op2.ora_e = e;
op2.o_bd = select_backend( &op2.o_req_ndn, 0 );
op2.o_dn = op2.o_bd->be_rootdn;
op2.o_ndn = op2.o_bd->be_rootndn;
op2.ors_limit = NULL;
rc = op2.o_bd->be_add( &op2, &rs2 );
done:
if ( e ) entry_free( e );
return;
}

View file

@ -0,0 +1,233 @@
/* rbacperm.c - RBAC permission */
/* $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/string.h>
#include "slap.h"
#include "slap-config.h"
#include "lutil.h"
#include "rbac.h"
static int
rbac_read_permission_cb( Operation *op, SlapReply *rs )
{
rbac_callback_info_t *cbp = op->o_callback->sc_private;
rbac_ad_t *permission_ads;
rbac_permission_t *permp;
int i;
if ( rs->sr_type != REP_SEARCH ) return 0;
assert( cbp );
permp = ch_calloc( 1, sizeof(rbac_permission_t) );
permission_ads = cbp->tenantp->schema->permission_ads;
ber_dupbv( &permp->dn, &rs->sr_entry->e_name );
for ( i = 0; !BER_BVISNULL( &permission_ads[i].attr ); i++ ) {
Attribute *attr = NULL;
attr = attr_find( rs->sr_entry->e_attrs, *permission_ads[i].ad );
if ( attr != NULL ) {
switch ( permission_ads[i].type ) {
case RBAC_USERS:
ber_bvarray_dup_x( &permp->uids, attr->a_nvals, NULL );
break;
case RBAC_ROLES:
ber_bvarray_dup_x( &permp->roles, attr->a_nvals, NULL );
break;
default:
break;
}
}
}
cbp->private = (void *)permp;
return 0;
}
/*
* check whether roles assigned to a user allows access to roles in
* a permission, subject to role constraints
*/
int
rbac_check_session_permission(
rbac_session_t *sessp,
rbac_permission_t *permp,
rbac_constraint_t *role_constraints )
{
int rc = LDAP_INSUFFICIENT_ACCESS;
rbac_constraint_t *cp = NULL;
int i, j;
if ( !sessp->roles || !permp->roles ) goto done;
for ( i = 0; !BER_BVISNULL( &sessp->roles[i] ); i++ ) {
for ( j = 0; !BER_BVISNULL( &permp->roles[j] ); j++ ) {
if ( ber_bvstrcasecmp( &sessp->roles[i], &permp->roles[j] ) == 0 ) {
/* role temporal constraint */
cp = rbac_role2constraint( &permp->roles[j], role_constraints );
if ( !cp || rbac_check_time_constraint( cp ) == LDAP_SUCCESS ) {
rc = LDAP_SUCCESS;
goto done;
}
}
}
}
done:;
return rc;
}
rbac_permission_t *
rbac_read_permission( Operation *op, rbac_req_t *reqp )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
rbac_callback_info_t rbac_cb;
int rc = LDAP_SUCCESS;
char fbuf[1024];
struct berval filter = { sizeof(fbuf), fbuf };
char permbuf[1024];
struct berval permdn = { sizeof(permbuf), permbuf };
struct berval permndn = BER_BVNULL;
char pcls[] = "(objectClass=ftOperation)";
SlapReply rs2 = { REP_RESULT };
slap_callback cb = { 0 };
tenant_info_t *tenantp = rbac_tid2tenant( &reqp->tenantid );
#if 0 /* check valid object name and op name */
if ( !is_valid_opname( &reqp->opname ) ||
!is_valid_objname( &reqp->objname ) ) {
Debug( LDAP_DEBUG_ANY, "rbac_read_permission: "
"invalid opname (%s) or objname (%s)\n",
reqp->opname.bv_val, reqp->objname.bv_val );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
#endif
if ( !tenantp ) {
Debug( LDAP_DEBUG_ANY, "rbac_read_permission: "
"missing tenant information\n" );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
if ( reqp->objid.bv_val != NULL ) {
permdn.bv_len = snprintf( permdn.bv_val, permdn.bv_len,
"ftObjId=%s+ftOpNm=%s,ftObjNm=%s,%s", reqp->objid.bv_val,
reqp->opname.bv_val, reqp->objname.bv_val,
tenantp->permissions_basedn.bv_val );
} else {
permdn.bv_len = snprintf( permdn.bv_val, permdn.bv_len,
"ftOpNm=%s,ftObjNm=%s,%s", reqp->opname.bv_val,
reqp->objname.bv_val, tenantp->permissions_basedn.bv_val );
}
rc = dnNormalize( 0, NULL, NULL, &permdn, &permndn, NULL );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "rbac_read_permission: "
"unable to normalize permission DN\n" );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
filter.bv_val = pcls;
filter.bv_len = strlen( pcls );
rbac_cb.tenantp = tenantp;
rbac_cb.private = NULL;
Operation op2 = *op;
cb.sc_private = &rbac_cb;
cb.sc_response = rbac_read_permission_cb;
op2.o_callback = &cb;
op2.o_tag = LDAP_REQ_SEARCH;
op2.o_dn = tenantp->admin;
op2.o_ndn = tenantp->admin;
op2.o_req_dn = permdn;
op2.o_req_ndn = permndn;
op2.ors_filterstr = filter;
op2.ors_filter = str2filter_x( &op2, filter.bv_val );
op2.ors_scope = LDAP_SCOPE_BASE;
op2.ors_attrs = tenantp->schema->perm_attrs;
op2.ors_tlimit = SLAP_NO_LIMIT;
op2.ors_slimit = SLAP_NO_LIMIT;
op2.ors_attrsonly = 0;
op2.ors_limit = NULL;
op2.o_bd = frontendDB;
rc = op2.o_bd->be_search( &op2, &rs2 );
filter_free_x( &op2, op2.ors_filter, 1 );
done:;
ch_free( permndn.bv_val );
if ( rc != LDAP_SUCCESS ) {
rbac_free_permission((rbac_permission_t *)rbac_cb.private);
}
return (rbac_permission_t *)rbac_cb.private;
}
void
rbac_free_permission( rbac_permission_t *permp )
{
if ( !permp ) return;
if ( !BER_BVISNULL( &permp->dn ) ) {
ber_memfree( permp->dn.bv_val );
}
if ( !BER_BVISNULL( &permp->internalId ) ) {
ber_memfree( permp->internalId.bv_val );
}
if ( permp->opName ) {
ber_bvarray_free( permp->opName );
}
if ( permp->objName ) {
ber_bvarray_free( permp->objName );
}
if ( !BER_BVISNULL( &permp->objectId ) ) {
ber_memfree( permp->objectId.bv_val );
}
if ( !BER_BVISNULL( &permp->abstractName ) ) {
ber_memfree( permp->abstractName.bv_val );
}
if ( !BER_BVISNULL( &permp->type ) ) {
ber_memfree( permp->type.bv_val );
}
if ( permp->roles ) {
ber_bvarray_free( permp->roles );
}
if ( permp->uids ) {
ber_bvarray_free( permp->uids );
}
ch_free( permp );
return;
}

View file

@ -0,0 +1,89 @@
/* rbacreq.c - RBAC requests */
/* $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/string.h>
#include "slap.h"
#include "slap-config.h"
#include "lutil.h"
#include "rbac.h"
rbac_req_t *
rbac_alloc_req( int type )
{
rbac_req_t *reqp = NULL;
reqp = ch_calloc( 1, sizeof(rbac_req_t) );
reqp->req_type = type;
BER_BVZERO( &reqp->sessid );
BER_BVZERO( &reqp->tenantid );
/* session creation */
BER_BVZERO( &reqp->uid );
BER_BVZERO( &reqp->authtok );
reqp->roles = NULL;
/* check access */
BER_BVZERO( &reqp->opname );
BER_BVZERO( &reqp->objname );
BER_BVZERO( &reqp->objid );
/* add/drop role */
BER_BVZERO( &reqp->role );
return reqp;
}
void
rbac_free_req( rbac_req_t *reqp )
{
if ( !reqp ) return;
if ( !BER_BVISNULL( &reqp->sessid ) )
ber_memfree( reqp->sessid.bv_val );
if ( !BER_BVISNULL( &reqp->tenantid ) )
ber_memfree( reqp->tenantid.bv_val );
/* session creation */
if ( !BER_BVISNULL( &reqp->uid ) )
ber_memfree( reqp->uid.bv_val );
if ( !BER_BVISNULL( &reqp->authtok ) )
ber_memfree( reqp->authtok.bv_val );
if ( reqp->roles )
ber_bvarray_free( reqp->roles );
/* check access */
if ( !BER_BVISNULL( &reqp->opname ) )
ber_memfree( reqp->opname.bv_val );
if ( !BER_BVISNULL( &reqp->objname ) )
ber_memfree( reqp->objname.bv_val );
if ( !BER_BVISNULL( &reqp->objid ) )
ber_memfree( reqp->objid.bv_val );
ch_free( reqp );
return;
}

View file

@ -0,0 +1,999 @@
/* rbacsess.c - RBAC session */
/* $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/string.h>
#include "slap.h"
#include "slap-config.h"
#include "lutil.h"
#include "rbac.h"
static slap_callback nullsc = { NULL, NULL, NULL, NULL };
extern rbac_ad_t rbac_session_permission_ads[];
extern rbac_ad_t rbac_session_ads[];
struct berval slapo_session_oc = BER_BVC("rbacSession");
typedef struct session_perm_req {
Operation *op;
SlapReply *rs;
struct berval *sessid;
struct berval permdn;
tenant_info_t *tenantp;
} session_perm_req_t;
static int
rbac_sess_fake_cb( Operation *op, SlapReply *rs )
{
Debug( LDAP_DEBUG_ANY, "rbac_sess_fake_cb\n" );
return 0;
}
static int
rbac_send_session_permission(
session_perm_req_t *sess_perm_reqp,
rbac_permission_t *perm )
{
int i, rc = LDAP_SUCCESS;
Operation *op = sess_perm_reqp->op;
SlapReply *rs = sess_perm_reqp->rs;
struct berval *sessidp = sess_perm_reqp->sessid;
struct berval *permdnp = &sess_perm_reqp->permdn;
Entry *e = entry_alloc();
e->e_attrs = NULL;
ber_dupbv( &e->e_name, permdnp );
ber_dupbv( &e->e_nname, permdnp );
e->e_private = NULL;
attr_merge_one( e, slap_rbac_schema.ad_session_id, sessidp, NULL );
for ( i = 0; !BER_BVISNULL( &rbac_session_permission_ads[i].attr ); i++ ) {
switch ( rbac_session_permission_ads[i].type ) {
case RBAC_OP_NAME:
attr_merge_one( e, *rbac_session_permission_ads[i].ad,
&perm->opName[0], NULL );
break;
case RBAC_OBJ_NAME:
attr_merge_one( e, *rbac_session_permission_ads[i].ad,
&perm->objName[0], NULL );
break;
case RBAC_ROLE_NAME:
attr_merge( e, *rbac_session_permission_ads[i].ad, perm->roles,
NULL );
break;
default:
break;
}
}
rs->sr_entry = e;
rs->sr_flags = REP_ENTRY_MUSTRELEASE;
rc = send_search_entry( op, rs );
return rc;
}
static int
rbac_session_permissions_cb( Operation *op, SlapReply *rs )
{
session_perm_req_t *sess_perm_reqp = op->o_callback->sc_private;
tenant_info_t *tenantp = NULL;
rbac_permission_t *permp = NULL;
rbac_ad_t *session_permissions_ads;
int i;
if ( rs->sr_type != REP_SEARCH ) return 0;
assert( sess_perm_reqp );
tenantp = sess_perm_reqp->tenantp;
session_permissions_ads = tenantp->schema->session_permissions_ads;
permp = ch_calloc( 1, sizeof(rbac_permission_t) );
for ( i = 0; !BER_BVISNULL( &session_permissions_ads[i].attr ); i++ ) {
Attribute *attr = NULL;
attr = attr_find(
rs->sr_entry->e_attrs, *session_permissions_ads[i].ad );
if ( attr != NULL ) {
switch ( session_permissions_ads[i].type ) {
case RBAC_USERS:
ber_bvarray_dup_x( &permp->uids, attr->a_nvals, NULL );
break;
case RBAC_ROLES:
ber_bvarray_dup_x( &permp->roles, attr->a_nvals, NULL );
break;
case RBAC_OBJ_NAME:
ber_bvarray_dup_x( &permp->objName, attr->a_nvals, NULL );
break;
case RBAC_OP_NAME:
ber_bvarray_dup_x( &permp->opName, attr->a_nvals, NULL );
break;
}
}
}
rbac_send_session_permission( sess_perm_reqp, permp );
rbac_free_permission( permp );
permp = NULL;
return SLAP_CB_CONTINUE;
}
static int
rbac_read_session_cb( Operation *op, SlapReply *rs )
{
rbac_session_t *sessp = op->o_callback->sc_private;
int i;
if ( rs->sr_type != REP_SEARCH ) return 0;
ber_dupbv( &sessp->sessdn, &rs->sr_entry->e_name );
for ( i = 0; !BER_BVISNULL( &rbac_session_ads[i].attr ); i++ ) {
Attribute *attr = NULL;
attr = attr_find( rs->sr_entry->e_attrs, *rbac_session_ads[i].ad );
if ( attr != NULL ) {
switch ( rbac_session_ads[i].type ) {
case RBAC_SESSION_ID:
ber_dupbv( &sessp->sessid, &attr->a_vals[0] );
break;
case RBAC_USER_DN:
ber_dupbv( &sessp->userdn, &attr->a_vals[0] );
break;
case RBAC_ROLES:
ber_bvarray_dup_x( &sessp->roles, attr->a_nvals, NULL );
break;
case RBAC_ROLE_CONSTRAINTS:
ber_bvarray_dup_x(
&sessp->role_constraints, attr->a_nvals, NULL );
break;
case RBAC_UID:
ber_dupbv( &sessp->uid, &attr->a_vals[0] );
break;
case RBAC_TENANT_ID:
ber_dupbv( &sessp->tenantid, &attr->a_vals[0] );
break;
default:
break;
}
}
}
//return SLAP_CB_CONTINUE;
return 0;
}
/* check whether the session is owned by the user */
int
rbac_is_session_owner( rbac_session_t *sessp, rbac_req_t *reqp )
{
int rc = 0;
if ( BER_BVISEMPTY( &sessp->uid ) || BER_BVISEMPTY( &reqp->uid ) ) {
Debug( LDAP_DEBUG_ANY, "session not owned by user\n" );
rc = 0;
goto done;
}
if ( !ber_bvstrcasecmp( &sessp->uid, &reqp->uid ) ) {
rc = 1;
goto done;
}
done:;
return rc;
}
int
rbac_session_add_role( Operation *op, rbac_session_t *sessp, rbac_req_t *reqp )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
slap_callback cb = { 0 };
SlapReply rs2 = { REP_RESULT };
Operation op2 = *op;
rbac_callback_info_t rbac_cb;
tenant_info_t *tenantp = NULL;
struct berval vals[2];
Modifications mod;
int rc = LDAP_SUCCESS;
tenantp = rbac_tid2tenant( &reqp->tenantid );
if ( !tenantp ) {
Debug( LDAP_DEBUG_ANY, "rbac_session_add_role: "
"no tenant info with the req\n" );
goto done;
}
// convert the role name to lower case:
rbac_to_lower( &reqp->role );
//ber_dupbv( &vals[0], &reqp->roles[0]);
ber_dupbv( &vals[0], &reqp->role );
BER_BVZERO( &vals[1] );
/* create mod list */
mod.sml_op = LDAP_MOD_ADD;
mod.sml_flags = 0;
mod.sml_type = slap_rbac_schema.ad_session_roles->ad_cname;
mod.sml_desc = slap_rbac_schema.ad_session_roles;
mod.sml_numvals = 1;
mod.sml_values = vals;
mod.sml_nvalues = NULL;
mod.sml_next = NULL;
cb.sc_private = &rbac_cb;
cb.sc_response = rbac_sess_fake_cb;
op2.o_callback = &cb;
op2.o_tag = LDAP_REQ_MODIFY;
op2.orm_modlist = &mod;
op2.o_req_dn = sessp->sessdn;
op2.o_req_ndn = sessp->sessdn;
op2.o_bd = select_backend( &op2.o_req_ndn, 0 );
op2.o_dn = op2.o_bd->be_rootdn;
op2.o_ndn = op2.o_bd->be_rootdn;
op2.ors_limit = NULL;
rc = op2.o_bd->be_modify( &op2, &rs2 );
ch_free( vals[0].bv_val );
done:;
if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
Debug( LDAP_DEBUG_ANY, "rbac_add_active_role: "
"role already activated in session\n" );
}
return rc;
}
int
rbac_session_drop_role( Operation *op, rbac_session_t *sessp, rbac_req_t *reqp )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
slap_callback cb = { 0 };
SlapReply rs2 = { REP_RESULT };
Operation op2 = *op;
rbac_callback_info_t rbac_cb;
tenant_info_t *tenantp = NULL;
Modifications *m = NULL;
int rc = LDAP_SUCCESS;
tenantp = rbac_tid2tenant( &reqp->tenantid );
if ( !tenantp ) {
Debug( LDAP_DEBUG_ANY, "rbac_session_drop_role: "
"no tenant info with the req\n" );
goto done;
}
/* create mod list */
m = ch_calloc( sizeof(Modifications), 1 );
m->sml_op = LDAP_MOD_DELETE;
m->sml_flags = 0;
m->sml_type = slap_rbac_schema.ad_session_roles->ad_cname;
m->sml_desc = slap_rbac_schema.ad_session_roles;
m->sml_numvals = 1;
m->sml_values = ch_calloc( sizeof(struct berval), 2 );
m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
//ber_dupbv( &m->sml_values[0], &reqp->roles[0]);
// convert the role name to lower case:
rbac_to_lower( &reqp->role );
ber_dupbv( &m->sml_values[0], &reqp->role );
// todo: determine if this needs to be done:
//BER_BVZERO(&m->sml_values[1]);
ber_dupbv( &m->sml_nvalues[0], &reqp->role );
BER_BVZERO( &m->sml_nvalues[1] );
//ber_dupbv( &m->sml_nvalues[0], &reqp->roles[0]);
//ber_dupbv( &m->sml_nvalues[0], &reqp->role);
//BER_BVZERO(&m->sml_nvalues[1]);
m->sml_next = NULL;
cb.sc_private = &rbac_cb;
cb.sc_response = rbac_sess_fake_cb;
op2.o_callback = &cb;
op2.o_dn = tenantp->session_admin;
op2.o_ndn = tenantp->session_admin;
op2.o_tag = LDAP_REQ_MODIFY;
op2.orm_modlist = m;
op2.o_req_dn = sessp->sessdn;
op2.o_req_ndn = sessp->sessdn;
op2.o_bd = select_backend( &op2.o_req_ndn, 0 );
op2.ors_limit = NULL;
rc = op2.o_bd->be_modify( &op2, &rs2 );
done:;
if ( m ) {
slap_mods_free( m, 1 );
}
return rc;
}
/* delete the session */
int
rbac_int_delete_session( Operation *op, rbac_session_t *sessp )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
slap_callback cb = { 0 };
SlapReply rs2 = { REP_RESULT };
Operation op2 = *op;
rbac_callback_info_t rbac_cb;
tenant_info_t *tenantp = NULL;
int rc = LDAP_SUCCESS;
tenantp = rbac_tid2tenant( &sessp->tenantid );
if ( !tenantp ) {
Debug( LDAP_DEBUG_ANY, "rbac_session_drop_role: "
"no tenant info with the req\n" );
goto done;
}
/* delete RBAC session */
cb.sc_private = &rbac_cb;
cb.sc_response = rbac_sess_fake_cb;
op2.o_callback = &cb;
op2.o_dn = tenantp->session_admin;
op2.o_ndn = tenantp->session_admin;
op2.o_tag = LDAP_REQ_DELETE;
op2.o_req_dn = sessp->sessdn;
op2.o_req_ndn = sessp->sessdn;
op2.o_bd = select_backend( &op2.o_req_ndn, 0 );
rc = op2.o_bd->be_delete( &op2, &rs2 );
done:;
return rc;
}
rbac_session_t *
rbac_alloc_session()
{
rbac_session_t *sessp = NULL;
sessp = ch_malloc( sizeof(rbac_session_t) );
sessp->sessid.bv_len =
lutil_uuidstr( sessp->uuidbuf, sizeof(sessp->uuidbuf) );
sessp->sessid.bv_val = sessp->uuidbuf;
sessp->user = NULL;
BER_BVZERO( &sessp->tenantid );
BER_BVZERO( &sessp->uid );
BER_BVZERO( &sessp->userdn );
BER_BVZERO( &sessp->sessdn );
BER_BVZERO( &sessp->message );
sessp->last_access = 0;
sessp->timeout = 0;
sessp->warning_id = 0;
sessp->error_id = 0;
sessp->grace_logins = 0;
sessp->expiration_secs = 0;
sessp->is_authenticated = 0;
sessp->roles = NULL;
sessp->role_constraints = NULL;
return sessp;
}
int
rbac_register_session( Operation *op, SlapReply *rs, rbac_session_t *sessp )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
struct berval rdn, nrdn;
SlapReply rs2 = { REP_RESULT };
OperationBuffer opbuf;
Operation *op2;
Connection conn = { 0 };
Entry *e = NULL;
int rc = LDAP_SUCCESS;
char rdnbuf[
STRLENOF(RBAC_SESSION_RDN_EQ) + LDAP_LUTIL_UUIDSTR_BUFSIZE + 1];
tenant_info_t *tenantp = rbac_tid2tenant( &sessp->tenantid );
#ifdef USE_NEW_THREAD_CONTEXT
void *thrctx = ldap_pvt_thread_pool_context();
#else
void *thrctx = op->o_tmpmemctx;
#endif
if ( !sessp ) {
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
/* dynamic objects */
e = entry_alloc();
strcpy( rdnbuf, RBAC_SESSION_RDN_EQ );
strncat( rdnbuf, sessp->sessid.bv_val, sessp->sessid.bv_len );
rdn.bv_val = rdnbuf;
rdn.bv_len = STRLENOF(RBAC_SESSION_RDN_EQ) + sessp->sessid.bv_len;
nrdn.bv_val = rdnbuf;
nrdn.bv_len = STRLENOF(RBAC_SESSION_RDN_EQ) + sessp->sessid.bv_len;
build_new_dn( &e->e_name, &tenantp->sessions_basedn, &rdn, NULL );
build_new_dn( &e->e_nname, &tenantp->sessions_basedn, &nrdn, NULL );
attr_merge_one( e, slap_schema.si_ad_objectClass, &slapo_session_oc, NULL );
attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
&slapo_session_oc, NULL );
attr_merge_one( e, slap_rbac_schema.ad_session_id, &sessp->sessid, NULL );
if ( !BER_BVISNULL( &sessp->uid ) ) {
attr_merge_one( e, slap_schema.si_ad_uid, &sessp->uid, NULL );
}
/* add tenant id */
if ( !BER_BVISNULL( &sessp->tenantid ) ) {
attr_merge_one(
e, slap_rbac_schema.ad_tenant_id, &sessp->tenantid, NULL );
}
/* add the userdn */
if ( !BER_BVISNULL( &sessp->userdn ) ) {
attr_merge_one(
e, slap_rbac_schema.ad_session_user_dn, &sessp->userdn, NULL );
}
if ( sessp->roles ) {
attr_merge( e, slap_rbac_schema.ad_session_roles, sessp->roles, NULL );
}
// TODO: ensure this is correct way to store constraints in session:
if ( sessp->role_constraints ) {
attr_merge( e, slap_rbac_schema.ad_session_role_constraints,
sessp->role_constraints, NULL );
}
/* rendered dynmaicObject */
attr_merge_one( e, slap_schema.si_ad_objectClass,
&slap_schema.si_oc_dynamicObject->soc_cname, NULL );
/* store RBAC session */
connection_fake_init2( &conn, &opbuf, thrctx, 0 );
op2 = &opbuf.ob_op;
//Operation op2 = *op;
//op2.o_callback = &nullsc;
//rbac_callback_info_t rbac_cb;
//cb.sc_private = &rbac_cb;
//cb.sc_response = rbac_sess_fake_cb;
//op2.o_callback = &cb;
//op2.ors_limit = NULL;
op->o_callback = &nullsc;
op2->o_dn = tenantp->session_admin;
op2->o_ndn = tenantp->session_admin;
op2->o_tag = LDAP_REQ_ADD;
op2->o_protocol = LDAP_VERSION3;
op2->o_req_dn = e->e_name;
op2->o_req_ndn = e->e_nname;
op2->ora_e = e;
op2->o_bd = frontendDB;
rc = op2->o_bd->be_add( op2, &rs2 );
done:;
if ( e ) entry_free( e );
return rc;
}
int
rbac_register_session2( Operation *op, SlapReply *rs, rbac_session_t *sessp )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
struct berval rdn, nrdn;
SlapReply rs2 = { REP_RESULT };
Operation op2 = *op;
rbac_callback_info_t rbac_cb;
//OperationBuffer opbuf;
//Connection conn = {0};
Entry *e = NULL;
int rc = LDAP_SUCCESS;
char rdnbuf[STRLENOF(RBAC_SESSION_RDN_EQ) + LDAP_LUTIL_UUIDSTR_BUFSIZE +
1];
tenant_info_t *tenantp = rbac_tid2tenant( &sessp->tenantid );
slap_callback cb = { 0 };
//#ifdef USE_NEW_THREAD_CONTEXT
// void *thrctx = ldap_pvt_thread_pool_context();
//#else
// void *thrctx = op->o_tmpmemctx;
//#endif
if ( !sessp ) {
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
/* dynamic objects */
e = entry_alloc();
strcpy( rdnbuf, RBAC_SESSION_RDN_EQ );
strncat( rdnbuf, sessp->sessid.bv_val, sessp->sessid.bv_len );
rdn.bv_val = rdnbuf;
rdn.bv_len = STRLENOF(RBAC_SESSION_RDN_EQ) + sessp->sessid.bv_len;
nrdn.bv_val = rdnbuf;
nrdn.bv_len = STRLENOF(RBAC_SESSION_RDN_EQ) + sessp->sessid.bv_len;
build_new_dn( &e->e_name, &tenantp->sessions_basedn, &rdn, NULL );
build_new_dn( &e->e_nname, &tenantp->sessions_basedn, &nrdn, NULL );
attr_merge_one( e, slap_schema.si_ad_objectClass, &slapo_session_oc, NULL );
attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
&slapo_session_oc, NULL );
attr_merge_one( e, slap_rbac_schema.ad_session_id, &sessp->sessid, NULL );
if ( !BER_BVISNULL( &sessp->uid ) ) {
attr_merge_one( e, slap_schema.si_ad_uid, &sessp->uid, NULL );
}
/* add tenant id */
if ( !BER_BVISNULL( &sessp->tenantid ) ) {
attr_merge_one(
e, slap_rbac_schema.ad_tenant_id, &sessp->tenantid, NULL );
}
/* add the userdn */
if ( !BER_BVISNULL( &sessp->userdn ) ) {
attr_merge_one(
e, slap_rbac_schema.ad_session_user_dn, &sessp->userdn, NULL );
}
if ( sessp->roles ) {
attr_merge( e, slap_rbac_schema.ad_session_roles, sessp->roles, NULL );
}
// TODO: ensure this is correct way to store constraints in session:
if ( sessp->role_constraints ) {
attr_merge( e, slap_rbac_schema.ad_session_role_constraints,
sessp->role_constraints, NULL );
}
/* rendered dynmaicObject */
attr_merge_one( e, slap_schema.si_ad_objectClass,
&slap_schema.si_oc_dynamicObject->soc_cname, NULL );
/* store RBAC session */
//connection_fake_init2( &conn, &opbuf, thrctx, 0 );
//op2 = &opbuf.ob_op;
//op2.o_ctrlflag = op->o_ctrlflag;
// todo this ain't right"
//op2.o_ctrlflag = 0;
//OperationBuffer *opbuf;
//memset( opbuf, 0, sizeof(OperationBuffer));
//op2.o_hdr = &opbuf->ob_hdr;
//op2.o_controls = opbuf->ob_controls;
// fails on modify.c:353 with segfault
//op2.o_callback = &nullsc;
cb.sc_private = &rbac_cb;
cb.sc_response = rbac_sess_fake_cb;
op2.o_callback = &cb;
op2.o_dn = tenantp->session_admin;
op2.o_ndn = tenantp->session_admin;
op2.o_tag = LDAP_REQ_ADD;
op2.o_protocol = LDAP_VERSION3;
op2.o_req_dn = e->e_name;
op2.o_req_ndn = e->e_nname;
op2.ora_e = e;
op2.o_bd = frontendDB;
//op2.ors_limit = NULL;
rc = op2.o_bd->be_add( &op2, &rs2 );
done:;
if ( e ) entry_free( e );
return rc;
}
int
rbac_is_valid_session_id( struct berval *sessid )
{
/* TODO: simple test */
if ( !sessid || sessid->bv_len != 36 ) {
if ( !sessid ) {
Debug( LDAP_DEBUG_ANY, "rbac_is_valid_session_id: "
"null sessid\n" );
} else {
Debug( LDAP_DEBUG_ANY, "rbac_is_valid_session_id: "
"len (%lu)\n",
sessid->bv_len );
}
return 0;
}
else {
return 1;
}
}
/* create an rbac request with the session ID */
rbac_req_t *
rbac_is_search_session_permissions( Operation *op )
{
rbac_req_t *reqp = NULL;
/* check whether the search for sessionPermissions and *
* with a valid sessionID */
return reqp;
}
rbac_session_t *
rbac_session_byid_fake( Operation *op, rbac_req_t *reqp )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
rbac_session_t *sessp = NULL;
int rc = LDAP_SUCCESS;
char fbuf[RBAC_BUFLEN];
struct berval filter = { sizeof(fbuf), fbuf };
SlapReply rs2 = { REP_RESULT };
Operation op2 = *op;
rbac_callback_info_t rbac_cb;
slap_callback cb = { 0 };
tenant_info_t *tenantp = NULL;
if ( !rbac_is_valid_session_id( &reqp->sessid ) ) {
Debug( LDAP_DEBUG_ANY, "rbac_session_byid: "
"invalid session id (%s)\n",
reqp->sessid.bv_val );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
sessp = rbac_alloc_session();
if ( !sessp ) {
Debug( LDAP_DEBUG_ANY, "rbac_session_byid: "
"unable to allocate session memory\n" );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
tenantp = rbac_tid2tenant( &reqp->tenantid );
/* session id filter */
memset( fbuf, 0, sizeof(fbuf) );
strcpy( fbuf, RBAC_SESSION_RDN_EQ );
strncpy( &fbuf[0] + sizeof(RBAC_SESSION_RDN_EQ) - 1, reqp->sessid.bv_val,
reqp->sessid.bv_len );
filter.bv_val = fbuf;
filter.bv_len = strlen( fbuf );
//cb.sc_private = sessp;
//cb.sc_response = rbac_read_session_cb;
cb.sc_private = &rbac_cb;
cb.sc_response = rbac_sess_fake_cb;
op2.o_callback = &cb;
op2.o_tag = LDAP_REQ_SEARCH;
op2.o_dn = tenantp->session_admin;
op2.o_ndn = tenantp->session_admin;
op2.o_req_dn = tenantp->sessions_basedn;
op2.o_req_ndn = tenantp->sessions_basedn;
op2.ors_filterstr = filter;
op2.ors_filter = str2filter_x( &op2, filter.bv_val );
op2.ors_scope = LDAP_SCOPE_SUBTREE;
op2.ors_attrs = slap_rbac_schema.session_attrs;
op2.ors_tlimit = SLAP_NO_LIMIT;
op2.ors_slimit = SLAP_NO_LIMIT;
op2.o_bd = frontendDB;
// hyc change to fix seg fault:
op2.ors_limit = NULL;
rc = op2.o_bd->be_search( &op2, &rs2 );
filter_free_x( &op2, op2.ors_filter, 1 );
done:
// TODO: find equivilant way of check nentries (broke with fake connection fix)
//if ( rc != LDAP_SUCCESS || rs2.sr_nentries <= 0 ) {
if ( rc != LDAP_SUCCESS ) {
rbac_free_session( sessp );
sessp = NULL;
}
return sessp;
}
rbac_session_t *
rbac_session_byid( Operation *op, rbac_req_t *reqp )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
rbac_session_t *sessp = NULL;
int rc = LDAP_SUCCESS;
char fbuf[RBAC_BUFLEN];
struct berval filter = { sizeof(fbuf), fbuf };
SlapReply rs2 = { REP_RESULT };
Operation op2 = *op;
slap_callback cb = { 0 };
tenant_info_t *tenantp = NULL;
if ( !rbac_is_valid_session_id( &reqp->sessid ) ) {
Debug( LDAP_DEBUG_ANY, "rbac_session_byid: "
"invalid session id (%s)\n",
reqp->sessid.bv_val );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
sessp = rbac_alloc_session();
if ( !sessp ) {
Debug( LDAP_DEBUG_ANY, "rbac_session_byid: "
"unable to allocate session memory\n" );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
tenantp = rbac_tid2tenant( &reqp->tenantid );
/* session id filter */
memset( fbuf, 0, sizeof(fbuf) );
strcpy( fbuf, RBAC_SESSION_RDN_EQ );
strncpy( &fbuf[0] + sizeof(RBAC_SESSION_RDN_EQ) - 1, reqp->sessid.bv_val,
reqp->sessid.bv_len );
filter.bv_val = fbuf;
filter.bv_len = strlen( fbuf );
cb.sc_private = sessp;
cb.sc_response = rbac_read_session_cb;
op2.o_callback = &cb;
op2.o_tag = LDAP_REQ_SEARCH;
op2.o_dn = tenantp->session_admin;
op2.o_ndn = tenantp->session_admin;
op2.o_req_dn = tenantp->sessions_basedn;
op2.o_req_ndn = tenantp->sessions_basedn;
op2.ors_filterstr = filter;
op2.ors_filter = str2filter_x( &op2, filter.bv_val );
op2.ors_scope = LDAP_SCOPE_SUBTREE;
op2.ors_attrs = slap_rbac_schema.session_attrs;
op2.ors_tlimit = SLAP_NO_LIMIT;
op2.ors_slimit = SLAP_NO_LIMIT;
op2.o_bd = frontendDB;
// hyc change to fix seg fault:
op2.ors_limit = NULL;
rc = op2.o_bd->be_search( &op2, &rs2 );
filter_free_x( &op2, op2.ors_filter, 1 );
done:
// TODO: find equivalent way of check nentries (broke with fake connection fix)
//if ( rc != LDAP_SUCCESS || rs2.sr_nentries <= 0 ) {
if ( rc != LDAP_SUCCESS ) {
rbac_free_session( sessp );
sessp = NULL;
}
return sessp;
}
static char *
rbac_int_session_permissions_filterstr( Operation *op, rbac_session_t *sessp )
{
char filterbuf[RBAC_BUFLEN];
int i;
memset( filterbuf, 0, sizeof(filterbuf) );
strcat( filterbuf, "(&(objectClass=ftOperation)(|" );
strcat( filterbuf, "(ftUsers=" );
strcat( filterbuf, sessp->uid.bv_val );
strcat( filterbuf, ")" );
/* add ftRoles filters */
for ( i = 0; !BER_BVISEMPTY( &sessp->roles[i] ); i++ ) {
strcat( filterbuf, "(ftRoles=" );
strncat( filterbuf, sessp->roles[i].bv_val, sessp->roles[i].bv_len );
strcat( filterbuf, ")" );
}
strcat( filterbuf, "))" );
return strdup( filterbuf );
}
int
rbac_int_session_permissions(
Operation *op,
SlapReply *rs,
rbac_req_t *reqp,
rbac_session_t *sessp )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
tenant_info_t *tenantp = NULL;
int rc;
struct berval filter;
char *filterstr;
struct berval permndn = BER_BVNULL;
OperationBuffer opbuf;
Connection conn = { 0 };
SlapReply rs2 = { REP_RESULT };
Operation *op2;
slap_callback cb = { 0 };
char permbuf[1024];
session_perm_req_t sess_perm_req;
#ifdef USE_NEW_THREAD_CONTEXT
void *thrctx = ldap_pvt_thread_pool_context();
#else
void *thrctx = op->o_tmpmemctx;
#endif
tenantp = rbac_tid2tenant( &reqp->tenantid );
/* construct session permissions dn */
memset( permbuf, 0, sizeof(permbuf) );
strcat( permbuf, "rbacSessid=" );
strncat( permbuf, sessp->sessid.bv_val, sessp->sessid.bv_len );
strcat( permbuf, ",dc=rbac" );
sess_perm_req.op = op;
sess_perm_req.rs = rs;
sess_perm_req.permdn.bv_val = permbuf;
sess_perm_req.permdn.bv_len = strlen( permbuf );
sess_perm_req.sessid = &reqp->sessid;
sess_perm_req.tenantp = tenantp;
filterstr = rbac_int_session_permissions_filterstr( op, sessp );
if ( !filterstr ) {
Debug( LDAP_DEBUG_ANY, "unable to construct filter for session permissions\n" );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
filter.bv_val = filterstr;
filter.bv_len = strlen( filterstr );
rc = dnNormalize(
0, NULL, NULL, &tenantp->permissions_basedn, &permndn, NULL );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "rbac_read_permission: "
"unable to normalize permission DN\n" );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
connection_fake_init2( &conn, &opbuf, thrctx, 0 );
op2 = &opbuf.ob_op;
//Operation op2 = *op;
cb.sc_private = &sess_perm_req;
cb.sc_response = rbac_session_permissions_cb;
op2->o_callback = &cb;
op2->o_tag = LDAP_REQ_SEARCH;
op2->o_dn = tenantp->admin;
op2->o_ndn = tenantp->admin;
op2->o_req_dn = tenantp->permissions_basedn;
op2->o_req_ndn = permndn;
op2->ors_filterstr = filter;
op2->ors_filter = str2filter_x( op, filter.bv_val );
op2->ors_scope = LDAP_SCOPE_SUB;
op2->ors_attrs = tenantp->schema->session_perm_attrs;
op2->ors_tlimit = SLAP_NO_LIMIT;
op2->ors_slimit = SLAP_NO_LIMIT;
op2->ors_attrsonly = 0;
op2->o_bd = frontendDB;
//op2.ors_limit = NULL;
rc = op2->o_bd->be_search( op2, &rs2 );
filter_free_x( op, op2->ors_filter, 1 );
done:;
/* generate audit log */
rbac_audit( op, SessionPermissions, sessp, reqp, rc, (char *)rs->sr_text );
rs->sr_err = rc;
return rs->sr_err;
}
void
rbac_free_session( rbac_session_t *sessp )
{
if ( !sessp ) return;
if ( sessp->user ) {
rbac_free_user( sessp->user );
}
if ( !BER_BVISNULL( &sessp->uid ) ) {
ber_memfree( sessp->uid.bv_val );
}
if ( !BER_BVISNULL( &sessp->tenantid ) ) {
ber_memfree( sessp->tenantid.bv_val );
}
if ( !BER_BVISNULL( &sessp->userdn ) ) {
ber_memfree( sessp->userdn.bv_val );
}
if ( !BER_BVISNULL( &sessp->sessdn ) ) {
ber_memfree( sessp->sessdn.bv_val );
}
if ( !BER_BVISNULL( &sessp->message ) ) {
ber_memfree( sessp->message.bv_val );
}
if ( sessp->roles ) {
ber_bvarray_free( sessp->roles );
}
if ( sessp->role_constraints ) {
ber_bvarray_free( sessp->role_constraints );
}
ch_free( sessp );
return;
}
/* roles included from request are activated into a session only when
* they exist and have been assigned to the user. If no roles included in request, all
* roles assigned to the user are activated into the rbac session.
*/
int
activate_session_roles(
rbac_session_t *sessp,
rbac_req_t *reqp,
rbac_user_t *userp )
{
int i, j, rc = LDAP_UNWILLING_TO_PERFORM;
if ( !sessp || !reqp || !userp ) {
goto done;
}
/* no role requested, assign all roles from the user to the session. */
if ( reqp->roles == NULL || BER_BVISNULL( &reqp->roles[0] ) ) {
//if (!reqp->roles || BER_BVISNULL(&reqp->roles[0])) {
/* no roles assigned to the user */
if ( !userp->roles || BER_BVISNULL( &userp->roles[0] ) ) goto done;
for ( i = 0; !BER_BVISNULL( &userp->roles[i] ); i++ ) {
struct berval role;
ber_dupbv_x( &role, &userp->roles[i], NULL );
ber_bvarray_add( &sessp->roles, &role );
rc = LDAP_SUCCESS;
}
// TODO: smm 20141218 - make sure this is correct way to add constraints to user session.
for ( i = 0; !BER_BVISNULL( &userp->role_constraints[i] ); i++ ) {
struct berval roleconstraint;
ber_dupbv_x( &roleconstraint, &userp->role_constraints[i], NULL );
ber_bvarray_add( &sessp->role_constraints, &roleconstraint );
rc = LDAP_SUCCESS;
}
} else {
for ( i = 0; !BER_BVISNULL( &reqp->roles[i] ); i++ ) {
for ( j = 0; !BER_BVISNULL( &userp->roles[j] ); j++ ) {
if ( !ber_bvstrcasecmp( &reqp->roles[i], &userp->roles[j] ) ) {
/* requested role is assigned to the user */
struct berval role;
ber_dupbv_x( &role, &userp->roles[i], NULL );
ber_bvarray_add( &sessp->roles, &role );
rc = LDAP_SUCCESS;
}
}
}
}
done:;
return rc;
}

View file

@ -0,0 +1,620 @@
/* rbacuser.c - RBAC users */
/* $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/string.h>
#include "slap.h"
#include "slap-config.h"
#include "lutil.h"
#include "rbac.h"
static int ppolicy_cid = -1;
static rbac_user_t *
rbac_alloc_user()
{
rbac_user_t *userp = ch_calloc( 1, sizeof(rbac_user_t) );
BER_BVZERO( &userp->tenantid );
BER_BVZERO( &userp->uid );
BER_BVZERO( &userp->dn );
BER_BVZERO( &userp->password );
BER_BVZERO( &userp->constraints );
BER_BVZERO( &userp->msg );
userp->roles = NULL;
userp->role_constraints = NULL;
return userp;
}
static int
rbac_read_user_cb( Operation *op, SlapReply *rs )
{
rbac_callback_info_t *cbp = op->o_callback->sc_private;
rbac_ad_t *user_ads;
rbac_user_t *userp = NULL;
int rc = 0, i;
Debug( LDAP_DEBUG_ANY, "rbac_read_user_cb\n" );
if ( rs->sr_type != REP_SEARCH ) {
Debug( LDAP_DEBUG_ANY, "rbac_read_user_cb: "
"sr_type != REP_SEARCH\n" );
return 0;
}
assert( cbp );
user_ads = cbp->tenantp->schema->user_ads;
userp = rbac_alloc_user();
if ( !userp ) {
Debug( LDAP_DEBUG_ANY, "rbac_read_user_cb: "
"rbac_alloc_user failed\n" );
goto done;
}
ber_dupbv( &userp->dn, &rs->sr_entry->e_name );
Debug( LDAP_DEBUG_ANY, "DEBUG rbac_read_user_cb (%s): "
"rc (%d)\n",
userp->dn.bv_val, rc );
for ( i = 0; !BER_BVISNULL( &user_ads[i].attr ); i++ ) {
Attribute *attr = NULL;
attr = attr_find( rs->sr_entry->e_attrs, *user_ads[i].ad );
if ( attr != NULL ) {
switch ( user_ads[i].type ) {
case RBAC_ROLE_ASSIGNMENT:
ber_bvarray_dup_x( &userp->roles, attr->a_nvals, NULL );
break;
case RBAC_ROLE_CONSTRAINTS:
ber_bvarray_dup_x(
&userp->role_constraints, attr->a_nvals, NULL );
break;
case RBAC_USER_CONSTRAINTS:
ber_dupbv_x( &userp->constraints, &attr->a_nvals[0], NULL );
break;
case RBAC_UID:
ber_dupbv_x( &userp->uid, &attr->a_nvals[0], NULL );
break;
default:
break;
}
}
}
done:;
cbp->private = userp;
return 0;
}
static int
rbac_bind_cb( Operation *op, SlapReply *rs )
{
rbac_user_t *ui = op->o_callback->sc_private;
LDAPControl *ctrl = ldap_control_find(
LDAP_CONTROL_PASSWORDPOLICYRESPONSE, rs->sr_ctrls, NULL );
if ( ctrl ) {
LDAP *ld;
ber_int_t expire, grace;
LDAPPasswordPolicyError error;
ldap_create( &ld );
if ( ld ) {
int rc = ldap_parse_passwordpolicy_control(
ld, ctrl, &expire, &grace, &error );
if ( rc == LDAP_SUCCESS ) {
ui->authz = RBAC_PASSWORD_GOOD;
if ( grace > 0 ) {
//ui->msg.bv_len = sprintf(ui->msg.bv_val,
// "Password expired; %d grace logins remaining",
// grace);
ui->authz = RBAC_BIND_NEW_AUTHTOK_REQD;
} else if ( error != PP_noError ) {
ber_str2bv( ldap_passwordpolicy_err2txt( error ), 0, 0,
&ui->msg );
switch ( error ) {
case PP_passwordExpired:
ui->authz = RBAC_PASSWORD_EXPIRATION_WARNING;
if ( expire >= 0 ) {
char *unit = "seconds";
if ( expire > 60 ) {
expire /= 60;
unit = "minutes";
}
if ( expire > 60 ) {
expire /= 60;
unit = "hours";
}
if ( expire > 24 ) {
expire /= 24;
unit = "days";
}
#if 0 /* Who warns about expiration so far in advance? */
if (expire > 7) {
expire /= 7;
unit = "weeks";
}
if (expire > 4) {
expire /= 4;
unit = "months";
}
if (expire > 12) {
expire /= 12;
unit = "years";
}
#endif
}
//rs->sr_err = ;
break;
case PP_accountLocked:
ui->authz = RBAC_ACCOUNT_LOCKED;
//rs->sr_err = ;
break;
case PP_changeAfterReset:
ui->authz = RBAC_CHANGE_AFTER_RESET;
rs->sr_err = LDAP_SUCCESS;
break;
case PP_passwordModNotAllowed:
ui->authz = RBAC_NO_MODIFICATIONS;
//rs->sr_err = ;
break;
case PP_mustSupplyOldPassword:
ui->authz = RBAC_MUST_SUPPLY_OLD;
//rs->sr_err = ;
break;
case PP_insufficientPasswordQuality:
ui->authz = RBAC_INSUFFICIENT_QUALITY;
//rs->sr_err = ;
break;
case PP_passwordTooShort:
ui->authz = RBAC_PASSWORD_TOO_SHORT;
//rs->sr_err = ;
break;
case PP_passwordTooYoung:
ui->authz = RBAC_PASSWORD_TOO_YOUNG;
//rs->sr_err = ;
break;
case PP_passwordInHistory:
ui->authz = RBAC_HISTORY_VIOLATION;
//rs->sr_err = ;
break;
case PP_noError:
default:
// do nothing
//ui->authz = RBAC_PASSWORD_GOOD;
rs->sr_err = LDAP_SUCCESS;
break;
}
// switch (error) {
// case PP_passwordExpired:
/* report this during authz */
// rs->sr_err = LDAP_SUCCESS;
/* fallthru */
// case PP_changeAfterReset:
// ui->authz = RBAC_BIND_NEW_AUTHTOK_REQD;
// }
}
}
ldap_unbind_ext( ld, NULL, NULL );
}
}
return 0;
}
/* exported user functions */
int
rbac_authenticate_user( Operation *op, rbac_user_t *userp )
{
int rc = LDAP_SUCCESS;
slap_callback cb = { 0 };
SlapReply rs2 = { REP_RESULT };
Operation op2 = *op;
LDAPControl *sctrls[4];
LDAPControl sctrl[3];
int nsctrls = 0;
LDAPControl c;
struct berval ber_bvnull = BER_BVNULL;
struct berval dn, ndn;
rc = dnPrettyNormal( 0, &userp->dn, &dn, &ndn, NULL );
if ( rc != LDAP_SUCCESS ) {
goto done;
}
cb.sc_response = rbac_bind_cb;
cb.sc_private = userp;
op2.o_callback = &cb;
op2.o_dn = ber_bvnull;
op2.o_ndn = ber_bvnull;
op2.o_tag = LDAP_REQ_BIND;
op2.o_protocol = LDAP_VERSION3;
op2.orb_method = LDAP_AUTH_SIMPLE;
op2.orb_cred = userp->password;
op2.o_req_dn = dn;
op2.o_req_ndn = ndn;
// loading the ldap pw policy controls loaded into here, added by smm:
c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
c.ldctl_value.bv_val = NULL;
c.ldctl_value.bv_len = 0;
c.ldctl_iscritical = 0;
sctrl[nsctrls] = c;
sctrls[nsctrls] = &sctrl[nsctrls];
sctrls[++nsctrls] = NULL;
op2.o_ctrls = sctrls;
if ( ppolicy_cid < 0 ) {
rc = slap_find_control_id( LDAP_CONTROL_PASSWORDPOLICYREQUEST,
&ppolicy_cid );
if ( rc != LDAP_SUCCESS ) {
goto done;
}
}
// smm - need to set the control flag too:
op2.o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_CRITICAL;
slap_op_time( &op2.o_time, &op2.o_tincr );
op2.o_bd = frontendDB;
rc = op2.o_bd->be_bind( &op2, &rs2 );
if ( userp->authz > 0 ) {
Debug( LDAP_DEBUG_ANY, "rbac_authenticate_user (%s): "
"password policy violation (%d)\n",
userp->dn.bv_val ? userp->dn.bv_val : "NULL", userp->authz );
}
done:;
ch_free( dn.bv_val );
ch_free( ndn.bv_val );
Debug( LDAP_DEBUG_ANY, "rbac_authenticate_user (%s): "
"rc (%d)\n",
userp->dn.bv_val ? userp->dn.bv_val : "NULL", rc );
return rc;
}
/*
isvalidusername(): from OpenLDAP ~/contrib/slapd-modules/nssov/passwd.c
Checks to see if the specified name is a valid user name.
This test is based on the definition from POSIX (IEEE Std 1003.1, 2004, 3.426 User Name
and 3.276 Portable Filename Character Set):
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_426
http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276
The standard defines user names valid if they contain characters from
the set [A-Za-z0-9._-] where the hyphen should not be used as first
character. As an extension this test allows the dolar '$' sign as the last
character to support Samba special accounts.
*/
static int
isvalidusername( struct berval *bv )
{
int i;
char *name = bv->bv_val;
if ( (name == NULL) || ( name[0] == '\0' ) ) return 0;
/* check first character */
if ( !( ( name[0] >= 'A' && name[0] <= 'Z' ) ||
( name[0] >= 'a' && name[0] <= 'z' ) ||
( name[0] >= '0' && name[0] <= '9' ) || name[0] == '.' ||
name[0] == '_' ) )
return 0;
/* check other characters */
for ( i = 1; i < bv->bv_len; i++ ) {
if ( name[i] == '$' ) {
/* if the char is $ we require it to be the last char */
if ( name[i + 1] != '\0' ) return 0;
} else if ( !( ( name[i] >= 'A' && name[i] <= 'Z' ) ||
( name[i] >= 'a' && name[i] <= 'z' ) ||
( name[i] >= '0' && name[i] <= '9' ) ||
name[i] == '.' || name[i] == '_' ||
name[i] == '-' ) )
return 0;
}
/* no test failed so it must be good */
return -1;
}
rbac_user_t *
rbac_read_user( Operation *op, rbac_req_t *reqp )
{
int rc = LDAP_SUCCESS;
tenant_info_t *tenantp = rbac_tid2tenant( &reqp->tenantid );
rbac_user_t *userp = NULL;
char fbuf[RBAC_BUFLEN];
struct berval filter = { sizeof(fbuf), fbuf };
SlapReply rs2 = { REP_RESULT };
Operation op2 = *op;
slap_callback cb = { 0 };
rbac_callback_info_t rbac_cb;
if ( !tenantp ) {
Debug( LDAP_DEBUG_ANY, "rbac_read_user: "
"missing tenant information\n" );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
/* uid is a pre-requisite for reading the user information */
if ( BER_BVISNULL( &reqp->uid ) ) {
Debug( LDAP_DEBUG_ANY, "rbac_read_user: "
"missing uid, unable to read user entry\n" );
rc = LDAP_UNWILLING_TO_PERFORM;
goto done;
}
if ( !isvalidusername( &reqp->uid ) ) {
Debug( LDAP_DEBUG_ANY, "rbac_read_user: "
"invalid user id\n" );
rc = LDAP_NO_SUCH_OBJECT;
goto done;
}
rbac_cb.tenantp = tenantp;
rbac_cb.private = NULL;
memset( fbuf, 0, sizeof(fbuf) );
strcpy( fbuf, "uid=" );
strncat( fbuf, reqp->uid.bv_val, reqp->uid.bv_len );
filter.bv_val = fbuf;
filter.bv_len = strlen( fbuf );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY, "rbac_create_session: "
"invalid DN syntax\n" );
goto done;
}
cb.sc_private = &rbac_cb;
cb.sc_response = rbac_read_user_cb;
op2.o_callback = &cb;
op2.o_tag = LDAP_REQ_SEARCH;
op2.o_dn = tenantp->admin;
op2.o_ndn = tenantp->admin;
op2.o_req_dn = tenantp->users_basedn;
op2.o_req_ndn = tenantp->users_basedn;
op2.ors_filterstr = filter;
op2.ors_filter = str2filter_x( &op2, filter.bv_val );
op2.ors_scope = LDAP_SCOPE_SUBTREE;
op2.ors_attrs = tenantp->schema->user_attrs;
op2.ors_tlimit = SLAP_NO_LIMIT;
op2.ors_slimit = SLAP_NO_LIMIT;
op2.ors_attrsonly = 0;
op2.o_bd = frontendDB;
op2.ors_limit = NULL;
rc = op2.o_bd->be_search( &op2, &rs2 );
filter_free_x( &op2, op2.ors_filter, 1 );
done:;
if ( rc == LDAP_SUCCESS && rbac_cb.private ) {
userp = (rbac_user_t *)rbac_cb.private;
if ( !BER_BVISNULL( &reqp->authtok ) )
ber_dupbv( &userp->password, &reqp->authtok );
rbac_cb.private = NULL;
return userp;
} else {
userp = (rbac_user_t *)rbac_cb.private;
rbac_free_user( userp );
return NULL;
}
}
/* evaluate temporal constraints for the user */
int
rbac_user_temporal_constraint( rbac_user_t *userp )
{
int rc = LDAP_SUCCESS;
rbac_constraint_t *cp = NULL;
if ( BER_BVISNULL( &userp->constraints ) ) {
/* no temporal constraint */
goto done;
}
cp = rbac_bv2constraint( &userp->constraints );
if ( !cp ) {
Debug( LDAP_DEBUG_ANY, "rbac_user_temporal_constraint: "
"invalid user constraint \n" );
rc = LDAP_OTHER;
goto done;
}
rc = rbac_check_time_constraint( cp );
done:;
rbac_free_constraint( cp );
return rc;
}
/*
rbac_constraint_t *
rbac_user_role_constraintsx(rbac_user_t *userp)
{
rbac_constraint_t *tmp, *cp = NULL;
int i = 0;
if (!userp || !userp->role_constraints)
goto done;
while (!BER_BVISNULL(&userp->role_constraints[i])) {
tmp = rbac_bv2constraint(&userp->role_constraints[i++]);
if (tmp) {
if (!cp) {
cp = tmp;
} else {
tmp->next = cp;
cp = tmp;
}
}
}
done:;
return cp;
}
*/
rbac_constraint_t *
rbac_user_role_constraints( BerVarray values )
{
rbac_constraint_t *curr, *head = NULL;
int i = 0;
if ( values ) {
while ( !BER_BVISNULL( &values[i] ) ) {
curr = rbac_bv2constraint( &values[i++] );
if ( curr ) {
curr->next = head;
head = curr;
}
}
}
return head;
}
/*
void main() {
item * curr, * head;
int i;
head = NULL;
for(i=1;i<=10;i++) {
curr = (item *)malloc(sizeof(item));
curr->val = i;
curr->next = head;
head = curr;
}
curr = head;
while(curr) {
printf("%d\n", curr->val);
curr = curr->next ;
}
}
*/
/*
*
rbac_user_role_constraints2(BerVarray values)
{
rbac_constraint_t *tmp, *cp = NULL;
int i = 0;
if (!values)
goto done;
while (!BER_BVISNULL(&values[i])) {
tmp = rbac_bv2constraint(&values[i++]);
if (tmp) {
if (!cp) {
cp = tmp;
} else {
tmp->next = cp;
cp = tmp;
//cp->next = tmp;
//cp = tmp->next;
}
}
}
done:;
return cp;
}
rbac_user_role_constraints3(rbac_constraint_t *values)
{
rbac_constraint_t *tmp, *cp = NULL;
int i = 0;
if (!values)
goto done;
while (!BER_BVISNULL(values[i])) {
tmp = rbac_bv2constraint(&values[i++]);
if (tmp) {
if (!cp) {
cp = tmp;
} else {
tmp->next = cp;
cp = tmp;
}
}
}
done:;
return cp;
}
*/
void
rbac_free_user( rbac_user_t *userp )
{
if ( !userp ) return;
if ( !BER_BVISNULL( &userp->tenantid ) ) {
ber_memfree( userp->tenantid.bv_val );
}
if ( !BER_BVISNULL( &userp->uid ) ) {
ber_memfree( userp->uid.bv_val );
}
if ( !BER_BVISNULL( &userp->dn ) ) {
ber_memfree( userp->dn.bv_val );
}
if ( !BER_BVISNULL( &userp->constraints ) ) {
ber_memfree( userp->constraints.bv_val );
}
if ( !BER_BVISNULL( &userp->password ) ) {
ber_memfree( userp->password.bv_val );
}
if ( !BER_BVISNULL( &userp->msg ) ) {
ber_memfree( userp->msg.bv_val );
}
if ( userp->roles ) ber_bvarray_free( userp->roles );
if ( userp->role_constraints ) ber_bvarray_free( userp->role_constraints );
ch_free( userp );
}

View file

@ -0,0 +1,157 @@
.TH SLAPO_RBAC 5 "RELEASEDATE" "OpenLDAP LDVERSION"
.\" Copyright 1999-2021 SYMAS Corporation All Rights Reserved.
.\" Copying restrictions apply. See COPYRIGHT/LICENSE.
.\" $OpenLDAP$
.SH NAME
slapo\-rbac \- RBAC0 overlay to slapd
.SH SYNOPSIS
ETCDIR/slapd.conf
.SH DESCRIPTION
.LP
The
.B slapo-rbac
overlay
is an implementation of the ANSI INCITS 359 Role-Based Access Control (RBAC) Core.
When instantiated, it intercepts, decodes and enforces specific RBAC policies per the Apache Fortress RBAC data formats.
.P
The overlay provides a set of extended operations.
They include session create/delete, checkAccess, addActiveRole, dropActiveRole and sessionRoles.
.P
.SH CONFIGURATION
These
.B slapd.conf
configuration options apply to the slapo-rbac overlay.
.TP
.B overlay rbac
This tag gets applied to the RBAC configuration db (see example below).
.TP
.B rbac-default-users-base-dn "ou=People,dc=example,dc=com"
Points to the container that contains the Apache Fortress users.
.TP
.B rbac-default-roles-base-dn "ou=Roles,ou=RBAC,dc=example,dc=com"
Points to the container that contains the Apache Fortress roles.
.TP
.B rbac-default-permissions-base-dn "ou=Permissions,ou=RBAC,dc=example,dc=com"
Points to the container that contains the Apache Fortress perms.
.TP
.B rbac-default-sessions-base-dn "cn=rbac"
Points to the suffix of the RBAC sessions.
.TP
.B rbac-default-audit-base-dn "cn=audit"
Points to the suffix where the audit records are stored.
.TP
.B rbac-admin "cn=manager,dc=example,dc=com"
A service account that has read access to the entire Apache Fortress DIT.
.TP
.B rbac-pwd "{SSHA}pSOV2TpCxj2NMACijkcMko4fGrFopctU"
The password according to the service account.
.TP
.B rbac-session-admin "cn=manager,cn=rbac"
The root dn of the RBAC sessions database.
.TP
.B rbac-session-admin-pwd {SSHA}pSOV2TpCxj2NMACijkcMko4fGrFopctU
The password corresponding with the session database.
.TP
.RE
.SH EXAMPLES
.LP
.RS
.nf
This overlay requires the
.B rbac.schema
loaded and three additional database config sections, one to store rbac
sessions, second to store the audit records and third to hold the overlay's
config parameters. They should appear after the existing Apache Fortress db
config.
.TP
1. Session Database: Used to store the RBAC sessions corresponding to a logged in user.
.B database mdb
.B suffix "cn=rbac"
.B rootdn "cn=manager,cn=rbac"
.B rootpw {SSHA}pSOV2TpCxj2NMACijkcMko4fGrFopctU
.B index rbacSessid eq
.B directory "/var/openldap/rbacsess"
.B overlay dds
.B dds-default-ttl 3600
.B dds-max-dynamicObjects 100000
.B dbnosync
.B checkpoint 64 5
.PP
.TP
2. Audit Database: Stores records that track user's activities.
.B database mdb
.B suffix "cn=audit"
.B rootdn "cn=manager,cn=audit"
.B rootpw {SSHA}pSOV2TpCxj2NMACijkcMko4fGrFopctU
.B directory "/var/openldap/rbacaudit"
.B dbnosync
.B checkpoint 64 5
.PP
.TP
3. Config Database: Stores the parameters needed for this overlay to work.
.B database mdb
.B suffix "dc=rbac"
.B rootdn "cn=manager,dc=rbac"
.B rootpw {SSHA}pSOV2TpCxj2NMACijkcMko4fGrFopctU
.B directory "/var/openldap/rbacoverlay"
.B overlay rbac
.B rbac-default-tenant-id "example"
.B rbac-default-users-base-dn "ou=People,dc=example,dc=com"
.B rbac-default-roles-base-dn "ou=Roles,ou=RBAC,dc=example,dc=com"
.B rbac-default-permissions-base-dn "ou=Permissions,ou=RBAC,dc=example,dc=com"
.B rbac-default-sessions-base-dn "cn=rbac"
.B rbac-default-audit-base-dn "cn=audit"
.B rbac-admin "cn=manager,dc=example,dc=com"
.B rbac-pwd "{SSHA}pSOV2TpCxj2NMACijkcMko4fGrFopctU"
.B rbac-session-admin "cn=manager,cn=rbac"
.B rbac-session-admin-pwd {SSHA}pSOV2TpCxj2NMACijkcMko4fGrFopctU
.fi
.RE
.SH SEE ALSO
.BR ldap (3),
.BR slapd.conf (5),
.BR slapd\-config (5),
.BR slapo\-chain (5).
.LP
"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/)
.LP
.BR ldap (3),
.BR slapd.conf (5),
.BR slapd\-config (5),
.BR slapo\-chain (5).
.LP
"OpenLDAP Administrator's Guide" (http://www.OpenLDAP.org/doc/admin/)
.LP
.UR https://profsandhu.com/journals/tissec/ANSI+INCITS+359-2004.pdf
.UE ANSI INCITS 359 Role-Based Access Control specification
.UR https://github.com/apache/directory-fortress-core/blob/master/README.md
.UE Apache Fortress README
.UR https://github.com/apache/directory-fortress-core/blob/master/README-QUICKSTART-SLAPD.md
.UE Apache Fortress OpenLDAP Quickstart
.UR https://github.com/apache/directory-fortress-core/blob/master/ldap/schema/fortress.schema
.UE Apache Fortress RBAC schema
.SH BUGS
This overlay is experimental.
.SH ACKNOWLEDGEMENTS
.P
This module was written in 2013 by Ted Cheng of Symas Corporation
with a little help from Matt Hardin, Howard Chu, Shawn McKinney.
.P
.so ../Project

View file

@ -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 withing 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] );
}
}