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
36static slap_callback nullsc = { NULL, NULL, NULL, NULL };
37
38extern rbac_ad_t rbac_session_permission_ads[];
39extern rbac_ad_t rbac_session_ads[];
40
41struct berval slapo_session_oc = BER_BVC("rbacSession");
42
43typedef 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
51static int
52rbac_sess_fake_cb( Operation *op, SlapReply *rs )
53{
54	Debug( LDAP_DEBUG_ANY, "rbac_sess_fake_cb\n" );
55
56	return 0;
57}
58
59static int
60rbac_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
103static int
104rbac_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
151static int
152rbac_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 */
196int
197rbac_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
212done:;
213	return rc;
214}
215
216int
217rbac_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
268done:;
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
276int
277rbac_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
338done:;
339	if ( m ) {
340		slap_mods_free( m, 1 );
341	}
342
343	return rc;
344}
345
346/* delete the session */
347int
348rbac_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
378done:;
379	return rc;
380}
381
382rbac_session_t *
383rbac_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
413int
414rbac_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
507done:;
508	if ( e ) entry_free( e );
509	return rc;
510}
511
512int
513rbac_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
615done:;
616	if ( e ) entry_free( e );
617
618	return rc;
619}
620
621int
622rbac_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 */
643rbac_req_t *
644rbac_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
654rbac_session_t *
655rbac_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
717done:
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
728rbac_session_t *
729rbac_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
788done:
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
799static char *
800rbac_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
822int
823rbac_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
903done:;
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
911void
912rbac_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 */
957int
958activate_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
1002done:;
1003	return rc;
1004}
1005