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 if (req != NULL) { 423 ret = princ_to_value(req->second_ticket[0]->enc_part2->client, 424 obj, AU_REQ_U2U_USER); 425 if (ret) 426 goto error; 427 } 428 /* Enctype of a session key of the second ticket. */ 429 ret = int32_to_value(req->second_ticket[0]->enc_part2->session->enctype, 430 obj, AU_SRV_ETYPE); 431 if (ret) 432 goto error; 433 434 ret = k5_json_encode(obj, jout); 435 436 error: 437 k5_json_release(obj); 438 return ret; 439 } 440 441 /* Low level utilities */ 442 443 /* Converts string into a property of a JSON object. Returns 0 on success.*/ 444 static krb5_error_code 445 string_to_value(const char *in, k5_json_object obj, const char *key) 446 { 447 krb5_error_code ret = 0; 448 k5_json_string str = NULL; 449 450 if (in == NULL) 451 return 0; 452 453 ret = k5_json_string_create(in, &str); 454 if (ret) 455 return ret; 456 ret = k5_json_object_set(obj, key, str); 457 k5_json_release(str); 458 459 return ret; 460 } 461 462 /* 463 * Converts a krb5_data struct into a property of a JSON object. 464 * (Borrowed from preauth_otp.c) 465 * Returns 0 on success. 466 */ 467 static krb5_error_code 468 data_to_value(krb5_data *data, k5_json_object obj, const char *key) 469 { 470 krb5_error_code ret = 0; 471 k5_json_string str = NULL; 472 473 if (data == NULL || data->data == NULL || data->length < 1) 474 return 0; 475 476 ret = k5_json_string_create_len(data->data, data->length, &str); 477 if (ret) 478 return ret; 479 ret = k5_json_object_set(obj, key, str); 480 k5_json_release(str); 481 482 return ret; 483 } 484 485 /* 486 * Converts krb5_int32 into a property of a JSON object. 487 * Returns 0 on success. 488 */ 489 static krb5_error_code 490 int32_to_value(krb5_int32 int32, k5_json_object obj, const char *key) 491 { 492 krb5_error_code ret = 0; 493 k5_json_number num = NULL; 494 495 ret = k5_json_number_create(int32, &num); 496 if (ret) 497 return ENOMEM; 498 ret = k5_json_object_set(obj, key, num); 499 k5_json_release(num); 500 501 return ret; 502 } 503 504 /* 505 * Converts krb5_boolean into a property of a JSON object. 506 * Returns 0 on success. 507 */ 508 static krb5_error_code 509 bool_to_value(krb5_boolean in, k5_json_object obj, const char *key) 510 { 511 krb5_error_code ret = 0; 512 k5_json_bool b = 0; 513 514 ret = k5_json_bool_create(in, &b); 515 if (ret) 516 return ENOMEM; 517 518 ret = k5_json_object_set(obj, key, b); 519 k5_json_release(b); 520 521 return ret; 522 } 523 524 /* Wrapper-level utilities */ 525 526 /* Wrapper for stage and event_status tags. Returns 0 on success. */ 527 static krb5_error_code 528 eventinfo_to_value(k5_json_object obj, const char *name, 529 const int stage, const krb5_boolean ev_success) 530 { 531 krb5_error_code ret = 0; 532 533 ret = string_to_value(name, obj, AU_EVENT_NAME); 534 if (ret) 535 return ret; 536 ret = int32_to_value(stage, obj, AU_STAGE); 537 if (!ret) 538 ret = bool_to_value(ev_success, obj, AU_EVENT_STATUS); 539 540 return ret; 541 } 542 543 /* 544 * Converts krb5_principal into a property of a JSON object. 545 * Returns 0 on success. 546 */ 547 static krb5_error_code 548 princ_to_value(krb5_principal princ, k5_json_object obj, const char *key) 549 { 550 krb5_error_code ret = 0; 551 k5_json_object tmp = NULL; 552 k5_json_array arr = NULL; 553 k5_json_string str = NULL; 554 int i = 0; 555 556 if (princ == NULL || princ->data == NULL) 557 return 0; 558 559 /* Main object. */ 560 if (k5_json_object_create(&tmp)) 561 return ENOMEM; 562 563 ret = k5_json_array_create(&arr); 564 if (ret) 565 goto error; 566 for (i = 0; i < princ->length; i++) { 567 ret = k5_json_string_create_len((&princ->data[i])->data, 568 (&princ->data[i])->length, &str); 569 if (ret) 570 goto error; 571 ret = k5_json_array_add(arr, str); 572 k5_json_release(str); 573 if (ret) 574 goto error; 575 } 576 ret = k5_json_object_set(tmp, AU_COMPONENTS, arr); 577 if (ret) 578 goto error; 579 ret = data_to_value(&princ->realm, tmp, AU_REALM); 580 if (ret) 581 goto error; 582 ret = int32_to_value(princ->length, tmp, AU_LENGTH); 583 if (ret) 584 goto error; 585 ret = int32_to_value(princ->type, tmp, AU_TYPE); 586 if (ret) 587 goto error; 588 589 ret = k5_json_object_set(obj, key, tmp); 590 591 error: 592 k5_json_release(tmp); 593 k5_json_release(arr); 594 return ret; 595 } 596 597 /* 598 * Helper for JSON encoding of krb5_address. 599 * Returns 0 on success. 600 */ 601 static krb5_error_code 602 addr_to_obj(krb5_address *a, k5_json_object obj) 603 { 604 krb5_error_code ret = 0; 605 k5_json_number num = NULL; 606 k5_json_array arr = NULL; 607 int i; 608 609 if (a == NULL || a->contents == NULL || a->length <= 0) 610 return 0; 611 612 ret = int32_to_value(a->addrtype, obj, AU_TYPE); 613 if (ret) 614 goto error; 615 ret = int32_to_value(a->length, obj, AU_LENGTH); 616 if (ret) 617 goto error; 618 619 if (a->addrtype == ADDRTYPE_INET || a->addrtype == ADDRTYPE_INET6) { 620 ret = k5_json_array_create(&arr); 621 if (ret) 622 goto error; 623 for (i = 0; i < (int)a->length; i++) { 624 ret = k5_json_number_create(a->contents[i], &num); 625 if (ret) 626 goto error; 627 ret = k5_json_array_add(arr, num); 628 k5_json_release(num); 629 if (ret) 630 goto error; 631 } 632 ret = k5_json_object_set(obj, AU_IP, arr); 633 if (ret) 634 goto error; 635 } 636 637 error: 638 k5_json_release(arr); 639 return ret; 640 } 641 642 /* 643 * Converts krb5_fulladdr into a property of a JSON object. 644 * Returns 0 on success. 645 */ 646 static krb5_error_code 647 addr_to_value(const krb5_address *address, k5_json_object obj, const char *key) 648 { 649 krb5_error_code ret = 0; 650 k5_json_object addr_obj = NULL; 651 652 if (address == NULL) 653 return 0; 654 655 ret = k5_json_object_create(&addr_obj); 656 if (ret) 657 return ret; 658 ret = addr_to_obj((krb5_address *)address, addr_obj); 659 if (!ret) 660 ret = k5_json_object_set(obj, key, addr_obj); 661 k5_json_release(addr_obj); 662 663 return ret; 664 } 665 666 /* 667 * Helper for JSON encoding of krb5_kdc_req. 668 * Returns 0 on success. 669 */ 670 static krb5_error_code 671 req_to_value(krb5_kdc_req *req, const krb5_boolean ev_success, 672 k5_json_object obj) 673 { 674 krb5_error_code ret = 0; 675 k5_json_number num = NULL; 676 k5_json_string str = NULL; 677 k5_json_object tmpa = NULL; 678 k5_json_array arr = NULL, arra = NULL, arrpa = NULL; 679 krb5_pa_data **padata; 680 int i = 0; 681 682 if (req == NULL) 683 return 0; 684 685 ret = princ_to_value(req->client, obj, AU_REQ_CLIENT); 686 if (ret) 687 goto error; 688 ret = princ_to_value(req->server, obj, AU_REQ_SERVER); 689 if (ret) 690 goto error; 691 692 ret = int32_to_value(req->kdc_options, obj, AU_REQ_KDC_OPTIONS); 693 if (ret) 694 goto error; 695 ret = int32_to_value(req->from, obj, AU_REQ_TKT_START); 696 if (ret) 697 goto error; 698 ret = int32_to_value(req->till, obj, AU_REQ_TKT_END); 699 if (ret) 700 goto error; 701 ret = int32_to_value(req->rtime, obj, AU_REQ_TKT_RENEW_TILL); 702 if (ret) 703 goto error; 704 /* Available/requested enctypes. */ 705 ret = k5_json_array_create(&arr); 706 if (ret) 707 goto error; 708 for (i = 0; (i < req->nktypes); i++) { 709 if (req->ktype[i] > 0) { 710 ret = k5_json_number_create(req->ktype[i], &num); 711 if (ret) 712 goto error; 713 ret = k5_json_array_add(arr, num); 714 k5_json_release(num); 715 if (ret) 716 goto error; 717 } 718 } 719 ret = k5_json_object_set(obj, AU_REQ_AVAIL_ETYPES, arr); 720 if (ret) 721 goto error; 722 /* Pre-auth types. */ 723 if (ev_success == TRUE && req->padata) { 724 ret = k5_json_array_create(&arrpa); 725 if (ret) 726 goto error; 727 for (padata = req->padata; *padata; padata++) { 728 if (strlen(map_patype((*padata)->pa_type)) > 1) { 729 ret = k5_json_string_create(map_patype((*padata)->pa_type), 730 &str); 731 if (ret) 732 goto error; 733 ret = k5_json_array_add(arrpa, str); 734 k5_json_release(str); 735 if (ret) 736 goto error; 737 } 738 } 739 ret = k5_json_object_set(obj, AU_REQ_PA_TYPE, arrpa); 740 } 741 /* List of requested addresses. */ 742 if (req->addresses) { 743 ret = k5_json_array_create(&arra); 744 if (ret) 745 goto error; 746 for (i = 0; req->addresses[i] != NULL; i++) { 747 ret = k5_json_object_create(&tmpa); 748 if (ret) 749 goto error; 750 ret = addr_to_obj(req->addresses[i], tmpa); 751 if (!ret) 752 ret = k5_json_array_add(arra, tmpa); 753 k5_json_release(tmpa); 754 if (ret) 755 goto error; 756 } 757 ret = k5_json_object_set(obj, AU_REQ_ADDRESSES, arra); 758 if (ret) 759 goto error; 760 } 761 error: 762 k5_json_release(arr); 763 k5_json_release(arra); 764 k5_json_release(arrpa); 765 return ret; 766 } 767 768 /* 769 * Helper for JSON encoding of krb5_kdc_rep. 770 * Returns 0 on success. 771 */ 772 static krb5_error_code 773 rep_to_value(krb5_kdc_rep *rep, const krb5_boolean ev_success, 774 k5_json_object obj) 775 { 776 krb5_error_code ret = 0; 777 krb5_pa_data **padata; 778 k5_json_array arrpa = NULL; 779 k5_json_string str = NULL; 780 781 if (rep == NULL) 782 return 0; 783 784 if (ev_success == TRUE) { 785 ret = tkt_to_value(rep->ticket, obj, AU_REP_TICKET); 786 /* Enctype of the reply-encrypting key. */ 787 ret = int32_to_value(rep->enc_part.enctype, obj, AU_REP_ETYPE); 788 if (ret) 789 goto error; 790 } else { 791 792 if (rep->padata) { 793 ret = k5_json_array_create(&arrpa); 794 if (ret) 795 goto error; 796 for (padata = rep->padata; *padata; padata++) { 797 if (strlen(map_patype((*padata)->pa_type)) > 1) { 798 ret = k5_json_string_create(map_patype((*padata)->pa_type), 799 &str); 800 if (ret) 801 goto error; 802 ret = k5_json_array_add(arrpa, str); 803 k5_json_release(str); 804 if (ret) 805 goto error; 806 } 807 } 808 } 809 ret = k5_json_object_set(obj, AU_REP_PA_TYPE, arrpa); 810 } 811 error: 812 k5_json_release(arrpa); 813 return ret; 814 } 815 816 /* 817 * Converts krb5_ticket into a property of a JSON object. 818 * Returns 0 on success. 819 */ 820 static krb5_error_code 821 tkt_to_value(krb5_ticket *tkt, k5_json_object obj, 822 const char *key) 823 { 824 krb5_error_code ret = 0; 825 k5_json_object tmp = NULL; 826 krb5_enc_tkt_part *part2 = NULL; 827 828 if (tkt == NULL) 829 return 0; 830 831 /* Main object. */ 832 if (k5_json_object_create(&tmp)) 833 return ENOMEM; 834 835 /* 836 * CNAME - potentially redundant data... 837 * ...but it is part of the ticket. So, record it as such. 838 */ 839 ret = princ_to_value(tkt->server, tmp, AU_CNAME); 840 if (ret) 841 goto error; 842 ret = princ_to_value(tkt->server, tmp, AU_SNAME); 843 if (ret) 844 goto error; 845 /* Enctype of a long-term key of service. */ 846 if (tkt->enc_part.enctype) 847 ret = int32_to_value(tkt->enc_part.enctype, tmp, AU_SRV_ETYPE); 848 if (ret) 849 goto error; 850 if (tkt->enc_part2) 851 part2 = tkt->enc_part2; 852 if (part2) { 853 ret = princ_to_value(part2->client, tmp, AU_CNAME); 854 if (ret) 855 goto error; 856 ret = int32_to_value(part2->flags, tmp, AU_FLAGS); 857 if (ret) 858 goto error; 859 /* Chosen by KDC session key enctype (short-term key). */ 860 ret = int32_to_value(part2->session->enctype, tmp, AU_SESS_ETYPE); 861 if (ret) 862 goto error; 863 ret = int32_to_value(part2->times.starttime, tmp, AU_START); 864 if (ret) 865 goto error; 866 ret = int32_to_value(part2->times.endtime, tmp, AU_END); 867 if (ret) 868 goto error; 869 ret = int32_to_value(part2->times.renew_till, tmp, AU_RENEW_TILL); 870 if (ret) 871 goto error; 872 ret = int32_to_value(part2->times.authtime, tmp, AU_AUTHTIME); 873 if (ret) 874 goto error; 875 if (part2->transited.tr_contents.length > 0) { 876 ret = data_to_value(&part2->transited.tr_contents, 877 tmp, AU_TR_CONTENTS); 878 if (ret) 879 goto error; 880 } 881 } /* part2 != NULL */ 882 883 if (!ret) 884 ret = k5_json_object_set(obj, key, tmp); 885 886 error: 887 k5_json_release(tmp); 888 return ret; 889 } 890 891 /* Map preauth numeric type to the naming string. */ 892 struct _patype_str { 893 krb5_preauthtype id; 894 char *name; 895 }; 896 struct _patype_str patype_str[] = { 897 {KRB5_PADATA_ENC_TIMESTAMP, "ENC_TIMESTAMP"}, 898 {KRB5_PADATA_PW_SALT, "PW_SALT"}, 899 {KRB5_PADATA_ENC_UNIX_TIME, "ENC_UNIX_TIME"}, 900 {KRB5_PADATA_SAM_CHALLENGE, "SAM_CHALLENGE"}, 901 {KRB5_PADATA_SAM_RESPONSE, "SAM_RESPONSE"}, 902 {KRB5_PADATA_PK_AS_REQ_OLD, "PK_AS_REQ_OLD"}, 903 {KRB5_PADATA_PK_AS_REP_OLD, "PK_AS_REP_OLD"}, 904 {KRB5_PADATA_PK_AS_REQ, "PK_AS_REQ"}, 905 {KRB5_PADATA_PK_AS_REP, "PK_AS_REP"}, 906 {KRB5_PADATA_ETYPE_INFO2, "ETYPE_INFO2"}, 907 {KRB5_PADATA_SAM_CHALLENGE_2, "SAM_CHALLENGE_2"}, 908 {KRB5_PADATA_SAM_RESPONSE_2, "SAM_RESPONSE_2"}, 909 {KRB5_PADATA_PAC_REQUEST, "PAC_REQUEST"}, 910 {KRB5_PADATA_FOR_USER, "FOR_USER"}, 911 {KRB5_PADATA_S4U_X509_USER, "S4U_X509_USER"}, 912 {KRB5_PADATA_ENCRYPTED_CHALLENGE, "ENCRYPTED_CHALLENGE"}, 913 {KRB5_PADATA_OTP_CHALLENGE, "OTP_CHALLENGE"}, 914 {KRB5_PADATA_OTP_REQUEST, "OTP_REQUEST"}, 915 {KRB5_PADATA_OTP_PIN_CHANGE, "OTP_PIN_CHANGE"} 916 }; 917 918 919 static char * 920 map_patype(krb5_preauthtype pa_type) 921 { 922 int i = 0; 923 int n = sizeof(patype_str)/sizeof(patype_str[0]); 924 925 for (i = 0; i < n; i++) { 926 if (pa_type == patype_str[i].id) 927 return patype_str[i].name; 928 } 929 return ""; 930 } 931