xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/rbac/rbacaudit.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
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
rbac_audit_fake_cb(Operation * op,SlapReply * rs)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
rbac_audit(Operation * op,audit_op_t rbac_op,rbac_session_t * sessp,rbac_req_t * reqp,int result,char * msg)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