/* rbac.c - RBAC main file */ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 2013-2022 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 * . */ /* ACKNOWLEDGEMENTS: */ #include "portable.h" #include #include #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; } // checkAcess 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; } // checkAcess 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; } // checkAcess 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; } // checkAcess 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; } // checkAcess 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; } // checkAcess 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=) */ 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(); }