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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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