Blame src/plugins/audit/kdc_j_encode.c

Packit fd8b60
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit fd8b60
/* plugins/audit/kdc_j_encode.c - Utilities to json encode KDC audit stuff */
Packit fd8b60
/*
Packit fd8b60
 * Copyright (C) 2013 by the Massachusetts Institute of Technology.
Packit fd8b60
 * All rights reserved.
Packit fd8b60
 *
Packit fd8b60
 * Redistribution and use in source and binary forms, with or without
Packit fd8b60
 * modification, are permitted provided that the following conditions
Packit fd8b60
 * are met:
Packit fd8b60
 *
Packit fd8b60
 * * Redistributions of source code must retain the above copyright
Packit fd8b60
 *   notice, this list of conditions and the following disclaimer.
Packit fd8b60
 *
Packit fd8b60
 * * Redistributions in binary form must reproduce the above copyright
Packit fd8b60
 *   notice, this list of conditions and the following disclaimer in
Packit fd8b60
 *   the documentation and/or other materials provided with the
Packit fd8b60
 *   distribution.
Packit fd8b60
 *
Packit fd8b60
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit fd8b60
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit fd8b60
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
Packit fd8b60
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
Packit fd8b60
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
Packit fd8b60
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit fd8b60
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit fd8b60
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit fd8b60
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
Packit fd8b60
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit fd8b60
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
Packit fd8b60
 * OF THE POSSIBILITY OF SUCH DAMAGE.
Packit fd8b60
 */
Packit fd8b60
Packit fd8b60
#include <k5-int.h>
Packit fd8b60
#include <k5-json.h>
Packit fd8b60
#include "kdc_j_encode.h"
Packit fd8b60
#include "j_dict.h"
Packit fd8b60
#include <krb5/audit_plugin.h>
Packit fd8b60
#include <syslog.h>
Packit fd8b60
Packit fd8b60
static krb5_error_code
Packit fd8b60
string_to_value(const char *in, k5_json_object obj, const char *key);
Packit fd8b60
static krb5_error_code
Packit fd8b60
princ_to_value(krb5_principal princ, k5_json_object obj, const char *key);
Packit fd8b60
static krb5_error_code
Packit fd8b60
data_to_value(krb5_data *data, k5_json_object obj, const char *key);
Packit fd8b60
static krb5_error_code
Packit fd8b60
int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key);
Packit fd8b60
static krb5_error_code
Packit fd8b60
bool_to_value(krb5_boolean b, k5_json_object obj, const char *key);
Packit fd8b60
static krb5_error_code
Packit fd8b60
addr_to_obj(krb5_address *a, k5_json_object obj);
Packit fd8b60
static krb5_error_code
Packit fd8b60
eventinfo_to_value(k5_json_object obj, const char *name,
Packit fd8b60
                   const int stage, const krb5_boolean ev_success);
Packit fd8b60
static krb5_error_code
Packit fd8b60
addr_to_value(const krb5_address *address, k5_json_object obj,
Packit fd8b60
              const char *key);
Packit fd8b60
static krb5_error_code
Packit fd8b60
req_to_value(krb5_kdc_req *req, const krb5_boolean ev_success,
Packit fd8b60
             k5_json_object obj);
Packit fd8b60
static krb5_error_code
Packit fd8b60
rep_to_value(krb5_kdc_rep *rep, const krb5_boolean ev_success,
Packit fd8b60
             k5_json_object obj);
Packit fd8b60
static krb5_error_code
Packit fd8b60
tkt_to_value(krb5_ticket *tkt, k5_json_object obj, const char *key);
Packit fd8b60
static char *map_patype(krb5_preauthtype pa_type);
Packit fd8b60
Packit fd8b60
#define NULL_STATE "state is NULL"
Packit fd8b60
#define T_RENEWED 1
Packit fd8b60
#define T_NOT_RENEWED 2
Packit fd8b60
#define T_VALIDATED 1
Packit fd8b60
#define T_NOT_VALIDATED 2
Packit fd8b60
Packit fd8b60
/* KDC server STOP. Returns 0 on success. */
Packit fd8b60
krb5_error_code
Packit fd8b60
kau_j_kdc_stop(const krb5_boolean ev_success, char **jout)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object obj = NULL;
Packit fd8b60
Packit fd8b60
    *jout = NULL;
Packit fd8b60
Packit fd8b60
    /* Main object. */
Packit fd8b60
    if (k5_json_object_create(&obj))
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    /* Audit event_ID and ev_success. */
Packit fd8b60
    ret = string_to_value("KDC_STOP", obj, AU_EVENT_NAME);
Packit fd8b60
    if (!ret)
Packit fd8b60
        ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
Packit fd8b60
    if (!ret)
Packit fd8b60
        ret = k5_json_encode(obj, jout);
Packit fd8b60
    k5_json_release(obj);
Packit fd8b60
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* KDC server START. Returns 0 on success. */
Packit fd8b60
krb5_error_code
Packit fd8b60
kau_j_kdc_start(const krb5_boolean ev_success, char **jout)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object obj = NULL;
Packit fd8b60
Packit fd8b60
    *jout = NULL;
Packit fd8b60
Packit fd8b60
    /* Main object. */
Packit fd8b60
    if (k5_json_object_create(&obj))
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    /* Audit event_ID and ev_success. */
Packit fd8b60
    ret = string_to_value("KDC_START", obj, AU_EVENT_NAME);
Packit fd8b60
    if (!ret)
Packit fd8b60
        ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
Packit fd8b60
    if (!ret)
Packit fd8b60
        ret = k5_json_encode(obj, jout);
Packit fd8b60
    k5_json_release(obj);
Packit fd8b60
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* AS-REQ. Returns 0 on success. */
Packit fd8b60
krb5_error_code
Packit fd8b60
kau_j_as_req(const krb5_boolean ev_success, krb5_audit_state *state,
Packit fd8b60
             char **jout)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object obj = NULL;
Packit fd8b60
Packit fd8b60
    *jout = NULL;
Packit fd8b60
Packit fd8b60
    if (!state) {
Packit fd8b60
        *jout = NULL_STATE;
Packit fd8b60
        return 0;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    /* Main object. */
Packit fd8b60
    if (k5_json_object_create(&obj))
Packit fd8b60
        return ENOMEM;
Packit fd8b60
    /* Audit event_ID and ev_success. */
Packit fd8b60
    ret = eventinfo_to_value(obj, "AS_REQ", state->stage, ev_success);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* TGT ticket ID */
Packit fd8b60
    ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Request ID. */
Packit fd8b60
    ret = string_to_value(state->req_id, obj, AU_REQ_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Client's port and address. */
Packit fd8b60
    ret = int32_to_value(state->cl_port, obj, AU_FROMPORT);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = addr_to_value(state->cl_addr, obj, AU_FROMADDR);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* KDC status msg */
Packit fd8b60
    ret = string_to_value(state->status, obj, AU_KDC_STATUS);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* non-local client's referral realm. */
Packit fd8b60
    ret = data_to_value(state->cl_realm, obj, AU_CREF_REALM);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Request. */
Packit fd8b60
    ret = req_to_value(state->request, ev_success, obj);
Packit fd8b60
    if (ret == ENOMEM)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Reply/ticket info. */
Packit fd8b60
    ret = rep_to_value(state->reply, ev_success, obj);
Packit fd8b60
    if (ret == ENOMEM)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = k5_json_encode(obj, jout);
Packit fd8b60
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(obj);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* TGS-REQ. Returns 0 on success. */
Packit fd8b60
krb5_error_code
Packit fd8b60
kau_j_tgs_req(const krb5_boolean ev_success, krb5_audit_state *state,
Packit fd8b60
              char **jout)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object obj = NULL;
Packit fd8b60
    krb5_kdc_req *req = state->request;
Packit fd8b60
    int tkt_validated = 0, tkt_renewed = 0;
Packit fd8b60
Packit fd8b60
    *jout = NULL;
Packit fd8b60
Packit fd8b60
    if (!state) {
Packit fd8b60
        *jout = NULL_STATE;
Packit fd8b60
        return 0;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    /* Main object. */
Packit fd8b60
    if (k5_json_object_create(&obj))
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    /* Audit Event ID and ev_success. */
Packit fd8b60
    ret = eventinfo_to_value(obj, "TGS_REQ", state->stage, ev_success);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Primary and derived ticket IDs. */
Packit fd8b60
    ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Request ID */
Packit fd8b60
    ret = string_to_value(state->req_id, obj, AU_REQ_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* client’s address and port. */
Packit fd8b60
    ret = int32_to_value(state->cl_port, obj, AU_FROMPORT);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = addr_to_value(state->cl_addr, obj, AU_FROMADDR);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Ticket was renewed, validated. */
Packit fd8b60
    if ((ev_success == TRUE) && (req != NULL)) {
Packit fd8b60
        tkt_renewed = (req->kdc_options & KDC_OPT_RENEW) ?
Packit fd8b60
                      T_RENEWED : T_NOT_RENEWED;
Packit fd8b60
        tkt_validated = (req->kdc_options & KDC_OPT_VALIDATE) ?
Packit fd8b60
                      T_VALIDATED : T_NOT_VALIDATED;
Packit fd8b60
    }
Packit fd8b60
    ret = int32_to_value(tkt_renewed, obj, AU_TKT_RENEWED);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = int32_to_value(tkt_validated, obj, AU_TKT_VALIDATED);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* KDC status msg, including "ISSUE". */
Packit fd8b60
    ret = string_to_value(state->status, obj, AU_KDC_STATUS);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* request */
Packit fd8b60
    ret = req_to_value(req, ev_success, obj);
Packit fd8b60
    if (ret == ENOMEM)
Packit fd8b60
        goto error;
Packit fd8b60
    /* reply/ticket */
Packit fd8b60
    ret = rep_to_value(state->reply, ev_success, obj);
Packit fd8b60
    if (ret == ENOMEM)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = k5_json_encode(obj, jout);
Packit fd8b60
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(obj);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* S4U2Self protocol extension. Returns 0 on success. */
Packit fd8b60
krb5_error_code
Packit fd8b60
kau_j_tgs_s4u2self(const krb5_boolean ev_success, krb5_audit_state *state,
Packit fd8b60
                   char **jout)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object obj = NULL;
Packit fd8b60
Packit fd8b60
    *jout = NULL;
Packit fd8b60
Packit fd8b60
    if (!state) {
Packit fd8b60
        *jout = NULL_STATE;
Packit fd8b60
        return 0;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    /* Main object. */
Packit fd8b60
    if (k5_json_object_create(&obj))
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    /* Audit Event ID and ev_success. */
Packit fd8b60
    ret = eventinfo_to_value(obj, "S4U2SELF", state->stage, ev_success);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Front-end server's TGT ticket ID. */
Packit fd8b60
    ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* service "to self" ticket or referral TGT ticket ID. */
Packit fd8b60
    ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Request ID. */
Packit fd8b60
    ret = string_to_value(state->req_id, obj, AU_REQ_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    if (ev_success == FALSE) {
Packit fd8b60
        /* KDC status msg. */
Packit fd8b60
        ret = string_to_value(state->status, obj, AU_KDC_STATUS);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        /* Local policy or S4U protocol constraints. */
Packit fd8b60
        ret = int32_to_value(state->violation, obj, AU_VIOLATION);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    }
Packit fd8b60
    /* Impersonated user. */
Packit fd8b60
    ret = princ_to_value(state->s4u2self_user, obj, AU_REQ_S4U2S_USER);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
Packit fd8b60
    ret = k5_json_encode(obj, jout);
Packit fd8b60
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(obj);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* S4U2Proxy protocol extension. Returns 0 on success. */
Packit fd8b60
krb5_error_code
Packit fd8b60
kau_j_tgs_s4u2proxy(const krb5_boolean ev_success, krb5_audit_state *state,
Packit fd8b60
                    char **jout)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object obj = NULL;
Packit fd8b60
    krb5_kdc_req *req = state->request;
Packit fd8b60
Packit fd8b60
    *jout = NULL;
Packit fd8b60
Packit fd8b60
    if (!state) {
Packit fd8b60
        *jout = NULL_STATE;
Packit fd8b60
        return 0;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    /* Main object. */
Packit fd8b60
    if (k5_json_object_create(&obj))
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    /* Audit Event ID and ev_success. */
Packit fd8b60
    ret = eventinfo_to_value(obj, "S4U2PROXY", state->stage, ev_success);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Front-end server's TGT ticket ID. */
Packit fd8b60
    ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Resource service or referral TGT ticket ID. */
Packit fd8b60
    ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* User's evidence ticket ID. */
Packit fd8b60
    ret = string_to_value(state->evid_tkt_id, obj, AU_EVIDENCE_TKT_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Request ID. */
Packit fd8b60
    ret = string_to_value(state->req_id, obj, AU_REQ_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
Packit fd8b60
    if (ev_success == FALSE) {
Packit fd8b60
        /* KDC status msg. */
Packit fd8b60
        ret = string_to_value(state->status, obj, AU_KDC_STATUS);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        /* Local policy or S4U protocol constraints. */
Packit fd8b60
        ret = int32_to_value(state->violation, obj, AU_VIOLATION);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    }
Packit fd8b60
    /* Delegated user. */
Packit fd8b60
    if (req != NULL) {
Packit fd8b60
        ret = princ_to_value(req->second_ticket[0]->enc_part2->client,
Packit fd8b60
                             obj, AU_REQ_S4U2P_USER);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    }
Packit fd8b60
    ret = k5_json_encode(obj, jout);
Packit fd8b60
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(obj);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* U2U. Returns 0 on success. */
Packit fd8b60
krb5_error_code
Packit fd8b60
kau_j_tgs_u2u(const krb5_boolean ev_success, krb5_audit_state *state,
Packit fd8b60
              char **jout)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object obj = NULL;
Packit fd8b60
    krb5_kdc_req *req = state->request;
Packit fd8b60
Packit fd8b60
    if (!state) {
Packit fd8b60
        *jout = NULL_STATE;
Packit fd8b60
        return 0;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
    *jout = NULL;
Packit fd8b60
Packit fd8b60
    /* Main object. */
Packit fd8b60
    if (k5_json_object_create(&obj))
Packit fd8b60
        return ENOMEM;
Packit fd8b60
    /* Audit Event ID and ev_success. */
Packit fd8b60
    ret = eventinfo_to_value(obj, "U2U", state->stage, ev_success);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Front-end server's TGT ticket ID. */
Packit fd8b60
    ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Service ticket ID. */
Packit fd8b60
    ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Request ID. */
Packit fd8b60
    ret = string_to_value(state->req_id, obj, AU_REQ_ID);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
Packit fd8b60
    if (ev_success == FALSE) {
Packit fd8b60
        /* KDC status msg. */
Packit fd8b60
        ret = string_to_value(state->status, obj, AU_KDC_STATUS);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    }
Packit fd8b60
    /* Client in the second ticket. */
Packit fd8b60
    if (req != NULL) {
Packit fd8b60
        ret = princ_to_value(req->second_ticket[0]->enc_part2->client,
Packit fd8b60
                             obj, AU_REQ_U2U_USER);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    }
Packit fd8b60
    /* Enctype of a session key of the second ticket. */
Packit fd8b60
    ret = int32_to_value(req->second_ticket[0]->enc_part2->session->enctype,
Packit fd8b60
                         obj, AU_SRV_ETYPE);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
Packit fd8b60
    ret = k5_json_encode(obj, jout);
Packit fd8b60
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(obj);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* Low level utilities */
Packit fd8b60
Packit fd8b60
/* Converts string into a property of a JSON object. Returns 0 on success.*/
Packit fd8b60
static krb5_error_code
Packit fd8b60
string_to_value(const char *in, k5_json_object obj, const char *key)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_string str = NULL;
Packit fd8b60
Packit fd8b60
    if (in == NULL)
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    ret = k5_json_string_create(in, &str);
Packit fd8b60
    if (ret)
Packit fd8b60
        return ret;
Packit fd8b60
    ret = k5_json_object_set(obj, key, str);
Packit fd8b60
    k5_json_release(str);
Packit fd8b60
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Converts a krb5_data struct into a property of a JSON object.
Packit fd8b60
 * (Borrowed from preauth_otp.c)
Packit fd8b60
 * Returns 0 on success.
Packit fd8b60
 */
Packit fd8b60
static krb5_error_code
Packit fd8b60
data_to_value(krb5_data *data, k5_json_object obj, const char *key)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_string str = NULL;
Packit fd8b60
Packit fd8b60
    if (data == NULL || data->data == NULL || data->length < 1)
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    ret = k5_json_string_create_len(data->data, data->length, &str);
Packit fd8b60
    if (ret)
Packit fd8b60
        return ret;
Packit fd8b60
    ret = k5_json_object_set(obj, key, str);
Packit fd8b60
    k5_json_release(str);
Packit fd8b60
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Converts krb5_int32 into a property of a JSON object.
Packit fd8b60
 * Returns 0 on success.
Packit fd8b60
 */
Packit fd8b60
static krb5_error_code
Packit fd8b60
int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_number num = NULL;
Packit fd8b60
Packit fd8b60
    ret = k5_json_number_create(int32, &num);
Packit fd8b60
    if (ret)
Packit fd8b60
        return ENOMEM;
Packit fd8b60
    ret = k5_json_object_set(obj, key, num);
Packit fd8b60
    k5_json_release(num);
Packit fd8b60
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Converts krb5_boolean into a property of a JSON object.
Packit fd8b60
 * Returns 0 on success.
Packit fd8b60
 */
Packit fd8b60
static krb5_error_code
Packit fd8b60
bool_to_value(krb5_boolean in, k5_json_object obj, const char *key)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_bool b = 0;
Packit fd8b60
Packit fd8b60
    ret = k5_json_bool_create(in, &b);
Packit fd8b60
    if (ret)
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    ret = k5_json_object_set(obj, key, b);
Packit fd8b60
    k5_json_release(b);
Packit fd8b60
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* Wrapper-level utilities */
Packit fd8b60
Packit fd8b60
/* Wrapper for stage and event_status tags. Returns 0 on success. */
Packit fd8b60
static krb5_error_code
Packit fd8b60
eventinfo_to_value(k5_json_object obj, const char *name,
Packit fd8b60
                   const int stage, const krb5_boolean ev_success)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
Packit fd8b60
    ret = string_to_value(name, obj, AU_EVENT_NAME);
Packit fd8b60
    if (ret)
Packit fd8b60
        return ret;
Packit fd8b60
    ret = int32_to_value(stage, obj, AU_STAGE);
Packit fd8b60
    if (!ret)
Packit fd8b60
        ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
Packit fd8b60
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Converts krb5_principal into a property of a JSON object.
Packit fd8b60
 * Returns 0 on success.
Packit fd8b60
 */
Packit fd8b60
static krb5_error_code
Packit fd8b60
princ_to_value(krb5_principal princ, k5_json_object obj, const char *key)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object tmp = NULL;
Packit fd8b60
    k5_json_array arr = NULL;
Packit fd8b60
    k5_json_string str = NULL;
Packit fd8b60
    int i = 0;
Packit fd8b60
Packit fd8b60
    if (princ == NULL || princ->data == NULL)
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    /* Main object. */
Packit fd8b60
    if (k5_json_object_create(&tmp))
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    ret = k5_json_array_create(&arr;;
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    for (i = 0; i < princ->length; i++) {
Packit fd8b60
        ret = k5_json_string_create_len((&princ->data[i])->data,
Packit fd8b60
                                       (&princ->data[i])->length, &str);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        ret = k5_json_array_add(arr, str);
Packit fd8b60
        k5_json_release(str);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    }
Packit fd8b60
    ret = k5_json_object_set(tmp, AU_COMPONENTS, arr);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = data_to_value(&princ->realm, tmp, AU_REALM);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = int32_to_value(princ->length, tmp, AU_LENGTH);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = int32_to_value(princ->type, tmp, AU_TYPE);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
Packit fd8b60
    ret = k5_json_object_set(obj, key, tmp);
Packit fd8b60
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(tmp);
Packit fd8b60
    k5_json_release(arr);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Helper for JSON encoding of krb5_address.
Packit fd8b60
 * Returns 0 on success.
Packit fd8b60
 */
Packit fd8b60
static krb5_error_code
Packit fd8b60
addr_to_obj(krb5_address *a, k5_json_object obj)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_number num = NULL;
Packit fd8b60
    k5_json_array arr = NULL;
Packit fd8b60
    int i;
Packit fd8b60
Packit fd8b60
    if (a == NULL || a->contents == NULL || a->length <= 0)
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    ret = int32_to_value(a->addrtype, obj, AU_TYPE);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = int32_to_value(a->length, obj, AU_LENGTH);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
Packit fd8b60
    if (a->addrtype == ADDRTYPE_INET || a->addrtype == ADDRTYPE_INET6) {
Packit fd8b60
        ret = k5_json_array_create(&arr;;
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        for (i = 0; i < (int)a->length; i++) {
Packit fd8b60
            ret = k5_json_number_create(a->contents[i], &num);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
            ret = k5_json_array_add(arr, num);
Packit fd8b60
            k5_json_release(num);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
        }
Packit fd8b60
        ret = k5_json_object_set(obj, AU_IP, arr);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    }
Packit fd8b60
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(arr);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Converts krb5_fulladdr into a property of a JSON object.
Packit fd8b60
 * Returns 0 on success.
Packit fd8b60
 */
Packit fd8b60
static krb5_error_code
Packit fd8b60
addr_to_value(const krb5_address *address, k5_json_object obj, const char *key)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object addr_obj = NULL;
Packit fd8b60
Packit fd8b60
    if (address == NULL)
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    ret = k5_json_object_create(&addr_obj);
Packit fd8b60
    if (ret)
Packit fd8b60
        return ret;
Packit fd8b60
    ret = addr_to_obj((krb5_address *)address, addr_obj);
Packit fd8b60
    if (!ret)
Packit fd8b60
        ret = k5_json_object_set(obj, key, addr_obj);
Packit fd8b60
    k5_json_release(addr_obj);
Packit fd8b60
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Helper for JSON encoding of krb5_kdc_req.
Packit fd8b60
 * Returns 0 on success.
Packit fd8b60
 */
Packit fd8b60
static krb5_error_code
Packit fd8b60
req_to_value(krb5_kdc_req *req, const krb5_boolean ev_success,
Packit fd8b60
             k5_json_object obj)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_number num = NULL;
Packit fd8b60
    k5_json_string str = NULL;
Packit fd8b60
    k5_json_object tmpa = NULL;
Packit fd8b60
    k5_json_array arr = NULL, arra = NULL, arrpa = NULL;
Packit fd8b60
    krb5_pa_data **padata;
Packit fd8b60
    int i = 0;
Packit fd8b60
Packit fd8b60
    if (req == NULL)
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    ret = princ_to_value(req->client, obj, AU_REQ_CLIENT);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = princ_to_value(req->server, obj, AU_REQ_SERVER);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
Packit fd8b60
    ret = int32_to_value(req->kdc_options, obj, AU_REQ_KDC_OPTIONS);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    ret = int32_to_value(req->from, obj, AU_REQ_TKT_START);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    ret = int32_to_value(req->till, obj, AU_REQ_TKT_END);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    ret = int32_to_value(req->rtime, obj, AU_REQ_TKT_RENEW_TILL);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    /* Available/requested enctypes. */
Packit fd8b60
    ret = k5_json_array_create(&arr;;
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    for (i = 0; (i < req->nktypes); i++) {
Packit fd8b60
        if (req->ktype[i] > 0) {
Packit fd8b60
            ret = k5_json_number_create(req->ktype[i], &num);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
            ret = k5_json_array_add(arr, num);
Packit fd8b60
            k5_json_release(num);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
        }
Packit fd8b60
    }
Packit fd8b60
    ret = k5_json_object_set(obj, AU_REQ_AVAIL_ETYPES, arr);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Pre-auth types. */
Packit fd8b60
    if (ev_success == TRUE && req->padata) {
Packit fd8b60
            ret = k5_json_array_create(&arrpa);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
            for (padata = req->padata; *padata; padata++) {
Packit fd8b60
                if (strlen(map_patype((*padata)->pa_type)) > 1) {
Packit fd8b60
                    ret = k5_json_string_create(map_patype((*padata)->pa_type),
Packit fd8b60
                                                &str);
Packit fd8b60
                    if (ret)
Packit fd8b60
                        goto error;
Packit fd8b60
                    ret = k5_json_array_add(arrpa, str);
Packit fd8b60
                    k5_json_release(str);
Packit fd8b60
                    if (ret)
Packit fd8b60
                        goto error;
Packit fd8b60
                }
Packit fd8b60
            }
Packit fd8b60
            ret = k5_json_object_set(obj, AU_REQ_PA_TYPE, arrpa);
Packit fd8b60
    }
Packit fd8b60
    /* List of requested addresses. */
Packit fd8b60
    if (req->addresses) {
Packit fd8b60
        ret = k5_json_array_create(&arra);
Packit fd8b60
        if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
        for (i = 0; req->addresses[i] != NULL; i++) {
Packit fd8b60
            ret = k5_json_object_create(&tmpa);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
            ret = addr_to_obj(req->addresses[i], tmpa);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
            ret = k5_json_array_add(arra, tmpa);
Packit fd8b60
            k5_json_release(tmpa);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
        }
Packit fd8b60
        ret = k5_json_object_set(obj, AU_REQ_ADDRESSES, arra);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    }
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(arr);
Packit fd8b60
    k5_json_release(arra);
Packit fd8b60
    k5_json_release(arrpa);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Helper for JSON encoding of krb5_kdc_rep.
Packit fd8b60
 * Returns 0 on success.
Packit fd8b60
 */
Packit fd8b60
static krb5_error_code
Packit fd8b60
rep_to_value(krb5_kdc_rep *rep, const krb5_boolean ev_success,
Packit fd8b60
             k5_json_object obj)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    krb5_pa_data **padata;
Packit fd8b60
    k5_json_array arrpa = NULL;
Packit fd8b60
    k5_json_string str = NULL;
Packit fd8b60
Packit fd8b60
    if (rep == NULL)
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    if (ev_success == TRUE) {
Packit fd8b60
        ret = tkt_to_value(rep->ticket, obj, AU_REP_TICKET);
Packit fd8b60
        /* Enctype of the reply-encrypting key. */
Packit fd8b60
        ret = int32_to_value(rep->enc_part.enctype, obj, AU_REP_ETYPE);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
    } else {
Packit fd8b60
Packit fd8b60
        if (rep->padata) {
Packit fd8b60
            ret = k5_json_array_create(&arrpa);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
            for (padata = rep->padata; *padata; padata++) {
Packit fd8b60
                if (strlen(map_patype((*padata)->pa_type)) > 1) {
Packit fd8b60
                    ret = k5_json_string_create(map_patype((*padata)->pa_type),
Packit fd8b60
                                                          &str);
Packit fd8b60
                    if (ret)
Packit fd8b60
                        goto error;
Packit fd8b60
                    ret = k5_json_array_add(arrpa, str);
Packit fd8b60
                    k5_json_release(str);
Packit fd8b60
                    if (ret)
Packit fd8b60
                        goto error;
Packit fd8b60
                }
Packit fd8b60
            }
Packit fd8b60
        }
Packit fd8b60
        ret = k5_json_object_set(obj, AU_REP_PA_TYPE, arrpa);
Packit fd8b60
    }
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(arrpa);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/*
Packit fd8b60
 * Converts krb5_ticket into a property of a JSON object.
Packit fd8b60
 * Returns 0 on success.
Packit fd8b60
 */
Packit fd8b60
static krb5_error_code
Packit fd8b60
tkt_to_value(krb5_ticket *tkt, k5_json_object obj,
Packit fd8b60
              const char *key)
Packit fd8b60
{
Packit fd8b60
    krb5_error_code ret = 0;
Packit fd8b60
    k5_json_object tmp = NULL;
Packit fd8b60
    krb5_enc_tkt_part *part2 = NULL;
Packit fd8b60
Packit fd8b60
    if (tkt == NULL)
Packit fd8b60
        return 0;
Packit fd8b60
Packit fd8b60
    /* Main object. */
Packit fd8b60
    if (k5_json_object_create(&tmp))
Packit fd8b60
        return ENOMEM;
Packit fd8b60
Packit fd8b60
    /*
Packit fd8b60
     * CNAME - potentially redundant data...
Packit fd8b60
     * ...but it is part of the ticket. So, record it as such.
Packit fd8b60
     */
Packit fd8b60
    ret = princ_to_value(tkt->server, tmp, AU_CNAME);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    ret = princ_to_value(tkt->server, tmp, AU_SNAME);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    /* Enctype of a long-term key of service. */
Packit fd8b60
    if (tkt->enc_part.enctype)
Packit fd8b60
        ret = int32_to_value(tkt->enc_part.enctype, tmp, AU_SRV_ETYPE);
Packit fd8b60
    if (ret)
Packit fd8b60
        goto error;
Packit fd8b60
    if (tkt->enc_part2)
Packit fd8b60
        part2 = tkt->enc_part2;
Packit fd8b60
    if (part2) {
Packit fd8b60
        ret = princ_to_value(part2->client, tmp, AU_CNAME);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        ret = int32_to_value(part2->flags, tmp, AU_FLAGS);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        /* Chosen by KDC session key enctype (short-term key). */
Packit fd8b60
        ret = int32_to_value(part2->session->enctype, tmp, AU_SESS_ETYPE);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        ret = int32_to_value(part2->times.starttime, tmp, AU_START);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        ret = int32_to_value(part2->times.endtime, tmp, AU_END);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        ret = int32_to_value(part2->times.renew_till, tmp, AU_RENEW_TILL);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        ret = int32_to_value(part2->times.authtime, tmp, AU_AUTHTIME);
Packit fd8b60
        if (ret)
Packit fd8b60
            goto error;
Packit fd8b60
        if (part2->transited.tr_contents.length > 0) {
Packit fd8b60
            ret = data_to_value(&part2->transited.tr_contents,
Packit fd8b60
                               tmp, AU_TR_CONTENTS);
Packit fd8b60
            if (ret)
Packit fd8b60
                goto error;
Packit fd8b60
        }
Packit fd8b60
    } /* part2 != NULL */
Packit fd8b60
Packit fd8b60
    if (!ret)
Packit fd8b60
        ret = k5_json_object_set(obj, key, tmp);
Packit fd8b60
Packit fd8b60
error:
Packit fd8b60
    k5_json_release(tmp);
Packit fd8b60
    return ret;
Packit fd8b60
}
Packit fd8b60
Packit fd8b60
/* Map preauth numeric type to the naming string. */
Packit fd8b60
struct _patype_str {
Packit fd8b60
    krb5_preauthtype id;
Packit fd8b60
    char *name;
Packit fd8b60
};
Packit fd8b60
struct _patype_str  patype_str[] = {
Packit fd8b60
    {KRB5_PADATA_ENC_TIMESTAMP, "ENC_TIMESTAMP"},
Packit fd8b60
    {KRB5_PADATA_PW_SALT, "PW_SALT"},
Packit fd8b60
    {KRB5_PADATA_ENC_UNIX_TIME, "ENC_UNIX_TIME"},
Packit fd8b60
    {KRB5_PADATA_SAM_CHALLENGE, "SAM_CHALLENGE"},
Packit fd8b60
    {KRB5_PADATA_SAM_RESPONSE, "SAM_RESPONSE"},
Packit fd8b60
    {KRB5_PADATA_PK_AS_REQ_OLD, "PK_AS_REQ_OLD"},
Packit fd8b60
    {KRB5_PADATA_PK_AS_REP_OLD, "PK_AS_REP_OLD"},
Packit fd8b60
    {KRB5_PADATA_PK_AS_REQ, "PK_AS_REQ"},
Packit fd8b60
    {KRB5_PADATA_PK_AS_REP, "PK_AS_REP"},
Packit fd8b60
    {KRB5_PADATA_ETYPE_INFO2, "ETYPE_INFO2"},
Packit fd8b60
    {KRB5_PADATA_SAM_CHALLENGE_2, "SAM_CHALLENGE_2"},
Packit fd8b60
    {KRB5_PADATA_SAM_RESPONSE_2, "SAM_RESPONSE_2"},
Packit fd8b60
    {KRB5_PADATA_PAC_REQUEST, "PAC_REQUEST"},
Packit fd8b60
    {KRB5_PADATA_FOR_USER, "FOR_USER"},
Packit fd8b60
    {KRB5_PADATA_S4U_X509_USER, "S4U_X509_USER"},
Packit fd8b60
    {KRB5_PADATA_ENCRYPTED_CHALLENGE, "ENCRYPTED_CHALLENGE"},
Packit fd8b60
    {KRB5_PADATA_OTP_CHALLENGE, "OTP_CHALLENGE"},
Packit fd8b60
    {KRB5_PADATA_OTP_REQUEST, "OTP_REQUEST"},
Packit fd8b60
    {KRB5_PADATA_OTP_PIN_CHANGE, "OTP_PIN_CHANGE"}
Packit fd8b60
};
Packit fd8b60
Packit fd8b60
Packit fd8b60
static char *
Packit fd8b60
map_patype(krb5_preauthtype pa_type)
Packit fd8b60
{
Packit fd8b60
    int i = 0;
Packit fd8b60
    int n = sizeof(patype_str)/sizeof(patype_str[0]);
Packit fd8b60
Packit fd8b60
    for (i = 0; i < n; i++) {
Packit fd8b60
        if (pa_type == patype_str[i].id)
Packit fd8b60
            return patype_str[i].name;
Packit fd8b60
    }
Packit fd8b60
    return "";
Packit fd8b60
}