Home | History | Annotate | Line # | Download | only in rbac
      1 /*	$NetBSD: rbacsess.c,v 1.2 2021/08/14 16:14:53 christos Exp $	*/
      2 
      3 /* rbacsess.c - RBAC session */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  *
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* ACKNOWLEDGEMENTS:
     19  */
     20 
     21 #include <sys/cdefs.h>
     22 __RCSID("$NetBSD: rbacsess.c,v 1.2 2021/08/14 16:14:53 christos Exp $");
     23 
     24 #include "portable.h"
     25 
     26 #include <stdio.h>
     27 
     28 #include <ac/string.h>
     29 
     30 #include "slap.h"
     31 #include "slap-config.h"
     32 #include "lutil.h"
     33 
     34 #include "rbac.h"
     35 
     36 static slap_callback nullsc = { NULL, NULL, NULL, NULL };
     37 
     38 extern rbac_ad_t rbac_session_permission_ads[];
     39 extern rbac_ad_t rbac_session_ads[];
     40 
     41 struct berval slapo_session_oc = BER_BVC("rbacSession");
     42 
     43 typedef struct session_perm_req {
     44 	Operation *op;
     45 	SlapReply *rs;
     46 	struct berval *sessid;
     47 	struct berval permdn;
     48 	tenant_info_t *tenantp;
     49 } session_perm_req_t;
     50 
     51 static int
     52 rbac_sess_fake_cb( Operation *op, SlapReply *rs )
     53 {
     54 	Debug( LDAP_DEBUG_ANY, "rbac_sess_fake_cb\n" );
     55 
     56 	return 0;
     57 }
     58 
     59 static int
     60 rbac_send_session_permission(
     61 		session_perm_req_t *sess_perm_reqp,
     62 		rbac_permission_t *perm )
     63 {
     64 	int i, rc = LDAP_SUCCESS;
     65 	Operation *op = sess_perm_reqp->op;
     66 	SlapReply *rs = sess_perm_reqp->rs;
     67 	struct berval *sessidp = sess_perm_reqp->sessid;
     68 	struct berval *permdnp = &sess_perm_reqp->permdn;
     69 
     70 	Entry *e = entry_alloc();
     71 	e->e_attrs = NULL;
     72 	ber_dupbv( &e->e_name, permdnp );
     73 	ber_dupbv( &e->e_nname, permdnp );
     74 	e->e_private = NULL;
     75 	attr_merge_one( e, slap_rbac_schema.ad_session_id, sessidp, NULL );
     76 
     77 	for ( i = 0; !BER_BVISNULL( &rbac_session_permission_ads[i].attr ); i++ ) {
     78 		switch ( rbac_session_permission_ads[i].type ) {
     79 			case RBAC_OP_NAME:
     80 				attr_merge_one( e, *rbac_session_permission_ads[i].ad,
     81 						&perm->opName[0], NULL );
     82 				break;
     83 			case RBAC_OBJ_NAME:
     84 				attr_merge_one( e, *rbac_session_permission_ads[i].ad,
     85 						&perm->objName[0], NULL );
     86 				break;
     87 			case RBAC_ROLE_NAME:
     88 				attr_merge( e, *rbac_session_permission_ads[i].ad, perm->roles,
     89 						NULL );
     90 				break;
     91 			default:
     92 				break;
     93 		}
     94 	}
     95 
     96 	rs->sr_entry = e;
     97 	rs->sr_flags = REP_ENTRY_MUSTRELEASE;
     98 	rc = send_search_entry( op, rs );
     99 
    100 	return rc;
    101 }
    102 
    103 static int
    104 rbac_session_permissions_cb( Operation *op, SlapReply *rs )
    105 {
    106 	session_perm_req_t *sess_perm_reqp = op->o_callback->sc_private;
    107 	tenant_info_t *tenantp = NULL;
    108 	rbac_permission_t *permp = NULL;
    109 	rbac_ad_t *session_permissions_ads;
    110 	int i;
    111 
    112 	if ( rs->sr_type != REP_SEARCH ) return 0;
    113 
    114 	assert( sess_perm_reqp );
    115 
    116 	tenantp = sess_perm_reqp->tenantp;
    117 	session_permissions_ads = tenantp->schema->session_permissions_ads;
    118 
    119 	permp = ch_calloc( 1, sizeof(rbac_permission_t) );
    120 
    121 	for ( i = 0; !BER_BVISNULL( &session_permissions_ads[i].attr ); i++ ) {
    122 		Attribute *attr = NULL;
    123 
    124 		attr = attr_find(
    125 				rs->sr_entry->e_attrs, *session_permissions_ads[i].ad );
    126 		if ( attr != NULL ) {
    127 			switch ( session_permissions_ads[i].type ) {
    128 				case RBAC_USERS:
    129 					ber_bvarray_dup_x( &permp->uids, attr->a_nvals, NULL );
    130 					break;
    131 				case RBAC_ROLES:
    132 					ber_bvarray_dup_x( &permp->roles, attr->a_nvals, NULL );
    133 					break;
    134 				case RBAC_OBJ_NAME:
    135 					ber_bvarray_dup_x( &permp->objName, attr->a_nvals, NULL );
    136 					break;
    137 				case RBAC_OP_NAME:
    138 					ber_bvarray_dup_x( &permp->opName, attr->a_nvals, NULL );
    139 					break;
    140 			}
    141 		}
    142 	}
    143 
    144 	rbac_send_session_permission( sess_perm_reqp, permp );
    145 	rbac_free_permission( permp );
    146 	permp = NULL;
    147 
    148 	return SLAP_CB_CONTINUE;
    149 }
    150 
    151 static int
    152 rbac_read_session_cb( Operation *op, SlapReply *rs )
    153 {
    154 	rbac_session_t *sessp = op->o_callback->sc_private;
    155 	int i;
    156 
    157 	if ( rs->sr_type != REP_SEARCH ) return 0;
    158 
    159 	ber_dupbv( &sessp->sessdn, &rs->sr_entry->e_name );
    160 
    161 	for ( i = 0; !BER_BVISNULL( &rbac_session_ads[i].attr ); i++ ) {
    162 		Attribute *attr = NULL;
    163 		attr = attr_find( rs->sr_entry->e_attrs, *rbac_session_ads[i].ad );
    164 		if ( attr != NULL ) {
    165 			switch ( rbac_session_ads[i].type ) {
    166 				case RBAC_SESSION_ID:
    167 					ber_dupbv( &sessp->sessid, &attr->a_vals[0] );
    168 					break;
    169 				case RBAC_USER_DN:
    170 					ber_dupbv( &sessp->userdn, &attr->a_vals[0] );
    171 					break;
    172 				case RBAC_ROLES:
    173 					ber_bvarray_dup_x( &sessp->roles, attr->a_nvals, NULL );
    174 					break;
    175 				case RBAC_ROLE_CONSTRAINTS:
    176 					ber_bvarray_dup_x(
    177 							&sessp->role_constraints, attr->a_nvals, NULL );
    178 					break;
    179 				case RBAC_UID:
    180 					ber_dupbv( &sessp->uid, &attr->a_vals[0] );
    181 					break;
    182 				case RBAC_TENANT_ID:
    183 					ber_dupbv( &sessp->tenantid, &attr->a_vals[0] );
    184 					break;
    185 				default:
    186 					break;
    187 			}
    188 		}
    189 	}
    190 
    191 	//return SLAP_CB_CONTINUE;
    192 	return 0;
    193 }
    194 
    195 /* check whether the session is owned by the user */
    196 int
    197 rbac_is_session_owner( rbac_session_t *sessp, rbac_req_t *reqp )
    198 {
    199 	int rc = 0;
    200 
    201 	if ( BER_BVISEMPTY( &sessp->uid ) || BER_BVISEMPTY( &reqp->uid ) ) {
    202 		Debug( LDAP_DEBUG_ANY, "session not owned by user\n" );
    203 		rc = 0;
    204 		goto done;
    205 	}
    206 
    207 	if ( !ber_bvstrcasecmp( &sessp->uid, &reqp->uid ) ) {
    208 		rc = 1;
    209 		goto done;
    210 	}
    211 
    212 done:;
    213 	return rc;
    214 }
    215 
    216 int
    217 rbac_session_add_role( Operation *op, rbac_session_t *sessp, rbac_req_t *reqp )
    218 {
    219 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    220 	slap_callback cb = { 0 };
    221 	SlapReply rs2 = { REP_RESULT };
    222 	Operation op2 = *op;
    223 	rbac_callback_info_t rbac_cb;
    224 	tenant_info_t *tenantp = NULL;
    225 	struct berval vals[2];
    226 	Modifications mod;
    227 	int rc = LDAP_SUCCESS;
    228 
    229 	tenantp = rbac_tid2tenant( &reqp->tenantid );
    230 	if ( !tenantp ) {
    231 		Debug( LDAP_DEBUG_ANY, "rbac_session_add_role: "
    232 				"no tenant info with the req\n" );
    233 		goto done;
    234 	}
    235 
    236 	// convert the role name to lower case:
    237 	rbac_to_lower( &reqp->role );
    238 
    239 	//ber_dupbv( &vals[0], &reqp->roles[0]);
    240 	ber_dupbv( &vals[0], &reqp->role );
    241 	BER_BVZERO( &vals[1] );
    242 
    243 	/* create mod list */
    244 	mod.sml_op = LDAP_MOD_ADD;
    245 	mod.sml_flags = 0;
    246 	mod.sml_type = slap_rbac_schema.ad_session_roles->ad_cname;
    247 	mod.sml_desc = slap_rbac_schema.ad_session_roles;
    248 	mod.sml_numvals = 1;
    249 	mod.sml_values = vals;
    250 	mod.sml_nvalues = NULL;
    251 	mod.sml_next = NULL;
    252 
    253 	cb.sc_private = &rbac_cb;
    254 	cb.sc_response = rbac_sess_fake_cb;
    255 	op2.o_callback = &cb;
    256 
    257 	op2.o_tag = LDAP_REQ_MODIFY;
    258 	op2.orm_modlist = &mod;
    259 	op2.o_req_dn = sessp->sessdn;
    260 	op2.o_req_ndn = sessp->sessdn;
    261 	op2.o_bd = select_backend( &op2.o_req_ndn, 0 );
    262 	op2.o_dn = op2.o_bd->be_rootdn;
    263 	op2.o_ndn = op2.o_bd->be_rootdn;
    264 	op2.ors_limit = NULL;
    265 	rc = op2.o_bd->be_modify( &op2, &rs2 );
    266 	ch_free( vals[0].bv_val );
    267 
    268 done:;
    269 	if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
    270 		Debug( LDAP_DEBUG_ANY, "rbac_add_active_role: "
    271 				"role already activated in session\n" );
    272 	}
    273 	return rc;
    274 }
    275 
    276 int
    277 rbac_session_drop_role( Operation *op, rbac_session_t *sessp, rbac_req_t *reqp )
    278 {
    279 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    280 	slap_callback cb = { 0 };
    281 	SlapReply rs2 = { REP_RESULT };
    282 	Operation op2 = *op;
    283 	rbac_callback_info_t rbac_cb;
    284 	tenant_info_t *tenantp = NULL;
    285 	Modifications *m = NULL;
    286 	int rc = LDAP_SUCCESS;
    287 
    288 	tenantp = rbac_tid2tenant( &reqp->tenantid );
    289 	if ( !tenantp ) {
    290 		Debug( LDAP_DEBUG_ANY, "rbac_session_drop_role: "
    291 				"no tenant info with the req\n" );
    292 		goto done;
    293 	}
    294 
    295 	/* create mod list */
    296 	m = ch_calloc( sizeof(Modifications), 1 );
    297 	m->sml_op = LDAP_MOD_DELETE;
    298 	m->sml_flags = 0;
    299 	m->sml_type = slap_rbac_schema.ad_session_roles->ad_cname;
    300 	m->sml_desc = slap_rbac_schema.ad_session_roles;
    301 	m->sml_numvals = 1;
    302 	m->sml_values = ch_calloc( sizeof(struct berval), 2 );
    303 	m->sml_nvalues = ch_calloc( sizeof(struct berval), 2 );
    304 	//ber_dupbv( &m->sml_values[0], &reqp->roles[0]);
    305 
    306 	// convert the role name to lower case:
    307 	rbac_to_lower( &reqp->role );
    308 
    309 	ber_dupbv( &m->sml_values[0], &reqp->role );
    310 
    311 	// todo: determine if this needs to be done:
    312 	//BER_BVZERO(&m->sml_values[1]);
    313 
    314 	ber_dupbv( &m->sml_nvalues[0], &reqp->role );
    315 	BER_BVZERO( &m->sml_nvalues[1] );
    316 
    317 	//ber_dupbv( &m->sml_nvalues[0], &reqp->roles[0]);
    318 	//ber_dupbv( &m->sml_nvalues[0], &reqp->role);
    319 	//BER_BVZERO(&m->sml_nvalues[1]);
    320 
    321 	m->sml_next = NULL;
    322 
    323 	cb.sc_private = &rbac_cb;
    324 	cb.sc_response = rbac_sess_fake_cb;
    325 	op2.o_callback = &cb;
    326 
    327 	op2.o_dn = tenantp->session_admin;
    328 	op2.o_ndn = tenantp->session_admin;
    329 	op2.o_tag = LDAP_REQ_MODIFY;
    330 	op2.orm_modlist = m;
    331 	op2.o_req_dn = sessp->sessdn;
    332 	op2.o_req_ndn = sessp->sessdn;
    333 	op2.o_bd = select_backend( &op2.o_req_ndn, 0 );
    334 
    335 	op2.ors_limit = NULL;
    336 	rc = op2.o_bd->be_modify( &op2, &rs2 );
    337 
    338 done:;
    339 	if ( m ) {
    340 		slap_mods_free( m, 1 );
    341 	}
    342 
    343 	return rc;
    344 }
    345 
    346 /* delete the session */
    347 int
    348 rbac_int_delete_session( Operation *op, rbac_session_t *sessp )
    349 {
    350 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    351 	slap_callback cb = { 0 };
    352 	SlapReply rs2 = { REP_RESULT };
    353 	Operation op2 = *op;
    354 	rbac_callback_info_t rbac_cb;
    355 	tenant_info_t *tenantp = NULL;
    356 	int rc = LDAP_SUCCESS;
    357 
    358 	tenantp = rbac_tid2tenant( &sessp->tenantid );
    359 	if ( !tenantp ) {
    360 		Debug( LDAP_DEBUG_ANY, "rbac_session_drop_role: "
    361 				"no tenant info with the req\n" );
    362 		goto done;
    363 	}
    364 
    365 	/* delete RBAC session */
    366 	cb.sc_private = &rbac_cb;
    367 	cb.sc_response = rbac_sess_fake_cb;
    368 	op2.o_callback = &cb;
    369 
    370 	op2.o_dn = tenantp->session_admin;
    371 	op2.o_ndn = tenantp->session_admin;
    372 	op2.o_tag = LDAP_REQ_DELETE;
    373 	op2.o_req_dn = sessp->sessdn;
    374 	op2.o_req_ndn = sessp->sessdn;
    375 	op2.o_bd = select_backend( &op2.o_req_ndn, 0 );
    376 	rc = op2.o_bd->be_delete( &op2, &rs2 );
    377 
    378 done:;
    379 	return rc;
    380 }
    381 
    382 rbac_session_t *
    383 rbac_alloc_session()
    384 {
    385 	rbac_session_t *sessp = NULL;
    386 
    387 	sessp = ch_malloc( sizeof(rbac_session_t) );
    388 	sessp->sessid.bv_len =
    389 			lutil_uuidstr( sessp->uuidbuf, sizeof(sessp->uuidbuf) );
    390 	sessp->sessid.bv_val = sessp->uuidbuf;
    391 
    392 	sessp->user = NULL;
    393 	BER_BVZERO( &sessp->tenantid );
    394 	BER_BVZERO( &sessp->uid );
    395 	BER_BVZERO( &sessp->userdn );
    396 	BER_BVZERO( &sessp->sessdn );
    397 	BER_BVZERO( &sessp->message );
    398 
    399 	sessp->last_access = 0;
    400 	sessp->timeout = 0;
    401 	sessp->warning_id = 0;
    402 	sessp->error_id = 0;
    403 	sessp->grace_logins = 0;
    404 	sessp->expiration_secs = 0;
    405 	sessp->is_authenticated = 0;
    406 
    407 	sessp->roles = NULL;
    408 	sessp->role_constraints = NULL;
    409 
    410 	return sessp;
    411 }
    412 
    413 int
    414 rbac_register_session( Operation *op, SlapReply *rs, rbac_session_t *sessp )
    415 {
    416 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    417 	struct berval rdn, nrdn;
    418 	SlapReply rs2 = { REP_RESULT };
    419 	OperationBuffer opbuf;
    420 	Operation *op2;
    421 	Connection conn = { 0 };
    422 	Entry *e = NULL;
    423 	int rc = LDAP_SUCCESS;
    424 	char rdnbuf[
    425 		STRLENOF(RBAC_SESSION_RDN_EQ) + LDAP_LUTIL_UUIDSTR_BUFSIZE + 1];
    426 	tenant_info_t *tenantp = rbac_tid2tenant( &sessp->tenantid );
    427 #ifdef USE_NEW_THREAD_CONTEXT
    428 	void *thrctx = ldap_pvt_thread_pool_context();
    429 #else
    430 	void *thrctx = op->o_tmpmemctx;
    431 #endif
    432 
    433 	if ( !sessp ) {
    434 		rc = LDAP_UNWILLING_TO_PERFORM;
    435 		goto done;
    436 	}
    437 
    438 	/* dynamic objects */
    439 	e = entry_alloc();
    440 
    441 	strcpy( rdnbuf, RBAC_SESSION_RDN_EQ );
    442 	strncat( rdnbuf, sessp->sessid.bv_val, sessp->sessid.bv_len );
    443 	rdn.bv_val = rdnbuf;
    444 	rdn.bv_len = STRLENOF(RBAC_SESSION_RDN_EQ) + sessp->sessid.bv_len;
    445 	nrdn.bv_val = rdnbuf;
    446 	nrdn.bv_len = STRLENOF(RBAC_SESSION_RDN_EQ) + sessp->sessid.bv_len;
    447 
    448 	build_new_dn( &e->e_name, &tenantp->sessions_basedn, &rdn, NULL );
    449 	build_new_dn( &e->e_nname, &tenantp->sessions_basedn, &nrdn, NULL );
    450 
    451 	attr_merge_one( e, slap_schema.si_ad_objectClass, &slapo_session_oc, NULL );
    452 	attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
    453 			&slapo_session_oc, NULL );
    454 	attr_merge_one( e, slap_rbac_schema.ad_session_id, &sessp->sessid, NULL );
    455 
    456 	if ( !BER_BVISNULL( &sessp->uid ) ) {
    457 		attr_merge_one( e, slap_schema.si_ad_uid, &sessp->uid, NULL );
    458 	}
    459 
    460 	/* add tenant id */
    461 	if ( !BER_BVISNULL( &sessp->tenantid ) ) {
    462 		attr_merge_one(
    463 				e, slap_rbac_schema.ad_tenant_id, &sessp->tenantid, NULL );
    464 	}
    465 
    466 	/* add the userdn */
    467 	if ( !BER_BVISNULL( &sessp->userdn ) ) {
    468 		attr_merge_one(
    469 				e, slap_rbac_schema.ad_session_user_dn, &sessp->userdn, NULL );
    470 	}
    471 
    472 	if ( sessp->roles ) {
    473 		attr_merge( e, slap_rbac_schema.ad_session_roles, sessp->roles, NULL );
    474 	}
    475 
    476 	// TODO: ensure this is correct way to store constraints in session:
    477 	if ( sessp->role_constraints ) {
    478 		attr_merge( e, slap_rbac_schema.ad_session_role_constraints,
    479 				sessp->role_constraints, NULL );
    480 	}
    481 	/* rendered dynmaicObject */
    482 	attr_merge_one( e, slap_schema.si_ad_objectClass,
    483 			&slap_schema.si_oc_dynamicObject->soc_cname, NULL );
    484 
    485 	/* store RBAC session */
    486 	connection_fake_init2( &conn, &opbuf, thrctx, 0 );
    487 	op2 = &opbuf.ob_op;
    488 	//Operation op2 = *op;
    489 	//op2.o_callback = &nullsc;
    490 	//rbac_callback_info_t rbac_cb;
    491 	//cb.sc_private      = &rbac_cb;
    492 	//cb.sc_response     = rbac_sess_fake_cb;
    493 	//op2.o_callback    = &cb;
    494 	//op2.ors_limit     = NULL;
    495 	op->o_callback = &nullsc;
    496 	op2->o_dn = tenantp->session_admin;
    497 	op2->o_ndn = tenantp->session_admin;
    498 	op2->o_tag = LDAP_REQ_ADD;
    499 	op2->o_protocol = LDAP_VERSION3;
    500 	op2->o_req_dn = e->e_name;
    501 	op2->o_req_ndn = e->e_nname;
    502 	op2->ora_e = e;
    503 	op2->o_bd = frontendDB;
    504 
    505 	rc = op2->o_bd->be_add( op2, &rs2 );
    506 
    507 done:;
    508 	if ( e ) entry_free( e );
    509 	return rc;
    510 }
    511 
    512 int
    513 rbac_register_session2( Operation *op, SlapReply *rs, rbac_session_t *sessp )
    514 {
    515 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    516 	struct berval rdn, nrdn;
    517 	SlapReply rs2 = { REP_RESULT };
    518 	Operation op2 = *op;
    519 	rbac_callback_info_t rbac_cb;
    520 	//OperationBuffer opbuf;
    521 	//Connection conn = {0};
    522 	Entry *e = NULL;
    523 	int rc = LDAP_SUCCESS;
    524 	char rdnbuf[STRLENOF(RBAC_SESSION_RDN_EQ) + LDAP_LUTIL_UUIDSTR_BUFSIZE +
    525 			1];
    526 	tenant_info_t *tenantp = rbac_tid2tenant( &sessp->tenantid );
    527 	slap_callback cb = { 0 };
    528 	//#ifdef USE_NEW_THREAD_CONTEXT
    529 	//	void *thrctx = ldap_pvt_thread_pool_context();
    530 	//#else
    531 	//	void *thrctx = op->o_tmpmemctx;
    532 	//#endif
    533 
    534 	if ( !sessp ) {
    535 		rc = LDAP_UNWILLING_TO_PERFORM;
    536 		goto done;
    537 	}
    538 
    539 	/* dynamic objects */
    540 	e = entry_alloc();
    541 
    542 	strcpy( rdnbuf, RBAC_SESSION_RDN_EQ );
    543 	strncat( rdnbuf, sessp->sessid.bv_val, sessp->sessid.bv_len );
    544 	rdn.bv_val = rdnbuf;
    545 	rdn.bv_len = STRLENOF(RBAC_SESSION_RDN_EQ) + sessp->sessid.bv_len;
    546 	nrdn.bv_val = rdnbuf;
    547 	nrdn.bv_len = STRLENOF(RBAC_SESSION_RDN_EQ) + sessp->sessid.bv_len;
    548 
    549 	build_new_dn( &e->e_name, &tenantp->sessions_basedn, &rdn, NULL );
    550 	build_new_dn( &e->e_nname, &tenantp->sessions_basedn, &nrdn, NULL );
    551 
    552 	attr_merge_one( e, slap_schema.si_ad_objectClass, &slapo_session_oc, NULL );
    553 	attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
    554 			&slapo_session_oc, NULL );
    555 	attr_merge_one( e, slap_rbac_schema.ad_session_id, &sessp->sessid, NULL );
    556 
    557 	if ( !BER_BVISNULL( &sessp->uid ) ) {
    558 		attr_merge_one( e, slap_schema.si_ad_uid, &sessp->uid, NULL );
    559 	}
    560 
    561 	/* add tenant id */
    562 	if ( !BER_BVISNULL( &sessp->tenantid ) ) {
    563 		attr_merge_one(
    564 				e, slap_rbac_schema.ad_tenant_id, &sessp->tenantid, NULL );
    565 	}
    566 
    567 	/* add the userdn */
    568 	if ( !BER_BVISNULL( &sessp->userdn ) ) {
    569 		attr_merge_one(
    570 				e, slap_rbac_schema.ad_session_user_dn, &sessp->userdn, NULL );
    571 	}
    572 
    573 	if ( sessp->roles ) {
    574 		attr_merge( e, slap_rbac_schema.ad_session_roles, sessp->roles, NULL );
    575 	}
    576 
    577 	// TODO: ensure this is correct way to store constraints in session:
    578 	if ( sessp->role_constraints ) {
    579 		attr_merge( e, slap_rbac_schema.ad_session_role_constraints,
    580 				sessp->role_constraints, NULL );
    581 	}
    582 	/* rendered dynmaicObject */
    583 	attr_merge_one( e, slap_schema.si_ad_objectClass,
    584 			&slap_schema.si_oc_dynamicObject->soc_cname, NULL );
    585 
    586 	/* store RBAC session */
    587 	//connection_fake_init2( &conn, &opbuf, thrctx, 0 );
    588 	//op2 = &opbuf.ob_op;
    589 	//op2.o_ctrlflag = op->o_ctrlflag;
    590 	// todo this ain't right"
    591 	//op2.o_ctrlflag = 0;
    592 	//OperationBuffer *opbuf;
    593 	//memset( opbuf, 0, sizeof(OperationBuffer));
    594 	//op2.o_hdr = &opbuf->ob_hdr;
    595 	//op2.o_controls = opbuf->ob_controls;
    596 
    597 	// fails on modify.c:353 with segfault
    598 
    599 	//op2.o_callback = &nullsc;
    600 	cb.sc_private = &rbac_cb;
    601 	cb.sc_response = rbac_sess_fake_cb;
    602 	op2.o_callback = &cb;
    603 	op2.o_dn = tenantp->session_admin;
    604 	op2.o_ndn = tenantp->session_admin;
    605 	op2.o_tag = LDAP_REQ_ADD;
    606 	op2.o_protocol = LDAP_VERSION3;
    607 	op2.o_req_dn = e->e_name;
    608 	op2.o_req_ndn = e->e_nname;
    609 	op2.ora_e = e;
    610 	op2.o_bd = frontendDB;
    611 	//op2.ors_limit     = NULL;
    612 
    613 	rc = op2.o_bd->be_add( &op2, &rs2 );
    614 
    615 done:;
    616 	if ( e ) entry_free( e );
    617 
    618 	return rc;
    619 }
    620 
    621 int
    622 rbac_is_valid_session_id( struct berval *sessid )
    623 {
    624 	/* TODO: simple test */
    625 	if ( !sessid || sessid->bv_len != 36 ) {
    626 		if ( !sessid ) {
    627 			Debug( LDAP_DEBUG_ANY, "rbac_is_valid_session_id: "
    628 					"null sessid\n" );
    629 		} else {
    630 			Debug( LDAP_DEBUG_ANY, "rbac_is_valid_session_id: "
    631 					"len (%lu)\n",
    632 					sessid->bv_len );
    633 		}
    634 		return 0;
    635 	}
    636 
    637 	else {
    638 		return 1;
    639 	}
    640 }
    641 
    642 /* create an rbac request with the session ID */
    643 rbac_req_t *
    644 rbac_is_search_session_permissions( Operation *op )
    645 {
    646 	rbac_req_t *reqp = NULL;
    647 
    648 	/* check whether the search for sessionPermissions and *
    649 	 * with a valid sessionID */
    650 
    651 	return reqp;
    652 }
    653 
    654 rbac_session_t *
    655 rbac_session_byid_fake( Operation *op, rbac_req_t *reqp )
    656 {
    657 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    658 	rbac_session_t *sessp = NULL;
    659 	int rc = LDAP_SUCCESS;
    660 	char fbuf[RBAC_BUFLEN];
    661 	struct berval filter = { sizeof(fbuf), fbuf };
    662 	SlapReply rs2 = { REP_RESULT };
    663 	Operation op2 = *op;
    664 	rbac_callback_info_t rbac_cb;
    665 	slap_callback cb = { 0 };
    666 	tenant_info_t *tenantp = NULL;
    667 
    668 	if ( !rbac_is_valid_session_id( &reqp->sessid ) ) {
    669 		Debug( LDAP_DEBUG_ANY, "rbac_session_byid: "
    670 				"invalid session id (%s)\n",
    671 				reqp->sessid.bv_val );
    672 		rc = LDAP_UNWILLING_TO_PERFORM;
    673 		goto done;
    674 	}
    675 
    676 	sessp = rbac_alloc_session();
    677 	if ( !sessp ) {
    678 		Debug( LDAP_DEBUG_ANY, "rbac_session_byid: "
    679 				"unable to allocate session memory\n" );
    680 		rc = LDAP_UNWILLING_TO_PERFORM;
    681 		goto done;
    682 	}
    683 
    684 	tenantp = rbac_tid2tenant( &reqp->tenantid );
    685 
    686 	/* session id filter */
    687 	memset( fbuf, 0, sizeof(fbuf) );
    688 	strcpy( fbuf, RBAC_SESSION_RDN_EQ );
    689 	strncpy( &fbuf[0] + sizeof(RBAC_SESSION_RDN_EQ) - 1, reqp->sessid.bv_val,
    690 			reqp->sessid.bv_len );
    691 	filter.bv_val = fbuf;
    692 	filter.bv_len = strlen( fbuf );
    693 
    694 	//cb.sc_private     = sessp;
    695 	//cb.sc_response    = rbac_read_session_cb;
    696 	cb.sc_private = &rbac_cb;
    697 	cb.sc_response = rbac_sess_fake_cb;
    698 	op2.o_callback = &cb;
    699 	op2.o_tag = LDAP_REQ_SEARCH;
    700 	op2.o_dn = tenantp->session_admin;
    701 	op2.o_ndn = tenantp->session_admin;
    702 	op2.o_req_dn = tenantp->sessions_basedn;
    703 	op2.o_req_ndn = tenantp->sessions_basedn;
    704 	op2.ors_filterstr = filter;
    705 	op2.ors_filter = str2filter_x( &op2, filter.bv_val );
    706 	op2.ors_scope = LDAP_SCOPE_SUBTREE;
    707 	op2.ors_attrs = slap_rbac_schema.session_attrs;
    708 	op2.ors_tlimit = SLAP_NO_LIMIT;
    709 	op2.ors_slimit = SLAP_NO_LIMIT;
    710 	op2.o_bd = frontendDB;
    711 	// hyc change to fix seg fault:
    712 	op2.ors_limit = NULL;
    713 
    714 	rc = op2.o_bd->be_search( &op2, &rs2 );
    715 	filter_free_x( &op2, op2.ors_filter, 1 );
    716 
    717 done:
    718 	// TODO: find equivalent way of check nentries (broke with fake connection fix)
    719 	//if ( rc != LDAP_SUCCESS || rs2.sr_nentries <= 0 ) {
    720 	if ( rc != LDAP_SUCCESS ) {
    721 		rbac_free_session( sessp );
    722 		sessp = NULL;
    723 	}
    724 
    725 	return sessp;
    726 }
    727 
    728 rbac_session_t *
    729 rbac_session_byid( Operation *op, rbac_req_t *reqp )
    730 {
    731 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    732 	rbac_session_t *sessp = NULL;
    733 	int rc = LDAP_SUCCESS;
    734 	char fbuf[RBAC_BUFLEN];
    735 	struct berval filter = { sizeof(fbuf), fbuf };
    736 	SlapReply rs2 = { REP_RESULT };
    737 	Operation op2 = *op;
    738 	slap_callback cb = { 0 };
    739 	tenant_info_t *tenantp = NULL;
    740 
    741 	if ( !rbac_is_valid_session_id( &reqp->sessid ) ) {
    742 		Debug( LDAP_DEBUG_ANY, "rbac_session_byid: "
    743 				"invalid session id (%s)\n",
    744 				reqp->sessid.bv_val );
    745 		rc = LDAP_UNWILLING_TO_PERFORM;
    746 		goto done;
    747 	}
    748 
    749 	sessp = rbac_alloc_session();
    750 	if ( !sessp ) {
    751 		Debug( LDAP_DEBUG_ANY, "rbac_session_byid: "
    752 				"unable to allocate session memory\n" );
    753 		rc = LDAP_UNWILLING_TO_PERFORM;
    754 		goto done;
    755 	}
    756 
    757 	tenantp = rbac_tid2tenant( &reqp->tenantid );
    758 
    759 	/* session id filter */
    760 	memset( fbuf, 0, sizeof(fbuf) );
    761 	strcpy( fbuf, RBAC_SESSION_RDN_EQ );
    762 	strncpy( &fbuf[0] + sizeof(RBAC_SESSION_RDN_EQ) - 1, reqp->sessid.bv_val,
    763 			reqp->sessid.bv_len );
    764 	filter.bv_val = fbuf;
    765 	filter.bv_len = strlen( fbuf );
    766 
    767 	cb.sc_private = sessp;
    768 	cb.sc_response = rbac_read_session_cb;
    769 	op2.o_callback = &cb;
    770 	op2.o_tag = LDAP_REQ_SEARCH;
    771 	op2.o_dn = tenantp->session_admin;
    772 	op2.o_ndn = tenantp->session_admin;
    773 	op2.o_req_dn = tenantp->sessions_basedn;
    774 	op2.o_req_ndn = tenantp->sessions_basedn;
    775 	op2.ors_filterstr = filter;
    776 	op2.ors_filter = str2filter_x( &op2, filter.bv_val );
    777 	op2.ors_scope = LDAP_SCOPE_SUBTREE;
    778 	op2.ors_attrs = slap_rbac_schema.session_attrs;
    779 	op2.ors_tlimit = SLAP_NO_LIMIT;
    780 	op2.ors_slimit = SLAP_NO_LIMIT;
    781 	op2.o_bd = frontendDB;
    782 	// hyc change to fix seg fault:
    783 	op2.ors_limit = NULL;
    784 
    785 	rc = op2.o_bd->be_search( &op2, &rs2 );
    786 	filter_free_x( &op2, op2.ors_filter, 1 );
    787 
    788 done:
    789 	// TODO: find equivalent way of check nentries (broke with fake connection fix)
    790 	//if ( rc != LDAP_SUCCESS || rs2.sr_nentries <= 0 ) {
    791 	if ( rc != LDAP_SUCCESS ) {
    792 		rbac_free_session( sessp );
    793 		sessp = NULL;
    794 	}
    795 
    796 	return sessp;
    797 }
    798 
    799 static char *
    800 rbac_int_session_permissions_filterstr( Operation *op, rbac_session_t *sessp )
    801 {
    802 	char filterbuf[RBAC_BUFLEN];
    803 	int i;
    804 
    805 	memset( filterbuf, 0, sizeof(filterbuf) );
    806 
    807 	strcat( filterbuf, "(&(objectClass=ftOperation)(|" );
    808 	strcat( filterbuf, "(ftUsers=" );
    809 	strcat( filterbuf, sessp->uid.bv_val );
    810 	strcat( filterbuf, ")" );
    811 
    812 	/* add ftRoles filters */
    813 	for ( i = 0; !BER_BVISEMPTY( &sessp->roles[i] ); i++ ) {
    814 		strcat( filterbuf, "(ftRoles=" );
    815 		strncat( filterbuf, sessp->roles[i].bv_val, sessp->roles[i].bv_len );
    816 		strcat( filterbuf, ")" );
    817 	}
    818 	strcat( filterbuf, "))" );
    819 	return strdup( filterbuf );
    820 }
    821 
    822 int
    823 rbac_int_session_permissions(
    824 		Operation *op,
    825 		SlapReply *rs,
    826 		rbac_req_t *reqp,
    827 		rbac_session_t *sessp )
    828 {
    829 	slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
    830 	tenant_info_t *tenantp = NULL;
    831 	int rc;
    832 	struct berval filter;
    833 	char *filterstr;
    834 	struct berval permndn = BER_BVNULL;
    835 	OperationBuffer opbuf;
    836 	Connection conn = { 0 };
    837 	SlapReply rs2 = { REP_RESULT };
    838 	Operation *op2;
    839 	slap_callback cb = { 0 };
    840 	char permbuf[1024];
    841 	session_perm_req_t sess_perm_req;
    842 #ifdef USE_NEW_THREAD_CONTEXT
    843 	void *thrctx = ldap_pvt_thread_pool_context();
    844 #else
    845 	void *thrctx = op->o_tmpmemctx;
    846 #endif
    847 
    848 	tenantp = rbac_tid2tenant( &reqp->tenantid );
    849 
    850 	/* construct session permissions dn */
    851 	memset( permbuf, 0, sizeof(permbuf) );
    852 	strcat( permbuf, "rbacSessid=" );
    853 	strncat( permbuf, sessp->sessid.bv_val, sessp->sessid.bv_len );
    854 	strcat( permbuf, ",dc=rbac" );
    855 	sess_perm_req.op = op;
    856 	sess_perm_req.rs = rs;
    857 	sess_perm_req.permdn.bv_val = permbuf;
    858 	sess_perm_req.permdn.bv_len = strlen( permbuf );
    859 	sess_perm_req.sessid = &reqp->sessid;
    860 	sess_perm_req.tenantp = tenantp;
    861 
    862 	filterstr = rbac_int_session_permissions_filterstr( op, sessp );
    863 	if ( !filterstr ) {
    864 		Debug( LDAP_DEBUG_ANY, "unable to construct filter for session permissions\n" );
    865 		rc = LDAP_UNWILLING_TO_PERFORM;
    866 		goto done;
    867 	}
    868 	filter.bv_val = filterstr;
    869 	filter.bv_len = strlen( filterstr );
    870 
    871 	rc = dnNormalize(
    872 			0, NULL, NULL, &tenantp->permissions_basedn, &permndn, NULL );
    873 	if ( rc != LDAP_SUCCESS ) {
    874 		Debug( LDAP_DEBUG_ANY, "rbac_read_permission: "
    875 				"unable to normalize permission DN\n" );
    876 		rc = LDAP_UNWILLING_TO_PERFORM;
    877 		goto done;
    878 	}
    879 
    880 	connection_fake_init2( &conn, &opbuf, thrctx, 0 );
    881 	op2 = &opbuf.ob_op;
    882 	//Operation op2 = *op;
    883 	cb.sc_private = &sess_perm_req;
    884 	cb.sc_response = rbac_session_permissions_cb;
    885 	op2->o_callback = &cb;
    886 	op2->o_tag = LDAP_REQ_SEARCH;
    887 	op2->o_dn = tenantp->admin;
    888 	op2->o_ndn = tenantp->admin;
    889 	op2->o_req_dn = tenantp->permissions_basedn;
    890 	op2->o_req_ndn = permndn;
    891 	op2->ors_filterstr = filter;
    892 	op2->ors_filter = str2filter_x( op, filter.bv_val );
    893 	op2->ors_scope = LDAP_SCOPE_SUB;
    894 	op2->ors_attrs = tenantp->schema->session_perm_attrs;
    895 	op2->ors_tlimit = SLAP_NO_LIMIT;
    896 	op2->ors_slimit = SLAP_NO_LIMIT;
    897 	op2->ors_attrsonly = 0;
    898 	op2->o_bd = frontendDB;
    899 	//op2.ors_limit     = NULL;
    900 	rc = op2->o_bd->be_search( op2, &rs2 );
    901 	filter_free_x( op, op2->ors_filter, 1 );
    902 
    903 done:;
    904 	/* generate audit log */
    905 	rbac_audit( op, SessionPermissions, sessp, reqp, rc, (char *)rs->sr_text );
    906 
    907 	rs->sr_err = rc;
    908 	return rs->sr_err;
    909 }
    910 
    911 void
    912 rbac_free_session( rbac_session_t *sessp )
    913 {
    914 	if ( !sessp ) return;
    915 
    916 	if ( sessp->user ) {
    917 		rbac_free_user( sessp->user );
    918 	}
    919 
    920 	if ( !BER_BVISNULL( &sessp->uid ) ) {
    921 		ber_memfree( sessp->uid.bv_val );
    922 	}
    923 
    924 	if ( !BER_BVISNULL( &sessp->tenantid ) ) {
    925 		ber_memfree( sessp->tenantid.bv_val );
    926 	}
    927 
    928 	if ( !BER_BVISNULL( &sessp->userdn ) ) {
    929 		ber_memfree( sessp->userdn.bv_val );
    930 	}
    931 
    932 	if ( !BER_BVISNULL( &sessp->sessdn ) ) {
    933 		ber_memfree( sessp->sessdn.bv_val );
    934 	}
    935 
    936 	if ( !BER_BVISNULL( &sessp->message ) ) {
    937 		ber_memfree( sessp->message.bv_val );
    938 	}
    939 
    940 	if ( sessp->roles ) {
    941 		ber_bvarray_free( sessp->roles );
    942 	}
    943 
    944 	if ( sessp->role_constraints ) {
    945 		ber_bvarray_free( sessp->role_constraints );
    946 	}
    947 
    948 	ch_free( sessp );
    949 
    950 	return;
    951 }
    952 
    953 /* roles included from request are activated into a session only when
    954  * they exist and have been assigned to the user. If no roles included in request, all
    955  * roles assigned to the user are activated into the rbac session.
    956  */
    957 int
    958 activate_session_roles(
    959 		rbac_session_t *sessp,
    960 		rbac_req_t *reqp,
    961 		rbac_user_t *userp )
    962 {
    963 	int i, j, rc = LDAP_UNWILLING_TO_PERFORM;
    964 	if ( !sessp || !reqp || !userp ) {
    965 		goto done;
    966 	}
    967 
    968 	/* no role requested, assign all roles from the user to the session. */
    969 	if ( reqp->roles == NULL || BER_BVISNULL( &reqp->roles[0] ) ) {
    970 		//if (!reqp->roles || BER_BVISNULL(&reqp->roles[0])) {
    971 		/* no roles assigned to the user */
    972 		if ( !userp->roles || BER_BVISNULL( &userp->roles[0] ) ) goto done;
    973 		for ( i = 0; !BER_BVISNULL( &userp->roles[i] ); i++ ) {
    974 			struct berval role;
    975 			ber_dupbv_x( &role, &userp->roles[i], NULL );
    976 			ber_bvarray_add( &sessp->roles, &role );
    977 			rc = LDAP_SUCCESS;
    978 		}
    979 
    980 		// TODO: smm 20141218 - make sure this is correct way to add constraints to user session.
    981 		for ( i = 0; !BER_BVISNULL( &userp->role_constraints[i] ); i++ ) {
    982 			struct berval roleconstraint;
    983 			ber_dupbv_x( &roleconstraint, &userp->role_constraints[i], NULL );
    984 			ber_bvarray_add( &sessp->role_constraints, &roleconstraint );
    985 			rc = LDAP_SUCCESS;
    986 		}
    987 
    988 	} else {
    989 		for ( i = 0; !BER_BVISNULL( &reqp->roles[i] ); i++ ) {
    990 			for ( j = 0; !BER_BVISNULL( &userp->roles[j] ); j++ ) {
    991 				if ( !ber_bvstrcasecmp( &reqp->roles[i], &userp->roles[j] ) ) {
    992 					/* requested role is assigned to the user */
    993 					struct berval role;
    994 					ber_dupbv_x( &role, &userp->roles[i], NULL );
    995 					ber_bvarray_add( &sessp->roles, &role );
    996 					rc = LDAP_SUCCESS;
    997 				}
    998 			}
    999 		}
   1000 	}
   1001 
   1002 done:;
   1003 	return rc;
   1004 }
   1005