1 /* 2 * Copyright (c) 2006 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "krb5_locl.h" 35 #include "digest_asn1.h" 36 37 #ifndef HEIMDAL_SMALLER 38 39 struct krb5_digest_data { 40 char *cbtype; 41 char *cbbinding; 42 43 DigestInit init; 44 DigestInitReply initReply; 45 DigestRequest request; 46 DigestResponse response; 47 }; 48 49 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 50 krb5_digest_alloc(krb5_context context, krb5_digest *digest) 51 { 52 krb5_digest d; 53 54 d = calloc(1, sizeof(*d)); 55 if (d == NULL) { 56 *digest = NULL; 57 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 58 return ENOMEM; 59 } 60 *digest = d; 61 62 return 0; 63 } 64 65 KRB5_LIB_FUNCTION void KRB5_LIB_CALL 66 krb5_digest_free(krb5_digest digest) 67 { 68 if (digest == NULL) 69 return; 70 free_DigestInit(&digest->init); 71 free_DigestInitReply(&digest->initReply); 72 free_DigestRequest(&digest->request); 73 free_DigestResponse(&digest->response); 74 memset(digest, 0, sizeof(*digest)); 75 free(digest); 76 return; 77 } 78 79 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 80 krb5_digest_set_server_cb(krb5_context context, 81 krb5_digest digest, 82 const char *type, 83 const char *binding) 84 { 85 if (digest->init.channel) { 86 krb5_set_error_message(context, EINVAL, 87 N_("server channel binding already set", "")); 88 return EINVAL; 89 } 90 digest->init.channel = calloc(1, sizeof(*digest->init.channel)); 91 if (digest->init.channel == NULL) 92 goto error; 93 94 digest->init.channel->cb_type = strdup(type); 95 if (digest->init.channel->cb_type == NULL) 96 goto error; 97 98 digest->init.channel->cb_binding = strdup(binding); 99 if (digest->init.channel->cb_binding == NULL) 100 goto error; 101 return 0; 102 error: 103 if (digest->init.channel) { 104 free(digest->init.channel->cb_type); 105 free(digest->init.channel->cb_binding); 106 free(digest->init.channel); 107 digest->init.channel = NULL; 108 } 109 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 110 return ENOMEM; 111 } 112 113 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 114 krb5_digest_set_type(krb5_context context, 115 krb5_digest digest, 116 const char *type) 117 { 118 if (digest->init.type) { 119 krb5_set_error_message(context, EINVAL, "client type already set"); 120 return EINVAL; 121 } 122 digest->init.type = strdup(type); 123 if (digest->init.type == NULL) { 124 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 125 return ENOMEM; 126 } 127 return 0; 128 } 129 130 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 131 krb5_digest_set_hostname(krb5_context context, 132 krb5_digest digest, 133 const char *hostname) 134 { 135 if (digest->init.hostname) { 136 krb5_set_error_message(context, EINVAL, "server hostname already set"); 137 return EINVAL; 138 } 139 digest->init.hostname = malloc(sizeof(*digest->init.hostname)); 140 if (digest->init.hostname == NULL) { 141 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 142 return ENOMEM; 143 } 144 *digest->init.hostname = strdup(hostname); 145 if (*digest->init.hostname == NULL) { 146 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 147 free(digest->init.hostname); 148 digest->init.hostname = NULL; 149 return ENOMEM; 150 } 151 return 0; 152 } 153 154 KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL 155 krb5_digest_get_server_nonce(krb5_context context, 156 krb5_digest digest) 157 { 158 return digest->initReply.nonce; 159 } 160 161 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 162 krb5_digest_set_server_nonce(krb5_context context, 163 krb5_digest digest, 164 const char *nonce) 165 { 166 if (digest->request.serverNonce) { 167 krb5_set_error_message(context, EINVAL, N_("nonce already set", "")); 168 return EINVAL; 169 } 170 digest->request.serverNonce = strdup(nonce); 171 if (digest->request.serverNonce == NULL) { 172 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 173 return ENOMEM; 174 } 175 return 0; 176 } 177 178 KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL 179 krb5_digest_get_opaque(krb5_context context, 180 krb5_digest digest) 181 { 182 return digest->initReply.opaque; 183 } 184 185 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 186 krb5_digest_set_opaque(krb5_context context, 187 krb5_digest digest, 188 const char *opaque) 189 { 190 if (digest->request.opaque) { 191 krb5_set_error_message(context, EINVAL, "opaque already set"); 192 return EINVAL; 193 } 194 digest->request.opaque = strdup(opaque); 195 if (digest->request.opaque == NULL) { 196 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 197 return ENOMEM; 198 } 199 return 0; 200 } 201 202 KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL 203 krb5_digest_get_identifier(krb5_context context, 204 krb5_digest digest) 205 { 206 if (digest->initReply.identifier == NULL) 207 return NULL; 208 return *digest->initReply.identifier; 209 } 210 211 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 212 krb5_digest_set_identifier(krb5_context context, 213 krb5_digest digest, 214 const char *id) 215 { 216 if (digest->request.identifier) { 217 krb5_set_error_message(context, EINVAL, N_("identifier already set", "")); 218 return EINVAL; 219 } 220 digest->request.identifier = calloc(1, sizeof(*digest->request.identifier)); 221 if (digest->request.identifier == NULL) { 222 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 223 return ENOMEM; 224 } 225 *digest->request.identifier = strdup(id); 226 if (*digest->request.identifier == NULL) { 227 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 228 free(digest->request.identifier); 229 digest->request.identifier = NULL; 230 return ENOMEM; 231 } 232 return 0; 233 } 234 235 static krb5_error_code 236 digest_request(krb5_context context, 237 krb5_realm realm, 238 krb5_ccache ccache, 239 krb5_key_usage usage, 240 const DigestReqInner *ireq, 241 DigestRepInner *irep) 242 { 243 DigestREQ req; 244 DigestREP rep; 245 krb5_error_code ret; 246 krb5_data data, data2; 247 size_t size = 0; 248 krb5_crypto crypto = NULL; 249 krb5_auth_context ac = NULL; 250 krb5_principal principal = NULL; 251 krb5_ccache id = NULL; 252 krb5_realm r = NULL; 253 254 krb5_data_zero(&data); 255 krb5_data_zero(&data2); 256 memset(&req, 0, sizeof(req)); 257 memset(&rep, 0, sizeof(rep)); 258 259 if (ccache == NULL) { 260 ret = krb5_cc_default(context, &id); 261 if (ret) 262 goto out; 263 } else 264 id = ccache; 265 266 if (realm == NULL) { 267 ret = krb5_get_default_realm(context, &r); 268 if (ret) 269 goto out; 270 } else 271 r = realm; 272 273 /* 274 * 275 */ 276 277 ret = krb5_make_principal(context, &principal, 278 r, KRB5_DIGEST_NAME, r, NULL); 279 if (ret) 280 goto out; 281 282 ASN1_MALLOC_ENCODE(DigestReqInner, data.data, data.length, 283 ireq, &size, ret); 284 if (ret) { 285 krb5_set_error_message(context, ret, 286 N_("Failed to encode digest inner request", "")); 287 goto out; 288 } 289 if (size != data.length) 290 krb5_abortx(context, "ASN.1 internal encoder error"); 291 292 ret = krb5_mk_req_exact(context, &ac, 293 AP_OPTS_USE_SUBKEY|AP_OPTS_MUTUAL_REQUIRED, 294 principal, NULL, id, &req.apReq); 295 if (ret) 296 goto out; 297 298 { 299 krb5_keyblock *key; 300 301 ret = krb5_auth_con_getlocalsubkey(context, ac, &key); 302 if (ret) 303 goto out; 304 if (key == NULL) { 305 ret = EINVAL; 306 krb5_set_error_message(context, ret, 307 N_("Digest failed to get local subkey", "")); 308 goto out; 309 } 310 311 ret = krb5_crypto_init(context, key, 0, &crypto); 312 krb5_free_keyblock (context, key); 313 if (ret) 314 goto out; 315 } 316 317 ret = krb5_encrypt_EncryptedData(context, crypto, usage, 318 data.data, data.length, 0, 319 &req.innerReq); 320 if (ret) 321 goto out; 322 323 krb5_data_free(&data); 324 325 ASN1_MALLOC_ENCODE(DigestREQ, data.data, data.length, 326 &req, &size, ret); 327 if (ret) { 328 krb5_set_error_message(context, ret, 329 N_("Failed to encode DigestREQest", "")); 330 goto out; 331 } 332 if (size != data.length) 333 krb5_abortx(context, "ASN.1 internal encoder error"); 334 335 ret = krb5_sendto_kdc(context, &data, &r, &data2); 336 if (ret) 337 goto out; 338 339 ret = decode_DigestREP(data2.data, data2.length, &rep, NULL); 340 if (ret) { 341 krb5_set_error_message(context, ret, 342 N_("Failed to parse digest response", "")); 343 goto out; 344 } 345 346 { 347 krb5_ap_rep_enc_part *repl; 348 349 ret = krb5_rd_rep(context, ac, &rep.apRep, &repl); 350 if (ret) 351 goto out; 352 353 krb5_free_ap_rep_enc_part(context, repl); 354 } 355 { 356 krb5_keyblock *key; 357 358 ret = krb5_auth_con_getremotesubkey(context, ac, &key); 359 if (ret) 360 goto out; 361 if (key == NULL) { 362 ret = EINVAL; 363 krb5_set_error_message(context, ret, 364 N_("Digest reply have no remote subkey", "")); 365 goto out; 366 } 367 368 krb5_crypto_destroy(context, crypto); 369 ret = krb5_crypto_init(context, key, 0, &crypto); 370 krb5_free_keyblock (context, key); 371 if (ret) 372 goto out; 373 } 374 375 krb5_data_free(&data); 376 ret = krb5_decrypt_EncryptedData(context, crypto, usage, 377 &rep.innerRep, &data); 378 if (ret) 379 goto out; 380 381 ret = decode_DigestRepInner(data.data, data.length, irep, NULL); 382 if (ret) { 383 krb5_set_error_message(context, ret, 384 N_("Failed to decode digest inner reply", "")); 385 goto out; 386 } 387 388 out: 389 if (ccache == NULL && id) 390 krb5_cc_close(context, id); 391 if (realm == NULL && r) 392 free(r); 393 if (crypto) 394 krb5_crypto_destroy(context, crypto); 395 if (ac) 396 krb5_auth_con_free(context, ac); 397 if (principal) 398 krb5_free_principal(context, principal); 399 400 krb5_data_free(&data); 401 krb5_data_free(&data2); 402 403 free_DigestREQ(&req); 404 free_DigestREP(&rep); 405 406 return ret; 407 } 408 409 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 410 krb5_digest_init_request(krb5_context context, 411 krb5_digest digest, 412 krb5_realm realm, 413 krb5_ccache ccache) 414 { 415 DigestReqInner ireq; 416 DigestRepInner irep; 417 krb5_error_code ret; 418 419 memset(&ireq, 0, sizeof(ireq)); 420 memset(&irep, 0, sizeof(irep)); 421 422 if (digest->init.type == NULL) { 423 krb5_set_error_message(context, EINVAL, 424 N_("Type missing from init req", "")); 425 return EINVAL; 426 } 427 428 ireq.element = choice_DigestReqInner_init; 429 ireq.u.init = digest->init; 430 431 ret = digest_request(context, realm, ccache, 432 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 433 if (ret) 434 goto out; 435 436 if (irep.element == choice_DigestRepInner_error) { 437 ret = irep.u.error.code; 438 krb5_set_error_message(context, ret, N_("Digest init error: %s", ""), 439 irep.u.error.reason); 440 goto out; 441 } 442 443 if (irep.element != choice_DigestRepInner_initReply) { 444 ret = EINVAL; 445 krb5_set_error_message(context, ret, 446 N_("digest reply not an initReply", "")); 447 goto out; 448 } 449 450 ret = copy_DigestInitReply(&irep.u.initReply, &digest->initReply); 451 if (ret) { 452 krb5_set_error_message(context, ret, 453 N_("Failed to copy initReply", "")); 454 goto out; 455 } 456 457 out: 458 free_DigestRepInner(&irep); 459 460 return ret; 461 } 462 463 464 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 465 krb5_digest_set_client_nonce(krb5_context context, 466 krb5_digest digest, 467 const char *nonce) 468 { 469 if (digest->request.clientNonce) { 470 krb5_set_error_message(context, EINVAL, 471 N_("clientNonce already set", "")); 472 return EINVAL; 473 } 474 digest->request.clientNonce = 475 calloc(1, sizeof(*digest->request.clientNonce)); 476 if (digest->request.clientNonce == NULL) { 477 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 478 return ENOMEM; 479 } 480 *digest->request.clientNonce = strdup(nonce); 481 if (*digest->request.clientNonce == NULL) { 482 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 483 free(digest->request.clientNonce); 484 digest->request.clientNonce = NULL; 485 return ENOMEM; 486 } 487 return 0; 488 } 489 490 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 491 krb5_digest_set_digest(krb5_context context, 492 krb5_digest digest, 493 const char *dgst) 494 { 495 if (digest->request.digest) { 496 krb5_set_error_message(context, EINVAL, 497 N_("digest already set", "")); 498 return EINVAL; 499 } 500 digest->request.digest = strdup(dgst); 501 if (digest->request.digest == NULL) { 502 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 503 return ENOMEM; 504 } 505 return 0; 506 } 507 508 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 509 krb5_digest_set_username(krb5_context context, 510 krb5_digest digest, 511 const char *username) 512 { 513 if (digest->request.username) { 514 krb5_set_error_message(context, EINVAL, "username already set"); 515 return EINVAL; 516 } 517 digest->request.username = strdup(username); 518 if (digest->request.username == NULL) { 519 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 520 return ENOMEM; 521 } 522 return 0; 523 } 524 525 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 526 krb5_digest_set_authid(krb5_context context, 527 krb5_digest digest, 528 const char *authid) 529 { 530 if (digest->request.authid) { 531 krb5_set_error_message(context, EINVAL, "authid already set"); 532 return EINVAL; 533 } 534 digest->request.authid = malloc(sizeof(*digest->request.authid)); 535 if (digest->request.authid == NULL) { 536 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 537 return ENOMEM; 538 } 539 *digest->request.authid = strdup(authid); 540 if (*digest->request.authid == NULL) { 541 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 542 free(digest->request.authid); 543 digest->request.authid = NULL; 544 return ENOMEM; 545 } 546 return 0; 547 } 548 549 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 550 krb5_digest_set_authentication_user(krb5_context context, 551 krb5_digest digest, 552 krb5_principal authentication_user) 553 { 554 krb5_error_code ret; 555 556 if (digest->request.authentication_user) { 557 krb5_set_error_message(context, EINVAL, 558 N_("authentication_user already set", "")); 559 return EINVAL; 560 } 561 ret = krb5_copy_principal(context, 562 authentication_user, 563 &digest->request.authentication_user); 564 if (ret) 565 return ret; 566 return 0; 567 } 568 569 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 570 krb5_digest_set_realm(krb5_context context, 571 krb5_digest digest, 572 const char *realm) 573 { 574 if (digest->request.realm) { 575 krb5_set_error_message(context, EINVAL, "realm already set"); 576 return EINVAL; 577 } 578 digest->request.realm = malloc(sizeof(*digest->request.realm)); 579 if (digest->request.realm == NULL) { 580 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 581 return ENOMEM; 582 } 583 *digest->request.realm = strdup(realm); 584 if (*digest->request.realm == NULL) { 585 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 586 free(digest->request.realm); 587 digest->request.realm = NULL; 588 return ENOMEM; 589 } 590 return 0; 591 } 592 593 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 594 krb5_digest_set_method(krb5_context context, 595 krb5_digest digest, 596 const char *method) 597 { 598 if (digest->request.method) { 599 krb5_set_error_message(context, EINVAL, 600 N_("method already set", "")); 601 return EINVAL; 602 } 603 digest->request.method = malloc(sizeof(*digest->request.method)); 604 if (digest->request.method == NULL) { 605 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 606 return ENOMEM; 607 } 608 *digest->request.method = strdup(method); 609 if (*digest->request.method == NULL) { 610 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 611 free(digest->request.method); 612 digest->request.method = NULL; 613 return ENOMEM; 614 } 615 return 0; 616 } 617 618 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 619 krb5_digest_set_uri(krb5_context context, 620 krb5_digest digest, 621 const char *uri) 622 { 623 if (digest->request.uri) { 624 krb5_set_error_message(context, EINVAL, N_("uri already set", "")); 625 return EINVAL; 626 } 627 digest->request.uri = malloc(sizeof(*digest->request.uri)); 628 if (digest->request.uri == NULL) { 629 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 630 return ENOMEM; 631 } 632 *digest->request.uri = strdup(uri); 633 if (*digest->request.uri == NULL) { 634 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 635 free(digest->request.uri); 636 digest->request.uri = NULL; 637 return ENOMEM; 638 } 639 return 0; 640 } 641 642 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 643 krb5_digest_set_nonceCount(krb5_context context, 644 krb5_digest digest, 645 const char *nonce_count) 646 { 647 if (digest->request.nonceCount) { 648 krb5_set_error_message(context, EINVAL, 649 N_("nonceCount already set", "")); 650 return EINVAL; 651 } 652 digest->request.nonceCount = 653 malloc(sizeof(*digest->request.nonceCount)); 654 if (digest->request.nonceCount == NULL) { 655 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 656 return ENOMEM; 657 } 658 *digest->request.nonceCount = strdup(nonce_count); 659 if (*digest->request.nonceCount == NULL) { 660 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 661 free(digest->request.nonceCount); 662 digest->request.nonceCount = NULL; 663 return ENOMEM; 664 } 665 return 0; 666 } 667 668 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 669 krb5_digest_set_qop(krb5_context context, 670 krb5_digest digest, 671 const char *qop) 672 { 673 if (digest->request.qop) { 674 krb5_set_error_message(context, EINVAL, "qop already set"); 675 return EINVAL; 676 } 677 digest->request.qop = malloc(sizeof(*digest->request.qop)); 678 if (digest->request.qop == NULL) { 679 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 680 return ENOMEM; 681 } 682 *digest->request.qop = strdup(qop); 683 if (*digest->request.qop == NULL) { 684 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 685 free(digest->request.qop); 686 digest->request.qop = NULL; 687 return ENOMEM; 688 } 689 return 0; 690 } 691 692 KRB5_LIB_FUNCTION int KRB5_LIB_CALL 693 krb5_digest_set_responseData(krb5_context context, 694 krb5_digest digest, 695 const char *response) 696 { 697 digest->request.responseData = strdup(response); 698 if (digest->request.responseData == NULL) { 699 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 700 return ENOMEM; 701 } 702 return 0; 703 } 704 705 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 706 krb5_digest_request(krb5_context context, 707 krb5_digest digest, 708 krb5_realm realm, 709 krb5_ccache ccache) 710 { 711 DigestReqInner ireq; 712 DigestRepInner irep; 713 krb5_error_code ret; 714 715 memset(&ireq, 0, sizeof(ireq)); 716 memset(&irep, 0, sizeof(irep)); 717 718 ireq.element = choice_DigestReqInner_digestRequest; 719 ireq.u.digestRequest = digest->request; 720 721 if (digest->request.type == NULL) { 722 if (digest->init.type == NULL) { 723 krb5_set_error_message(context, EINVAL, 724 N_("Type missing from req", "")); 725 return EINVAL; 726 } 727 ireq.u.digestRequest.type = digest->init.type; 728 } 729 730 if (ireq.u.digestRequest.digest == NULL) { 731 static char md5[] = "md5"; 732 ireq.u.digestRequest.digest = md5; 733 } 734 735 ret = digest_request(context, realm, ccache, 736 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 737 if (ret) 738 return ret; 739 740 if (irep.element == choice_DigestRepInner_error) { 741 ret = irep.u.error.code; 742 krb5_set_error_message(context, ret, 743 N_("Digest response error: %s", ""), 744 irep.u.error.reason); 745 goto out; 746 } 747 748 if (irep.element != choice_DigestRepInner_response) { 749 krb5_set_error_message(context, EINVAL, 750 N_("digest reply not an DigestResponse", "")); 751 ret = EINVAL; 752 goto out; 753 } 754 755 ret = copy_DigestResponse(&irep.u.response, &digest->response); 756 if (ret) { 757 krb5_set_error_message(context, ret, 758 N_("Failed to copy initReply,", "")); 759 goto out; 760 } 761 762 out: 763 free_DigestRepInner(&irep); 764 765 return ret; 766 } 767 768 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 769 krb5_digest_rep_get_status(krb5_context context, 770 krb5_digest digest) 771 { 772 return digest->response.success ? TRUE : FALSE; 773 } 774 775 KRB5_LIB_FUNCTION const char * KRB5_LIB_CALL 776 krb5_digest_get_rsp(krb5_context context, 777 krb5_digest digest) 778 { 779 if (digest->response.rsp == NULL) 780 return NULL; 781 return *digest->response.rsp; 782 } 783 784 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 785 krb5_digest_get_tickets(krb5_context context, 786 krb5_digest digest, 787 Ticket **tickets) 788 { 789 *tickets = NULL; 790 return 0; 791 } 792 793 794 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 795 krb5_digest_get_client_binding(krb5_context context, 796 krb5_digest digest, 797 char **type, 798 char **binding) 799 { 800 if (digest->response.channel) { 801 *type = strdup(digest->response.channel->cb_type); 802 *binding = strdup(digest->response.channel->cb_binding); 803 if (*type == NULL || *binding == NULL) { 804 free(*type); 805 free(*binding); 806 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 807 return ENOMEM; 808 } 809 } else { 810 *type = NULL; 811 *binding = NULL; 812 } 813 return 0; 814 } 815 816 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 817 krb5_digest_get_session_key(krb5_context context, 818 krb5_digest digest, 819 krb5_data *data) 820 { 821 krb5_error_code ret; 822 823 krb5_data_zero(data); 824 if (digest->response.session_key == NULL) 825 return 0; 826 ret = der_copy_octet_string(digest->response.session_key, data); 827 if (ret) 828 krb5_clear_error_message(context); 829 830 return ret; 831 } 832 833 struct krb5_ntlm_data { 834 NTLMInit init; 835 NTLMInitReply initReply; 836 NTLMRequest request; 837 NTLMResponse response; 838 }; 839 840 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 841 krb5_ntlm_alloc(krb5_context context, 842 krb5_ntlm *ntlm) 843 { 844 *ntlm = calloc(1, sizeof(**ntlm)); 845 if (*ntlm == NULL) { 846 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 847 return ENOMEM; 848 } 849 return 0; 850 } 851 852 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 853 krb5_ntlm_free(krb5_context context, krb5_ntlm ntlm) 854 { 855 free_NTLMInit(&ntlm->init); 856 free_NTLMInitReply(&ntlm->initReply); 857 free_NTLMRequest(&ntlm->request); 858 free_NTLMResponse(&ntlm->response); 859 memset(ntlm, 0, sizeof(*ntlm)); 860 free(ntlm); 861 return 0; 862 } 863 864 865 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 866 krb5_ntlm_init_request(krb5_context context, 867 krb5_ntlm ntlm, 868 krb5_realm realm, 869 krb5_ccache ccache, 870 uint32_t flags, 871 const char *hostname, 872 const char *domainname) 873 { 874 DigestReqInner ireq; 875 DigestRepInner irep; 876 krb5_error_code ret; 877 878 memset(&ireq, 0, sizeof(ireq)); 879 memset(&irep, 0, sizeof(irep)); 880 881 ntlm->init.flags = flags; 882 if (hostname) { 883 ALLOC(ntlm->init.hostname, 1); 884 *ntlm->init.hostname = strdup(hostname); 885 } 886 if (domainname) { 887 ALLOC(ntlm->init.domain, 1); 888 *ntlm->init.domain = strdup(domainname); 889 } 890 891 ireq.element = choice_DigestReqInner_ntlmInit; 892 ireq.u.ntlmInit = ntlm->init; 893 894 ret = digest_request(context, realm, ccache, 895 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 896 if (ret) 897 goto out; 898 899 if (irep.element == choice_DigestRepInner_error) { 900 ret = irep.u.error.code; 901 krb5_set_error_message(context, ret, N_("Digest init error: %s", ""), 902 irep.u.error.reason); 903 goto out; 904 } 905 906 if (irep.element != choice_DigestRepInner_ntlmInitReply) { 907 ret = EINVAL; 908 krb5_set_error_message(context, ret, 909 N_("ntlm reply not an initReply", "")); 910 goto out; 911 } 912 913 ret = copy_NTLMInitReply(&irep.u.ntlmInitReply, &ntlm->initReply); 914 if (ret) { 915 krb5_set_error_message(context, ret, 916 N_("Failed to copy initReply", "")); 917 goto out; 918 } 919 920 out: 921 free_DigestRepInner(&irep); 922 923 return ret; 924 } 925 926 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 927 krb5_ntlm_init_get_flags(krb5_context context, 928 krb5_ntlm ntlm, 929 uint32_t *flags) 930 { 931 *flags = ntlm->initReply.flags; 932 return 0; 933 } 934 935 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 936 krb5_ntlm_init_get_challange(krb5_context context, 937 krb5_ntlm ntlm, 938 krb5_data *challange) 939 { 940 krb5_error_code ret; 941 942 ret = der_copy_octet_string(&ntlm->initReply.challange, challange); 943 if (ret) 944 krb5_clear_error_message(context); 945 946 return ret; 947 } 948 949 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 950 krb5_ntlm_init_get_opaque(krb5_context context, 951 krb5_ntlm ntlm, 952 krb5_data *opaque) 953 { 954 krb5_error_code ret; 955 956 ret = der_copy_octet_string(&ntlm->initReply.opaque, opaque); 957 if (ret) 958 krb5_clear_error_message(context); 959 960 return ret; 961 } 962 963 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 964 krb5_ntlm_init_get_targetname(krb5_context context, 965 krb5_ntlm ntlm, 966 char **name) 967 { 968 *name = strdup(ntlm->initReply.targetname); 969 if (*name == NULL) { 970 krb5_clear_error_message(context); 971 return ENOMEM; 972 } 973 return 0; 974 } 975 976 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 977 krb5_ntlm_init_get_targetinfo(krb5_context context, 978 krb5_ntlm ntlm, 979 krb5_data *data) 980 { 981 krb5_error_code ret; 982 983 if (ntlm->initReply.targetinfo == NULL) { 984 krb5_data_zero(data); 985 return 0; 986 } 987 988 ret = krb5_data_copy(data, 989 ntlm->initReply.targetinfo->data, 990 ntlm->initReply.targetinfo->length); 991 if (ret) { 992 krb5_clear_error_message(context); 993 return ret; 994 } 995 return 0; 996 } 997 998 999 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1000 krb5_ntlm_request(krb5_context context, 1001 krb5_ntlm ntlm, 1002 krb5_realm realm, 1003 krb5_ccache ccache) 1004 { 1005 DigestReqInner ireq; 1006 DigestRepInner irep; 1007 krb5_error_code ret; 1008 1009 memset(&ireq, 0, sizeof(ireq)); 1010 memset(&irep, 0, sizeof(irep)); 1011 1012 ireq.element = choice_DigestReqInner_ntlmRequest; 1013 ireq.u.ntlmRequest = ntlm->request; 1014 1015 ret = digest_request(context, realm, ccache, 1016 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 1017 if (ret) 1018 return ret; 1019 1020 if (irep.element == choice_DigestRepInner_error) { 1021 ret = irep.u.error.code; 1022 krb5_set_error_message(context, ret, 1023 N_("NTLM response error: %s", ""), 1024 irep.u.error.reason); 1025 goto out; 1026 } 1027 1028 if (irep.element != choice_DigestRepInner_ntlmResponse) { 1029 ret = EINVAL; 1030 krb5_set_error_message(context, ret, 1031 N_("NTLM reply not an NTLMResponse", "")); 1032 goto out; 1033 } 1034 1035 ret = copy_NTLMResponse(&irep.u.ntlmResponse, &ntlm->response); 1036 if (ret) { 1037 krb5_set_error_message(context, ret, 1038 N_("Failed to copy NTLMResponse", "")); 1039 goto out; 1040 } 1041 1042 out: 1043 free_DigestRepInner(&irep); 1044 1045 return ret; 1046 } 1047 1048 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1049 krb5_ntlm_req_set_flags(krb5_context context, 1050 krb5_ntlm ntlm, 1051 uint32_t flags) 1052 { 1053 ntlm->request.flags = flags; 1054 return 0; 1055 } 1056 1057 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1058 krb5_ntlm_req_set_username(krb5_context context, 1059 krb5_ntlm ntlm, 1060 const char *username) 1061 { 1062 ntlm->request.username = strdup(username); 1063 if (ntlm->request.username == NULL) { 1064 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1065 return ENOMEM; 1066 } 1067 return 0; 1068 } 1069 1070 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1071 krb5_ntlm_req_set_targetname(krb5_context context, 1072 krb5_ntlm ntlm, 1073 const char *targetname) 1074 { 1075 ntlm->request.targetname = strdup(targetname); 1076 if (ntlm->request.targetname == NULL) { 1077 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1078 return ENOMEM; 1079 } 1080 return 0; 1081 } 1082 1083 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1084 krb5_ntlm_req_set_lm(krb5_context context, 1085 krb5_ntlm ntlm, 1086 void *hash, size_t len) 1087 { 1088 ntlm->request.lm.data = malloc(len); 1089 if (ntlm->request.lm.data == NULL && len != 0) { 1090 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1091 return ENOMEM; 1092 } 1093 ntlm->request.lm.length = len; 1094 memcpy(ntlm->request.lm.data, hash, len); 1095 return 0; 1096 } 1097 1098 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1099 krb5_ntlm_req_set_ntlm(krb5_context context, 1100 krb5_ntlm ntlm, 1101 void *hash, size_t len) 1102 { 1103 ntlm->request.ntlm.data = malloc(len); 1104 if (ntlm->request.ntlm.data == NULL && len != 0) { 1105 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1106 return ENOMEM; 1107 } 1108 ntlm->request.ntlm.length = len; 1109 memcpy(ntlm->request.ntlm.data, hash, len); 1110 return 0; 1111 } 1112 1113 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1114 krb5_ntlm_req_set_opaque(krb5_context context, 1115 krb5_ntlm ntlm, 1116 krb5_data *opaque) 1117 { 1118 ntlm->request.opaque.data = malloc(opaque->length); 1119 if (ntlm->request.opaque.data == NULL && opaque->length != 0) { 1120 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1121 return ENOMEM; 1122 } 1123 ntlm->request.opaque.length = opaque->length; 1124 memcpy(ntlm->request.opaque.data, opaque->data, opaque->length); 1125 return 0; 1126 } 1127 1128 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1129 krb5_ntlm_req_set_session(krb5_context context, 1130 krb5_ntlm ntlm, 1131 void *sessionkey, size_t length) 1132 { 1133 ntlm->request.sessionkey = calloc(1, sizeof(*ntlm->request.sessionkey)); 1134 if (ntlm->request.sessionkey == NULL) { 1135 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1136 return ENOMEM; 1137 } 1138 ntlm->request.sessionkey->data = malloc(length); 1139 if (ntlm->request.sessionkey->data == NULL && length != 0) { 1140 krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1141 return ENOMEM; 1142 } 1143 memcpy(ntlm->request.sessionkey->data, sessionkey, length); 1144 ntlm->request.sessionkey->length = length; 1145 return 0; 1146 } 1147 1148 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL 1149 krb5_ntlm_rep_get_status(krb5_context context, 1150 krb5_ntlm ntlm) 1151 { 1152 return ntlm->response.success ? TRUE : FALSE; 1153 } 1154 1155 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1156 krb5_ntlm_rep_get_sessionkey(krb5_context context, 1157 krb5_ntlm ntlm, 1158 krb5_data *data) 1159 { 1160 if (ntlm->response.sessionkey == NULL) { 1161 krb5_set_error_message(context, EINVAL, 1162 N_("no ntlm session key", "")); 1163 return EINVAL; 1164 } 1165 krb5_clear_error_message(context); 1166 return krb5_data_copy(data, 1167 ntlm->response.sessionkey->data, 1168 ntlm->response.sessionkey->length); 1169 } 1170 1171 /** 1172 * Get the supported/allowed mechanism for this principal. 1173 * 1174 * @param context A Keberos context. 1175 * @param realm The realm of the KDC. 1176 * @param ccache The credential cache to use when talking to the KDC. 1177 * @param flags The supported mechanism. 1178 * 1179 * @return Return an error code or 0. 1180 * 1181 * @ingroup krb5_digest 1182 */ 1183 1184 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1185 krb5_digest_probe(krb5_context context, 1186 krb5_realm realm, 1187 krb5_ccache ccache, 1188 unsigned *flags) 1189 { 1190 DigestReqInner ireq; 1191 DigestRepInner irep; 1192 krb5_error_code ret; 1193 1194 memset(&ireq, 0, sizeof(ireq)); 1195 memset(&irep, 0, sizeof(irep)); 1196 1197 ireq.element = choice_DigestReqInner_supportedMechs; 1198 1199 ret = digest_request(context, realm, ccache, 1200 KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 1201 if (ret) 1202 goto out; 1203 1204 if (irep.element == choice_DigestRepInner_error) { 1205 ret = irep.u.error.code; 1206 krb5_set_error_message(context, ret, "Digest probe error: %s", 1207 irep.u.error.reason); 1208 goto out; 1209 } 1210 1211 if (irep.element != choice_DigestRepInner_supportedMechs) { 1212 ret = EINVAL; 1213 krb5_set_error_message(context, ret, "Digest reply not an probe"); 1214 goto out; 1215 } 1216 1217 *flags = DigestTypes2int(irep.u.supportedMechs); 1218 1219 out: 1220 free_DigestRepInner(&irep); 1221 1222 return ret; 1223 } 1224 1225 #endif /* HEIMDAL_SMALLER */ 1226