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