xref: /freebsd/crypto/krb5/src/kdc/kdc_audit.c (revision ee3960cba1068e12fb032a68c46d74841d9edab3)
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
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
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
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
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
178 kau_init_kdc_req(krb5_context context,
179                  krb5_kdc_req *request, const krb5_fulladdr *from,
180                  krb5_audit_state **state_out)
181 {
182     krb5_error_code ret = 0;
183     krb5_audit_state *state = NULL;
184 
185     state = k5calloc(1, sizeof(*state), &ret);
186     if (state == NULL)
187         return ret;
188 
189     state->request = request;
190     state->cl_addr = from->address;
191     state->cl_port = from->port;
192     state->stage = AUTHN_REQ_CL;
193     ret = krb5int_random_string(context, state->req_id,
194                                 sizeof(state->req_id));
195     if (ret) {
196         free(state);
197         return ret;
198     }
199     *state_out = state;
200 
201     return 0;
202 }
203 
204 /* Free resources allocated by kau_init_kdc_req() and kau_make_tkt_id()
205  * routines. */
206 void
207 kau_free_kdc_req(krb5_audit_state *state)
208 {
209     if (state == NULL)
210         return;
211     free(state->tkt_in_id);
212     free(state->tkt_out_id);
213     free(state->evid_tkt_id);
214     free(state);
215 }
216 
217 /* Call the KDC start/stop audit plugin entry points. */
218 
219 void
220 kau_kdc_stop(krb5_context context, const krb5_boolean ev_success)
221 {
222     audit_module_handle *hp, hdl;
223 
224     if (handles == NULL)
225         return;
226 
227     for (hp = handles; *hp != NULL; hp++) {
228         hdl = *hp;
229         if (hdl->vt.kdc_stop != NULL)
230             hdl->vt.kdc_stop(hdl->auctx, ev_success);
231     }
232 }
233 
234 void
235 kau_kdc_start(krb5_context context, const krb5_boolean ev_success)
236 {
237     audit_module_handle *hp, hdl;
238 
239     if (handles == NULL)
240         return;
241 
242     for (hp = handles; *hp != NULL; hp++) {
243         hdl = *hp;
244         if (hdl->vt.kdc_start != NULL)
245             hdl->vt.kdc_start(hdl->auctx, ev_success);
246     }
247 }
248 
249 /* Call the AS-REQ audit plugin entry point. */
250 void
251 kau_as_req(krb5_context context, const krb5_boolean ev_success,
252            krb5_audit_state *state)
253 {
254     audit_module_handle *hp, hdl;
255 
256     if (handles == NULL)
257         return;
258 
259     for (hp = handles; *hp != NULL; hp++) {
260         hdl = *hp;
261         if (hdl->vt.as_req != NULL)
262             hdl->vt.as_req(hdl->auctx, ev_success, state);
263     }
264 }
265 
266 /* Call the TGS-REQ audit plugin entry point. */
267 void
268 kau_tgs_req(krb5_context context, const krb5_boolean ev_success,
269             krb5_audit_state *state)
270 {
271     audit_module_handle *hp, hdl;
272 
273     if (handles == NULL)
274         return;
275 
276     for (hp = handles; *hp != NULL; hp++) {
277         hdl = *hp;
278         if (hdl->vt.tgs_req != NULL)
279             hdl->vt.tgs_req(hdl->auctx, ev_success, state);
280     }
281 }
282 
283 /* Call the S4U2Self audit plugin entry point. */
284 void
285 kau_s4u2self(krb5_context context, const krb5_boolean ev_success,
286              krb5_audit_state *state)
287 {
288     audit_module_handle *hp, hdl;
289 
290     if (handles == NULL)
291         return;
292 
293     for (hp = handles; *hp != NULL; hp++) {
294         hdl = *hp;
295         if (hdl->vt.tgs_s4u2self != NULL)
296             hdl->vt.tgs_s4u2self(hdl->auctx, ev_success, state);
297     }
298 }
299 
300 /* Call the S4U2Proxy audit plugin entry point. */
301 void
302 kau_s4u2proxy(krb5_context context,const krb5_boolean ev_success,
303               krb5_audit_state *state)
304 {
305     audit_module_handle *hp, hdl;
306 
307     if (handles == NULL)
308         return;
309 
310     for (hp = handles; *hp != NULL; hp++) {
311         hdl = *hp;
312         if (hdl->vt.tgs_s4u2proxy != NULL)
313             hdl->vt.tgs_s4u2proxy(hdl->auctx, ev_success, state);
314     }
315 }
316 
317 /* Call the U2U audit plugin entry point. */
318 void
319 kau_u2u(krb5_context context, const krb5_boolean ev_success,
320         krb5_audit_state *state)
321 {
322     audit_module_handle *hp, hdl;
323 
324     if (handles == NULL)
325         return;
326 
327     for (hp = handles; *hp != NULL; hp++) {
328         hdl = *hp;
329         if (hdl->vt.tgs_u2u != NULL)
330             hdl->vt.tgs_u2u(hdl->auctx, ev_success, state);
331     }
332 }
333