xref: /freebsd/crypto/krb5/src/kdc/kdc_audit.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* kdc_audit.c - Interface for KDC audit plugins. */
3 /*
4  * Copyright (C) 2013 by the Massachusetts Institute of Technology.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "k5-int.h"
34 #include "kdc_util.h"
35 #include "kdc_audit.h"
36 /* for krb5_klog_syslog */
37 #include <syslog.h>
38 #include "adm_proto.h"
39 
40 struct audit_module_handle_st {
41     struct krb5_audit_vtable_st vt;
42     krb5_audit_moddata auctx;
43 };
44 typedef struct audit_module_handle_st *audit_module_handle;
45 
46 static audit_module_handle *handles = NULL;
47 
48 static void
free_handles(audit_module_handle * list)49 free_handles(audit_module_handle *list)
50 {
51     audit_module_handle *hp, hdl;
52 
53     if (list == NULL)
54         return;
55 
56     for (hp = list; *hp != NULL; hp++) {
57         hdl = *hp;
58         if (hdl->vt.close != NULL)
59             hdl->vt.close(hdl->auctx);
60         free(hdl);
61     }
62     free(list);
63 }
64 
65 /*
66  * Load all available audit plugin modules and prepare for logging. The list of
67  * modules is stored as an array in handles. Use unload_audit_modules() to free
68  * resources allocated by this function.
69  */
70 krb5_error_code
load_audit_modules(krb5_context context)71 load_audit_modules(krb5_context context)
72 {
73     krb5_error_code ret = 0;
74     krb5_plugin_initvt_fn *modules = NULL, *mod;
75     struct krb5_audit_vtable_st vtable;
76     audit_module_handle *list = NULL, hdl = NULL;
77     krb5_audit_moddata auctx;
78     int count = 0;
79 
80     if (context == NULL || handles != NULL)
81         return EINVAL;
82 
83     /* Get audit plugin vtable. */
84     ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_AUDIT, &modules);
85     if (ret)
86         return ret;
87 
88     /* Allocate handle, initialize vtable. */
89     for (count = 0; modules[count] != NULL; count++);
90     list = k5calloc(count + 1, sizeof(*list), &ret);
91     if (list == NULL)
92         goto cleanup;
93     count = 0;
94     for (mod = modules; *mod != NULL; mod++) {
95         hdl = k5alloc(sizeof(*hdl), &ret);
96         if (hdl == NULL)
97             goto cleanup;
98         ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&hdl->vt);
99         if (ret) {
100             free(hdl);
101             hdl = NULL;
102             continue;
103         }
104 
105         vtable = hdl->vt;
106         if (vtable.open != NULL) {
107             ret = vtable.open(&auctx);
108             if (ret) {
109                 krb5_klog_syslog(LOG_ERR,
110                                  _("audit plugin %s failed to open. error=%i"),
111                                  vtable.name, ret);
112                 goto cleanup;
113             }
114             hdl->auctx = auctx;
115         }
116         list[count++] = hdl;
117         list[count] = NULL;
118         hdl = NULL;
119     }
120     list[count] = NULL;
121     handles = list;
122     list = NULL;
123     ret = 0;
124 
125 cleanup:
126     free(hdl);
127     k5_plugin_free_modules(context, modules);
128     free_handles(list);
129     return ret;
130 }
131 
132 /* Free resources allocated by load_audit_modules() function. */
133 void
unload_audit_modules(krb5_context context)134 unload_audit_modules(krb5_context context)
135 {
136     free_handles(handles);
137 }
138 
139 /*
140  * Write the output ticket ID into newly-allocated buffer.
141  * Returns 0 on success.
142  */
143 krb5_error_code
kau_make_tkt_id(krb5_context context,const krb5_ticket * ticket,char ** out)144 kau_make_tkt_id(krb5_context context,
145                 const krb5_ticket *ticket, char **out)
146 {
147     krb5_error_code ret = 0;
148     char *hash = NULL, *ptr;
149     uint8_t hashbytes[K5_SHA256_HASHLEN];
150     unsigned int i;
151 
152     *out = NULL;
153 
154     if (ticket == NULL)
155         return EINVAL;
156 
157     ret = k5_sha256(&ticket->enc_part.ciphertext, 1, hashbytes);
158     if (ret)
159         return ret;
160 
161     hash = k5alloc(sizeof(hashbytes) * 2 + 1, &ret);
162     if (hash == NULL)
163         return ret;
164 
165     for (i = 0, ptr = hash; i < sizeof(hashbytes); i++, ptr += 2)
166         snprintf(ptr, 3, "%02X", hashbytes[i]);
167     *ptr = '\0';
168     *out = hash;
169 
170     return 0;
171 }
172 
173 /*
174  * Create and initialize krb5_audit_state structure.
175  * Returns 0 on success.
176  */
177 krb5_error_code
kau_init_kdc_req(krb5_context context,krb5_kdc_req * request,const struct sockaddr * from,krb5_audit_state ** state_out)178 kau_init_kdc_req(krb5_context context,
179                  krb5_kdc_req *request, const struct sockaddr *from,
180                  krb5_audit_state **state_out)
181 {
182     krb5_error_code ret = 0;
183     krb5_audit_state *state = NULL;
184     krb5_address addr;
185     const krb5_address unknown_addr = { KV5M_ADDRESS, 0, 0, NULL };
186 
187     state = k5calloc(1, sizeof(*state), &ret);
188     if (state == NULL)
189         return ret;
190 
191     ret = k5_sockaddr_to_address(from, TRUE, &addr);
192     if (ret)
193         addr = unknown_addr;
194     ret = krb5_copy_addr(context, &addr, &state->cl_addr);
195     if (ret)
196         goto cleanup;
197     state->request = request;
198     state->cl_port = sa_getport(from);
199     state->stage = AUTHN_REQ_CL;
200     ret = krb5int_random_string(context, state->req_id,
201                                 sizeof(state->req_id));
202     if (ret)
203         goto cleanup;
204     *state_out = state;
205     state = NULL;
206 
207 cleanup:
208     kau_free_kdc_req(state);
209     return ret;
210 }
211 
212 /* Free resources allocated by kau_init_kdc_req() and kau_make_tkt_id()
213  * routines. */
214 void
kau_free_kdc_req(krb5_audit_state * state)215 kau_free_kdc_req(krb5_audit_state *state)
216 {
217     if (state == NULL)
218         return;
219     free(state->tkt_in_id);
220     free(state->tkt_out_id);
221     free(state->evid_tkt_id);
222     krb5_free_address(NULL, state->cl_addr);
223     free(state);
224 }
225 
226 /* Call the KDC start/stop audit plugin entry points. */
227 
228 void
kau_kdc_stop(krb5_context context,const krb5_boolean ev_success)229 kau_kdc_stop(krb5_context context, const krb5_boolean ev_success)
230 {
231     audit_module_handle *hp, hdl;
232 
233     if (handles == NULL)
234         return;
235 
236     for (hp = handles; *hp != NULL; hp++) {
237         hdl = *hp;
238         if (hdl->vt.kdc_stop != NULL)
239             hdl->vt.kdc_stop(hdl->auctx, ev_success);
240     }
241 }
242 
243 void
kau_kdc_start(krb5_context context,const krb5_boolean ev_success)244 kau_kdc_start(krb5_context context, const krb5_boolean ev_success)
245 {
246     audit_module_handle *hp, hdl;
247 
248     if (handles == NULL)
249         return;
250 
251     for (hp = handles; *hp != NULL; hp++) {
252         hdl = *hp;
253         if (hdl->vt.kdc_start != NULL)
254             hdl->vt.kdc_start(hdl->auctx, ev_success);
255     }
256 }
257 
258 /* Call the AS-REQ audit plugin entry point. */
259 void
kau_as_req(krb5_context context,const krb5_boolean ev_success,krb5_audit_state * state)260 kau_as_req(krb5_context context, const krb5_boolean ev_success,
261            krb5_audit_state *state)
262 {
263     audit_module_handle *hp, hdl;
264 
265     if (handles == NULL)
266         return;
267 
268     for (hp = handles; *hp != NULL; hp++) {
269         hdl = *hp;
270         if (hdl->vt.as_req != NULL)
271             hdl->vt.as_req(hdl->auctx, ev_success, state);
272     }
273 }
274 
275 /* Call the TGS-REQ audit plugin entry point. */
276 void
kau_tgs_req(krb5_context context,const krb5_boolean ev_success,krb5_audit_state * state)277 kau_tgs_req(krb5_context context, const krb5_boolean ev_success,
278             krb5_audit_state *state)
279 {
280     audit_module_handle *hp, hdl;
281 
282     if (handles == NULL)
283         return;
284 
285     for (hp = handles; *hp != NULL; hp++) {
286         hdl = *hp;
287         if (hdl->vt.tgs_req != NULL)
288             hdl->vt.tgs_req(hdl->auctx, ev_success, state);
289     }
290 }
291 
292 /* Call the S4U2Self audit plugin entry point. */
293 void
kau_s4u2self(krb5_context context,const krb5_boolean ev_success,krb5_audit_state * state)294 kau_s4u2self(krb5_context context, const krb5_boolean ev_success,
295              krb5_audit_state *state)
296 {
297     audit_module_handle *hp, hdl;
298 
299     if (handles == NULL)
300         return;
301 
302     for (hp = handles; *hp != NULL; hp++) {
303         hdl = *hp;
304         if (hdl->vt.tgs_s4u2self != NULL)
305             hdl->vt.tgs_s4u2self(hdl->auctx, ev_success, state);
306     }
307 }
308 
309 /* Call the S4U2Proxy audit plugin entry point. */
310 void
kau_s4u2proxy(krb5_context context,const krb5_boolean ev_success,krb5_audit_state * state)311 kau_s4u2proxy(krb5_context context,const krb5_boolean ev_success,
312               krb5_audit_state *state)
313 {
314     audit_module_handle *hp, hdl;
315 
316     if (handles == NULL)
317         return;
318 
319     for (hp = handles; *hp != NULL; hp++) {
320         hdl = *hp;
321         if (hdl->vt.tgs_s4u2proxy != NULL)
322             hdl->vt.tgs_s4u2proxy(hdl->auctx, ev_success, state);
323     }
324 }
325 
326 /* Call the U2U audit plugin entry point. */
327 void
kau_u2u(krb5_context context,const krb5_boolean ev_success,krb5_audit_state * state)328 kau_u2u(krb5_context context, const krb5_boolean ev_success,
329         krb5_audit_state *state)
330 {
331     audit_module_handle *hp, hdl;
332 
333     if (handles == NULL)
334         return;
335 
336     for (hp = handles; *hp != NULL; hp++) {
337         hdl = *hp;
338         if (hdl->vt.tgs_u2u != NULL)
339             hdl->vt.tgs_u2u(hdl->auctx, ev_success, state);
340     }
341 }
342