diff options
Diffstat (limited to 'contrib/slapd-modules/rbac/rbacsess.c')
-rw-r--r-- | contrib/slapd-modules/rbac/rbacsess.c | 999 |
1 files changed, 999 insertions, 0 deletions
diff --git a/contrib/slapd-modules/rbac/rbacsess.c b/contrib/slapd-modules/rbac/rbacsess.c new file mode 100644 index 0000000..d18e312 --- /dev/null +++ b/contrib/slapd-modules/rbac/rbacsess.c @@ -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 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; +} |