Home | History | Annotate | Line # | Download | only in rbac
      1 /*	$NetBSD: rbacaudit.c,v 1.2 2021/08/14 16:14:53 christos Exp $	*/
      2 
      3 /* rbacaudit.c - RBAC Audit */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  *
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 /* ACKNOWLEDGEMENTS:
     19  */
     20 
     21 #include <sys/cdefs.h>
     22 __RCSID("$NetBSD: rbacaudit.c,v 1.2 2021/08/14 16:14:53 christos Exp $");
     23 
     24 #include "portable.h"
     25 
     26 #include <stdio.h>
     27 
     28 #include <ac/string.h>
     29 
     30 #include "slap.h"
     31 #include "slap-config.h"
     32 #include "lutil.h"
     33 
     34 #include "rbac.h"
     35 
     36 static struct rbac_audit_op {
     37 	audit_op_t op;
     38 	struct berval op_bv;
     39 } rbac_audit_ops[] = {
     40 	{ CreateSession, BER_BVC("CreateSession") },
     41 	{ CheckAccess, BER_BVC("CheckAccess") },
     42 	{ AddActiveRole, BER_BVC("AddActiveRole") },
     43 	{ DropActiveRole, BER_BVC("DropActiveRole") },
     44 	{ SessionPermissions, BER_BVC("SessionPermissions") },
     45 	{ DeleteSession, BER_BVC("DeleteSession") },
     46 	{ SessionRoles, BER_BVC("SessionRoles") },
     47 
     48 	{ -1, BER_BVNULL }
     49 };
     50 
     51 static int
     52 rbac_audit_fake_cb( Operation *op, SlapReply *rs )
     53 {
     54 	Debug( LDAP_DEBUG_ANY, "rbac_audit_fake_cb\n" );
     55 
     56 	return 0;
     57 }
     58 
     59 void
     60 rbac_audit(
     61 		Operation *op,
     62 		audit_op_t rbac_op,
     63 		rbac_session_t *sessp,
     64 		rbac_req_t *reqp,
     65 		int result,
     66 		char *msg )
     67 {
     68 	int op_idx, rc = LDAP_SUCCESS;
     69 	int found = 0;
     70 	struct berval timestamp;
     71 	tenant_info_t *tenantp = rbac_tid2tenant( &sessp->tenantid );
     72 	slap_callback cb = { 0 };
     73 	SlapReply rs2 = { REP_RESULT };
     74 	Entry *e = NULL;
     75 	struct berval auditObjectClass = BER_BVC("rbacAudit");
     76 	struct berval auditResultSuccess = BER_BVC("success");
     77 	struct berval auditResultFailed = BER_BVC("failed");
     78 	struct berval bv, rdn, nrdn;
     79 	char rdnbuf[RBAC_BUFLEN];
     80 	time_t now;
     81 	char nowstr[LDAP_LUTIL_GENTIME_BUFSIZE];
     82 
     83 	for ( op_idx = 0; rbac_audit_ops[op_idx].op != -1; op_idx++ ) {
     84 		if ( rbac_op == rbac_audit_ops[op_idx].op ) {
     85 			/* legit audit op */
     86 			found = 1;
     87 			break;
     88 		}
     89 	}
     90 
     91 	if ( !found ) goto done;
     92 
     93 	e = entry_alloc();
     94 
     95 	/* audit timestamp */
     96 	now = slap_get_time(); /* stored for later consideration */
     97 	timestamp.bv_val = nowstr;
     98 	timestamp.bv_len = sizeof(nowstr);
     99 	slap_timestamp( &now, &timestamp );
    100 
    101 	/* construct audit record DN; FIXME: random() call  */
    102 	sprintf( rdnbuf, "%s%d", RBAC_AUDIT_RDN_EQ, (int)op->o_tid );
    103 	strcat( rdnbuf, "-" );
    104 	strncat( rdnbuf, timestamp.bv_val, timestamp.bv_len );
    105 	bv.bv_val = &rdnbuf[0];
    106 	bv.bv_len = strlen( &rdnbuf[0] );
    107 
    108 	rc = dnPrettyNormal( NULL, &bv, &rdn, &nrdn, NULL );
    109 	if ( rc != LDAP_SUCCESS ) {
    110 		Debug( LDAP_DEBUG_ANY, "rbac_audit: "
    111 				"unable to normalize audit rDN (rc=%d)\n", rc );
    112 		goto done;
    113 	}
    114 
    115 	/* FIXME: audit_basedn should have been normalized */
    116 	build_new_dn( &e->e_name, &tenantp->audit_basedn, &rdn, NULL );
    117 	build_new_dn( &e->e_nname, &tenantp->audit_basedn, &nrdn, NULL );
    118 
    119 	ch_free( rdn.bv_val );
    120 	ch_free( nrdn.bv_val );
    121 
    122 	/* add timestamp */
    123 	attr_merge_one( e, slap_rbac_schema.ad_audit_timestamp, &timestamp, NULL );
    124 
    125 	/* add rbac audit objectClass */
    126 
    127 	attr_merge_one( e, slap_schema.si_ad_objectClass, &auditObjectClass, NULL );
    128 	attr_merge_one( e, slap_schema.si_ad_structuralObjectClass,
    129 			&auditObjectClass, NULL );
    130 
    131 	/* audit op */
    132 	attr_merge_one( e, slap_rbac_schema.ad_audit_op,
    133 			&rbac_audit_ops[op_idx].op_bv, NULL );
    134 
    135 	/* userid */
    136 	if ( sessp && !BER_BVISNULL( &sessp->uid ) ) {
    137 		attr_merge_one( e, slap_schema.si_ad_uid, &sessp->uid, NULL );
    138 	}
    139 
    140 	/* session id */
    141 
    142 	if ( sessp && !BER_BVISNULL( &sessp->sessid ) ) {
    143 		AttributeDescription *ad = NULL;
    144 		const char *text = NULL;
    145 		struct berval sessid = BER_BVC("rbacSessid");
    146 
    147 		rc = slap_bv2ad( &sessid, &ad, &text );
    148 		if ( rc != LDAP_SUCCESS ) {
    149 			goto done;
    150 		}
    151 		attr_merge_one( e, ad, &sessp->sessid, NULL );
    152 	}
    153 
    154 	/* audit result */
    155 	attr_merge_one( e, slap_rbac_schema.ad_audit_result,
    156 			result == LDAP_SUCCESS ? &auditResultSuccess : &auditResultFailed,
    157 			NULL );
    158 
    159 	switch ( rbac_op ) {
    160 		case CreateSession:
    161 			/* audit roles */
    162 			if ( sessp && sessp->roles ) {
    163 				attr_merge( e, slap_rbac_schema.ad_audit_roles, sessp->roles,
    164 						NULL );
    165 			}
    166 			if ( reqp && reqp->roles ) {
    167 				attr_merge( e, slap_rbac_schema.ad_audit_requested_roles,
    168 						reqp->roles, NULL );
    169 			}
    170 			break;
    171 
    172 		case CheckAccess:
    173 			if ( sessp && sessp->roles ) {
    174 				attr_merge( e, slap_rbac_schema.ad_audit_roles, sessp->roles,
    175 						NULL );
    176 			}
    177 			if ( reqp && !BER_BVISEMPTY( &reqp->opname ) ) {
    178 				attr_merge_one( e, slap_rbac_schema.ad_audit_operations,
    179 						&reqp->opname, NULL );
    180 			}
    181 			if ( reqp && !BER_BVISEMPTY( &reqp->objname ) ) {
    182 				attr_merge_one( e, slap_rbac_schema.ad_audit_objects,
    183 						&reqp->objname, NULL );
    184 			}
    185 			break;
    186 
    187 		case AddActiveRole:
    188 			if ( reqp && reqp->roles ) {
    189 				attr_merge( e, slap_rbac_schema.ad_audit_requested_roles,
    190 						reqp->roles, NULL );
    191 			}
    192 			break;
    193 
    194 		case DropActiveRole:
    195 			/* audit roles */
    196 			if ( reqp && reqp->roles ) {
    197 				attr_merge( e, slap_rbac_schema.ad_audit_requested_roles,
    198 						reqp->roles, NULL );
    199 			}
    200 			break;
    201 
    202 		case SessionPermissions:
    203 			if ( sessp && sessp->roles ) {
    204 				attr_merge( e, slap_rbac_schema.ad_audit_roles, sessp->roles,
    205 						NULL );
    206 			}
    207 			break;
    208 
    209 		case DeleteSession:
    210 		case SessionRoles:
    211 		default:
    212 			break;
    213 	}
    214 
    215 	/* record the audit record */
    216 	Operation op2 = *op;
    217 	rbac_callback_info_t rbac_cb;
    218 	cb.sc_private = &rbac_cb;
    219 	cb.sc_response = rbac_audit_fake_cb;
    220 	op2.o_callback = &cb;
    221 
    222 	op2.o_tag = LDAP_REQ_ADD;
    223 	op2.o_protocol = LDAP_VERSION3;
    224 	op2.o_req_dn = e->e_name;
    225 	op2.o_req_ndn = e->e_nname;
    226 	op2.ora_e = e;
    227 	op2.o_bd = select_backend( &op2.o_req_ndn, 0 );
    228 	op2.o_dn = op2.o_bd->be_rootdn;
    229 	op2.o_ndn = op2.o_bd->be_rootndn;
    230 
    231 	op2.ors_limit = NULL;
    232 	rc = op2.o_bd->be_add( &op2, &rs2 );
    233 
    234 done:
    235 	if ( e ) entry_free( e );
    236 
    237 	return;
    238 }
    239