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