mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-01-14 10:53:22 -05:00
2169 lines
54 KiB
C
2169 lines
54 KiB
C
/* rbac.c - RBAC main file */
|
|
/* $OpenLDAP$ */
|
|
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
*
|
|
* Copyright 2013-2024 The OpenLDAP Foundation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted only as authorized by the OpenLDAP
|
|
* Public License.
|
|
*
|
|
* A copy of this license is available in the file LICENSE in the
|
|
* top-level directory of the distribution or, alternatively, at
|
|
* <http://www.OpenLDAP.org/license.html>.
|
|
*/
|
|
/* ACKNOWLEDGEMENTS:
|
|
*/
|
|
|
|
#include "portable.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ac/string.h>
|
|
|
|
#include "slap.h"
|
|
#include "slap-config.h"
|
|
#include "lutil.h"
|
|
|
|
#include "rbac.h"
|
|
|
|
#define RBAC_REQ 1
|
|
|
|
static slap_overinst rbac;
|
|
|
|
static struct berval slap_EXOP_CREATE_SESSION =
|
|
BER_BVC(LDAP_RBAC_EXOP_CREATE_SESSION);
|
|
static struct berval slap_EXOP_CHECK_ACCESS =
|
|
BER_BVC(LDAP_RBAC_EXOP_CHECK_ACCESS);
|
|
static struct berval slap_EXOP_ADD_ACTIVE_ROLE =
|
|
BER_BVC(LDAP_RBAC_EXOP_ADD_ACTIVE_ROLE);
|
|
static struct berval slap_EXOP_DROP_ACTIVE_ROLE =
|
|
BER_BVC(LDAP_RBAC_EXOP_DROP_ACTIVE_ROLE);
|
|
static struct berval slap_EXOP_DELETE_SESSION =
|
|
BER_BVC(LDAP_RBAC_EXOP_DELETE_SESSION);
|
|
static struct berval slap_EXOP_SESSION_ROLES =
|
|
BER_BVC(LDAP_RBAC_EXOP_SESSION_ROLES);
|
|
|
|
rbac_tenant_t rbac_tenants = {
|
|
{
|
|
.schema = &slap_rbac_jts_schema,
|
|
},
|
|
NULL
|
|
};
|
|
|
|
static ConfigDriver rbac_cf_gen;
|
|
|
|
static ConfigTable rbaccfg[] = {
|
|
{ "rbac-default-users-base-dn", "usersDN", 2, 2, 0,
|
|
ARG_MAGIC|ARG_DN|RBAC_DEFAULT_USERS_BASE_DN,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.1 NAME 'olcRBACDefaultUsersBaseDn' "
|
|
"DESC 'default Base DN for RBAC users ' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "rbac-default-roles-base-dn", "rolesDN", 2, 2, 0,
|
|
ARG_MAGIC|ARG_DN|RBAC_DEFAULT_ROLES_BASE_DN,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.2 NAME 'olcRBACDefaultRolesBaseDn' "
|
|
"DESC 'default base DN for RBAC roles ' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "rbac-default-permissions-base-dn", "permissionsDN", 2, 2, 0,
|
|
ARG_MAGIC|ARG_DN|RBAC_DEFAULT_PERMISSIONS_BASE_DN,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.3 NAME 'olcRBACDefaultPermissionsBaseDn' "
|
|
"DESC 'default base DN for RBAC permissions ' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "rbac-default-sessions-base-dn", "sessionsDN", 2, 2, 0,
|
|
ARG_MAGIC|ARG_DN|RBAC_DEFAULT_SESSIONS_BASE_DN,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.4 NAME 'olcRBACDefaultSessionsBaseDn' "
|
|
"DESC 'default base DN for RBAC permissions ' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "rbac-admin", "adminDN", 2, 2, 0,
|
|
ARG_MAGIC|ARG_DN|RBAC_ADMIN_DN,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.5 NAME 'olcRBACAdminDn' "
|
|
"DESC 'default admin DN for RBAC repository ' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "rbac-pwd", "adminPwd", 2, 2, 0,
|
|
ARG_MAGIC|RBAC_ADMIN_PWD,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.6 NAME 'olcRBACAdminPwd' "
|
|
"DESC 'default admin pwd for RBAC repository ' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "rbac-session-admin", "sessionAdminDN", 2, 2, 0,
|
|
ARG_MAGIC|ARG_DN|RBAC_SESSION_ADMIN_DN,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.7 NAME 'olcRBACSessionAdminDn' "
|
|
"DESC 'admin DN for RBAC session repository ' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "rbac-session-admin-pwd", "sessionAdminPwd", 2, 2, 0,
|
|
ARG_MAGIC|RBAC_SESSION_ADMIN_PWD,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.8 NAME 'olcRBACSessionAdminPwd' "
|
|
"DESC 'admin pwd for RBAC session repository ' "
|
|
"SYNTAX OMsDirectoryString SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "tenant", "tenant", 2, 2, 0,
|
|
ARG_MAGIC|ARG_DN|RBAC_TENANT,
|
|
rbac_cf_gen, "(OLcfgCtAt:7.9 NAME 'olcRBACTenant' "
|
|
"DESC 'RBAC tenant ' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "rbac-default-audit-base-dn", "auditDN", 2, 2, 0,
|
|
ARG_MAGIC|ARG_DN|RBAC_DEFAULT_AUDIT_BASE_DN,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.10 NAME 'olcRBACDefaultAuditBaseDn' "
|
|
"DESC 'default base DN for RBAC audit records ' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
{ "rbac-default-tenant-id", "tenantId", 2, 2, 0,
|
|
ARG_MAGIC|RBAC_DEFAULT_TENANT_ID,
|
|
rbac_cf_gen,
|
|
"(OLcfgCtAt:7.11 NAME 'olcRBACDefaultTenantId' "
|
|
"DESC 'default tenant id' "
|
|
"SYNTAX OMsDirectoryString "
|
|
"SINGLE-VALUE )",
|
|
NULL, NULL
|
|
},
|
|
|
|
{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
|
|
};
|
|
|
|
static ConfigOCs rbac_ocs[] = {
|
|
{ "( OLcfgCtOc:7.1 "
|
|
"NAME 'olcRBACConfig' "
|
|
"DESC 'RBAC configuration' "
|
|
"SUP olcOverlayConfig "
|
|
"MAY ( olcRBACDefaultUsersBaseDn $ olcRBACDefaultRolesBaseDn $ "
|
|
"olcRBACDefaultPermissionsBaseDn $ olcRBACDefaultSessionsBaseDn $ "
|
|
"olcRBACAdminDn $ olcRBACAdminPwd $ olcRBACSessionAdminDn $ "
|
|
"olcRBACSessionAdminPwd) )",
|
|
Cft_Overlay, rbaccfg },
|
|
|
|
{ NULL, 0, NULL }
|
|
};
|
|
|
|
static slap_verbmasks rbac_keys[] = {
|
|
{ BER_BVC("default_users_base_dn"), RBAC_DEFAULT_USERS_BASE_DN },
|
|
{ BER_BVC("default_roles_base_dn"), RBAC_DEFAULT_ROLES_BASE_DN },
|
|
{ BER_BVC("default_permissions_base_dn"),
|
|
RBAC_DEFAULT_PERMISSIONS_BASE_DN },
|
|
{ BER_BVC("tenant"), RBAC_TENANT },
|
|
|
|
{ BER_BVNULL, 0 }
|
|
};
|
|
|
|
static slap_verbmasks rbac_tenant_keys[] = {
|
|
{ BER_BVC("id"), RBAC_TENANT_ID },
|
|
{ BER_BVC("users_base_dn"), RBAC_USERS_BASE_DN },
|
|
{ BER_BVC("roles_base_dn"), RBAC_ROLES_BASE_DN },
|
|
{ BER_BVC("permissions_base_dn"), RBAC_PERMISSIONS_BASE_DN },
|
|
|
|
{ BER_BVNULL, 0 }
|
|
};
|
|
|
|
static void
|
|
rbac_tenant_parse( char *tenent_info, tenant_info_t *tenants )
|
|
{
|
|
return;
|
|
}
|
|
|
|
static int
|
|
rbac_cf_gen( ConfigArgs *c )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)c->bi;
|
|
rbac_tenant_t *ri = &rbac_tenants;
|
|
int rc = 0;
|
|
|
|
if ( c->op == SLAP_CONFIG_EMIT ) {
|
|
switch ( c->type ) {
|
|
case RBAC_DEFAULT_USERS_BASE_DN:
|
|
value_add_one( &c->rvalue_vals, &ri->tenant_info.users_basedn );
|
|
break;
|
|
case RBAC_DEFAULT_ROLES_BASE_DN:
|
|
value_add_one( &c->rvalue_vals, &ri->tenant_info.roles_basedn );
|
|
break;
|
|
case RBAC_DEFAULT_PERMISSIONS_BASE_DN:
|
|
value_add_one(
|
|
&c->rvalue_vals, &ri->tenant_info.permissions_basedn );
|
|
break;
|
|
case RBAC_DEFAULT_SESSIONS_BASE_DN:
|
|
value_add_one(
|
|
&c->rvalue_vals, &ri->tenant_info.sessions_basedn );
|
|
break;
|
|
case RBAC_DEFAULT_AUDIT_BASE_DN:
|
|
value_add_one( &c->rvalue_vals, &ri->tenant_info.audit_basedn );
|
|
break;
|
|
case RBAC_ADMIN_DN:
|
|
value_add_one( &c->rvalue_vals, &ri->tenant_info.admin );
|
|
break;
|
|
case RBAC_ADMIN_PWD:
|
|
value_add_one( &c->rvalue_vals, &ri->tenant_info.pwd );
|
|
break;
|
|
case RBAC_SESSION_ADMIN_DN:
|
|
value_add_one(
|
|
&c->rvalue_vals, &ri->tenant_info.session_admin );
|
|
break;
|
|
case RBAC_DEFAULT_TENANT_ID:
|
|
value_add_one( &c->rvalue_vals, &ri->tenant_info.tid );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return rc;
|
|
} else if ( c->op == LDAP_MOD_DELETE ) {
|
|
/* FIXME */
|
|
return 1;
|
|
}
|
|
switch ( c->type ) {
|
|
case RBAC_DEFAULT_USERS_BASE_DN: {
|
|
struct berval dn = BER_BVNULL;
|
|
ber_str2bv( c->argv[1], 0, 0, &dn );
|
|
rc = dnNormalize(
|
|
0, NULL, NULL, &dn, &ri->tenant_info.users_basedn, NULL );
|
|
break;
|
|
}
|
|
case RBAC_DEFAULT_ROLES_BASE_DN: {
|
|
ber_str2bv( c->argv[1], 0, 1, &ri->tenant_info.roles_basedn );
|
|
break;
|
|
}
|
|
case RBAC_DEFAULT_PERMISSIONS_BASE_DN: {
|
|
ber_str2bv( c->argv[1], 0, 1, &ri->tenant_info.permissions_basedn );
|
|
break;
|
|
}
|
|
case RBAC_DEFAULT_SESSIONS_BASE_DN: {
|
|
ber_str2bv( c->argv[1], 0, 1, &ri->tenant_info.sessions_basedn );
|
|
break;
|
|
}
|
|
case RBAC_DEFAULT_AUDIT_BASE_DN: {
|
|
ber_str2bv( c->argv[1], 0, 1, &ri->tenant_info.audit_basedn );
|
|
break;
|
|
}
|
|
case RBAC_ADMIN_DN: {
|
|
ber_str2bv( c->argv[1], 0, 1, &ri->tenant_info.admin );
|
|
break;
|
|
}
|
|
case RBAC_ADMIN_PWD: {
|
|
ber_str2bv( c->argv[1], 0, 1, &ri->tenant_info.pwd );
|
|
break;
|
|
}
|
|
case RBAC_SESSION_ADMIN_DN: {
|
|
ber_str2bv( c->argv[1], 0, 1, &ri->tenant_info.session_admin );
|
|
break;
|
|
}
|
|
case RBAC_SESSION_ADMIN_PWD: {
|
|
ber_str2bv( c->argv[1], 0, 1, &ri->tenant_info.session_admin_pwd );
|
|
break;
|
|
}
|
|
case RBAC_DEFAULT_TENANT_ID: {
|
|
ber_str2bv( c->argv[1], 0, 1, &ri->tenant_info.tid );
|
|
break;
|
|
}
|
|
case RBAC_TENANT: {
|
|
rbac_tenant_parse( c->argv[1], &ri->tenant_info );
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* rbac configuration
|
|
*/
|
|
|
|
tenant_info_t *
|
|
rbac_tid2tenant( struct berval *tid )
|
|
{
|
|
/* return the only tenant for now */
|
|
return &rbac_tenants.tenant_info;
|
|
}
|
|
|
|
//{ BER_BVC(LDAP_RBAC_EXOP_SESSION_ROLES), rbac_session_roles },
|
|
|
|
static int
|
|
slap_parse_rbac_session_roles(
|
|
struct berval *in,
|
|
rbac_req_t **reqpp,
|
|
const char **text,
|
|
void *ctx )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
struct berval reqdata = BER_BVNULL;
|
|
rbac_req_t *reqp = NULL;
|
|
BerElementBuffer berbuf;
|
|
BerElement *ber = (BerElement *)&berbuf;
|
|
ber_tag_t tag;
|
|
ber_len_t len = -1;
|
|
|
|
*text = NULL;
|
|
|
|
if ( in == NULL || in->bv_len == 0 ) {
|
|
*text = "empty request data field in rbac_session_roles exop";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
reqp = rbac_alloc_req( RBAC_REQ_SESSION_ROLES );
|
|
|
|
if ( !reqp ) {
|
|
*text = "unable to allocate memory for rbac_session_roles exop";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
ber_dupbv_x( &reqdata, in, ctx );
|
|
|
|
/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
|
|
ber_init2( ber, &reqdata, 0 );
|
|
|
|
tag = ber_scanf( ber, "{" /*}*/ );
|
|
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_session_roles: "
|
|
"decoding error.\n" );
|
|
goto decoding_error;
|
|
}
|
|
|
|
tag = ber_peek_tag( ber, &len );
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_USER_ID_SESS ) {
|
|
struct berval uid;
|
|
tag = ber_scanf( ber, "m", &uid );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_session_roles: "
|
|
"user id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->uid, &uid, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
//tag = ber_peek_tag( ber, &len );
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_SESSION_ID_SESS ) {
|
|
struct berval sessid;
|
|
tag = ber_scanf( ber, "m", &sessid );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_session_roles: "
|
|
"session id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->sessid, &sessid, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
if ( tag != LBER_DEFAULT || len != 0 ) {
|
|
decoding_error:;
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_session_roles: "
|
|
"decoding error, len=%ld\n",
|
|
(long)len );
|
|
rc = LDAP_PROTOCOL_ERROR;
|
|
*text = "data decoding error";
|
|
}
|
|
|
|
if ( rc == LDAP_SUCCESS ) {
|
|
*reqpp = reqp;
|
|
} else {
|
|
rbac_free_req( reqp );
|
|
*reqpp = NULL;
|
|
}
|
|
|
|
if ( !BER_BVISNULL( &reqdata ) ) {
|
|
ber_memfree_x( reqdata.bv_val, ctx );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
rbac_session_roles( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
const struct berval rbac_op = BER_BVC("SessionRoles");
|
|
rbac_req_t *reqp = NULL;
|
|
rbac_session_t *sessp;
|
|
int rc;
|
|
|
|
rs->sr_err = slap_parse_rbac_session_roles(
|
|
op->ore_reqdata, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
/* get the session using the session id */
|
|
sessp = rbac_session_byid( op, reqp );
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_session_roles: "
|
|
"session not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/* checking whether the session is owned by the user */
|
|
if ( !rbac_is_session_owner( sessp, reqp ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_session_roles: "
|
|
"session not owned by user\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
rc = rbac_int_delete_session( op, sessp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_session_roles: "
|
|
"unable to delete session\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* If we wanted to...
|
|
* load these roles into a response with a sequence nested within a
|
|
* sequence: (No, we're not actually doing this here.)
|
|
* 0x30 LL ber_printf( ber, "{" );
|
|
* 0x04 L1
|
|
* 0x04 L2 a b c d
|
|
* 0x04 L3 e f g h
|
|
* 0x04 L4 i j k l
|
|
* add all three ber_bvarray_add_x( &roles, &tmpbv, NULL );
|
|
* close it ber_printf( ber, "t{W}", LDAP_TAG_EXOP_RBAC_ROLES, roles );
|
|
*/
|
|
|
|
/*
|
|
* Instead we are...
|
|
* loading these roles into the response within a sequence: (Yes, we are doing this here.)
|
|
* 0x30 LL ber_printf( ber, "{" );
|
|
* 0x04 L1 a b c d
|
|
* 0x04 L2 e f g h
|
|
* 0x04 L3 i j k l
|
|
* add all three ber_bvarray_add_x( &roles, &tmpbv, NULL );
|
|
* close it ber_printf( ber, "tW", LDAP_TAG_EXOP_RBAC_ROLES, roles );
|
|
*/
|
|
BerElementBuffer berbuf;
|
|
BerElement *ber = (BerElement *)&berbuf;
|
|
ber_init_w_nullc( ber, LBER_USE_DER );
|
|
BerVarray roles = NULL;
|
|
if ( sessp->roles ) {
|
|
struct berval tmpbv;
|
|
// open the sequence:
|
|
ber_printf( ber, "{" /*}*/ );
|
|
//char *role;
|
|
int i = 0;
|
|
//BerVarray roles = NULL;
|
|
for ( i = 0; !BER_BVISNULL( &sessp->roles[i] ); i++ ) {
|
|
tmpbv.bv_val = sessp->roles[i].bv_val;
|
|
tmpbv.bv_len = sessp->roles[i].bv_len;
|
|
// add role name:
|
|
ber_bvarray_add_x( &roles, &tmpbv, NULL );
|
|
|
|
//LBER_F( int )
|
|
//ber_bvecadd_x LDAP_P(( struct berval ***bvec,
|
|
// struct berval *bv, void *ctx ));
|
|
|
|
// first attempt at sequence within a sequence...
|
|
// open another sequence:
|
|
/*
|
|
ber_printf( ber, "{" } );
|
|
// add role name (again):
|
|
ber_bvarray_add_x(&roles, &tmpbv, NULL);
|
|
// close the nested sequence:
|
|
ber_printf( ber, { "}" );
|
|
*/
|
|
// end 2nd sequence
|
|
}
|
|
/*
|
|
* This is how we add several octet strings at one time. An array of struct berval's is supplied.
|
|
* The array is terminated by a struct berval with a NULL bv_val.
|
|
* Note that a construct like '{W}' is required to get an actual SEQUENCE OF octet strings.
|
|
* But here we are using 'tW' which allows passing a collection of octets w/out a nesting within a sequence.
|
|
*/
|
|
ber_printf( ber, "tW",
|
|
LDAP_TAG_EXOP_RBAC_ROLES, roles);
|
|
|
|
// TODO: determine why free on roles array causes a seg fault:
|
|
//ber_bvarray_free_x(roles, NULL);
|
|
|
|
// close the sequence:
|
|
ber_printf( ber, /*{*/ "N}" );
|
|
}
|
|
|
|
if ( rc < 0 ) {
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "internal error";
|
|
} else {
|
|
(void)ber_flatten( ber, &rs->sr_rspdata );
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
}
|
|
ber_free_buf( ber );
|
|
// END LOAD ROLES INTO RESPONSE
|
|
|
|
done:;
|
|
rs->sr_err = rc;
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_SESSION_ROLES.bv_val );
|
|
|
|
/* generate audit log */
|
|
rbac_audit(
|
|
op, SessionRoles, sessp, reqp, rs->sr_err, (char *)rs->sr_text );
|
|
rbac_free_session( sessp );
|
|
rbac_free_req( reqp );
|
|
return rs->sr_err;
|
|
}
|
|
|
|
static int
|
|
rbac_session_rolesx( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
const struct berval rbac_op = BER_BVC("SessionRoles");
|
|
rbac_session_t *sessp = NULL;
|
|
rbac_req_t *reqp = NULL;
|
|
int rc;
|
|
|
|
rs->sr_err = slap_parse_rbac_session_roles(
|
|
op->ore_reqdata, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
/* get the session using the session id */
|
|
sessp = rbac_session_byid( op, reqp );
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_session_roles: "
|
|
"session not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/* checking whether the session is owned by the user */
|
|
if ( !rbac_is_session_owner( sessp, reqp ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_session_roles: "
|
|
"session not owned by user\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
rc = rbac_int_delete_session( op, sessp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_session_roles: "
|
|
"unable to delete session\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* If we wanted to...
|
|
* load these roles into a response with a sequence nested within a
|
|
* sequence: (No, we're not actually doing this here.)
|
|
* 0x30 LL ber_printf( ber, "{" );
|
|
* 0x04 L1
|
|
* 0x04 L2 a b c d
|
|
* 0x04 L3 e f g h
|
|
* 0x04 L4 i j k l
|
|
* add all three ber_bvarray_add_x( &roles, &tmpbv, NULL );
|
|
* close it ber_printf( ber, "t{W}", LDAP_TAG_EXOP_RBAC_ROLES, roles );
|
|
*/
|
|
|
|
/*
|
|
* Instead we are...
|
|
* loading these roles into the response within a sequence: (Yes, we are doing this here.)
|
|
* 0x30 LL ber_printf( ber, "{" );
|
|
* 0x04 L1 a b c d
|
|
* 0x04 L2 e f g h
|
|
* 0x04 L3 i j k l
|
|
* add all three ber_bvarray_add_x( &roles, &tmpbv, NULL );
|
|
* close it ber_printf( ber, "tW", LDAP_TAG_EXOP_RBAC_ROLES, roles );
|
|
*/
|
|
BerElementBuffer berbuf;
|
|
BerElement *ber = (BerElement *)&berbuf;
|
|
ber_init_w_nullc( ber, LBER_USE_DER );
|
|
BerVarray roles = NULL;
|
|
if ( sessp->roles ) {
|
|
struct berval tmpbv;
|
|
// open the sequence:
|
|
ber_printf( ber, "{" /*}*/ );
|
|
//char *role;
|
|
int i = 0;
|
|
//BerVarray roles = NULL;
|
|
for ( i = 0; !BER_BVISNULL( &sessp->roles[i] ); i++ ) {
|
|
tmpbv.bv_val = sessp->roles[i].bv_val;
|
|
tmpbv.bv_len = sessp->roles[i].bv_len;
|
|
// add role name:
|
|
ber_bvarray_add_x( &roles, &tmpbv, NULL );
|
|
|
|
// first attempt at sequence within a sequence...
|
|
// open another sequence:
|
|
/*
|
|
ber_printf( ber, "{" } );
|
|
// add role name (again):
|
|
ber_bvarray_add_x(&roles, &tmpbv, NULL);
|
|
// close the nested sequence:
|
|
ber_printf( ber, { "}" );
|
|
*/
|
|
// end 2nd sequence
|
|
}
|
|
/*
|
|
* This is how we add several octet strings at one time. An array of struct berval's is supplied.
|
|
* The array is terminated by a struct berval with a NULL bv_val.
|
|
* Note that a construct like '{W}' is required to get an actual SEQUENCE OF octet strings.
|
|
* But here we are using 'tW' which allows passing a collection of octets w/out a nesting within a sequence.
|
|
*/
|
|
ber_printf( ber, "tW",
|
|
LDAP_TAG_EXOP_RBAC_ROLES, roles);
|
|
|
|
// TODO: determine why free on roles array causes a seg fault:
|
|
//ber_bvarray_free_x(roles, NULL);
|
|
|
|
// close the sequence:
|
|
ber_printf( ber, /*{*/ "N}" );
|
|
}
|
|
|
|
if ( rc < 0 ) {
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "internal error";
|
|
} else {
|
|
(void)ber_flatten( ber, &rs->sr_rspdata );
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
}
|
|
ber_free_buf( ber );
|
|
// END LOAD ROLES INTO RESPONSE
|
|
|
|
done:;
|
|
rs->sr_err = rc;
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_SESSION_ROLES.bv_val );
|
|
|
|
/* generate audit log */
|
|
rbac_audit(
|
|
op, SessionRoles, sessp, reqp, rs->sr_err, (char *)rs->sr_text );
|
|
rbac_free_session( sessp );
|
|
rbac_free_req( reqp );
|
|
return rs->sr_err;
|
|
}
|
|
|
|
/*
|
|
* slap_parse_rbac_create_session
|
|
*/
|
|
static int
|
|
slap_parse_rbac_create_session(
|
|
struct berval *in,
|
|
rbac_req_t **reqpp,
|
|
const char **text,
|
|
void *ctx )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
struct berval reqdata = BER_BVNULL;
|
|
rbac_req_t *reqp = NULL;
|
|
BerElementBuffer berbuf;
|
|
BerElement *ber = (BerElement *)&berbuf;
|
|
ber_tag_t tag;
|
|
ber_len_t len = -1;
|
|
|
|
*text = NULL;
|
|
|
|
if ( in == NULL || in->bv_len == 0 ) {
|
|
*text = "empty request data field in rbac_create_session exop";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
reqp = rbac_alloc_req( RBAC_REQ_CREATE_SESSION );
|
|
|
|
if ( !reqp ) {
|
|
*text = "unable to allocate memory for bac_create_session exop";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
ber_dupbv_x( &reqdata, in, ctx );
|
|
|
|
/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
|
|
ber_init2( ber, &reqdata, 0 );
|
|
|
|
tag = ber_scanf( ber, "{" /*}*/ );
|
|
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_create_session: "
|
|
"decoding error.\n" );
|
|
goto decoding_error;
|
|
}
|
|
|
|
// Order: 1. sessionId, 2. tenantId, 3. userId, 4. password and 5. roles
|
|
/* must-have */
|
|
tag = ber_peek_tag( ber, &len );
|
|
|
|
// 1. SESSIONID
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_SESSION_ID ) {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_create_session: "
|
|
"session id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->sessid, &bv, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
// 2. TENANT ID
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_TENANT_ID ) {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_create_session: "
|
|
"tenant id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->tenantid, &bv, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
// 3. USERID
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_USER_ID ) {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_create_session: "
|
|
"user id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->uid, &bv, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
// 4. PASSWORD
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_AUTHTOK ) {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv);
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_create_session: "
|
|
"authtok parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->authtok, &bv, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
// 5. ROLES
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_ACTIVE_ROLE ) {
|
|
tag = ber_scanf( ber, "W", &reqp->roles);
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_create_session: "
|
|
"role parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
if ( tag != LBER_DEFAULT || len != 0 ) {
|
|
decoding_error:;
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_create_session: "
|
|
"decoding error, len=%ld\n",
|
|
(long)len );
|
|
rc = LDAP_PROTOCOL_ERROR;
|
|
*text = "data decoding error";
|
|
}
|
|
|
|
if ( rc == LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "slap_parse_rbac_create_session: "
|
|
"SUCCESS\n" );
|
|
|
|
*reqpp = reqp;
|
|
} else {
|
|
Debug( LDAP_DEBUG_ANY, "slap_parse_rbac_create_session: "
|
|
"NO SUCCESS RC=%d\n", rc );
|
|
|
|
rbac_free_req( reqp );
|
|
*reqpp = NULL;
|
|
}
|
|
|
|
if ( !BER_BVISNULL( &reqdata ) ) {
|
|
ber_memfree_x( reqdata.bv_val, ctx );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* rbac_create_session:
|
|
* 1. authenticate user
|
|
* 2. evaluate pwd policy
|
|
* 3. create session
|
|
*/
|
|
static int
|
|
rbac_create_session( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
struct berval rbac_op = BER_BVC("CreateSession");
|
|
BerElementBuffer berbuf;
|
|
BerElement *ber = (BerElement *)&berbuf;
|
|
int rc = LDAP_SUCCESS;
|
|
rbac_session_t *sessp = NULL;
|
|
rbac_user_t *userp = NULL;
|
|
rbac_req_t *reqp = NULL;
|
|
|
|
rs->sr_err = slap_parse_rbac_create_session(
|
|
op->ore_reqdata, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
/* read user entry */
|
|
userp = rbac_read_user( op, reqp );
|
|
if ( !userp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_create_session: "
|
|
"unable to read user entry\n" );
|
|
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
|
rs->sr_text = "rbac_create_session: unable to read user entry";
|
|
goto done;
|
|
}
|
|
|
|
if ( !BER_BVISNULL( &userp->password ) ) {
|
|
/* if request is with pwd, authenticate the user */
|
|
rc = rbac_authenticate_user( op, userp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_create_session: "
|
|
"rbac_authenticate_user failed!\n" );
|
|
rs->sr_err = LDAP_INVALID_CREDENTIALS;
|
|
rs->sr_text = "rbac_create_session: invalid credential";
|
|
goto done;
|
|
}
|
|
/*
|
|
rbac_user_t *ui = op->o_callback->sc_private;
|
|
int pVal = ui->authz;
|
|
printf("password reset val=%d", pVal );
|
|
*/
|
|
|
|
} else {
|
|
/* no pwd is provided, check whether the requesting session */
|
|
/* id has the access privilege to create a session on behalf */
|
|
/* of the user */
|
|
rc = rbac_create_session_acl_check( &reqp->sessid, userp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_create_session: "
|
|
"rbac_authenticate_user failed!\n" );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "rbac_create_session: session permission denied";
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* check user temporal constraint */
|
|
rc = rbac_user_temporal_constraint( userp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_create_session: "
|
|
"rbac_user_temporal_constraint() failed!\n" );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "rbac_create_session: temporal constraint violation";
|
|
goto done;
|
|
}
|
|
|
|
sessp = rbac_alloc_session();
|
|
if ( !sessp ) {
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "rbac_create_session: unable to allocate session";
|
|
goto done;
|
|
}
|
|
|
|
rc = activate_session_roles( sessp, reqp, userp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_create_session: "
|
|
"failed to activate roles to session!\n" );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text =
|
|
"rbac_create_session: failed to activate roles into session";
|
|
goto done;
|
|
}
|
|
|
|
/* store uid and tenant id in session */
|
|
ber_dupbv( &sessp->userdn, &userp->dn );
|
|
ber_dupbv( &sessp->uid, &reqp->uid );
|
|
ber_dupbv( &sessp->tenantid, &reqp->tenantid );
|
|
|
|
/* register RBAC session */
|
|
rc = rbac_register_session( op, rs, sessp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
goto done;
|
|
}
|
|
|
|
ber_init_w_nullc( ber, LBER_USE_DER );
|
|
rc = ber_printf( ber, "{tO}", LDAP_TAG_EXOP_RBAC_SESSION_ID,
|
|
&sessp->sessid );
|
|
if ( rc < 0 ) {
|
|
rs->sr_err = LDAP_OTHER;
|
|
rs->sr_text = "internal error";
|
|
} else {
|
|
(void)ber_flatten( ber, &rs->sr_rspdata );
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_CREATE_SESSION.bv_val );
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
}
|
|
|
|
ber_free_buf( ber );
|
|
|
|
done:;
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_CREATE_SESSION.bv_val );
|
|
/* generate audit log */
|
|
rbac_audit(
|
|
op, CreateSession, sessp, reqp, rs->sr_err, (char *)rs->sr_text );
|
|
|
|
rbac_free_req( reqp );
|
|
rbac_free_session( sessp );
|
|
|
|
//if (rs->sr_err != LDAP_SUCCESS) {
|
|
//send_ldap_result( op, rs );
|
|
//}
|
|
|
|
return rs->sr_err;
|
|
}
|
|
|
|
/*
|
|
* slap_parse_rbac_check_access
|
|
*/
|
|
static int
|
|
slap_parse_rbac_check_access(
|
|
struct berval *in,
|
|
rbac_req_t **reqpp,
|
|
const char **text,
|
|
void *ctx )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
struct berval reqdata = BER_BVNULL;
|
|
rbac_req_t *reqp = NULL;
|
|
BerElementBuffer berbuf;
|
|
BerElement *ber = (BerElement *)&berbuf;
|
|
ber_tag_t tag;
|
|
ber_len_t len;
|
|
|
|
*text = NULL;
|
|
reqp = rbac_alloc_req( RBAC_REQ_CHECK_ACCESS );
|
|
|
|
if ( !reqp ) {
|
|
*text = "unable to allocate memory for slap_parse_rbac_check_access";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
if ( in == NULL || in->bv_len == 0 ) {
|
|
*text = "empty request data field in rbac_check_access exop";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
ber_dupbv_x( &reqdata, in, ctx );
|
|
|
|
/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
|
|
ber_init2( ber, &reqdata, 0 );
|
|
|
|
tag = ber_scanf( ber, "{" /*}*/ );
|
|
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_check_access: "
|
|
"decoding error.\n" );
|
|
goto decoding_error;
|
|
}
|
|
|
|
// sessionId is required:
|
|
tag = ber_peek_tag( ber, &len );
|
|
if ( tag != LDAP_TAG_EXOP_RBAC_SESSION_ID ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_check_access: "
|
|
"decoding error.\n" );
|
|
goto decoding_error;
|
|
} else {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_check_access: "
|
|
"session id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->sessid, &bv, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
// operationName is required:
|
|
if ( tag != LDAP_TAG_EXOP_RBAC_OPNAME ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_check_access: "
|
|
"decoding error.\n" );
|
|
goto decoding_error;
|
|
} else {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_check_access: "
|
|
"opname parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->opname, &bv, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
// objectName is required:
|
|
if ( tag != LDAP_TAG_EXOP_RBAC_OBJNAME ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_check_access: "
|
|
"decoding error.\n" );
|
|
goto decoding_error;
|
|
} else {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_check_access: "
|
|
"objname parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->objname, &bv, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
// objectId is optional:
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_OBJID ) {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_check_access: "
|
|
"objid parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->objid, &bv, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
if ( tag != LBER_DEFAULT || len != 0 ) {
|
|
decoding_error:;
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_check_access: "
|
|
"decoding error, len=%ld\n",
|
|
(long)len );
|
|
rc = LDAP_PROTOCOL_ERROR;
|
|
*text = "data decoding error";
|
|
}
|
|
|
|
if ( rc == LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "slap_parse_rbac_check_access: "
|
|
"SUCCESS\n" );
|
|
*reqpp = reqp;
|
|
} else {
|
|
Debug( LDAP_DEBUG_ANY, "slap_parse_rbac_check_access: "
|
|
"FAIL\n" );
|
|
rbac_free_req( reqp );
|
|
}
|
|
|
|
if ( !BER_BVISNULL( &reqdata ) ) {
|
|
ber_memfree_x( reqdata.bv_val, ctx );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
// checkAccess F (ALL)
|
|
static int
|
|
rbac_check_access( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
rbac_session_t *sessp = NULL;
|
|
rbac_permission_t *permp = NULL;
|
|
rbac_constraint_t *cp = NULL;
|
|
rbac_req_t *reqp = NULL;
|
|
const struct berval rbac_op = BER_BVC("CheckAccess");
|
|
int rc = LDAP_SUCCESS;
|
|
int found = 0;
|
|
|
|
rs->sr_err = slap_parse_rbac_check_access(
|
|
op->ore_reqdata, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
BER_BVZERO( &op->o_req_dn );
|
|
BER_BVZERO( &op->o_req_ndn );
|
|
|
|
/* get the session using the session id */
|
|
sessp = rbac_session_byid( op, reqp );
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access: "
|
|
"session not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/* read the permission using objectName and OpName */
|
|
permp = rbac_read_permission( op, reqp );
|
|
if ( !permp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access: "
|
|
"permission not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
// Convert the user-role constraint data from BerVarray to rbac_constraint_t format
|
|
cp = rbac_user_role_constraints( sessp->role_constraints );
|
|
|
|
// Now do the actual rbac checkAccess:
|
|
rc = rbac_check_session_permission( sessp, permp, cp );
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_user_permission: "
|
|
"failed\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
|
|
rs->sr_err = rc;
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_CHECK_ACCESS.bv_val );
|
|
|
|
/* generate audit log */
|
|
rbac_audit( op, CheckAccess, sessp, reqp, rs->sr_err, (char *)rs->sr_text );
|
|
|
|
rbac_free_permission( permp );
|
|
rbac_free_req( reqp );
|
|
rbac_free_session( sessp );
|
|
rbac_free_constraints( cp );
|
|
|
|
return rs->sr_err;
|
|
}
|
|
|
|
// checkAccess A loop back
|
|
static int
|
|
rbac_check_accessA( Operation *op, SlapReply *rs )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
//rs->sr_err = slap_parse_rbac_check_access(op->ore_reqdata,
|
|
// &reqp, &rs->sr_text, NULL);
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_CHECK_ACCESS.bv_val );
|
|
rs->sr_err = rc;
|
|
|
|
return rc;
|
|
}
|
|
|
|
// checkAccess B parse
|
|
static int
|
|
rbac_check_accessB( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
rbac_req_t *reqp = NULL;
|
|
const struct berval rbac_op = BER_BVC("CheckAccess");
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access\n" );
|
|
|
|
rs->sr_err = slap_parse_rbac_check_access(
|
|
op->ore_reqdata, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
BER_BVZERO( &op->o_req_dn );
|
|
BER_BVZERO( &op->o_req_ndn );
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_CHECK_ACCESS.bv_val );
|
|
rs->sr_err = rc;
|
|
|
|
rbac_free_req( reqp );
|
|
|
|
return rc;
|
|
}
|
|
|
|
// checkAccess C - parse request & read session record
|
|
static int
|
|
rbac_check_accessC( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
rbac_session_t *sessp = NULL;
|
|
rbac_req_t *reqp = NULL;
|
|
const struct berval rbac_op = BER_BVC("CheckAccess");
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access\n" );
|
|
|
|
rs->sr_err = slap_parse_rbac_check_access(
|
|
op->ore_reqdata, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
BER_BVZERO( &op->o_req_dn );
|
|
BER_BVZERO( &op->o_req_ndn );
|
|
|
|
/* get the session using the session id */
|
|
sessp = rbac_session_byid( op, reqp );
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access: "
|
|
"session not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_CHECK_ACCESS.bv_val );
|
|
rs->sr_err = rc;
|
|
|
|
rbac_free_req( reqp );
|
|
rbac_free_session( sessp );
|
|
return rc;
|
|
}
|
|
|
|
// checkAccess D, parse, read perm
|
|
static int
|
|
rbac_check_accessD( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
rbac_permission_t *permp = NULL;
|
|
rbac_req_t *reqp = NULL;
|
|
const struct berval rbac_op = BER_BVC("CheckAccess");
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access\n" );
|
|
|
|
rs->sr_err = slap_parse_rbac_check_access(
|
|
op->ore_reqdata, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
BER_BVZERO( &op->o_req_dn );
|
|
BER_BVZERO( &op->o_req_ndn );
|
|
|
|
/* get the session using the session id */
|
|
/*
|
|
sessp = rbac_session_byid(op, reqp);
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access: "
|
|
"session not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
*/
|
|
|
|
/* read the permission using objectName and OpName */
|
|
permp = rbac_read_permission( op, reqp );
|
|
if ( !permp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access: "
|
|
"permission not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_CHECK_ACCESS.bv_val );
|
|
rs->sr_err = rc;
|
|
|
|
rbac_free_permission( permp );
|
|
rbac_free_req( reqp );
|
|
|
|
return rc;
|
|
}
|
|
|
|
// checkAccess E everything but the audit insert
|
|
static int
|
|
rbac_check_accessE( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
rbac_session_t *sessp = NULL;
|
|
rbac_permission_t *permp = NULL;
|
|
rbac_constraint_t *cp = NULL;
|
|
rbac_req_t *reqp = NULL;
|
|
const struct berval rbac_op = BER_BVC("CheckAccess");
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access\n" );
|
|
|
|
rs->sr_err = slap_parse_rbac_check_access(
|
|
op->ore_reqdata, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
BER_BVZERO( &op->o_req_dn );
|
|
BER_BVZERO( &op->o_req_ndn );
|
|
|
|
/* get the session using the session id */
|
|
sessp = rbac_session_byid( op, reqp );
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access: "
|
|
"session not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/* read the permission using objectName and OpName */
|
|
permp = rbac_read_permission( op, reqp );
|
|
if ( !permp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_access: "
|
|
"permission not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
// Convert the user-role constraint data from BerVarray to rbac_constraint_t format
|
|
cp = rbac_user_role_constraints( sessp->role_constraints );
|
|
|
|
// Now do the actual rbac checkAccess:
|
|
rc = rbac_check_session_permission( sessp, permp, cp );
|
|
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_check_user_permission: "
|
|
"failed\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
|
|
rs->sr_err = rc;
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_CHECK_ACCESS.bv_val );
|
|
|
|
/* generate audit log */
|
|
//rbac_audit(op, CheckAccess, sessp, reqp, rs->sr_err,
|
|
// (char *) rs->sr_text);
|
|
|
|
rbac_free_permission( permp );
|
|
rbac_free_req( reqp );
|
|
rbac_free_session( sessp );
|
|
rbac_free_constraints( cp );
|
|
|
|
return rs->sr_err;
|
|
}
|
|
|
|
/* check whether role exists and role assigned to the user */
|
|
static int
|
|
rbac_check_user_role(
|
|
rbac_req_t *reqp,
|
|
rbac_session_t *sessp,
|
|
rbac_user_t *userp )
|
|
{
|
|
int rc = 0;
|
|
int i;
|
|
|
|
//assert(!BER_BVISEMPTY(&reqp->roles[0]));
|
|
assert( !BER_BVISEMPTY( &reqp->role ) );
|
|
|
|
for ( i = 0; !BER_BVISNULL( &userp->roles[i] ); i++ ) {
|
|
//if (!ber_bvstrcasecmp(&userp->roles[i], &reqp->roles[0])) {
|
|
if ( !ber_bvstrcasecmp( &userp->roles[i], &reqp->role ) ) {
|
|
rc = 1; /* found the match */
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:;
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* check whether role exists and role assigned to the session */
|
|
static int
|
|
rbac_check_session_role( rbac_req_t *reqp, rbac_session_t *sessp )
|
|
{
|
|
int rc = 0;
|
|
int i;
|
|
|
|
for ( i = 0; !BER_BVISNULL( &sessp->roles[i] ); i++ ) {
|
|
//if (!ber_bvstrcasecmp(&sessp->roles[i], &reqp->roles[0])) {
|
|
if ( !ber_bvstrcasecmp( &sessp->roles[i], &reqp->role ) ) {
|
|
rc = 1; /* found the match */
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:;
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* make sure user is the owner of the session */
|
|
static int
|
|
rbac_check_user_session( rbac_session_t *sessp, rbac_req_t *reqp )
|
|
{
|
|
int rc = 0;
|
|
|
|
if ( BER_BVISNULL( &sessp->uid ) || BER_BVISNULL( &reqp->uid ) ||
|
|
sessp->uid.bv_len != reqp->uid.bv_len ) {
|
|
goto done;
|
|
}
|
|
|
|
if ( !strncasecmp(
|
|
sessp->uid.bv_val, reqp->uid.bv_val, reqp->uid.bv_len ) ) {
|
|
rc = 1;
|
|
goto done;
|
|
}
|
|
|
|
done:;
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* slap_parse_rbac_active_role
|
|
*/
|
|
static int
|
|
slap_parse_rbac_active_role(
|
|
struct berval *in,
|
|
int add_or_drop_role,
|
|
rbac_req_t **reqpp,
|
|
const char **text,
|
|
void *ctx )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
struct berval reqdata = BER_BVNULL;
|
|
rbac_req_t *reqp = NULL;
|
|
BerElementBuffer berbuf;
|
|
BerElement *ber = (BerElement *)&berbuf;
|
|
ber_tag_t tag;
|
|
ber_len_t len = -1;
|
|
|
|
*text = NULL;
|
|
|
|
if ( in == NULL || in->bv_len == 0 ) {
|
|
*text = "empty request data field in rbac_create_session exop";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
reqp = rbac_alloc_req( add_or_drop_role );
|
|
|
|
if ( !reqp ) {
|
|
*text = "unable to allocate memory for rbac_add_drop_active_role exop";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
ber_dupbv_x( &reqdata, in, ctx );
|
|
|
|
/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
|
|
ber_init2( ber, &reqdata, 0 );
|
|
|
|
tag = ber_scanf( ber, "{" /*}*/ );
|
|
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_active_role: "
|
|
"decoding error.\n" );
|
|
goto decoding_error;
|
|
}
|
|
|
|
tag = ber_peek_tag( ber, &len );
|
|
//if ( tag == LDAP_TAG_EXOP_RBAC_USER_ID ) {
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_USER_ID_SESS ) {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_active_role: "
|
|
"user id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv( &reqp->uid, &bv );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_SESSION_ID_SESS ) {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_active_role: "
|
|
"session id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv( &reqp->sessid, &bv );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_ROLE_NM_SESS ) {
|
|
struct berval bv;
|
|
tag = ber_scanf( ber, "m", &bv );
|
|
//tag = ber_scanf( ber, "W", &reqp->roles);
|
|
//tag = ber_scanf( ber, "m", &reqp->roles);
|
|
//tag = ber_scanf( ber, "m", &reqp->roles[0]);
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_create_session: "
|
|
"role parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv( &reqp->role, &bv );
|
|
//ber_dupbv(&reqp->roles[0], &bv);
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
if ( tag != LBER_DEFAULT || len != 0 ) {
|
|
decoding_error:;
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_create_session: "
|
|
"decoding error, len=%ld\n",
|
|
(long)len );
|
|
rc = LDAP_PROTOCOL_ERROR;
|
|
*text = "data decoding error";
|
|
}
|
|
|
|
if ( rc == LDAP_SUCCESS ) {
|
|
*reqpp = reqp;
|
|
} else {
|
|
rbac_free_req( reqp );
|
|
*reqpp = NULL;
|
|
}
|
|
|
|
if ( !BER_BVISNULL( &reqdata ) ) {
|
|
ber_memfree_x( reqdata.bv_val, ctx );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
rbac_add_active_role( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
struct berval rbac_op = BER_BVC("AddActiveRole");
|
|
rbac_req_t *reqp = NULL;
|
|
rbac_user_t *userp = NULL;
|
|
rbac_session_t *sessp;
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
rs->sr_err = slap_parse_rbac_active_role( op->ore_reqdata,
|
|
RBAC_REQ_ADD_ACTIVE_ROLE, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
/* get the session using the session id */
|
|
sessp = rbac_session_byid( op, reqp );
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_add_active_role: "
|
|
"session not found\n" );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "rbac_add_active_role: session not found";
|
|
goto done;
|
|
}
|
|
|
|
/* read user entry */
|
|
userp = rbac_read_user( op, reqp );
|
|
if ( !userp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_add_active_role: "
|
|
"unable to read user entry\n" );
|
|
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
|
rs->sr_text = "rbac_add_active_role: unable to read user entry";
|
|
goto done;
|
|
}
|
|
|
|
/* make sure role exists and role assigned to the user */
|
|
if ( !rbac_check_user_role( reqp, sessp, userp ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_add_active_role: "
|
|
"role not assigned to the user\n" );
|
|
rs->sr_err = LDAP_NO_SUCH_OBJECT;
|
|
rs->sr_text = "rbac_add_active_role: role not assigned to the user";
|
|
goto done;
|
|
}
|
|
|
|
/* make sure user is the owner of the session */
|
|
if ( !rbac_check_user_session( sessp, reqp ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_add_active_role: "
|
|
"user not owner of session\n" );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "rbac_add_active_role: user not owner of the session";
|
|
goto done;
|
|
}
|
|
|
|
/* add the role to the session */
|
|
rc = rbac_session_add_role( op, sessp, reqp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
rs->sr_err = rc;
|
|
if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
|
|
rs->sr_text =
|
|
"rbac_add_active_role: role already activated in session";
|
|
Debug( LDAP_DEBUG_ANY, "rbac_add_active_role: "
|
|
"role already activated in session\n" );
|
|
} else {
|
|
rs->sr_text = "rbac_add_active_role: unable to add role to session";
|
|
Debug( LDAP_DEBUG_ANY, "rbac_add_active_role: "
|
|
"unable to add role to session\n" );
|
|
}
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_ADD_ACTIVE_ROLE.bv_val );
|
|
|
|
/* generate audit log */
|
|
rbac_audit(
|
|
op, AddActiveRole, sessp, reqp, rs->sr_err, (char *)rs->sr_text );
|
|
|
|
rbac_free_session( sessp );
|
|
rbac_free_user( userp );
|
|
rbac_free_req( reqp );
|
|
|
|
return rs->sr_err;
|
|
}
|
|
|
|
static int
|
|
rbac_drop_active_role( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
const struct berval rbac_op = BER_BVC("DropActiveRole");
|
|
rbac_session_t *sessp;
|
|
rbac_req_t *reqp = NULL;
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
rs->sr_err = slap_parse_rbac_active_role( op->ore_reqdata,
|
|
RBAC_REQ_DROP_ACTIVE_ROLE, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
/* get the session using the session id */
|
|
sessp = rbac_session_byid( op, reqp );
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_drop_active_role: "
|
|
"session not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
if ( BER_BVISNULL( &reqp->role ) || !sessp->roles ||
|
|
BER_BVISNULL( &sessp->roles[0] ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_drop_active_role: "
|
|
"unavailable role\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/* make sure role exists and role assigned to the user */
|
|
if ( !rbac_check_session_role( reqp, sessp ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_drop_active_role: "
|
|
"role not assigned to session\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/* make sure user is the owner of the session */
|
|
if ( !rbac_check_user_session( sessp, reqp ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_drop_active_role: "
|
|
"user not owner of session\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "rbac_drop_active_role: user not owner of the session";
|
|
goto done;
|
|
}
|
|
|
|
/* drop the role to the session */
|
|
rc = rbac_session_drop_role( op, sessp, reqp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_drop_active_role: "
|
|
"unable to drop active role from session\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
rs->sr_text = "rbac_drop_active_role: unable to drop role from session";
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
rs->sr_err = rc;
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_DROP_ACTIVE_ROLE.bv_val );
|
|
|
|
/* generate audit log */
|
|
rbac_audit(
|
|
op, DropActiveRole, sessp, reqp, rs->sr_err, (char *)rs->sr_text );
|
|
|
|
rbac_free_session( sessp );
|
|
rbac_free_req( reqp );
|
|
|
|
return rs->sr_err;
|
|
}
|
|
|
|
/*
|
|
* slap_parse_rbac_delete_session
|
|
*/
|
|
static int
|
|
slap_parse_rbac_delete_session(
|
|
struct berval *in,
|
|
rbac_req_t **reqpp,
|
|
const char **text,
|
|
void *ctx )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
struct berval reqdata = BER_BVNULL;
|
|
rbac_req_t *reqp = NULL;
|
|
BerElementBuffer berbuf;
|
|
BerElement *ber = (BerElement *)&berbuf;
|
|
ber_tag_t tag;
|
|
ber_len_t len = -1;
|
|
|
|
*text = NULL;
|
|
|
|
if ( in == NULL || in->bv_len == 0 ) {
|
|
*text = "empty request data field in rbac_delete_session exop";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
reqp = rbac_alloc_req( RBAC_REQ_DELETE_SESSION );
|
|
|
|
if ( !reqp ) {
|
|
*text = "unable to allocate memory for rbac_delete_session exop";
|
|
return LDAP_PROTOCOL_ERROR;
|
|
}
|
|
|
|
ber_dupbv_x( &reqdata, in, ctx );
|
|
|
|
/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
|
|
ber_init2( ber, &reqdata, 0 );
|
|
|
|
tag = ber_scanf( ber, "{" /*}*/ );
|
|
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_delete_session: "
|
|
"decoding error.\n" );
|
|
goto decoding_error;
|
|
}
|
|
|
|
tag = ber_peek_tag( ber, &len );
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_USER_ID_SESS ) {
|
|
struct berval uid;
|
|
tag = ber_scanf( ber, "m", &uid );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_delete_session: "
|
|
"user id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->uid, &uid, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
//tag = ber_peek_tag( ber, &len );
|
|
if ( tag == LDAP_TAG_EXOP_RBAC_SESSION_ID_SESS ) {
|
|
struct berval sessid;
|
|
tag = ber_scanf( ber, "m", &sessid );
|
|
if ( tag == LBER_ERROR ) {
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_delete_session: "
|
|
"session id parse failed.\n" );
|
|
goto decoding_error;
|
|
}
|
|
ber_dupbv_x( &reqp->sessid, &sessid, ctx );
|
|
tag = ber_peek_tag( ber, &len );
|
|
}
|
|
|
|
if ( tag != LBER_DEFAULT || len != 0 ) {
|
|
decoding_error:;
|
|
|
|
Debug( LDAP_DEBUG_TRACE, "slap_parse_rbac_delete_session: "
|
|
"decoding error, len=%ld\n",
|
|
(long)len );
|
|
rc = LDAP_PROTOCOL_ERROR;
|
|
*text = "data decoding error";
|
|
}
|
|
|
|
if ( rc == LDAP_SUCCESS ) {
|
|
*reqpp = reqp;
|
|
} else {
|
|
rbac_free_req( reqp );
|
|
*reqpp = NULL;
|
|
}
|
|
|
|
if ( !BER_BVISNULL( &reqdata ) ) {
|
|
ber_memfree_x( reqdata.bv_val, ctx );
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
rbac_delete_session( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
const struct berval rbac_op = BER_BVC("DeleteSession");
|
|
rbac_session_t *sessp = NULL;
|
|
rbac_req_t *reqp = NULL;
|
|
int rc;
|
|
|
|
rs->sr_err = slap_parse_rbac_delete_session(
|
|
op->ore_reqdata, &reqp, &rs->sr_text, NULL );
|
|
|
|
assert( rs->sr_err == LDAP_SUCCESS );
|
|
|
|
/* get the session using the session id */
|
|
sessp = rbac_session_byid( op, reqp );
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_delete_session: "
|
|
"session not found\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/* checking whether the session is owned by the user */
|
|
if ( !rbac_is_session_owner( sessp, reqp ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_delete_session: "
|
|
"session not owned by user\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
rc = rbac_int_delete_session( op, sessp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_int_delete_session: "
|
|
"unable to delete session\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
done:;
|
|
|
|
rs->sr_err = rc;
|
|
|
|
// always put the OID in the response:
|
|
rs->sr_rspoid = ch_strdup( slap_EXOP_DELETE_SESSION.bv_val );
|
|
|
|
/* generate audit log */
|
|
rbac_audit(
|
|
op, DeleteSession, sessp, reqp, rs->sr_err, (char *)rs->sr_text );
|
|
|
|
rbac_free_session( sessp );
|
|
rbac_free_req( reqp );
|
|
|
|
return rs->sr_err;
|
|
}
|
|
|
|
/* returns the permissions associated with a session */
|
|
static int
|
|
rbac_session_permissions( Operation *op, SlapReply *rs, rbac_req_t *reqp )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
const struct berval rbac_op = BER_BVC("SessionPermissions");
|
|
rbac_session_t *sessp;
|
|
|
|
sessp = rbac_session_byid( op, reqp );
|
|
if ( !sessp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_session_permissions: "
|
|
"session id not found\n" );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
rs->sr_err = rbac_int_session_permissions( op, rs, reqp, sessp );
|
|
if ( rs->sr_err != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_session_permissions: "
|
|
"permissions not found\n" );
|
|
goto done;
|
|
}
|
|
|
|
done:;
|
|
return rs->sr_err;
|
|
}
|
|
|
|
/* extract session permission info from op */
|
|
int
|
|
rbac_search_parse_session_permissions_req(
|
|
Operation *op,
|
|
rbac_req_t **reqpp,
|
|
const char **text,
|
|
void *ctx )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
struct berval *sessid = NULL;
|
|
rbac_req_t *reqp = NULL;
|
|
*text = NULL;
|
|
struct berval rbac_session_id = BER_BVC("sessionID");
|
|
struct berval rbac_session_permissions_attr =
|
|
BER_BVC("sessionPermissions");
|
|
AttributeDescription *ad = NULL;
|
|
Filter *f;
|
|
|
|
/* check simple assertion (sessionID=<session id>) */
|
|
f = op->ors_filter;
|
|
ad = f->f_ava->aa_desc;
|
|
if ( !ad || ber_bvstrcasecmp( &rbac_session_id, &ad->ad_cname ) ) {
|
|
goto done;
|
|
}
|
|
sessid = &f->f_ava->aa_value;
|
|
|
|
if ( !rbac_is_valid_session_id( sessid ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_search_parse_session_permissions_req: "
|
|
"invalid session id\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/* check requested attr */
|
|
|
|
if ( !op->oq_search.rs_attrs ||
|
|
BER_BVISNULL( &op->oq_search.rs_attrs[0].an_name ) ||
|
|
ber_bvstrcasecmp( &op->oq_search.rs_attrs[0].an_name,
|
|
&rbac_session_permissions_attr ) ||
|
|
!BER_BVISNULL( &op->oq_search.rs_attrs[1].an_name ) ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_search_parse_session_permissions_req: "
|
|
"only sessionPermissions allowed\n" );
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
reqp = rbac_alloc_req( RBAC_REQ_SESSION_PERMISSIONS );
|
|
if ( !reqp ) {
|
|
*text = "unable to allocate memory for rbac_session_permissions req";
|
|
rc = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
/* retrieve session id from search filter */
|
|
ber_dupbv_x( &reqp->sessid, sessid, ctx );
|
|
|
|
done:;
|
|
|
|
if ( rc == LDAP_SUCCESS ) {
|
|
*reqpp = reqp;
|
|
} else {
|
|
rbac_free_req( reqp );
|
|
*reqpp = NULL;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
rbac_search( Operation *op, SlapReply *rs )
|
|
{
|
|
Debug( LDAP_DEBUG_ANY, "rbac_search entry\n" );
|
|
|
|
return SLAP_CB_CONTINUE;
|
|
}
|
|
|
|
/*
|
|
static int
|
|
rbac_search( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
rbac_req_t *reqp = NULL;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
|
|
only session_permissions is implemented for now
|
|
rc = rbac_search_parse_session_permissions_req(
|
|
op, &reqp, &rs->sr_text, NULL );
|
|
if ( !reqp ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_search: "
|
|
"invalid search for session permissions\n" );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
rc = rbac_session_permissions( op, rs, reqp );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_search: "
|
|
"session permissions failed\n" );
|
|
rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
|
|
goto done;
|
|
}
|
|
|
|
rs->sr_err = LDAP_SUCCESS;
|
|
|
|
done:;
|
|
send_ldap_result( op, rs );
|
|
|
|
return rc;
|
|
}
|
|
*/
|
|
|
|
static struct exop {
|
|
struct berval oid;
|
|
BI_op_extended *extended;
|
|
} rbac_exop_table[] = {
|
|
{ BER_BVC(LDAP_RBAC_EXOP_CREATE_SESSION), rbac_create_session },
|
|
{ BER_BVC(LDAP_RBAC_EXOP_CHECK_ACCESS), rbac_check_access },
|
|
{ BER_BVC(LDAP_RBAC_EXOP_ADD_ACTIVE_ROLE), rbac_add_active_role },
|
|
{ BER_BVC(LDAP_RBAC_EXOP_DROP_ACTIVE_ROLE), rbac_drop_active_role },
|
|
{ BER_BVC(LDAP_RBAC_EXOP_DELETE_SESSION), rbac_delete_session },
|
|
{ BER_BVC(LDAP_RBAC_EXOP_SESSION_ROLES), rbac_session_roles },
|
|
|
|
{ BER_BVNULL, NULL }
|
|
};
|
|
|
|
static int
|
|
rbac_add( Operation *op, SlapReply *rs )
|
|
{
|
|
return SLAP_CB_CONTINUE;
|
|
}
|
|
|
|
static int
|
|
rbac_bind( Operation *op, SlapReply *rs )
|
|
{
|
|
return SLAP_CB_CONTINUE;
|
|
}
|
|
|
|
static int
|
|
rbac_compare( Operation *op, SlapReply *rs )
|
|
{
|
|
return SLAP_CB_CONTINUE;
|
|
}
|
|
|
|
static int
|
|
rbac_delete( Operation *op, SlapReply *rs )
|
|
{
|
|
return SLAP_CB_CONTINUE;
|
|
}
|
|
|
|
static int
|
|
rbac_modify( Operation *op, SlapReply *rs )
|
|
{
|
|
return SLAP_CB_CONTINUE;
|
|
}
|
|
|
|
static int
|
|
rbac_extended( Operation *op, SlapReply *rs )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
|
|
int rc = SLAP_CB_CONTINUE;
|
|
int i;
|
|
|
|
for ( i = 0; rbac_exop_table[i].extended != NULL; i++ ) {
|
|
if ( bvmatch( &rbac_exop_table[i].oid, &op->oq_extended.rs_reqoid ) ) {
|
|
rc = rbac_exop_table[i].extended( op, rs );
|
|
switch ( rc ) {
|
|
case LDAP_SUCCESS:
|
|
break;
|
|
case SLAP_CB_CONTINUE:
|
|
case SLAPD_ABANDON:
|
|
return rc;
|
|
default:
|
|
send_ldap_result( op, rs );
|
|
return rc;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
rbac_db_init( BackendDB *be, ConfigReply *cr )
|
|
{
|
|
slap_overinst *on = (slap_overinst *)be->bd_info;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
rbac_db_open( BackendDB *be, ConfigReply *cr )
|
|
{
|
|
int rc = LDAP_SUCCESS;
|
|
|
|
rc = rbac_initialize_tenants( be, cr );
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
rbac_db_close( BackendDB *be, ConfigReply *cr )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
rbac_initialize()
|
|
{
|
|
int rc;
|
|
|
|
rc = load_extop2( (struct berval *)&slap_EXOP_CREATE_SESSION,
|
|
SLAP_EXOP_WRITES|SLAP_EXOP_HIDE, rbac_create_session, 0 );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
|
|
"unable to register rbac_create_session exop: %d\n",
|
|
rc );
|
|
return rc;
|
|
}
|
|
|
|
rc = load_extop2( (struct berval *)&slap_EXOP_CHECK_ACCESS,
|
|
SLAP_EXOP_WRITES|SLAP_EXOP_HIDE, rbac_check_access, 0 );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
|
|
"unable to register rbac_check_access exop: %d\n",
|
|
rc );
|
|
return rc;
|
|
}
|
|
|
|
rc = load_extop2( (struct berval *)&slap_EXOP_ADD_ACTIVE_ROLE,
|
|
SLAP_EXOP_WRITES|SLAP_EXOP_HIDE, rbac_add_active_role, 0 );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
|
|
"unable to register rbac_add_active_role exop: %d\n",
|
|
rc );
|
|
return rc;
|
|
}
|
|
|
|
rc = load_extop2( (struct berval *)&slap_EXOP_DROP_ACTIVE_ROLE,
|
|
SLAP_EXOP_WRITES|SLAP_EXOP_HIDE, rbac_drop_active_role, 0 );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
|
|
"unable to register rbac_drop_active_role exop: %d\n",
|
|
rc );
|
|
return rc;
|
|
}
|
|
|
|
rc = load_extop2( (struct berval *)&slap_EXOP_DELETE_SESSION,
|
|
SLAP_EXOP_WRITES|SLAP_EXOP_HIDE, rbac_delete_session, 0 );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
|
|
"unable to register rbac_delete_session exop: %d\n",
|
|
rc );
|
|
return rc;
|
|
}
|
|
|
|
rc = load_extop2( (struct berval *)&slap_EXOP_SESSION_ROLES,
|
|
SLAP_EXOP_WRITES|SLAP_EXOP_HIDE, rbac_session_roles, 0 );
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
Debug( LDAP_DEBUG_ANY, "rbac_initialize: "
|
|
"unable to register rbac_session_roles exop: %d\n",
|
|
rc );
|
|
return rc;
|
|
}
|
|
|
|
rbac.on_bi.bi_type = "rbac";
|
|
rbac.on_bi.bi_db_init = rbac_db_init;
|
|
rbac.on_bi.bi_db_open = rbac_db_open;
|
|
rbac.on_bi.bi_db_close = rbac_db_close;
|
|
|
|
rbac.on_bi.bi_op_add = rbac_add;
|
|
rbac.on_bi.bi_op_bind = rbac_bind;
|
|
rbac.on_bi.bi_op_compare = rbac_compare;
|
|
rbac.on_bi.bi_op_delete = rbac_delete;
|
|
rbac.on_bi.bi_op_modify = rbac_modify;
|
|
rbac.on_bi.bi_op_search = rbac_search;
|
|
rbac.on_bi.bi_extended = rbac_extended;
|
|
rbac.on_bi.bi_cf_ocs = rbac_ocs;
|
|
|
|
/* rbac.on_bi.bi_connection_destroy = rbac_connection_destroy; */
|
|
|
|
rc = config_register_schema( rbaccfg, rbac_ocs );
|
|
if ( rc ) return rc;
|
|
|
|
rc = rbac_initialize_repository();
|
|
if ( rc != LDAP_SUCCESS ) {
|
|
return rc;
|
|
}
|
|
|
|
return overlay_register( &rbac );
|
|
}
|
|
|
|
int
|
|
init_module( int argc, char *argv[] )
|
|
{
|
|
return rbac_initialize();
|
|
}
|