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, ×tamp );
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, ×tamp, 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