1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/audit/kdc_j_encode.c - Utilities to json encode KDC audit stuff */
4 * Copyright (C) 2013 by the Massachusetts Institute of Technology.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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
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.
35 #include "kdc_j_encode.h"
37 #include <krb5/audit_plugin.h>
40 static krb5_error_code
41 string_to_value(const char *in, k5_json_object obj, const char *key);
42 static krb5_error_code
43 princ_to_value(krb5_principal princ, k5_json_object obj, const char *key);
44 static krb5_error_code
45 data_to_value(krb5_data *data, k5_json_object obj, const char *key);
46 static krb5_error_code
47 int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key);
48 static krb5_error_code
49 bool_to_value(krb5_boolean b, k5_json_object obj, const char *key);
50 static krb5_error_code
51 addr_to_obj(krb5_address *a, k5_json_object obj);
52 static krb5_error_code
53 eventinfo_to_value(k5_json_object obj, const char *name,
54 const int stage, const krb5_boolean ev_success);
55 static krb5_error_code
56 addr_to_value(const krb5_address *address, k5_json_object obj,
58 static krb5_error_code
59 req_to_value(krb5_kdc_req *req, const krb5_boolean ev_success,
61 static krb5_error_code
62 rep_to_value(krb5_kdc_rep *rep, const krb5_boolean ev_success,
64 static krb5_error_code
65 tkt_to_value(krb5_ticket *tkt, k5_json_object obj, const char *key);
66 static char *map_patype(krb5_preauthtype pa_type);
68 #define NULL_STATE "state is NULL"
70 #define T_NOT_RENEWED 2
72 #define T_NOT_VALIDATED 2
74 /* KDC server STOP. Returns 0 on success. */
76 kau_j_kdc_stop(const krb5_boolean ev_success, char **jout)
78 krb5_error_code ret = 0;
79 k5_json_object obj = NULL;
84 if (k5_json_object_create(&obj))
87 /* Audit event_ID and ev_success. */
88 ret = string_to_value("KDC_STOP", obj, AU_EVENT_NAME);
90 ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
92 ret = k5_json_encode(obj, jout);
98 /* KDC server START. Returns 0 on success. */
100 kau_j_kdc_start(const krb5_boolean ev_success, char **jout)
102 krb5_error_code ret = 0;
103 k5_json_object obj = NULL;
108 if (k5_json_object_create(&obj))
111 /* Audit event_ID and ev_success. */
112 ret = string_to_value("KDC_START", obj, AU_EVENT_NAME);
114 ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
116 ret = k5_json_encode(obj, jout);
117 k5_json_release(obj);
122 /* AS-REQ. Returns 0 on success. */
124 kau_j_as_req(const krb5_boolean ev_success, krb5_audit_state *state,
127 krb5_error_code ret = 0;
128 k5_json_object obj = NULL;
138 if (k5_json_object_create(&obj))
140 /* Audit event_ID and ev_success. */
141 ret = eventinfo_to_value(obj, "AS_REQ", state->stage, ev_success);
145 ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
149 ret = string_to_value(state->req_id, obj, AU_REQ_ID);
152 /* Client's port and address. */
153 ret = int32_to_value(state->cl_port, obj, AU_FROMPORT);
156 ret = addr_to_value(state->cl_addr, obj, AU_FROMADDR);
160 ret = string_to_value(state->status, obj, AU_KDC_STATUS);
163 /* non-local client's referral realm. */
164 ret = data_to_value(state->cl_realm, obj, AU_CREF_REALM);
168 ret = req_to_value(state->request, ev_success, obj);
171 /* Reply/ticket info. */
172 ret = rep_to_value(state->reply, ev_success, obj);
175 ret = k5_json_encode(obj, jout);
178 k5_json_release(obj);
182 /* TGS-REQ. Returns 0 on success. */
184 kau_j_tgs_req(const krb5_boolean ev_success, krb5_audit_state *state,
187 krb5_error_code ret = 0;
188 k5_json_object obj = NULL;
189 krb5_kdc_req *req = state->request;
190 int tkt_validated = 0, tkt_renewed = 0;
200 if (k5_json_object_create(&obj))
203 /* Audit Event ID and ev_success. */
204 ret = eventinfo_to_value(obj, "TGS_REQ", state->stage, ev_success);
207 /* Primary and derived ticket IDs. */
208 ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
211 ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
215 ret = string_to_value(state->req_id, obj, AU_REQ_ID);
218 /* client’s address and port. */
219 ret = int32_to_value(state->cl_port, obj, AU_FROMPORT);
222 ret = addr_to_value(state->cl_addr, obj, AU_FROMADDR);
225 /* Ticket was renewed, validated. */
226 if ((ev_success == TRUE) && (req != NULL)) {
227 tkt_renewed = (req->kdc_options & KDC_OPT_RENEW) ?
228 T_RENEWED : T_NOT_RENEWED;
229 tkt_validated = (req->kdc_options & KDC_OPT_VALIDATE) ?
230 T_VALIDATED : T_NOT_VALIDATED;
232 ret = int32_to_value(tkt_renewed, obj, AU_TKT_RENEWED);
235 ret = int32_to_value(tkt_validated, obj, AU_TKT_VALIDATED);
238 /* KDC status msg, including "ISSUE". */
239 ret = string_to_value(state->status, obj, AU_KDC_STATUS);
243 ret = req_to_value(req, ev_success, obj);
247 ret = rep_to_value(state->reply, ev_success, obj);
250 ret = k5_json_encode(obj, jout);
253 k5_json_release(obj);
257 /* S4U2Self protocol extension. Returns 0 on success. */
259 kau_j_tgs_s4u2self(const krb5_boolean ev_success, krb5_audit_state *state,
262 krb5_error_code ret = 0;
263 k5_json_object obj = NULL;
273 if (k5_json_object_create(&obj))
276 /* Audit Event ID and ev_success. */
277 ret = eventinfo_to_value(obj, "S4U2SELF", state->stage, ev_success);
280 /* Front-end server's TGT ticket ID. */
281 ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
284 /* service "to self" ticket or referral TGT ticket ID. */
285 ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
289 ret = string_to_value(state->req_id, obj, AU_REQ_ID);
292 if (ev_success == FALSE) {
293 /* KDC status msg. */
294 ret = string_to_value(state->status, obj, AU_KDC_STATUS);
297 /* Local policy or S4U protocol constraints. */
298 ret = int32_to_value(state->violation, obj, AU_VIOLATION);
302 /* Impersonated user. */
303 ret = princ_to_value(state->s4u2self_user, obj, AU_REQ_S4U2S_USER);
307 ret = k5_json_encode(obj, jout);
310 k5_json_release(obj);
314 /* S4U2Proxy protocol extension. Returns 0 on success. */
316 kau_j_tgs_s4u2proxy(const krb5_boolean ev_success, krb5_audit_state *state,
319 krb5_error_code ret = 0;
320 k5_json_object obj = NULL;
321 krb5_kdc_req *req = state->request;
331 if (k5_json_object_create(&obj))
334 /* Audit Event ID and ev_success. */
335 ret = eventinfo_to_value(obj, "S4U2PROXY", state->stage, ev_success);
338 /* Front-end server's TGT ticket ID. */
339 ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
342 /* Resource service or referral TGT ticket ID. */
343 ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
346 /* User's evidence ticket ID. */
347 ret = string_to_value(state->evid_tkt_id, obj, AU_EVIDENCE_TKT_ID);
351 ret = string_to_value(state->req_id, obj, AU_REQ_ID);
355 if (ev_success == FALSE) {
356 /* KDC status msg. */
357 ret = string_to_value(state->status, obj, AU_KDC_STATUS);
360 /* Local policy or S4U protocol constraints. */
361 ret = int32_to_value(state->violation, obj, AU_VIOLATION);
365 /* Delegated user. */
367 ret = princ_to_value(req->second_ticket[0]->enc_part2->client,
368 obj, AU_REQ_S4U2P_USER);
372 ret = k5_json_encode(obj, jout);
375 k5_json_release(obj);
379 /* U2U. Returns 0 on success. */
381 kau_j_tgs_u2u(const krb5_boolean ev_success, krb5_audit_state *state,
384 krb5_error_code ret = 0;
385 k5_json_object obj = NULL;
386 krb5_kdc_req *req = state->request;
396 if (k5_json_object_create(&obj))
398 /* Audit Event ID and ev_success. */
399 ret = eventinfo_to_value(obj, "U2U", state->stage, ev_success);
402 /* Front-end server's TGT ticket ID. */
403 ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
406 /* Service ticket ID. */
407 ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
411 ret = string_to_value(state->req_id, obj, AU_REQ_ID);
415 if (ev_success == FALSE) {
416 /* KDC status msg. */
417 ret = string_to_value(state->status, obj, AU_KDC_STATUS);
421 /* Client in the second ticket. */
423 ret = princ_to_value(req->second_ticket[0]->enc_part2->client,
424 obj, AU_REQ_U2U_USER);
428 /* Enctype of a session key of the second ticket. */
429 ret = int32_to_value(req->second_ticket[0]->enc_part2->session->enctype,
434 ret = k5_json_encode(obj, jout);
437 k5_json_release(obj);
441 /* Low level utilities */
443 /* Converts string into a property of a JSON object. Returns 0 on success.*/
444 static krb5_error_code
445 string_to_value(const char *in, k5_json_object obj, const char *key)
447 krb5_error_code ret = 0;
448 k5_json_string str = NULL;
453 ret = k5_json_string_create(in, &str);
456 ret = k5_json_object_set(obj, key, str);
457 k5_json_release(str);
463 * Converts a krb5_data struct into a property of a JSON object.
464 * (Borrowed from preauth_otp.c)
465 * Returns 0 on success.
467 static krb5_error_code
468 data_to_value(krb5_data *data, k5_json_object obj, const char *key)
470 krb5_error_code ret = 0;
471 k5_json_string str = NULL;
473 if (data == NULL || data->data == NULL || data->length < 1)
476 ret = k5_json_string_create_len(data->data, data->length, &str);
479 ret = k5_json_object_set(obj, key, str);
480 k5_json_release(str);
486 * Converts krb5_int32 into a property of a JSON object.
487 * Returns 0 on success.
489 static krb5_error_code
490 int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key)
492 krb5_error_code ret = 0;
493 k5_json_number num = NULL;
495 ret = k5_json_number_create(int32, &num);
498 ret = k5_json_object_set(obj, key, num);
499 k5_json_release(num);
505 * Converts krb5_boolean into a property of a JSON object.
506 * Returns 0 on success.
508 static krb5_error_code
509 bool_to_value(krb5_boolean in, k5_json_object obj, const char *key)
511 krb5_error_code ret = 0;
514 ret = k5_json_bool_create(in, &b);
518 ret = k5_json_object_set(obj, key, b);
524 /* Wrapper-level utilities */
526 /* Wrapper for stage and event_status tags. Returns 0 on success. */
527 static krb5_error_code
528 eventinfo_to_value(k5_json_object obj, const char *name,
529 const int stage, const krb5_boolean ev_success)
531 krb5_error_code ret = 0;
533 ret = string_to_value(name, obj, AU_EVENT_NAME);
536 ret = int32_to_value(stage, obj, AU_STAGE);
538 ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
544 * Converts krb5_principal into a property of a JSON object.
545 * Returns 0 on success.
547 static krb5_error_code
548 princ_to_value(krb5_principal princ, k5_json_object obj, const char *key)
550 krb5_error_code ret = 0;
551 k5_json_object tmp = NULL;
552 k5_json_array arr = NULL;
553 k5_json_string str = NULL;
556 if (princ == NULL || princ->data == NULL)
560 if (k5_json_object_create(&tmp))
563 ret = k5_json_array_create(&arr);
566 for (i = 0; i < princ->length; i++) {
567 ret = k5_json_string_create_len((&princ->data[i])->data,
568 (&princ->data[i])->length, &str);
571 ret = k5_json_array_add(arr, str);
572 k5_json_release(str);
576 ret = k5_json_object_set(tmp, AU_COMPONENTS, arr);
579 ret = data_to_value(&princ->realm, tmp, AU_REALM);
582 ret = int32_to_value(princ->length, tmp, AU_LENGTH);
585 ret = int32_to_value(princ->type, tmp, AU_TYPE);
589 ret = k5_json_object_set(obj, key, tmp);
592 k5_json_release(tmp);
593 k5_json_release(arr);
598 * Helper for JSON encoding of krb5_address.
599 * Returns 0 on success.
601 static krb5_error_code
602 addr_to_obj(krb5_address *a, k5_json_object obj)
604 krb5_error_code ret = 0;
605 k5_json_number num = NULL;
606 k5_json_array arr = NULL;
609 if (a == NULL || a->contents == NULL || a->length <= 0)
612 ret = int32_to_value(a->addrtype, obj, AU_TYPE);
615 ret = int32_to_value(a->length, obj, AU_LENGTH);
619 if (a->addrtype == ADDRTYPE_INET || a->addrtype == ADDRTYPE_INET6) {
620 ret = k5_json_array_create(&arr);
623 for (i = 0; i < (int)a->length; i++) {
624 ret = k5_json_number_create(a->contents[i], &num);
627 ret = k5_json_array_add(arr, num);
628 k5_json_release(num);
632 ret = k5_json_object_set(obj, AU_IP, arr);
638 k5_json_release(arr);
643 * Converts krb5_fulladdr into a property of a JSON object.
644 * Returns 0 on success.
646 static krb5_error_code
647 addr_to_value(const krb5_address *address, k5_json_object obj, const char *key)
649 krb5_error_code ret = 0;
650 k5_json_object addr_obj = NULL;
655 ret = k5_json_object_create(&addr_obj);
658 ret = addr_to_obj((krb5_address *)address, addr_obj);
660 ret = k5_json_object_set(obj, key, addr_obj);
661 k5_json_release(addr_obj);
667 * Helper for JSON encoding of krb5_kdc_req.
668 * Returns 0 on success.
670 static krb5_error_code
671 req_to_value(krb5_kdc_req *req, const krb5_boolean ev_success,
674 krb5_error_code ret = 0;
675 k5_json_number num = NULL;
676 k5_json_string str = NULL;
677 k5_json_object tmpa = NULL;
678 k5_json_array arr = NULL, arra = NULL, arrpa = NULL;
679 krb5_pa_data **padata;
685 ret = princ_to_value(req->client, obj, AU_REQ_CLIENT);
688 ret = princ_to_value(req->server, obj, AU_REQ_SERVER);
692 ret = int32_to_value(req->kdc_options, obj, AU_REQ_KDC_OPTIONS);
695 ret = int32_to_value(req->from, obj, AU_REQ_TKT_START);
698 ret = int32_to_value(req->till, obj, AU_REQ_TKT_END);
701 ret = int32_to_value(req->rtime, obj, AU_REQ_TKT_RENEW_TILL);
704 /* Available/requested enctypes. */
705 ret = k5_json_array_create(&arr);
708 for (i = 0; (i < req->nktypes); i++) {
709 if (req->ktype[i] > 0) {
710 ret = k5_json_number_create(req->ktype[i], &num);
713 ret = k5_json_array_add(arr, num);
714 k5_json_release(num);
719 ret = k5_json_object_set(obj, AU_REQ_AVAIL_ETYPES, arr);
722 /* Pre-auth types. */
723 if (ev_success == TRUE && req->padata) {
724 ret = k5_json_array_create(&arrpa);
727 for (padata = req->padata; *padata; padata++) {
728 if (strlen(map_patype((*padata)->pa_type)) > 1) {
729 ret = k5_json_string_create(map_patype((*padata)->pa_type),
733 ret = k5_json_array_add(arrpa, str);
734 k5_json_release(str);
739 ret = k5_json_object_set(obj, AU_REQ_PA_TYPE, arrpa);
741 /* List of requested addresses. */
742 if (req->addresses) {
743 ret = k5_json_array_create(&arra);
746 for (i = 0; req->addresses[i] != NULL; i++) {
747 ret = k5_json_object_create(&tmpa);
750 ret = addr_to_obj(req->addresses[i], tmpa);
753 ret = k5_json_array_add(arra, tmpa);
754 k5_json_release(tmpa);
758 ret = k5_json_object_set(obj, AU_REQ_ADDRESSES, arra);
763 k5_json_release(arr);
764 k5_json_release(arra);
765 k5_json_release(arrpa);
770 * Helper for JSON encoding of krb5_kdc_rep.
771 * Returns 0 on success.
773 static krb5_error_code
774 rep_to_value(krb5_kdc_rep *rep, const krb5_boolean ev_success,
777 krb5_error_code ret = 0;
778 krb5_pa_data **padata;
779 k5_json_array arrpa = NULL;
780 k5_json_string str = NULL;
785 if (ev_success == TRUE) {
786 ret = tkt_to_value(rep->ticket, obj, AU_REP_TICKET);
787 /* Enctype of the reply-encrypting key. */
788 ret = int32_to_value(rep->enc_part.enctype, obj, AU_REP_ETYPE);
794 ret = k5_json_array_create(&arrpa);
797 for (padata = rep->padata; *padata; padata++) {
798 if (strlen(map_patype((*padata)->pa_type)) > 1) {
799 ret = k5_json_string_create(map_patype((*padata)->pa_type),
803 ret = k5_json_array_add(arrpa, str);
804 k5_json_release(str);
810 ret = k5_json_object_set(obj, AU_REP_PA_TYPE, arrpa);
813 k5_json_release(arrpa);
818 * Converts krb5_ticket into a property of a JSON object.
819 * Returns 0 on success.
821 static krb5_error_code
822 tkt_to_value(krb5_ticket *tkt, k5_json_object obj,
825 krb5_error_code ret = 0;
826 k5_json_object tmp = NULL;
827 krb5_enc_tkt_part *part2 = NULL;
833 if (k5_json_object_create(&tmp))
837 * CNAME - potentially redundant data...
838 * ...but it is part of the ticket. So, record it as such.
840 ret = princ_to_value(tkt->server, tmp, AU_CNAME);
843 ret = princ_to_value(tkt->server, tmp, AU_SNAME);
846 /* Enctype of a long-term key of service. */
847 if (tkt->enc_part.enctype)
848 ret = int32_to_value(tkt->enc_part.enctype, tmp, AU_SRV_ETYPE);
852 part2 = tkt->enc_part2;
854 ret = princ_to_value(part2->client, tmp, AU_CNAME);
857 ret = int32_to_value(part2->flags, tmp, AU_FLAGS);
860 /* Chosen by KDC session key enctype (short-term key). */
861 ret = int32_to_value(part2->session->enctype, tmp, AU_SESS_ETYPE);
864 ret = int32_to_value(part2->times.starttime, tmp, AU_START);
867 ret = int32_to_value(part2->times.endtime, tmp, AU_END);
870 ret = int32_to_value(part2->times.renew_till, tmp, AU_RENEW_TILL);
873 ret = int32_to_value(part2->times.authtime, tmp, AU_AUTHTIME);
876 if (part2->transited.tr_contents.length > 0) {
877 ret = data_to_value(&part2->transited.tr_contents,
878 tmp, AU_TR_CONTENTS);
882 } /* part2 != NULL */
885 ret = k5_json_object_set(obj, key, tmp);
888 k5_json_release(tmp);
892 /* Map preauth numeric type to the naming string. */
897 struct _patype_str patype_str[] = {
898 {KRB5_PADATA_ENC_TIMESTAMP, "ENC_TIMESTAMP"},
899 {KRB5_PADATA_PW_SALT, "PW_SALT"},
900 {KRB5_PADATA_ENC_UNIX_TIME, "ENC_UNIX_TIME"},
901 {KRB5_PADATA_SAM_CHALLENGE, "SAM_CHALLENGE"},
902 {KRB5_PADATA_SAM_RESPONSE, "SAM_RESPONSE"},
903 {KRB5_PADATA_PK_AS_REQ_OLD, "PK_AS_REQ_OLD"},
904 {KRB5_PADATA_PK_AS_REP_OLD, "PK_AS_REP_OLD"},
905 {KRB5_PADATA_PK_AS_REQ, "PK_AS_REQ"},
906 {KRB5_PADATA_PK_AS_REP, "PK_AS_REP"},
907 {KRB5_PADATA_ETYPE_INFO2, "ETYPE_INFO2"},
908 {KRB5_PADATA_SAM_CHALLENGE_2, "SAM_CHALLENGE_2"},
909 {KRB5_PADATA_SAM_RESPONSE_2, "SAM_RESPONSE_2"},
910 {KRB5_PADATA_PAC_REQUEST, "PAC_REQUEST"},
911 {KRB5_PADATA_FOR_USER, "FOR_USER"},
912 {KRB5_PADATA_S4U_X509_USER, "S4U_X509_USER"},
913 {KRB5_PADATA_ENCRYPTED_CHALLENGE, "ENCRYPTED_CHALLENGE"},
914 {KRB5_PADATA_OTP_CHALLENGE, "OTP_CHALLENGE"},
915 {KRB5_PADATA_OTP_REQUEST, "OTP_REQUEST"},
916 {KRB5_PADATA_OTP_PIN_CHANGE, "OTP_PIN_CHANGE"}
921 map_patype(krb5_preauthtype pa_type)
924 int n = sizeof(patype_str)/sizeof(patype_str[0]);
926 for (i = 0; i < n; i++) {
927 if (pa_type == patype_str[i].id)
928 return patype_str[i].name;