xref: /freebsd/crypto/krb5/src/plugins/audit/kdc_j_encode.c (revision f1c4c3daccbaf3820f0e2224de53df12fc952fcc)
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 */
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 <k5-json.h>
35 #include "kdc_j_encode.h"
36 #include "j_dict.h"
37 #include <krb5/audit_plugin.h>
38 #include <syslog.h>
39 
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,
57               const char *key);
58 static krb5_error_code
59 req_to_value(krb5_kdc_req *req, const krb5_boolean ev_success,
60              k5_json_object obj);
61 static krb5_error_code
62 rep_to_value(krb5_kdc_rep *rep, const krb5_boolean ev_success,
63              k5_json_object obj);
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);
67 
68 #define NULL_STATE "state is NULL"
69 #define T_RENEWED 1
70 #define T_NOT_RENEWED 2
71 #define T_VALIDATED 1
72 #define T_NOT_VALIDATED 2
73 
74 /* KDC server STOP. Returns 0 on success. */
75 krb5_error_code
kau_j_kdc_stop(const krb5_boolean ev_success,char ** jout)76 kau_j_kdc_stop(const krb5_boolean ev_success, char **jout)
77 {
78     krb5_error_code ret = 0;
79     k5_json_object obj = NULL;
80 
81     *jout = NULL;
82 
83     /* Main object. */
84     if (k5_json_object_create(&obj))
85         return ENOMEM;
86 
87     /* Audit event_ID and ev_success. */
88     ret = string_to_value("KDC_STOP", obj, AU_EVENT_NAME);
89     if (!ret)
90         ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
91     if (!ret)
92         ret = k5_json_encode(obj, jout);
93     k5_json_release(obj);
94 
95     return ret;
96 }
97 
98 /* KDC server START. Returns 0 on success. */
99 krb5_error_code
kau_j_kdc_start(const krb5_boolean ev_success,char ** jout)100 kau_j_kdc_start(const krb5_boolean ev_success, char **jout)
101 {
102     krb5_error_code ret = 0;
103     k5_json_object obj = NULL;
104 
105     *jout = NULL;
106 
107     /* Main object. */
108     if (k5_json_object_create(&obj))
109         return ENOMEM;
110 
111     /* Audit event_ID and ev_success. */
112     ret = string_to_value("KDC_START", obj, AU_EVENT_NAME);
113     if (!ret)
114         ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
115     if (!ret)
116         ret = k5_json_encode(obj, jout);
117     k5_json_release(obj);
118 
119     return ret;
120 }
121 
122 /* AS-REQ. Returns 0 on success. */
123 krb5_error_code
kau_j_as_req(const krb5_boolean ev_success,krb5_audit_state * state,char ** jout)124 kau_j_as_req(const krb5_boolean ev_success, krb5_audit_state *state,
125              char **jout)
126 {
127     krb5_error_code ret = 0;
128     k5_json_object obj = NULL;
129 
130     *jout = NULL;
131 
132     if (!state) {
133         *jout = NULL_STATE;
134         return 0;
135     }
136 
137     /* Main object. */
138     if (k5_json_object_create(&obj))
139         return ENOMEM;
140     /* Audit event_ID and ev_success. */
141     ret = eventinfo_to_value(obj, "AS_REQ", state->stage, ev_success);
142     if (ret)
143         goto error;
144     /* TGT ticket ID */
145     ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
146     if (ret)
147         goto error;
148     /* Request ID. */
149     ret = string_to_value(state->req_id, obj, AU_REQ_ID);
150     if (ret)
151         goto error;
152     /* Client's port and address. */
153     ret = int32_to_value(state->cl_port, obj, AU_FROMPORT);
154     if (ret)
155         goto error;
156     ret = addr_to_value(state->cl_addr, obj, AU_FROMADDR);
157     if (ret)
158         goto error;
159     /* KDC status msg */
160     ret = string_to_value(state->status, obj, AU_KDC_STATUS);
161     if (ret)
162         goto error;
163     /* non-local client's referral realm. */
164     ret = data_to_value(state->cl_realm, obj, AU_CREF_REALM);
165     if (ret)
166         goto error;
167     /* Request. */
168     ret = req_to_value(state->request, ev_success, obj);
169     if (ret == ENOMEM)
170         goto error;
171     /* Reply/ticket info. */
172     ret = rep_to_value(state->reply, ev_success, obj);
173     if (ret == ENOMEM)
174         goto error;
175     ret = k5_json_encode(obj, jout);
176 
177 error:
178     k5_json_release(obj);
179     return ret;
180 }
181 
182 /* TGS-REQ. Returns 0 on success. */
183 krb5_error_code
kau_j_tgs_req(const krb5_boolean ev_success,krb5_audit_state * state,char ** jout)184 kau_j_tgs_req(const krb5_boolean ev_success, krb5_audit_state *state,
185               char **jout)
186 {
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;
191 
192     *jout = NULL;
193 
194     if (!state) {
195         *jout = NULL_STATE;
196         return 0;
197     }
198 
199     /* Main object. */
200     if (k5_json_object_create(&obj))
201         return ENOMEM;
202 
203     /* Audit Event ID and ev_success. */
204     ret = eventinfo_to_value(obj, "TGS_REQ", state->stage, ev_success);
205     if (ret)
206         goto error;
207     /* Primary and derived ticket IDs. */
208     ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
209     if (ret)
210         goto error;
211     ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
212     if (ret)
213         goto error;
214     /* Request ID */
215     ret = string_to_value(state->req_id, obj, AU_REQ_ID);
216     if (ret)
217         goto error;
218     /* client’s address and port. */
219     ret = int32_to_value(state->cl_port, obj, AU_FROMPORT);
220     if (ret)
221         goto error;
222     ret = addr_to_value(state->cl_addr, obj, AU_FROMADDR);
223     if (ret)
224         goto error;
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;
231     }
232     ret = int32_to_value(tkt_renewed, obj, AU_TKT_RENEWED);
233     if (ret)
234         goto error;
235     ret = int32_to_value(tkt_validated, obj, AU_TKT_VALIDATED);
236     if (ret)
237         goto error;
238     /* KDC status msg, including "ISSUE". */
239     ret = string_to_value(state->status, obj, AU_KDC_STATUS);
240     if (ret)
241         goto error;
242     /* request */
243     ret = req_to_value(req, ev_success, obj);
244     if (ret == ENOMEM)
245         goto error;
246     /* reply/ticket */
247     ret = rep_to_value(state->reply, ev_success, obj);
248     if (ret == ENOMEM)
249         goto error;
250     ret = k5_json_encode(obj, jout);
251 
252 error:
253     k5_json_release(obj);
254     return ret;
255 }
256 
257 /* S4U2Self protocol extension. Returns 0 on success. */
258 krb5_error_code
kau_j_tgs_s4u2self(const krb5_boolean ev_success,krb5_audit_state * state,char ** jout)259 kau_j_tgs_s4u2self(const krb5_boolean ev_success, krb5_audit_state *state,
260                    char **jout)
261 {
262     krb5_error_code ret = 0;
263     k5_json_object obj = NULL;
264 
265     *jout = NULL;
266 
267     if (!state) {
268         *jout = NULL_STATE;
269         return 0;
270     }
271 
272     /* Main object. */
273     if (k5_json_object_create(&obj))
274         return ENOMEM;
275 
276     /* Audit Event ID and ev_success. */
277     ret = eventinfo_to_value(obj, "S4U2SELF", state->stage, ev_success);
278     if (ret)
279         goto error;
280     /* Front-end server's TGT ticket ID. */
281     ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
282     if (ret)
283         goto error;
284     /* service "to self" ticket or referral TGT ticket ID. */
285     ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
286     if (ret)
287         goto error;
288     /* Request ID. */
289     ret = string_to_value(state->req_id, obj, AU_REQ_ID);
290     if (ret)
291         goto error;
292     if (ev_success == FALSE) {
293         /* KDC status msg. */
294         ret = string_to_value(state->status, obj, AU_KDC_STATUS);
295         if (ret)
296             goto error;
297         /* Local policy or S4U protocol constraints. */
298         ret = int32_to_value(state->violation, obj, AU_VIOLATION);
299         if (ret)
300             goto error;
301     }
302     /* Impersonated user. */
303     ret = princ_to_value(state->s4u2self_user, obj, AU_REQ_S4U2S_USER);
304     if (ret)
305         goto error;
306 
307     ret = k5_json_encode(obj, jout);
308 
309 error:
310     k5_json_release(obj);
311     return ret;
312 }
313 
314 /* S4U2Proxy protocol extension. Returns 0 on success. */
315 krb5_error_code
kau_j_tgs_s4u2proxy(const krb5_boolean ev_success,krb5_audit_state * state,char ** jout)316 kau_j_tgs_s4u2proxy(const krb5_boolean ev_success, krb5_audit_state *state,
317                     char **jout)
318 {
319     krb5_error_code ret = 0;
320     k5_json_object obj = NULL;
321     krb5_kdc_req *req = state->request;
322 
323     *jout = NULL;
324 
325     if (!state) {
326         *jout = NULL_STATE;
327         return 0;
328     }
329 
330     /* Main object. */
331     if (k5_json_object_create(&obj))
332         return ENOMEM;
333 
334     /* Audit Event ID and ev_success. */
335     ret = eventinfo_to_value(obj, "S4U2PROXY", state->stage, ev_success);
336     if (ret)
337         goto error;
338     /* Front-end server's TGT ticket ID. */
339     ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
340     if (ret)
341         goto error;
342     /* Resource service or referral TGT ticket ID. */
343     ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
344     if (ret)
345         goto error;
346     /* User's evidence ticket ID. */
347     ret = string_to_value(state->evid_tkt_id, obj, AU_EVIDENCE_TKT_ID);
348     if (ret)
349         goto error;
350     /* Request ID. */
351     ret = string_to_value(state->req_id, obj, AU_REQ_ID);
352     if (ret)
353         goto error;
354 
355     if (ev_success == FALSE) {
356         /* KDC status msg. */
357         ret = string_to_value(state->status, obj, AU_KDC_STATUS);
358         if (ret)
359             goto error;
360         /* Local policy or S4U protocol constraints. */
361         ret = int32_to_value(state->violation, obj, AU_VIOLATION);
362         if (ret)
363             goto error;
364     }
365     /* Delegated user. */
366     if (req != NULL) {
367         ret = princ_to_value(req->second_ticket[0]->enc_part2->client,
368                              obj, AU_REQ_S4U2P_USER);
369         if (ret)
370             goto error;
371     }
372     ret = k5_json_encode(obj, jout);
373 
374 error:
375     k5_json_release(obj);
376     return ret;
377 }
378 
379 /* U2U. Returns 0 on success. */
380 krb5_error_code
kau_j_tgs_u2u(const krb5_boolean ev_success,krb5_audit_state * state,char ** jout)381 kau_j_tgs_u2u(const krb5_boolean ev_success, krb5_audit_state *state,
382               char **jout)
383 {
384     krb5_error_code ret = 0;
385     k5_json_object obj = NULL;
386     krb5_kdc_req *req = state->request;
387 
388     if (!state) {
389         *jout = NULL_STATE;
390         return 0;
391     }
392 
393     *jout = NULL;
394 
395     /* Main object. */
396     if (k5_json_object_create(&obj))
397         return ENOMEM;
398     /* Audit Event ID and ev_success. */
399     ret = eventinfo_to_value(obj, "U2U", state->stage, ev_success);
400     if (ret)
401         goto error;
402     /* Front-end server's TGT ticket ID. */
403     ret = string_to_value(state->tkt_in_id, obj, AU_TKT_IN_ID);
404     if (ret)
405         goto error;
406     /* Service ticket ID. */
407     ret = string_to_value(state->tkt_out_id, obj, AU_TKT_OUT_ID);
408     if (ret)
409         goto error;
410     /* Request ID. */
411     ret = string_to_value(state->req_id, obj, AU_REQ_ID);
412     if (ret)
413         goto error;
414 
415     if (ev_success == FALSE) {
416         /* KDC status msg. */
417         ret = string_to_value(state->status, obj, AU_KDC_STATUS);
418         if (ret)
419             goto error;
420     }
421     /* Client in the second ticket. */
422     ret = princ_to_value(req->second_ticket[0]->enc_part2->client,
423                          obj, AU_REQ_U2U_USER);
424     if (ret)
425         goto error;
426     /* Enctype of a session key of the second ticket. */
427     ret = int32_to_value(req->second_ticket[0]->enc_part2->session->enctype,
428                          obj, AU_SRV_ETYPE);
429     if (ret)
430         goto error;
431 
432     ret = k5_json_encode(obj, jout);
433 
434 error:
435     k5_json_release(obj);
436     return ret;
437 }
438 
439 /* Low level utilities */
440 
441 /* Converts string into a property of a JSON object. Returns 0 on success.*/
442 static krb5_error_code
string_to_value(const char * in,k5_json_object obj,const char * key)443 string_to_value(const char *in, k5_json_object obj, const char *key)
444 {
445     krb5_error_code ret = 0;
446     k5_json_string str = NULL;
447 
448     if (in == NULL)
449         return 0;
450 
451     ret = k5_json_string_create(in, &str);
452     if (ret)
453         return ret;
454     ret = k5_json_object_set(obj, key, str);
455     k5_json_release(str);
456 
457     return ret;
458 }
459 
460 /*
461  * Converts a krb5_data struct into a property of a JSON object.
462  * (Borrowed from preauth_otp.c)
463  * Returns 0 on success.
464  */
465 static krb5_error_code
data_to_value(krb5_data * data,k5_json_object obj,const char * key)466 data_to_value(krb5_data *data, k5_json_object obj, const char *key)
467 {
468     krb5_error_code ret = 0;
469     k5_json_string str = NULL;
470 
471     if (data == NULL || data->data == NULL || data->length < 1)
472         return 0;
473 
474     ret = k5_json_string_create_len(data->data, data->length, &str);
475     if (ret)
476         return ret;
477     ret = k5_json_object_set(obj, key, str);
478     k5_json_release(str);
479 
480     return ret;
481 }
482 
483 /*
484  * Converts krb5_int32 into a property of a JSON object.
485  * Returns 0 on success.
486  */
487 static krb5_error_code
int32_to_value(krb5_int32 int32,k5_json_object obj,const char * key)488 int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key)
489 {
490     krb5_error_code ret = 0;
491     k5_json_number num = NULL;
492 
493     ret = k5_json_number_create(int32, &num);
494     if (ret)
495         return ENOMEM;
496     ret = k5_json_object_set(obj, key, num);
497     k5_json_release(num);
498 
499     return ret;
500 }
501 
502 /*
503  * Converts krb5_boolean into a property of a JSON object.
504  * Returns 0 on success.
505  */
506 static krb5_error_code
bool_to_value(krb5_boolean in,k5_json_object obj,const char * key)507 bool_to_value(krb5_boolean in, k5_json_object obj, const char *key)
508 {
509     krb5_error_code ret = 0;
510     k5_json_bool b = 0;
511 
512     ret = k5_json_bool_create(in, &b);
513     if (ret)
514         return ENOMEM;
515 
516     ret = k5_json_object_set(obj, key, b);
517     k5_json_release(b);
518 
519     return ret;
520 }
521 
522 /* Wrapper-level utilities */
523 
524 /* Wrapper for stage and event_status tags. Returns 0 on success. */
525 static krb5_error_code
eventinfo_to_value(k5_json_object obj,const char * name,const int stage,const krb5_boolean ev_success)526 eventinfo_to_value(k5_json_object obj, const char *name,
527                    const int stage, const krb5_boolean ev_success)
528 {
529     krb5_error_code ret = 0;
530 
531     ret = string_to_value(name, obj, AU_EVENT_NAME);
532     if (ret)
533         return ret;
534     ret = int32_to_value(stage, obj, AU_STAGE);
535     if (!ret)
536         ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS);
537 
538     return ret;
539 }
540 
541 /*
542  * Converts krb5_principal into a property of a JSON object.
543  * Returns 0 on success.
544  */
545 static krb5_error_code
princ_to_value(krb5_principal princ,k5_json_object obj,const char * key)546 princ_to_value(krb5_principal princ, k5_json_object obj, const char *key)
547 {
548     krb5_error_code ret = 0;
549     k5_json_object tmp = NULL;
550     k5_json_array arr = NULL;
551     k5_json_string str = NULL;
552     int i = 0;
553 
554     if (princ == NULL || princ->data == NULL)
555         return 0;
556 
557     /* Main object. */
558     if (k5_json_object_create(&tmp))
559         return ENOMEM;
560 
561     ret = k5_json_array_create(&arr);
562     if (ret)
563         goto error;
564     for (i = 0; i < princ->length; i++) {
565         ret = k5_json_string_create_len((&princ->data[i])->data,
566                                        (&princ->data[i])->length, &str);
567         if (ret)
568             goto error;
569         ret = k5_json_array_add(arr, str);
570         k5_json_release(str);
571         if (ret)
572             goto error;
573     }
574     ret = k5_json_object_set(tmp, AU_COMPONENTS, arr);
575     if (ret)
576         goto error;
577     ret = data_to_value(&princ->realm, tmp, AU_REALM);
578     if (ret)
579         goto error;
580     ret = int32_to_value(princ->length, tmp, AU_LENGTH);
581     if (ret)
582         goto error;
583     ret = int32_to_value(princ->type, tmp, AU_TYPE);
584     if (ret)
585         goto error;
586 
587     ret = k5_json_object_set(obj, key, tmp);
588 
589 error:
590     k5_json_release(tmp);
591     k5_json_release(arr);
592     return ret;
593 }
594 
595 /*
596  * Helper for JSON encoding of krb5_address.
597  * Returns 0 on success.
598  */
599 static krb5_error_code
addr_to_obj(krb5_address * a,k5_json_object obj)600 addr_to_obj(krb5_address *a, k5_json_object obj)
601 {
602     krb5_error_code ret = 0;
603     k5_json_number num = NULL;
604     k5_json_array arr = NULL;
605     int i;
606 
607     if (a == NULL || a->contents == NULL || a->length <= 0)
608         return 0;
609 
610     ret = int32_to_value(a->addrtype, obj, AU_TYPE);
611     if (ret)
612         goto error;
613     ret = int32_to_value(a->length, obj, AU_LENGTH);
614     if (ret)
615         goto error;
616 
617     if (a->addrtype == ADDRTYPE_INET || a->addrtype == ADDRTYPE_INET6) {
618         ret = k5_json_array_create(&arr);
619         if (ret)
620             goto error;
621         for (i = 0; i < (int)a->length; i++) {
622             ret = k5_json_number_create(a->contents[i], &num);
623             if (ret)
624                 goto error;
625             ret = k5_json_array_add(arr, num);
626             k5_json_release(num);
627             if (ret)
628                 goto error;
629         }
630         ret = k5_json_object_set(obj, AU_IP, arr);
631         if (ret)
632             goto error;
633     } else if (a->addrtype == ADDRTYPE_UNIXSOCK) {
634         k5_json_string str = NULL;
635 
636         ret = k5_json_string_create_len(a->contents, a->length, &str);
637         if (ret)
638             return ret;
639 
640         ret = k5_json_object_set(obj, AU_PATH, str);
641         k5_json_release(str);
642         if (ret)
643             goto error;
644     }
645 
646 error:
647     k5_json_release(arr);
648     return ret;
649 }
650 
651 /*
652  * Converts krb5_fulladdr into a property of a JSON object.
653  * Returns 0 on success.
654  */
655 static krb5_error_code
addr_to_value(const krb5_address * address,k5_json_object obj,const char * key)656 addr_to_value(const krb5_address *address, k5_json_object obj, const char *key)
657 {
658     krb5_error_code ret = 0;
659     k5_json_object addr_obj = NULL;
660 
661     if (address == NULL)
662         return 0;
663 
664     ret = k5_json_object_create(&addr_obj);
665     if (ret)
666         return ret;
667     ret = addr_to_obj((krb5_address *)address, addr_obj);
668     if (!ret)
669         ret = k5_json_object_set(obj, key, addr_obj);
670     k5_json_release(addr_obj);
671 
672     return ret;
673 }
674 
675 /*
676  * Helper for JSON encoding of krb5_kdc_req.
677  * Returns 0 on success.
678  */
679 static krb5_error_code
req_to_value(krb5_kdc_req * req,const krb5_boolean ev_success,k5_json_object obj)680 req_to_value(krb5_kdc_req *req, const krb5_boolean ev_success,
681              k5_json_object obj)
682 {
683     krb5_error_code ret = 0;
684     k5_json_number num = NULL;
685     k5_json_string str = NULL;
686     k5_json_object tmpa = NULL;
687     k5_json_array arr = NULL, arra = NULL, arrpa = NULL;
688     krb5_pa_data **padata;
689     int i = 0;
690 
691     if (req == NULL)
692         return 0;
693 
694     ret = princ_to_value(req->client, obj, AU_REQ_CLIENT);
695     if (ret)
696         goto error;
697     ret = princ_to_value(req->server, obj, AU_REQ_SERVER);
698     if (ret)
699         goto error;
700 
701     ret = int32_to_value(req->kdc_options, obj, AU_REQ_KDC_OPTIONS);
702         if (ret)
703             goto error;
704     ret = int32_to_value(req->from, obj, AU_REQ_TKT_START);
705         if (ret)
706             goto error;
707     ret = int32_to_value(req->till, obj, AU_REQ_TKT_END);
708         if (ret)
709             goto error;
710     ret = int32_to_value(req->rtime, obj, AU_REQ_TKT_RENEW_TILL);
711         if (ret)
712             goto error;
713     /* Available/requested enctypes. */
714     ret = k5_json_array_create(&arr);
715     if (ret)
716         goto error;
717     for (i = 0; (i < req->nktypes); i++) {
718         if (req->ktype[i] > 0) {
719             ret = k5_json_number_create(req->ktype[i], &num);
720             if (ret)
721                 goto error;
722             ret = k5_json_array_add(arr, num);
723             k5_json_release(num);
724             if (ret)
725                 goto error;
726         }
727     }
728     ret = k5_json_object_set(obj, AU_REQ_AVAIL_ETYPES, arr);
729     if (ret)
730         goto error;
731     /* Pre-auth types. */
732     if (ev_success == TRUE && req->padata) {
733             ret = k5_json_array_create(&arrpa);
734             if (ret)
735                 goto error;
736             for (padata = req->padata; *padata; padata++) {
737                 if (strlen(map_patype((*padata)->pa_type)) > 1) {
738                     ret = k5_json_string_create(map_patype((*padata)->pa_type),
739                                                 &str);
740                     if (ret)
741                         goto error;
742                     ret = k5_json_array_add(arrpa, str);
743                     k5_json_release(str);
744                     if (ret)
745                         goto error;
746                 }
747             }
748             ret = k5_json_object_set(obj, AU_REQ_PA_TYPE, arrpa);
749     }
750     /* List of requested addresses. */
751     if (req->addresses) {
752         ret = k5_json_array_create(&arra);
753         if (ret)
754                 goto error;
755         for (i = 0; req->addresses[i] != NULL; i++) {
756             ret = k5_json_object_create(&tmpa);
757             if (ret)
758                 goto error;
759             ret = addr_to_obj(req->addresses[i], tmpa);
760             if (!ret)
761                 ret = k5_json_array_add(arra, tmpa);
762             k5_json_release(tmpa);
763             if (ret)
764                 goto error;
765         }
766         ret = k5_json_object_set(obj, AU_REQ_ADDRESSES, arra);
767         if (ret)
768             goto error;
769     }
770 error:
771     k5_json_release(arr);
772     k5_json_release(arra);
773     k5_json_release(arrpa);
774     return ret;
775 }
776 
777 /*
778  * Helper for JSON encoding of krb5_kdc_rep.
779  * Returns 0 on success.
780  */
781 static krb5_error_code
rep_to_value(krb5_kdc_rep * rep,const krb5_boolean ev_success,k5_json_object obj)782 rep_to_value(krb5_kdc_rep *rep, const krb5_boolean ev_success,
783              k5_json_object obj)
784 {
785     krb5_error_code ret = 0;
786     krb5_pa_data **padata;
787     k5_json_array arrpa = NULL;
788     k5_json_string str = NULL;
789 
790     if (rep == NULL)
791         return 0;
792 
793     if (ev_success == TRUE) {
794         ret = tkt_to_value(rep->ticket, obj, AU_REP_TICKET);
795         /* Enctype of the reply-encrypting key. */
796         ret = int32_to_value(rep->enc_part.enctype, obj, AU_REP_ETYPE);
797         if (ret)
798             goto error;
799     } else {
800 
801         if (rep->padata) {
802             ret = k5_json_array_create(&arrpa);
803             if (ret)
804                 goto error;
805             for (padata = rep->padata; *padata; padata++) {
806                 if (strlen(map_patype((*padata)->pa_type)) > 1) {
807                     ret = k5_json_string_create(map_patype((*padata)->pa_type),
808                                                           &str);
809                     if (ret)
810                         goto error;
811                     ret = k5_json_array_add(arrpa, str);
812                     k5_json_release(str);
813                     if (ret)
814                         goto error;
815                 }
816             }
817         }
818         ret = k5_json_object_set(obj, AU_REP_PA_TYPE, arrpa);
819     }
820 error:
821     k5_json_release(arrpa);
822     return ret;
823 }
824 
825 /*
826  * Converts krb5_ticket into a property of a JSON object.
827  * Returns 0 on success.
828  */
829 static krb5_error_code
tkt_to_value(krb5_ticket * tkt,k5_json_object obj,const char * key)830 tkt_to_value(krb5_ticket *tkt, k5_json_object obj,
831               const char *key)
832 {
833     krb5_error_code ret = 0;
834     k5_json_object tmp = NULL;
835     krb5_enc_tkt_part *part2 = NULL;
836 
837     if (tkt == NULL)
838         return 0;
839 
840     /* Main object. */
841     if (k5_json_object_create(&tmp))
842         return ENOMEM;
843 
844     /*
845      * CNAME - potentially redundant data...
846      * ...but it is part of the ticket. So, record it as such.
847      */
848     ret = princ_to_value(tkt->server, tmp, AU_CNAME);
849     if (ret)
850         goto error;
851     ret = princ_to_value(tkt->server, tmp, AU_SNAME);
852     if (ret)
853         goto error;
854     /* Enctype of a long-term key of service. */
855     if (tkt->enc_part.enctype)
856         ret = int32_to_value(tkt->enc_part.enctype, tmp, AU_SRV_ETYPE);
857     if (ret)
858         goto error;
859     if (tkt->enc_part2)
860         part2 = tkt->enc_part2;
861     if (part2) {
862         ret = princ_to_value(part2->client, tmp, AU_CNAME);
863         if (ret)
864             goto error;
865         ret = int32_to_value(part2->flags, tmp, AU_FLAGS);
866         if (ret)
867             goto error;
868         /* Chosen by KDC session key enctype (short-term key). */
869         ret = int32_to_value(part2->session->enctype, tmp, AU_SESS_ETYPE);
870         if (ret)
871             goto error;
872         ret = int32_to_value(part2->times.starttime, tmp, AU_START);
873         if (ret)
874             goto error;
875         ret = int32_to_value(part2->times.endtime, tmp, AU_END);
876         if (ret)
877             goto error;
878         ret = int32_to_value(part2->times.renew_till, tmp, AU_RENEW_TILL);
879         if (ret)
880             goto error;
881         ret = int32_to_value(part2->times.authtime, tmp, AU_AUTHTIME);
882         if (ret)
883             goto error;
884         if (part2->transited.tr_contents.length > 0) {
885             ret = data_to_value(&part2->transited.tr_contents,
886                                tmp, AU_TR_CONTENTS);
887             if (ret)
888                 goto error;
889         }
890     } /* part2 != NULL */
891 
892     if (!ret)
893         ret = k5_json_object_set(obj, key, tmp);
894 
895 error:
896     k5_json_release(tmp);
897     return ret;
898 }
899 
900 /* Map preauth numeric type to the naming string. */
901 struct _patype_str {
902     krb5_preauthtype id;
903     char *name;
904 };
905 struct _patype_str  patype_str[] = {
906     {KRB5_PADATA_ENC_TIMESTAMP, "ENC_TIMESTAMP"},
907     {KRB5_PADATA_PW_SALT, "PW_SALT"},
908     {KRB5_PADATA_ENC_UNIX_TIME, "ENC_UNIX_TIME"},
909     {KRB5_PADATA_SAM_CHALLENGE, "SAM_CHALLENGE"},
910     {KRB5_PADATA_SAM_RESPONSE, "SAM_RESPONSE"},
911     {KRB5_PADATA_PK_AS_REQ_OLD, "PK_AS_REQ_OLD"},
912     {KRB5_PADATA_PK_AS_REP_OLD, "PK_AS_REP_OLD"},
913     {KRB5_PADATA_PK_AS_REQ, "PK_AS_REQ"},
914     {KRB5_PADATA_PK_AS_REP, "PK_AS_REP"},
915     {KRB5_PADATA_ETYPE_INFO2, "ETYPE_INFO2"},
916     {KRB5_PADATA_SAM_CHALLENGE_2, "SAM_CHALLENGE_2"},
917     {KRB5_PADATA_SAM_RESPONSE_2, "SAM_RESPONSE_2"},
918     {KRB5_PADATA_PAC_REQUEST, "PAC_REQUEST"},
919     {KRB5_PADATA_FOR_USER, "FOR_USER"},
920     {KRB5_PADATA_S4U_X509_USER, "S4U_X509_USER"},
921     {KRB5_PADATA_ENCRYPTED_CHALLENGE, "ENCRYPTED_CHALLENGE"},
922     {KRB5_PADATA_OTP_CHALLENGE, "OTP_CHALLENGE"},
923     {KRB5_PADATA_OTP_REQUEST, "OTP_REQUEST"},
924     {KRB5_PADATA_OTP_PIN_CHANGE, "OTP_PIN_CHANGE"}
925 };
926 
927 
928 static char *
map_patype(krb5_preauthtype pa_type)929 map_patype(krb5_preauthtype pa_type)
930 {
931     int i = 0;
932     int n = sizeof(patype_str)/sizeof(patype_str[0]);
933 
934     for (i = 0; i < n; i++) {
935         if (pa_type == patype_str[i].id)
936             return patype_str[i].name;
937     }
938     return "";
939 }
940