mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-22 06:43:17 -05:00
999 lines
26 KiB
C
999 lines
26 KiB
C
/* 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 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;
|
|
}
|
|
|
|
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;
|
|
}
|