#include <k5-int.h>
#include <k5-json.h>
#include "kdc_j_encode.h"
#include "j_dict.h"
#include <krb5/audit_plugin.h>
#include <syslog.h>
static krb5_error_code
string_to_value(const char *in, k5_json_object obj, const char *key);
static krb5_error_code
princ_to_value(krb5_principal princ, k5_json_object obj, const char *key);
static krb5_error_code
data_to_value(krb5_data *data, k5_json_object obj, const char *key);
static krb5_error_code
int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key);
static krb5_error_code
bool_to_value(krb5_boolean b, k5_json_object obj, const char *key);
static krb5_error_code
addr_to_obj(krb5_address *a, k5_json_object obj);
static krb5_error_code
eventinfo_to_value(k5_json_object obj, const char *name,
const int stage, const krb5_boolean ev_success);
static krb5_error_code
addr_to_value(const krb5_address *address, k5_json_object obj,
const char *key);
static krb5_error_code
req_to_value(krb5_kdc_req *req, const krb5_boolean ev_success,
k5_json_object obj);
static krb5_error_code
rep_to_value(krb5_kdc_rep *rep, const krb5_boolean ev_success,
k5_json_object obj);
static krb5_error_code
tkt_to_value(krb5_ticket *tkt, k5_json_object obj, const char *key);
static char *map_patype(krb5_preauthtype pa_type);
#define NULL_STATE "state is NULL"
#define T_RENEWED 1
#define T_NOT_RENEWED 2
#define T_VALIDATED 1
#define T_NOT_VALIDATED 2
krb5_error_code
kau_j_kdc_stop(const krb5_boolean ev_success, char **jout)
{
krb5_error_code ret = 0;
k5_json_object obj = NULL;
*jout = NULL;
if (k5_json_object_create(&obj))
return ENOMEM;
ret = string_to_value("KDC_STOP", obj, AU_EVENT_NAME);
if (!ret)
ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
if (!ret)
ret = k5_json_encode(obj, jout);
k5_json_release(obj);
return ret;
}
krb5_error_code
kau_j_kdc_start(const krb5_boolean ev_success, char **jout)
{
krb5_error_code ret = 0;
k5_json_object obj = NULL;
*jout = NULL;
if (k5_json_object_create(&obj))
return ENOMEM;
ret = string_to_value("KDC_START", obj, AU_EVENT_NAME);
if (!ret)
ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
if (!ret)
ret = k5_json_encode(obj, jout);
k5_json_release(obj);
return ret;
}
krb5_error_code
kau_j_as_req(const krb5_boolean ev_success, krb5_audit_state *state,
char **jout)
{
krb5_error_code ret = 0;
k5_json_object obj = NULL;
*jout = NULL;
if (!state) {
*jout = NULL_STATE;
return 0;
}
if (k5_json_object_create(&obj))
return ENOMEM;
ret = eventinfo_to_value(obj, "AS_REQ", state->stage, ev_success);
if (ret)
goto error;
ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
if (ret)
goto error;
ret = string_to_value(state->req_id, obj, AU_REQ_ID);
if (ret)
goto error;
ret = int32_to_value(state->cl_port, obj, AU_FROMPORT);
if (ret)
goto error;
ret = addr_to_value(state->cl_addr, obj, AU_FROMADDR);
if (ret)
goto error;
ret = string_to_value(state->status, obj, AU_KDC_STATUS);
if (ret)
goto error;
ret = data_to_value(state->cl_realm, obj, AU_CREF_REALM);
if (ret)
goto error;
ret = req_to_value(state->request, ev_success, obj);
if (ret == ENOMEM)
goto error;
ret = rep_to_value(state->reply, ev_success, obj);
if (ret == ENOMEM)
goto error;
ret = k5_json_encode(obj, jout);
error:
k5_json_release(obj);
return ret;
}
krb5_error_code
kau_j_tgs_req(const krb5_boolean ev_success, krb5_audit_state *state,
char **jout)
{
krb5_error_code ret = 0;
k5_json_object obj = NULL;
krb5_kdc_req *req = state->request;
int tkt_validated = 0, tkt_renewed = 0;
*jout = NULL;
if (!state) {
*jout = NULL_STATE;
return 0;
}
if (k5_json_object_create(&obj))
return ENOMEM;
ret = eventinfo_to_value(obj, "TGS_REQ", state->stage, ev_success);
if (ret)
goto error;
ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
if (ret)
goto error;
ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
if (ret)
goto error;
ret = string_to_value(state->req_id, obj, AU_REQ_ID);
if (ret)
goto error;
ret = int32_to_value(state->cl_port, obj, AU_FROMPORT);
if (ret)
goto error;
ret = addr_to_value(state->cl_addr, obj, AU_FROMADDR);
if (ret)
goto error;
if ((ev_success == TRUE) && (req != NULL)) {
tkt_renewed = (req->kdc_options & KDC_OPT_RENEW) ?
T_RENEWED : T_NOT_RENEWED;
tkt_validated = (req->kdc_options & KDC_OPT_VALIDATE) ?
T_VALIDATED : T_NOT_VALIDATED;
}
ret = int32_to_value(tkt_renewed, obj, AU_TKT_RENEWED);
if (ret)
goto error;
ret = int32_to_value(tkt_validated, obj, AU_TKT_VALIDATED);
if (ret)
goto error;
ret = string_to_value(state->status, obj, AU_KDC_STATUS);
if (ret)
goto error;
ret = req_to_value(req, ev_success, obj);
if (ret == ENOMEM)
goto error;
ret = rep_to_value(state->reply, ev_success, obj);
if (ret == ENOMEM)
goto error;
ret = k5_json_encode(obj, jout);
error:
k5_json_release(obj);
return ret;
}
krb5_error_code
kau_j_tgs_s4u2self(const krb5_boolean ev_success, krb5_audit_state *state,
char **jout)
{
krb5_error_code ret = 0;
k5_json_object obj = NULL;
*jout = NULL;
if (!state) {
*jout = NULL_STATE;
return 0;
}
if (k5_json_object_create(&obj))
return ENOMEM;
ret = eventinfo_to_value(obj, "S4U2SELF", state->stage, ev_success);
if (ret)
goto error;
ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
if (ret)
goto error;
ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
if (ret)
goto error;
ret = string_to_value(state->req_id, obj, AU_REQ_ID);
if (ret)
goto error;
if (ev_success == FALSE) {
ret = string_to_value(state->status, obj, AU_KDC_STATUS);
if (ret)
goto error;
ret = int32_to_value(state->violation, obj, AU_VIOLATION);
if (ret)
goto error;
}
ret = princ_to_value(state->s4u2self_user, obj, AU_REQ_S4U2S_USER);
if (ret)
goto error;
ret = k5_json_encode(obj, jout);
error:
k5_json_release(obj);
return ret;
}
krb5_error_code
kau_j_tgs_s4u2proxy(const krb5_boolean ev_success, krb5_audit_state *state,
char **jout)
{
krb5_error_code ret = 0;
k5_json_object obj = NULL;
krb5_kdc_req *req = state->request;
*jout = NULL;
if (!state) {
*jout = NULL_STATE;
return 0;
}
if (k5_json_object_create(&obj))
return ENOMEM;
ret = eventinfo_to_value(obj, "S4U2PROXY", state->stage, ev_success);
if (ret)
goto error;
ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
if (ret)
goto error;
ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
if (ret)
goto error;
ret = string_to_value(state->evid_tkt_id, obj, AU_EVIDENCE_TKT_ID);
if (ret)
goto error;
ret = string_to_value(state->req_id, obj, AU_REQ_ID);
if (ret)
goto error;
if (ev_success == FALSE) {
ret = string_to_value(state->status, obj, AU_KDC_STATUS);
if (ret)
goto error;
ret = int32_to_value(state->violation, obj, AU_VIOLATION);
if (ret)
goto error;
}
if (req != NULL) {
ret = princ_to_value(req->second_ticket[0]->enc_part2->client,
obj, AU_REQ_S4U2P_USER);
if (ret)
goto error;
}
ret = k5_json_encode(obj, jout);
error:
k5_json_release(obj);
return ret;
}
krb5_error_code
kau_j_tgs_u2u(const krb5_boolean ev_success, krb5_audit_state *state,
char **jout)
{
krb5_error_code ret = 0;
k5_json_object obj = NULL;
krb5_kdc_req *req = state->request;
if (!state) {
*jout = NULL_STATE;
return 0;
}
*jout = NULL;
if (k5_json_object_create(&obj))
return ENOMEM;
ret = eventinfo_to_value(obj, "U2U", state->stage, ev_success);
if (ret)
goto error;
ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
if (ret)
goto error;
ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
if (ret)
goto error;
ret = string_to_value(state->req_id, obj, AU_REQ_ID);
if (ret)
goto error;
if (ev_success == FALSE) {
ret = string_to_value(state->status, obj, AU_KDC_STATUS);
if (ret)
goto error;
}
ret = princ_to_value(req->second_ticket[0]->enc_part2->client,
obj, AU_REQ_U2U_USER);
if (ret)
goto error;
ret = int32_to_value(req->second_ticket[0]->enc_part2->session->enctype,
obj, AU_SRV_ETYPE);
if (ret)
goto error;
ret = k5_json_encode(obj, jout);
error:
k5_json_release(obj);
return ret;
}
static krb5_error_code
string_to_value(const char *in, k5_json_object obj, const char *key)
{
krb5_error_code ret = 0;
k5_json_string str = NULL;
if (in == NULL)
return 0;
ret = k5_json_string_create(in, &str);
if (ret)
return ret;
ret = k5_json_object_set(obj, key, str);
k5_json_release(str);
return ret;
}
static krb5_error_code
data_to_value(krb5_data *data, k5_json_object obj, const char *key)
{
krb5_error_code ret = 0;
k5_json_string str = NULL;
if (data == NULL || data->data == NULL || data->length < 1)
return 0;
ret = k5_json_string_create_len(data->data, data->length, &str);
if (ret)
return ret;
ret = k5_json_object_set(obj, key, str);
k5_json_release(str);
return ret;
}
static krb5_error_code
int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key)
{
krb5_error_code ret = 0;
k5_json_number num = NULL;
ret = k5_json_number_create(int32, &num);
if (ret)
return ENOMEM;
ret = k5_json_object_set(obj, key, num);
k5_json_release(num);
return ret;
}
static krb5_error_code
bool_to_value(krb5_boolean in, k5_json_object obj, const char *key)
{
krb5_error_code ret = 0;
k5_json_bool b = 0;
ret = k5_json_bool_create(in, &b);
if (ret)
return ENOMEM;
ret = k5_json_object_set(obj, key, b);
k5_json_release(b);
return ret;
}
static krb5_error_code
eventinfo_to_value(k5_json_object obj, const char *name,
const int stage, const krb5_boolean ev_success)
{
krb5_error_code ret = 0;
ret = string_to_value(name, obj, AU_EVENT_NAME);
if (ret)
return ret;
ret = int32_to_value(stage, obj, AU_STAGE);
if (!ret)
ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
return ret;
}
static krb5_error_code
princ_to_value(krb5_principal princ, k5_json_object obj, const char *key)
{
krb5_error_code ret = 0;
k5_json_object tmp = NULL;
k5_json_array arr = NULL;
k5_json_string str = NULL;
int i = 0;
if (princ == NULL || princ->data == NULL)
return 0;
if (k5_json_object_create(&tmp))
return ENOMEM;
ret = k5_json_array_create(&arr);
if (ret)
goto error;
for (i = 0; i < princ->length; i++) {
ret = k5_json_string_create_len((&princ->data[i])->data,
(&princ->data[i])->length, &str);
if (ret)
goto error;
ret = k5_json_array_add(arr, str);
k5_json_release(str);
if (ret)
goto error;
}
ret = k5_json_object_set(tmp, AU_COMPONENTS, arr);
if (ret)
goto error;
ret = data_to_value(&princ->realm, tmp, AU_REALM);
if (ret)
goto error;
ret = int32_to_value(princ->length, tmp, AU_LENGTH);
if (ret)
goto error;
ret = int32_to_value(princ->type, tmp, AU_TYPE);
if (ret)
goto error;
ret = k5_json_object_set(obj, key, tmp);
error:
k5_json_release(tmp);
k5_json_release(arr);
return ret;
}
static krb5_error_code
addr_to_obj(krb5_address *a, k5_json_object obj)
{
krb5_error_code ret = 0;
k5_json_number num = NULL;
k5_json_array arr = NULL;
int i;
if (a == NULL || a->contents == NULL || a->length <= 0)
return 0;
ret = int32_to_value(a->addrtype, obj, AU_TYPE);
if (ret)
goto error;
ret = int32_to_value(a->length, obj, AU_LENGTH);
if (ret)
goto error;
if (a->addrtype == ADDRTYPE_INET || a->addrtype == ADDRTYPE_INET6) {
ret = k5_json_array_create(&arr);
if (ret)
goto error;
for (i = 0; i < (int)a->length; i++) {
ret = k5_json_number_create(a->contents[i], &num);
if (ret)
goto error;
ret = k5_json_array_add(arr, num);
k5_json_release(num);
if (ret)
goto error;
}
ret = k5_json_object_set(obj, AU_IP, arr);
if (ret)
goto error;
} else if (a->addrtype == ADDRTYPE_UNIXSOCK) {
k5_json_string str = NULL;
ret = k5_json_string_create_len(a->contents, a->length, &str);
if (ret)
return ret;
ret = k5_json_object_set(obj, AU_PATH, str);
k5_json_release(str);
if (ret)
goto error;
}
error:
k5_json_release(arr);
return ret;
}
static krb5_error_code
addr_to_value(const krb5_address *address, k5_json_object obj, const char *key)
{
krb5_error_code ret = 0;
k5_json_object addr_obj = NULL;
if (address == NULL)
return 0;
ret = k5_json_object_create(&addr_obj);
if (ret)
return ret;
ret = addr_to_obj((krb5_address *)address, addr_obj);
if (!ret)
ret = k5_json_object_set(obj, key, addr_obj);
k5_json_release(addr_obj);
return ret;
}
static krb5_error_code
req_to_value(krb5_kdc_req *req, const krb5_boolean ev_success,
k5_json_object obj)
{
krb5_error_code ret = 0;
k5_json_number num = NULL;
k5_json_string str = NULL;
k5_json_object tmpa = NULL;
k5_json_array arr = NULL, arra = NULL, arrpa = NULL;
krb5_pa_data **padata;
int i = 0;
if (req == NULL)
return 0;
ret = princ_to_value(req->client, obj, AU_REQ_CLIENT);
if (ret)
goto error;
ret = princ_to_value(req->server, obj, AU_REQ_SERVER);
if (ret)
goto error;
ret = int32_to_value(req->kdc_options, obj, AU_REQ_KDC_OPTIONS);
if (ret)
goto error;
ret = int32_to_value(req->from, obj, AU_REQ_TKT_START);
if (ret)
goto error;
ret = int32_to_value(req->till, obj, AU_REQ_TKT_END);
if (ret)
goto error;
ret = int32_to_value(req->rtime, obj, AU_REQ_TKT_RENEW_TILL);
if (ret)
goto error;
ret = k5_json_array_create(&arr);
if (ret)
goto error;
for (i = 0; (i < req->nktypes); i++) {
if (req->ktype[i] > 0) {
ret = k5_json_number_create(req->ktype[i], &num);
if (ret)
goto error;
ret = k5_json_array_add(arr, num);
k5_json_release(num);
if (ret)
goto error;
}
}
ret = k5_json_object_set(obj, AU_REQ_AVAIL_ETYPES, arr);
if (ret)
goto error;
if (ev_success == TRUE && req->padata) {
ret = k5_json_array_create(&arrpa);
if (ret)
goto error;
for (padata = req->padata; *padata; padata++) {
if (strlen(map_patype((*padata)->pa_type)) > 1) {
ret = k5_json_string_create(map_patype((*padata)->pa_type),
&str);
if (ret)
goto error;
ret = k5_json_array_add(arrpa, str);
k5_json_release(str);
if (ret)
goto error;
}
}
ret = k5_json_object_set(obj, AU_REQ_PA_TYPE, arrpa);
}
if (req->addresses) {
ret = k5_json_array_create(&arra);
if (ret)
goto error;
for (i = 0; req->addresses[i] != NULL; i++) {
ret = k5_json_object_create(&tmpa);
if (ret)
goto error;
ret = addr_to_obj(req->addresses[i], tmpa);
if (!ret)
ret = k5_json_array_add(arra, tmpa);
k5_json_release(tmpa);
if (ret)
goto error;
}
ret = k5_json_object_set(obj, AU_REQ_ADDRESSES, arra);
if (ret)
goto error;
}
error:
k5_json_release(arr);
k5_json_release(arra);
k5_json_release(arrpa);
return ret;
}
static krb5_error_code
rep_to_value(krb5_kdc_rep *rep, const krb5_boolean ev_success,
k5_json_object obj)
{
krb5_error_code ret = 0;
krb5_pa_data **padata;
k5_json_array arrpa = NULL;
k5_json_string str = NULL;
if (rep == NULL)
return 0;
if (ev_success == TRUE) {
ret = tkt_to_value(rep->ticket, obj, AU_REP_TICKET);
ret = int32_to_value(rep->enc_part.enctype, obj, AU_REP_ETYPE);
if (ret)
goto error;
} else {
if (rep->padata) {
ret = k5_json_array_create(&arrpa);
if (ret)
goto error;
for (padata = rep->padata; *padata; padata++) {
if (strlen(map_patype((*padata)->pa_type)) > 1) {
ret = k5_json_string_create(map_patype((*padata)->pa_type),
&str);
if (ret)
goto error;
ret = k5_json_array_add(arrpa, str);
k5_json_release(str);
if (ret)
goto error;
}
}
}
ret = k5_json_object_set(obj, AU_REP_PA_TYPE, arrpa);
}
error:
k5_json_release(arrpa);
return ret;
}
static krb5_error_code
tkt_to_value(krb5_ticket *tkt, k5_json_object obj,
const char *key)
{
krb5_error_code ret = 0;
k5_json_object tmp = NULL;
krb5_enc_tkt_part *part2 = NULL;
if (tkt == NULL)
return 0;
if (k5_json_object_create(&tmp))
return ENOMEM;
ret = princ_to_value(tkt->server, tmp, AU_CNAME);
if (ret)
goto error;
ret = princ_to_value(tkt->server, tmp, AU_SNAME);
if (ret)
goto error;
if (tkt->enc_part.enctype)
ret = int32_to_value(tkt->enc_part.enctype, tmp, AU_SRV_ETYPE);
if (ret)
goto error;
if (tkt->enc_part2)
part2 = tkt->enc_part2;
if (part2) {
ret = princ_to_value(part2->client, tmp, AU_CNAME);
if (ret)
goto error;
ret = int32_to_value(part2->flags, tmp, AU_FLAGS);
if (ret)
goto error;
ret = int32_to_value(part2->session->enctype, tmp, AU_SESS_ETYPE);
if (ret)
goto error;
ret = int32_to_value(part2->times.starttime, tmp, AU_START);
if (ret)
goto error;
ret = int32_to_value(part2->times.endtime, tmp, AU_END);
if (ret)
goto error;
ret = int32_to_value(part2->times.renew_till, tmp, AU_RENEW_TILL);
if (ret)
goto error;
ret = int32_to_value(part2->times.authtime, tmp, AU_AUTHTIME);
if (ret)
goto error;
if (part2->transited.tr_contents.length > 0) {
ret = data_to_value(&part2->transited.tr_contents,
tmp, AU_TR_CONTENTS);
if (ret)
goto error;
}
}
if (!ret)
ret = k5_json_object_set(obj, key, tmp);
error:
k5_json_release(tmp);
return ret;
}
struct _patype_str {
krb5_preauthtype id;
char *name;
};
struct _patype_str patype_str[] = {
{KRB5_PADATA_ENC_TIMESTAMP, "ENC_TIMESTAMP"},
{KRB5_PADATA_PW_SALT, "PW_SALT"},
{KRB5_PADATA_ENC_UNIX_TIME, "ENC_UNIX_TIME"},
{KRB5_PADATA_SAM_CHALLENGE, "SAM_CHALLENGE"},
{KRB5_PADATA_SAM_RESPONSE, "SAM_RESPONSE"},
{KRB5_PADATA_PK_AS_REQ_OLD, "PK_AS_REQ_OLD"},
{KRB5_PADATA_PK_AS_REP_OLD, "PK_AS_REP_OLD"},
{KRB5_PADATA_PK_AS_REQ, "PK_AS_REQ"},
{KRB5_PADATA_PK_AS_REP, "PK_AS_REP"},
{KRB5_PADATA_ETYPE_INFO2, "ETYPE_INFO2"},
{KRB5_PADATA_SAM_CHALLENGE_2, "SAM_CHALLENGE_2"},
{KRB5_PADATA_SAM_RESPONSE_2, "SAM_RESPONSE_2"},
{KRB5_PADATA_PAC_REQUEST, "PAC_REQUEST"},
{KRB5_PADATA_FOR_USER, "FOR_USER"},
{KRB5_PADATA_S4U_X509_USER, "S4U_X509_USER"},
{KRB5_PADATA_ENCRYPTED_CHALLENGE, "ENCRYPTED_CHALLENGE"},
{KRB5_PADATA_OTP_CHALLENGE, "OTP_CHALLENGE"},
{KRB5_PADATA_OTP_REQUEST, "OTP_REQUEST"},
{KRB5_PADATA_OTP_PIN_CHANGE, "OTP_PIN_CHANGE"}
};
static char *
map_patype(krb5_preauthtype pa_type)
{
int i = 0;
int n = sizeof(patype_str)/sizeof(patype_str[0]);
for (i = 0; i < n; i++) {
if (pa_type == patype_str[i].id)
return patype_str[i].name;
}
return "";
}