1178825Sdfr/* 2178825Sdfr * Copyright (c) 2006 Kungliga Tekniska H�gskolan 3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden). 4178825Sdfr * All rights reserved. 5178825Sdfr * 6178825Sdfr * Redistribution and use in source and binary forms, with or without 7178825Sdfr * modification, are permitted provided that the following conditions 8178825Sdfr * are met: 9178825Sdfr * 10178825Sdfr * 1. Redistributions of source code must retain the above copyright 11178825Sdfr * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright 14178825Sdfr * notice, this list of conditions and the following disclaimer in the 15178825Sdfr * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors 18178825Sdfr * may be used to endorse or promote products derived from this software 19178825Sdfr * without specific prior written permission. 20178825Sdfr * 21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24178825Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31178825Sdfr * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34178825Sdfr#include "krb5_locl.h" 35178825SdfrRCSID("$Id: digest.c 22156 2007-12-04 20:02:49Z lha $"); 36178825Sdfr#include "digest_asn1.h" 37178825Sdfr 38178825Sdfrstruct krb5_digest_data { 39178825Sdfr char *cbtype; 40178825Sdfr char *cbbinding; 41178825Sdfr 42178825Sdfr DigestInit init; 43178825Sdfr DigestInitReply initReply; 44178825Sdfr DigestRequest request; 45178825Sdfr DigestResponse response; 46178825Sdfr}; 47178825Sdfr 48178825Sdfrkrb5_error_code 49178825Sdfrkrb5_digest_alloc(krb5_context context, krb5_digest *digest) 50178825Sdfr{ 51178825Sdfr krb5_digest d; 52178825Sdfr 53178825Sdfr d = calloc(1, sizeof(*d)); 54178825Sdfr if (d == NULL) { 55178825Sdfr *digest = NULL; 56178825Sdfr krb5_set_error_string(context, "out of memory"); 57178825Sdfr return ENOMEM; 58178825Sdfr } 59178825Sdfr *digest = d; 60178825Sdfr 61178825Sdfr return 0; 62178825Sdfr} 63178825Sdfr 64178825Sdfrvoid 65178825Sdfrkrb5_digest_free(krb5_digest digest) 66178825Sdfr{ 67178825Sdfr if (digest == NULL) 68178825Sdfr return; 69178825Sdfr free_DigestInit(&digest->init); 70178825Sdfr free_DigestInitReply(&digest->initReply); 71178825Sdfr free_DigestRequest(&digest->request); 72178825Sdfr free_DigestResponse(&digest->response); 73178825Sdfr memset(digest, 0, sizeof(*digest)); 74178825Sdfr free(digest); 75178825Sdfr return; 76178825Sdfr} 77178825Sdfr 78178825Sdfrkrb5_error_code 79178825Sdfrkrb5_digest_set_server_cb(krb5_context context, 80178825Sdfr krb5_digest digest, 81178825Sdfr const char *type, 82178825Sdfr const char *binding) 83178825Sdfr{ 84178825Sdfr if (digest->init.channel) { 85178825Sdfr krb5_set_error_string(context, "server channel binding already set"); 86178825Sdfr return EINVAL; 87178825Sdfr } 88178825Sdfr digest->init.channel = calloc(1, sizeof(*digest->init.channel)); 89178825Sdfr if (digest->init.channel == NULL) 90178825Sdfr goto error; 91178825Sdfr 92178825Sdfr digest->init.channel->cb_type = strdup(type); 93178825Sdfr if (digest->init.channel->cb_type == NULL) 94178825Sdfr goto error; 95178825Sdfr 96178825Sdfr digest->init.channel->cb_binding = strdup(binding); 97178825Sdfr if (digest->init.channel->cb_binding == NULL) 98178825Sdfr goto error; 99178825Sdfr return 0; 100178825Sdfrerror: 101178825Sdfr if (digest->init.channel) { 102178825Sdfr free(digest->init.channel->cb_type); 103178825Sdfr free(digest->init.channel->cb_binding); 104178825Sdfr free(digest->init.channel); 105178825Sdfr digest->init.channel = NULL; 106178825Sdfr } 107178825Sdfr krb5_set_error_string(context, "out of memory"); 108178825Sdfr return ENOMEM; 109178825Sdfr} 110178825Sdfr 111178825Sdfrkrb5_error_code 112178825Sdfrkrb5_digest_set_type(krb5_context context, 113178825Sdfr krb5_digest digest, 114178825Sdfr const char *type) 115178825Sdfr{ 116178825Sdfr if (digest->init.type) { 117178825Sdfr krb5_set_error_string(context, "client type already set"); 118178825Sdfr return EINVAL; 119178825Sdfr } 120178825Sdfr digest->init.type = strdup(type); 121178825Sdfr if (digest->init.type == NULL) { 122178825Sdfr krb5_set_error_string(context, "out of memory"); 123178825Sdfr return ENOMEM; 124178825Sdfr } 125178825Sdfr return 0; 126178825Sdfr} 127178825Sdfr 128178825Sdfrkrb5_error_code 129178825Sdfrkrb5_digest_set_hostname(krb5_context context, 130178825Sdfr krb5_digest digest, 131178825Sdfr const char *hostname) 132178825Sdfr{ 133178825Sdfr if (digest->init.hostname) { 134178825Sdfr krb5_set_error_string(context, "server hostname already set"); 135178825Sdfr return EINVAL; 136178825Sdfr } 137178825Sdfr digest->init.hostname = malloc(sizeof(*digest->init.hostname)); 138178825Sdfr if (digest->init.hostname == NULL) { 139178825Sdfr krb5_set_error_string(context, "out of memory"); 140178825Sdfr return ENOMEM; 141178825Sdfr } 142178825Sdfr *digest->init.hostname = strdup(hostname); 143178825Sdfr if (*digest->init.hostname == NULL) { 144178825Sdfr krb5_set_error_string(context, "out of memory"); 145178825Sdfr free(digest->init.hostname); 146178825Sdfr digest->init.hostname = NULL; 147178825Sdfr return ENOMEM; 148178825Sdfr } 149178825Sdfr return 0; 150178825Sdfr} 151178825Sdfr 152178825Sdfrconst char * 153178825Sdfrkrb5_digest_get_server_nonce(krb5_context context, 154178825Sdfr krb5_digest digest) 155178825Sdfr{ 156178825Sdfr return digest->initReply.nonce; 157178825Sdfr} 158178825Sdfr 159178825Sdfrkrb5_error_code 160178825Sdfrkrb5_digest_set_server_nonce(krb5_context context, 161178825Sdfr krb5_digest digest, 162178825Sdfr const char *nonce) 163178825Sdfr{ 164178825Sdfr if (digest->request.serverNonce) { 165178825Sdfr krb5_set_error_string(context, "nonce already set"); 166178825Sdfr return EINVAL; 167178825Sdfr } 168178825Sdfr digest->request.serverNonce = strdup(nonce); 169178825Sdfr if (digest->request.serverNonce == NULL) { 170178825Sdfr krb5_set_error_string(context, "out of memory"); 171178825Sdfr return ENOMEM; 172178825Sdfr } 173178825Sdfr return 0; 174178825Sdfr} 175178825Sdfr 176178825Sdfrconst char * 177178825Sdfrkrb5_digest_get_opaque(krb5_context context, 178178825Sdfr krb5_digest digest) 179178825Sdfr{ 180178825Sdfr return digest->initReply.opaque; 181178825Sdfr} 182178825Sdfr 183178825Sdfrkrb5_error_code 184178825Sdfrkrb5_digest_set_opaque(krb5_context context, 185178825Sdfr krb5_digest digest, 186178825Sdfr const char *opaque) 187178825Sdfr{ 188178825Sdfr if (digest->request.opaque) { 189178825Sdfr krb5_set_error_string(context, "opaque already set"); 190178825Sdfr return EINVAL; 191178825Sdfr } 192178825Sdfr digest->request.opaque = strdup(opaque); 193178825Sdfr if (digest->request.opaque == NULL) { 194178825Sdfr krb5_set_error_string(context, "out of memory"); 195178825Sdfr return ENOMEM; 196178825Sdfr } 197178825Sdfr return 0; 198178825Sdfr} 199178825Sdfr 200178825Sdfrconst char * 201178825Sdfrkrb5_digest_get_identifier(krb5_context context, 202178825Sdfr krb5_digest digest) 203178825Sdfr{ 204178825Sdfr if (digest->initReply.identifier == NULL) 205178825Sdfr return NULL; 206178825Sdfr return *digest->initReply.identifier; 207178825Sdfr} 208178825Sdfr 209178825Sdfrkrb5_error_code 210178825Sdfrkrb5_digest_set_identifier(krb5_context context, 211178825Sdfr krb5_digest digest, 212178825Sdfr const char *id) 213178825Sdfr{ 214178825Sdfr if (digest->request.identifier) { 215178825Sdfr krb5_set_error_string(context, "identifier already set"); 216178825Sdfr return EINVAL; 217178825Sdfr } 218178825Sdfr digest->request.identifier = calloc(1, sizeof(*digest->request.identifier)); 219178825Sdfr if (digest->request.identifier == NULL) { 220178825Sdfr krb5_set_error_string(context, "out of memory"); 221178825Sdfr return ENOMEM; 222178825Sdfr } 223178825Sdfr *digest->request.identifier = strdup(id); 224178825Sdfr if (*digest->request.identifier == NULL) { 225178825Sdfr krb5_set_error_string(context, "out of memory"); 226178825Sdfr free(digest->request.identifier); 227178825Sdfr digest->request.identifier = NULL; 228178825Sdfr return ENOMEM; 229178825Sdfr } 230178825Sdfr return 0; 231178825Sdfr} 232178825Sdfr 233178825Sdfrstatic krb5_error_code 234178825Sdfrdigest_request(krb5_context context, 235178825Sdfr krb5_realm realm, 236178825Sdfr krb5_ccache ccache, 237178825Sdfr krb5_key_usage usage, 238178825Sdfr const DigestReqInner *ireq, 239178825Sdfr DigestRepInner *irep) 240178825Sdfr{ 241178825Sdfr DigestREQ req; 242178825Sdfr DigestREP rep; 243178825Sdfr krb5_error_code ret; 244178825Sdfr krb5_data data, data2; 245178825Sdfr size_t size; 246178825Sdfr krb5_crypto crypto = NULL; 247178825Sdfr krb5_auth_context ac = NULL; 248178825Sdfr krb5_principal principal = NULL; 249178825Sdfr krb5_ccache id = NULL; 250178825Sdfr krb5_realm r = NULL; 251178825Sdfr 252178825Sdfr krb5_data_zero(&data); 253178825Sdfr krb5_data_zero(&data2); 254178825Sdfr memset(&req, 0, sizeof(req)); 255178825Sdfr memset(&rep, 0, sizeof(rep)); 256178825Sdfr 257178825Sdfr if (ccache == NULL) { 258178825Sdfr ret = krb5_cc_default(context, &id); 259178825Sdfr if (ret) 260178825Sdfr goto out; 261178825Sdfr } else 262178825Sdfr id = ccache; 263178825Sdfr 264178825Sdfr if (realm == NULL) { 265178825Sdfr ret = krb5_get_default_realm(context, &r); 266178825Sdfr if (ret) 267178825Sdfr goto out; 268178825Sdfr } else 269178825Sdfr r = realm; 270178825Sdfr 271178825Sdfr /* 272178825Sdfr * 273178825Sdfr */ 274178825Sdfr 275178825Sdfr ret = krb5_make_principal(context, &principal, 276178825Sdfr r, KRB5_DIGEST_NAME, r, NULL); 277178825Sdfr if (ret) 278178825Sdfr goto out; 279178825Sdfr 280178825Sdfr ASN1_MALLOC_ENCODE(DigestReqInner, data.data, data.length, 281178825Sdfr ireq, &size, ret); 282178825Sdfr if (ret) { 283178825Sdfr krb5_set_error_string(context, 284178825Sdfr "Failed to encode digest inner request"); 285178825Sdfr goto out; 286178825Sdfr } 287178825Sdfr if (size != data.length) 288178825Sdfr krb5_abortx(context, "ASN.1 internal encoder error"); 289178825Sdfr 290178825Sdfr ret = krb5_mk_req_exact(context, &ac, 291178825Sdfr AP_OPTS_USE_SUBKEY|AP_OPTS_MUTUAL_REQUIRED, 292178825Sdfr principal, NULL, id, &req.apReq); 293178825Sdfr if (ret) 294178825Sdfr goto out; 295178825Sdfr 296178825Sdfr { 297178825Sdfr krb5_keyblock *key; 298178825Sdfr 299178825Sdfr ret = krb5_auth_con_getlocalsubkey(context, ac, &key); 300178825Sdfr if (ret) 301178825Sdfr goto out; 302178825Sdfr if (key == NULL) { 303178825Sdfr krb5_set_error_string(context, "Digest failed to get local subkey"); 304178825Sdfr ret = EINVAL; 305178825Sdfr goto out; 306178825Sdfr } 307178825Sdfr 308178825Sdfr ret = krb5_crypto_init(context, key, 0, &crypto); 309178825Sdfr krb5_free_keyblock (context, key); 310178825Sdfr if (ret) 311178825Sdfr goto out; 312178825Sdfr } 313178825Sdfr 314178825Sdfr ret = krb5_encrypt_EncryptedData(context, crypto, usage, 315178825Sdfr data.data, data.length, 0, 316178825Sdfr &req.innerReq); 317178825Sdfr if (ret) 318178825Sdfr goto out; 319178825Sdfr 320178825Sdfr krb5_data_free(&data); 321178825Sdfr 322178825Sdfr ASN1_MALLOC_ENCODE(DigestREQ, data.data, data.length, 323178825Sdfr &req, &size, ret); 324178825Sdfr if (ret) { 325178825Sdfr krb5_set_error_string(context, "Failed to encode DigestREQest"); 326178825Sdfr goto out; 327178825Sdfr } 328178825Sdfr if (size != data.length) 329178825Sdfr krb5_abortx(context, "ASN.1 internal encoder error"); 330178825Sdfr 331178825Sdfr ret = krb5_sendto_kdc(context, &data, &r, &data2); 332178825Sdfr if (ret) 333178825Sdfr goto out; 334178825Sdfr 335178825Sdfr ret = decode_DigestREP(data2.data, data2.length, &rep, NULL); 336178825Sdfr if (ret) { 337178825Sdfr krb5_set_error_string(context, "Failed to parse digest response"); 338178825Sdfr goto out; 339178825Sdfr } 340178825Sdfr 341178825Sdfr { 342178825Sdfr krb5_ap_rep_enc_part *repl; 343178825Sdfr 344178825Sdfr ret = krb5_rd_rep(context, ac, &rep.apRep, &repl); 345178825Sdfr if (ret) 346178825Sdfr goto out; 347178825Sdfr 348178825Sdfr krb5_free_ap_rep_enc_part(context, repl); 349178825Sdfr } 350178825Sdfr { 351178825Sdfr krb5_keyblock *key; 352178825Sdfr 353178825Sdfr ret = krb5_auth_con_getremotesubkey(context, ac, &key); 354178825Sdfr if (ret) 355178825Sdfr goto out; 356178825Sdfr if (key == NULL) { 357178825Sdfr ret = EINVAL; 358178825Sdfr krb5_set_error_string(context, 359178825Sdfr "Digest reply have no remote subkey"); 360178825Sdfr goto out; 361178825Sdfr } 362178825Sdfr 363178825Sdfr krb5_crypto_destroy(context, crypto); 364178825Sdfr ret = krb5_crypto_init(context, key, 0, &crypto); 365178825Sdfr krb5_free_keyblock (context, key); 366178825Sdfr if (ret) 367178825Sdfr goto out; 368178825Sdfr } 369178825Sdfr 370178825Sdfr krb5_data_free(&data); 371178825Sdfr ret = krb5_decrypt_EncryptedData(context, crypto, usage, 372178825Sdfr &rep.innerRep, &data); 373178825Sdfr if (ret) 374178825Sdfr goto out; 375178825Sdfr 376178825Sdfr ret = decode_DigestRepInner(data.data, data.length, irep, NULL); 377178825Sdfr if (ret) { 378178825Sdfr krb5_set_error_string(context, "Failed to decode digest inner reply"); 379178825Sdfr goto out; 380178825Sdfr } 381178825Sdfr 382178825Sdfrout: 383178825Sdfr if (ccache == NULL && id) 384178825Sdfr krb5_cc_close(context, id); 385178825Sdfr if (realm == NULL && r) 386178825Sdfr free(r); 387178825Sdfr if (crypto) 388178825Sdfr krb5_crypto_destroy(context, crypto); 389178825Sdfr if (ac) 390178825Sdfr krb5_auth_con_free(context, ac); 391178825Sdfr if (principal) 392178825Sdfr krb5_free_principal(context, principal); 393178825Sdfr 394178825Sdfr krb5_data_free(&data); 395178825Sdfr krb5_data_free(&data2); 396178825Sdfr 397178825Sdfr free_DigestREQ(&req); 398178825Sdfr free_DigestREP(&rep); 399178825Sdfr 400178825Sdfr return ret; 401178825Sdfr} 402178825Sdfr 403178825Sdfrkrb5_error_code 404178825Sdfrkrb5_digest_init_request(krb5_context context, 405178825Sdfr krb5_digest digest, 406178825Sdfr krb5_realm realm, 407178825Sdfr krb5_ccache ccache) 408178825Sdfr{ 409178825Sdfr DigestReqInner ireq; 410178825Sdfr DigestRepInner irep; 411178825Sdfr krb5_error_code ret; 412178825Sdfr 413178825Sdfr memset(&ireq, 0, sizeof(ireq)); 414178825Sdfr memset(&irep, 0, sizeof(irep)); 415178825Sdfr 416178825Sdfr if (digest->init.type == NULL) { 417178825Sdfr krb5_set_error_string(context, "Type missing from init req"); 418178825Sdfr return EINVAL; 419178825Sdfr } 420178825Sdfr 421178825Sdfr ireq.element = choice_DigestReqInner_init; 422178825Sdfr ireq.u.init = digest->init; 423178825Sdfr 424178825Sdfr ret = digest_request(context, realm, ccache, 425178825Sdfr KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 426178825Sdfr if (ret) 427178825Sdfr goto out; 428178825Sdfr 429178825Sdfr if (irep.element == choice_DigestRepInner_error) { 430178825Sdfr krb5_set_error_string(context, "Digest init error: %s", 431178825Sdfr irep.u.error.reason); 432178825Sdfr ret = irep.u.error.code; 433178825Sdfr goto out; 434178825Sdfr } 435178825Sdfr 436178825Sdfr if (irep.element != choice_DigestRepInner_initReply) { 437178825Sdfr krb5_set_error_string(context, "digest reply not an initReply"); 438178825Sdfr ret = EINVAL; 439178825Sdfr goto out; 440178825Sdfr } 441178825Sdfr 442178825Sdfr ret = copy_DigestInitReply(&irep.u.initReply, &digest->initReply); 443178825Sdfr if (ret) { 444178825Sdfr krb5_set_error_string(context, "Failed to copy initReply"); 445178825Sdfr goto out; 446178825Sdfr } 447178825Sdfr 448178825Sdfrout: 449178825Sdfr free_DigestRepInner(&irep); 450178825Sdfr 451178825Sdfr return ret; 452178825Sdfr} 453178825Sdfr 454178825Sdfr 455178825Sdfrkrb5_error_code 456178825Sdfrkrb5_digest_set_client_nonce(krb5_context context, 457178825Sdfr krb5_digest digest, 458178825Sdfr const char *nonce) 459178825Sdfr{ 460178825Sdfr if (digest->request.clientNonce) { 461178825Sdfr krb5_set_error_string(context, "clientNonce already set"); 462178825Sdfr return EINVAL; 463178825Sdfr } 464178825Sdfr digest->request.clientNonce = 465178825Sdfr calloc(1, sizeof(*digest->request.clientNonce)); 466178825Sdfr if (digest->request.clientNonce == NULL) { 467178825Sdfr krb5_set_error_string(context, "out of memory"); 468178825Sdfr return ENOMEM; 469178825Sdfr } 470178825Sdfr *digest->request.clientNonce = strdup(nonce); 471178825Sdfr if (*digest->request.clientNonce == NULL) { 472178825Sdfr krb5_set_error_string(context, "out of memory"); 473178825Sdfr free(digest->request.clientNonce); 474178825Sdfr digest->request.clientNonce = NULL; 475178825Sdfr return ENOMEM; 476178825Sdfr } 477178825Sdfr return 0; 478178825Sdfr} 479178825Sdfr 480178825Sdfrkrb5_error_code 481178825Sdfrkrb5_digest_set_digest(krb5_context context, 482178825Sdfr krb5_digest digest, 483178825Sdfr const char *dgst) 484178825Sdfr{ 485178825Sdfr if (digest->request.digest) { 486178825Sdfr krb5_set_error_string(context, "digest already set"); 487178825Sdfr return EINVAL; 488178825Sdfr } 489178825Sdfr digest->request.digest = strdup(dgst); 490178825Sdfr if (digest->request.digest == NULL) { 491178825Sdfr krb5_set_error_string(context, "out of memory"); 492178825Sdfr return ENOMEM; 493178825Sdfr } 494178825Sdfr return 0; 495178825Sdfr} 496178825Sdfr 497178825Sdfrkrb5_error_code 498178825Sdfrkrb5_digest_set_username(krb5_context context, 499178825Sdfr krb5_digest digest, 500178825Sdfr const char *username) 501178825Sdfr{ 502178825Sdfr if (digest->request.username) { 503178825Sdfr krb5_set_error_string(context, "username already set"); 504178825Sdfr return EINVAL; 505178825Sdfr } 506178825Sdfr digest->request.username = strdup(username); 507178825Sdfr if (digest->request.username == NULL) { 508178825Sdfr krb5_set_error_string(context, "out of memory"); 509178825Sdfr return ENOMEM; 510178825Sdfr } 511178825Sdfr return 0; 512178825Sdfr} 513178825Sdfr 514178825Sdfrkrb5_error_code 515178825Sdfrkrb5_digest_set_authid(krb5_context context, 516178825Sdfr krb5_digest digest, 517178825Sdfr const char *authid) 518178825Sdfr{ 519178825Sdfr if (digest->request.authid) { 520178825Sdfr krb5_set_error_string(context, "authid already set"); 521178825Sdfr return EINVAL; 522178825Sdfr } 523178825Sdfr digest->request.authid = malloc(sizeof(*digest->request.authid)); 524178825Sdfr if (digest->request.authid == NULL) { 525178825Sdfr krb5_set_error_string(context, "out of memory"); 526178825Sdfr return ENOMEM; 527178825Sdfr } 528178825Sdfr *digest->request.authid = strdup(authid); 529178825Sdfr if (*digest->request.authid == NULL) { 530178825Sdfr krb5_set_error_string(context, "out of memory"); 531178825Sdfr free(digest->request.authid); 532178825Sdfr digest->request.authid = NULL; 533178825Sdfr return ENOMEM; 534178825Sdfr } 535178825Sdfr return 0; 536178825Sdfr} 537178825Sdfr 538178825Sdfrkrb5_error_code 539178825Sdfrkrb5_digest_set_authentication_user(krb5_context context, 540178825Sdfr krb5_digest digest, 541178825Sdfr krb5_principal authentication_user) 542178825Sdfr{ 543178825Sdfr krb5_error_code ret; 544178825Sdfr 545178825Sdfr if (digest->request.authentication_user) { 546178825Sdfr krb5_set_error_string(context, "authentication_user already set"); 547178825Sdfr return EINVAL; 548178825Sdfr } 549178825Sdfr ret = krb5_copy_principal(context, 550178825Sdfr authentication_user, 551178825Sdfr &digest->request.authentication_user); 552178825Sdfr if (digest->request.authentication_user == NULL) { 553178825Sdfr krb5_set_error_string(context, "out of memory"); 554178825Sdfr return ENOMEM; 555178825Sdfr } 556178825Sdfr return 0; 557178825Sdfr} 558178825Sdfr 559178825Sdfrkrb5_error_code 560178825Sdfrkrb5_digest_set_realm(krb5_context context, 561178825Sdfr krb5_digest digest, 562178825Sdfr const char *realm) 563178825Sdfr{ 564178825Sdfr if (digest->request.realm) { 565178825Sdfr krb5_set_error_string(context, "realm already set"); 566178825Sdfr return EINVAL; 567178825Sdfr } 568178825Sdfr digest->request.realm = malloc(sizeof(*digest->request.realm)); 569178825Sdfr if (digest->request.realm == NULL) { 570178825Sdfr krb5_set_error_string(context, "out of memory"); 571178825Sdfr return ENOMEM; 572178825Sdfr } 573178825Sdfr *digest->request.realm = strdup(realm); 574178825Sdfr if (*digest->request.realm == NULL) { 575178825Sdfr krb5_set_error_string(context, "out of memory"); 576178825Sdfr free(digest->request.realm); 577178825Sdfr digest->request.realm = NULL; 578178825Sdfr return ENOMEM; 579178825Sdfr } 580178825Sdfr return 0; 581178825Sdfr} 582178825Sdfr 583178825Sdfrkrb5_error_code 584178825Sdfrkrb5_digest_set_method(krb5_context context, 585178825Sdfr krb5_digest digest, 586178825Sdfr const char *method) 587178825Sdfr{ 588178825Sdfr if (digest->request.method) { 589178825Sdfr krb5_set_error_string(context, "method already set"); 590178825Sdfr return EINVAL; 591178825Sdfr } 592178825Sdfr digest->request.method = malloc(sizeof(*digest->request.method)); 593178825Sdfr if (digest->request.method == NULL) { 594178825Sdfr krb5_set_error_string(context, "out of memory"); 595178825Sdfr return ENOMEM; 596178825Sdfr } 597178825Sdfr *digest->request.method = strdup(method); 598178825Sdfr if (*digest->request.method == NULL) { 599178825Sdfr krb5_set_error_string(context, "out of memory"); 600178825Sdfr free(digest->request.method); 601178825Sdfr digest->request.method = NULL; 602178825Sdfr return ENOMEM; 603178825Sdfr } 604178825Sdfr return 0; 605178825Sdfr} 606178825Sdfr 607178825Sdfrkrb5_error_code 608178825Sdfrkrb5_digest_set_uri(krb5_context context, 609178825Sdfr krb5_digest digest, 610178825Sdfr const char *uri) 611178825Sdfr{ 612178825Sdfr if (digest->request.uri) { 613178825Sdfr krb5_set_error_string(context, "uri already set"); 614178825Sdfr return EINVAL; 615178825Sdfr } 616178825Sdfr digest->request.uri = malloc(sizeof(*digest->request.uri)); 617178825Sdfr if (digest->request.uri == NULL) { 618178825Sdfr krb5_set_error_string(context, "out of memory"); 619178825Sdfr return ENOMEM; 620178825Sdfr } 621178825Sdfr *digest->request.uri = strdup(uri); 622178825Sdfr if (*digest->request.uri == NULL) { 623178825Sdfr krb5_set_error_string(context, "out of memory"); 624178825Sdfr free(digest->request.uri); 625178825Sdfr digest->request.uri = NULL; 626178825Sdfr return ENOMEM; 627178825Sdfr } 628178825Sdfr return 0; 629178825Sdfr} 630178825Sdfr 631178825Sdfrkrb5_error_code 632178825Sdfrkrb5_digest_set_nonceCount(krb5_context context, 633178825Sdfr krb5_digest digest, 634178825Sdfr const char *nonce_count) 635178825Sdfr{ 636178825Sdfr if (digest->request.nonceCount) { 637178825Sdfr krb5_set_error_string(context, "nonceCount already set"); 638178825Sdfr return EINVAL; 639178825Sdfr } 640178825Sdfr digest->request.nonceCount = 641178825Sdfr malloc(sizeof(*digest->request.nonceCount)); 642178825Sdfr if (digest->request.nonceCount == NULL) { 643178825Sdfr krb5_set_error_string(context, "out of memory"); 644178825Sdfr return ENOMEM; 645178825Sdfr } 646178825Sdfr *digest->request.nonceCount = strdup(nonce_count); 647178825Sdfr if (*digest->request.nonceCount == NULL) { 648178825Sdfr krb5_set_error_string(context, "out of memory"); 649178825Sdfr free(digest->request.nonceCount); 650178825Sdfr digest->request.nonceCount = NULL; 651178825Sdfr return ENOMEM; 652178825Sdfr } 653178825Sdfr return 0; 654178825Sdfr} 655178825Sdfr 656178825Sdfrkrb5_error_code 657178825Sdfrkrb5_digest_set_qop(krb5_context context, 658178825Sdfr krb5_digest digest, 659178825Sdfr const char *qop) 660178825Sdfr{ 661178825Sdfr if (digest->request.qop) { 662178825Sdfr krb5_set_error_string(context, "qop already set"); 663178825Sdfr return EINVAL; 664178825Sdfr } 665178825Sdfr digest->request.qop = malloc(sizeof(*digest->request.qop)); 666178825Sdfr if (digest->request.qop == NULL) { 667178825Sdfr krb5_set_error_string(context, "out of memory"); 668178825Sdfr return ENOMEM; 669178825Sdfr } 670178825Sdfr *digest->request.qop = strdup(qop); 671178825Sdfr if (*digest->request.qop == NULL) { 672178825Sdfr krb5_set_error_string(context, "out of memory"); 673178825Sdfr free(digest->request.qop); 674178825Sdfr digest->request.qop = NULL; 675178825Sdfr return ENOMEM; 676178825Sdfr } 677178825Sdfr return 0; 678178825Sdfr} 679178825Sdfr 680178825Sdfrint 681178825Sdfrkrb5_digest_set_responseData(krb5_context context, 682178825Sdfr krb5_digest digest, 683178825Sdfr const char *response) 684178825Sdfr{ 685178825Sdfr digest->request.responseData = strdup(response); 686178825Sdfr if (digest->request.responseData == NULL) { 687178825Sdfr krb5_set_error_string(context, "out of memory"); 688178825Sdfr return ENOMEM; 689178825Sdfr } 690178825Sdfr return 0; 691178825Sdfr} 692178825Sdfr 693178825Sdfrkrb5_error_code 694178825Sdfrkrb5_digest_request(krb5_context context, 695178825Sdfr krb5_digest digest, 696178825Sdfr krb5_realm realm, 697178825Sdfr krb5_ccache ccache) 698178825Sdfr{ 699178825Sdfr DigestReqInner ireq; 700178825Sdfr DigestRepInner irep; 701178825Sdfr krb5_error_code ret; 702178825Sdfr 703178825Sdfr memset(&ireq, 0, sizeof(ireq)); 704178825Sdfr memset(&irep, 0, sizeof(irep)); 705178825Sdfr 706178825Sdfr ireq.element = choice_DigestReqInner_digestRequest; 707178825Sdfr ireq.u.digestRequest = digest->request; 708178825Sdfr 709178825Sdfr if (digest->request.type == NULL) { 710178825Sdfr if (digest->init.type == NULL) { 711178825Sdfr krb5_set_error_string(context, "Type missing from req"); 712178825Sdfr return EINVAL; 713178825Sdfr } 714178825Sdfr ireq.u.digestRequest.type = digest->init.type; 715178825Sdfr } 716178825Sdfr 717178825Sdfr if (ireq.u.digestRequest.digest == NULL) 718178825Sdfr ireq.u.digestRequest.digest = "md5"; 719178825Sdfr 720178825Sdfr ret = digest_request(context, realm, ccache, 721178825Sdfr KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 722178825Sdfr if (ret) 723178825Sdfr return ret; 724178825Sdfr 725178825Sdfr if (irep.element == choice_DigestRepInner_error) { 726178825Sdfr krb5_set_error_string(context, "Digest response error: %s", 727178825Sdfr irep.u.error.reason); 728178825Sdfr ret = irep.u.error.code; 729178825Sdfr goto out; 730178825Sdfr } 731178825Sdfr 732178825Sdfr if (irep.element != choice_DigestRepInner_response) { 733178825Sdfr krb5_set_error_string(context, "digest reply not an DigestResponse"); 734178825Sdfr ret = EINVAL; 735178825Sdfr goto out; 736178825Sdfr } 737178825Sdfr 738178825Sdfr ret = copy_DigestResponse(&irep.u.response, &digest->response); 739178825Sdfr if (ret) { 740178825Sdfr krb5_set_error_string(context, "Failed to copy initReply"); 741178825Sdfr goto out; 742178825Sdfr } 743178825Sdfr 744178825Sdfrout: 745178825Sdfr free_DigestRepInner(&irep); 746178825Sdfr 747178825Sdfr return ret; 748178825Sdfr} 749178825Sdfr 750178825Sdfrkrb5_boolean 751178825Sdfrkrb5_digest_rep_get_status(krb5_context context, 752178825Sdfr krb5_digest digest) 753178825Sdfr{ 754178825Sdfr return digest->response.success ? TRUE : FALSE; 755178825Sdfr} 756178825Sdfr 757178825Sdfrconst char * 758178825Sdfrkrb5_digest_get_rsp(krb5_context context, 759178825Sdfr krb5_digest digest) 760178825Sdfr{ 761178825Sdfr if (digest->response.rsp == NULL) 762178825Sdfr return NULL; 763178825Sdfr return *digest->response.rsp; 764178825Sdfr} 765178825Sdfr 766178825Sdfrkrb5_error_code 767178825Sdfrkrb5_digest_get_tickets(krb5_context context, 768178825Sdfr krb5_digest digest, 769178825Sdfr Ticket **tickets) 770178825Sdfr{ 771178825Sdfr *tickets = NULL; 772178825Sdfr return 0; 773178825Sdfr} 774178825Sdfr 775178825Sdfr 776178825Sdfrkrb5_error_code 777178825Sdfrkrb5_digest_get_client_binding(krb5_context context, 778178825Sdfr krb5_digest digest, 779178825Sdfr char **type, 780178825Sdfr char **binding) 781178825Sdfr{ 782178825Sdfr if (digest->response.channel) { 783178825Sdfr *type = strdup(digest->response.channel->cb_type); 784178825Sdfr *binding = strdup(digest->response.channel->cb_binding); 785178825Sdfr if (*type == NULL || *binding == NULL) { 786178825Sdfr free(*type); 787178825Sdfr free(*binding); 788178825Sdfr krb5_set_error_string(context, "out of memory"); 789178825Sdfr return ENOMEM; 790178825Sdfr } 791178825Sdfr } else { 792178825Sdfr *type = NULL; 793178825Sdfr *binding = NULL; 794178825Sdfr } 795178825Sdfr return 0; 796178825Sdfr} 797178825Sdfr 798178825Sdfrkrb5_error_code 799178825Sdfrkrb5_digest_get_session_key(krb5_context context, 800178825Sdfr krb5_digest digest, 801178825Sdfr krb5_data *data) 802178825Sdfr{ 803178825Sdfr krb5_error_code ret; 804178825Sdfr 805178825Sdfr krb5_data_zero(data); 806178825Sdfr if (digest->response.session_key == NULL) 807178825Sdfr return 0; 808178825Sdfr ret = der_copy_octet_string(digest->response.session_key, data); 809178825Sdfr if (ret) 810178825Sdfr krb5_clear_error_string(context); 811178825Sdfr 812178825Sdfr return ret; 813178825Sdfr} 814178825Sdfr 815178825Sdfrstruct krb5_ntlm_data { 816178825Sdfr NTLMInit init; 817178825Sdfr NTLMInitReply initReply; 818178825Sdfr NTLMRequest request; 819178825Sdfr NTLMResponse response; 820178825Sdfr}; 821178825Sdfr 822178825Sdfrkrb5_error_code 823178825Sdfrkrb5_ntlm_alloc(krb5_context context, 824178825Sdfr krb5_ntlm *ntlm) 825178825Sdfr{ 826178825Sdfr *ntlm = calloc(1, sizeof(**ntlm)); 827178825Sdfr if (*ntlm == NULL) { 828178825Sdfr krb5_set_error_string(context, "out of memory"); 829178825Sdfr return ENOMEM; 830178825Sdfr } 831178825Sdfr return 0; 832178825Sdfr} 833178825Sdfr 834178825Sdfrkrb5_error_code 835178825Sdfrkrb5_ntlm_free(krb5_context context, krb5_ntlm ntlm) 836178825Sdfr{ 837178825Sdfr free_NTLMInit(&ntlm->init); 838178825Sdfr free_NTLMInitReply(&ntlm->initReply); 839178825Sdfr free_NTLMRequest(&ntlm->request); 840178825Sdfr free_NTLMResponse(&ntlm->response); 841178825Sdfr memset(ntlm, 0, sizeof(*ntlm)); 842178825Sdfr free(ntlm); 843178825Sdfr return 0; 844178825Sdfr} 845178825Sdfr 846178825Sdfr 847178825Sdfrkrb5_error_code 848178825Sdfrkrb5_ntlm_init_request(krb5_context context, 849178825Sdfr krb5_ntlm ntlm, 850178825Sdfr krb5_realm realm, 851178825Sdfr krb5_ccache ccache, 852178825Sdfr uint32_t flags, 853178825Sdfr const char *hostname, 854178825Sdfr const char *domainname) 855178825Sdfr{ 856178825Sdfr DigestReqInner ireq; 857178825Sdfr DigestRepInner irep; 858178825Sdfr krb5_error_code ret; 859178825Sdfr 860178825Sdfr memset(&ireq, 0, sizeof(ireq)); 861178825Sdfr memset(&irep, 0, sizeof(irep)); 862178825Sdfr 863178825Sdfr ntlm->init.flags = flags; 864178825Sdfr if (hostname) { 865178825Sdfr ALLOC(ntlm->init.hostname, 1); 866178825Sdfr *ntlm->init.hostname = strdup(hostname); 867178825Sdfr } 868178825Sdfr if (domainname) { 869178825Sdfr ALLOC(ntlm->init.domain, 1); 870178825Sdfr *ntlm->init.domain = strdup(domainname); 871178825Sdfr } 872178825Sdfr 873178825Sdfr ireq.element = choice_DigestReqInner_ntlmInit; 874178825Sdfr ireq.u.ntlmInit = ntlm->init; 875178825Sdfr 876178825Sdfr ret = digest_request(context, realm, ccache, 877178825Sdfr KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 878178825Sdfr if (ret) 879178825Sdfr goto out; 880178825Sdfr 881178825Sdfr if (irep.element == choice_DigestRepInner_error) { 882178825Sdfr krb5_set_error_string(context, "Digest init error: %s", 883178825Sdfr irep.u.error.reason); 884178825Sdfr ret = irep.u.error.code; 885178825Sdfr goto out; 886178825Sdfr } 887178825Sdfr 888178825Sdfr if (irep.element != choice_DigestRepInner_ntlmInitReply) { 889178825Sdfr krb5_set_error_string(context, "ntlm reply not an initReply"); 890178825Sdfr ret = EINVAL; 891178825Sdfr goto out; 892178825Sdfr } 893178825Sdfr 894178825Sdfr ret = copy_NTLMInitReply(&irep.u.ntlmInitReply, &ntlm->initReply); 895178825Sdfr if (ret) { 896178825Sdfr krb5_set_error_string(context, "Failed to copy initReply"); 897178825Sdfr goto out; 898178825Sdfr } 899178825Sdfr 900178825Sdfrout: 901178825Sdfr free_DigestRepInner(&irep); 902178825Sdfr 903178825Sdfr return ret; 904178825Sdfr} 905178825Sdfr 906178825Sdfrkrb5_error_code 907178825Sdfrkrb5_ntlm_init_get_flags(krb5_context context, 908178825Sdfr krb5_ntlm ntlm, 909178825Sdfr uint32_t *flags) 910178825Sdfr{ 911178825Sdfr *flags = ntlm->initReply.flags; 912178825Sdfr return 0; 913178825Sdfr} 914178825Sdfr 915178825Sdfrkrb5_error_code 916178825Sdfrkrb5_ntlm_init_get_challange(krb5_context context, 917178825Sdfr krb5_ntlm ntlm, 918178825Sdfr krb5_data *challange) 919178825Sdfr{ 920178825Sdfr krb5_error_code ret; 921178825Sdfr 922178825Sdfr ret = der_copy_octet_string(&ntlm->initReply.challange, challange); 923178825Sdfr if (ret) 924178825Sdfr krb5_clear_error_string(context); 925178825Sdfr 926178825Sdfr return ret; 927178825Sdfr} 928178825Sdfr 929178825Sdfrkrb5_error_code 930178825Sdfrkrb5_ntlm_init_get_opaque(krb5_context context, 931178825Sdfr krb5_ntlm ntlm, 932178825Sdfr krb5_data *opaque) 933178825Sdfr{ 934178825Sdfr krb5_error_code ret; 935178825Sdfr 936178825Sdfr ret = der_copy_octet_string(&ntlm->initReply.opaque, opaque); 937178825Sdfr if (ret) 938178825Sdfr krb5_clear_error_string(context); 939178825Sdfr 940178825Sdfr return ret; 941178825Sdfr} 942178825Sdfr 943178825Sdfrkrb5_error_code 944178825Sdfrkrb5_ntlm_init_get_targetname(krb5_context context, 945178825Sdfr krb5_ntlm ntlm, 946178825Sdfr char **name) 947178825Sdfr{ 948178825Sdfr *name = strdup(ntlm->initReply.targetname); 949178825Sdfr if (*name == NULL) { 950178825Sdfr krb5_clear_error_string(context); 951178825Sdfr return ENOMEM; 952178825Sdfr } 953178825Sdfr return 0; 954178825Sdfr} 955178825Sdfr 956178825Sdfrkrb5_error_code 957178825Sdfrkrb5_ntlm_init_get_targetinfo(krb5_context context, 958178825Sdfr krb5_ntlm ntlm, 959178825Sdfr krb5_data *data) 960178825Sdfr{ 961178825Sdfr krb5_error_code ret; 962178825Sdfr 963178825Sdfr if (ntlm->initReply.targetinfo == NULL) { 964178825Sdfr krb5_data_zero(data); 965178825Sdfr return 0; 966178825Sdfr } 967178825Sdfr 968178825Sdfr ret = krb5_data_copy(data, 969178825Sdfr ntlm->initReply.targetinfo->data, 970178825Sdfr ntlm->initReply.targetinfo->length); 971178825Sdfr if (ret) { 972178825Sdfr krb5_clear_error_string(context); 973178825Sdfr return ret; 974178825Sdfr } 975178825Sdfr return 0; 976178825Sdfr} 977178825Sdfr 978178825Sdfr 979178825Sdfrkrb5_error_code 980178825Sdfrkrb5_ntlm_request(krb5_context context, 981178825Sdfr krb5_ntlm ntlm, 982178825Sdfr krb5_realm realm, 983178825Sdfr krb5_ccache ccache) 984178825Sdfr{ 985178825Sdfr DigestReqInner ireq; 986178825Sdfr DigestRepInner irep; 987178825Sdfr krb5_error_code ret; 988178825Sdfr 989178825Sdfr memset(&ireq, 0, sizeof(ireq)); 990178825Sdfr memset(&irep, 0, sizeof(irep)); 991178825Sdfr 992178825Sdfr ireq.element = choice_DigestReqInner_ntlmRequest; 993178825Sdfr ireq.u.ntlmRequest = ntlm->request; 994178825Sdfr 995178825Sdfr ret = digest_request(context, realm, ccache, 996178825Sdfr KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 997178825Sdfr if (ret) 998178825Sdfr return ret; 999178825Sdfr 1000178825Sdfr if (irep.element == choice_DigestRepInner_error) { 1001178825Sdfr krb5_set_error_string(context, "NTLM response error: %s", 1002178825Sdfr irep.u.error.reason); 1003178825Sdfr ret = irep.u.error.code; 1004178825Sdfr goto out; 1005178825Sdfr } 1006178825Sdfr 1007178825Sdfr if (irep.element != choice_DigestRepInner_ntlmResponse) { 1008178825Sdfr krb5_set_error_string(context, "NTLM reply not an NTLMResponse"); 1009178825Sdfr ret = EINVAL; 1010178825Sdfr goto out; 1011178825Sdfr } 1012178825Sdfr 1013178825Sdfr ret = copy_NTLMResponse(&irep.u.ntlmResponse, &ntlm->response); 1014178825Sdfr if (ret) { 1015178825Sdfr krb5_set_error_string(context, "Failed to copy NTLMResponse"); 1016178825Sdfr goto out; 1017178825Sdfr } 1018178825Sdfr 1019178825Sdfrout: 1020178825Sdfr free_DigestRepInner(&irep); 1021178825Sdfr 1022178825Sdfr return ret; 1023178825Sdfr} 1024178825Sdfr 1025178825Sdfrkrb5_error_code 1026178825Sdfrkrb5_ntlm_req_set_flags(krb5_context context, 1027178825Sdfr krb5_ntlm ntlm, 1028178825Sdfr uint32_t flags) 1029178825Sdfr{ 1030178825Sdfr ntlm->request.flags = flags; 1031178825Sdfr return 0; 1032178825Sdfr} 1033178825Sdfr 1034178825Sdfrkrb5_error_code 1035178825Sdfrkrb5_ntlm_req_set_username(krb5_context context, 1036178825Sdfr krb5_ntlm ntlm, 1037178825Sdfr const char *username) 1038178825Sdfr{ 1039178825Sdfr ntlm->request.username = strdup(username); 1040178825Sdfr if (ntlm->request.username == NULL) { 1041178825Sdfr krb5_set_error_string(context, "out of memory"); 1042178825Sdfr return ENOMEM; 1043178825Sdfr } 1044178825Sdfr return 0; 1045178825Sdfr} 1046178825Sdfr 1047178825Sdfrkrb5_error_code 1048178825Sdfrkrb5_ntlm_req_set_targetname(krb5_context context, 1049178825Sdfr krb5_ntlm ntlm, 1050178825Sdfr const char *targetname) 1051178825Sdfr{ 1052178825Sdfr ntlm->request.targetname = strdup(targetname); 1053178825Sdfr if (ntlm->request.targetname == NULL) { 1054178825Sdfr krb5_set_error_string(context, "out of memory"); 1055178825Sdfr return ENOMEM; 1056178825Sdfr } 1057178825Sdfr return 0; 1058178825Sdfr} 1059178825Sdfr 1060178825Sdfrkrb5_error_code 1061178825Sdfrkrb5_ntlm_req_set_lm(krb5_context context, 1062178825Sdfr krb5_ntlm ntlm, 1063178825Sdfr void *hash, size_t len) 1064178825Sdfr{ 1065178825Sdfr ntlm->request.lm.data = malloc(len); 1066178825Sdfr if (ntlm->request.lm.data == NULL) { 1067178825Sdfr krb5_set_error_string(context, "out of memory"); 1068178825Sdfr return ENOMEM; 1069178825Sdfr } 1070178825Sdfr ntlm->request.lm.length = len; 1071178825Sdfr memcpy(ntlm->request.lm.data, hash, len); 1072178825Sdfr return 0; 1073178825Sdfr} 1074178825Sdfr 1075178825Sdfrkrb5_error_code 1076178825Sdfrkrb5_ntlm_req_set_ntlm(krb5_context context, 1077178825Sdfr krb5_ntlm ntlm, 1078178825Sdfr void *hash, size_t len) 1079178825Sdfr{ 1080178825Sdfr ntlm->request.ntlm.data = malloc(len); 1081178825Sdfr if (ntlm->request.ntlm.data == NULL) { 1082178825Sdfr krb5_set_error_string(context, "out of memory"); 1083178825Sdfr return ENOMEM; 1084178825Sdfr } 1085178825Sdfr ntlm->request.ntlm.length = len; 1086178825Sdfr memcpy(ntlm->request.ntlm.data, hash, len); 1087178825Sdfr return 0; 1088178825Sdfr} 1089178825Sdfr 1090178825Sdfrkrb5_error_code 1091178825Sdfrkrb5_ntlm_req_set_opaque(krb5_context context, 1092178825Sdfr krb5_ntlm ntlm, 1093178825Sdfr krb5_data *opaque) 1094178825Sdfr{ 1095178825Sdfr ntlm->request.opaque.data = malloc(opaque->length); 1096178825Sdfr if (ntlm->request.opaque.data == NULL) { 1097178825Sdfr krb5_set_error_string(context, "out of memory"); 1098178825Sdfr return ENOMEM; 1099178825Sdfr } 1100178825Sdfr ntlm->request.opaque.length = opaque->length; 1101178825Sdfr memcpy(ntlm->request.opaque.data, opaque->data, opaque->length); 1102178825Sdfr return 0; 1103178825Sdfr} 1104178825Sdfr 1105178825Sdfrkrb5_error_code 1106178825Sdfrkrb5_ntlm_req_set_session(krb5_context context, 1107178825Sdfr krb5_ntlm ntlm, 1108178825Sdfr void *sessionkey, size_t length) 1109178825Sdfr{ 1110178825Sdfr ntlm->request.sessionkey = calloc(1, sizeof(*ntlm->request.sessionkey)); 1111178825Sdfr if (ntlm->request.sessionkey == NULL) { 1112178825Sdfr krb5_set_error_string(context, "out of memory"); 1113178825Sdfr return ENOMEM; 1114178825Sdfr } 1115178825Sdfr ntlm->request.sessionkey->data = malloc(length); 1116178825Sdfr if (ntlm->request.sessionkey->data == NULL) { 1117178825Sdfr krb5_set_error_string(context, "out of memory"); 1118178825Sdfr return ENOMEM; 1119178825Sdfr } 1120178825Sdfr memcpy(ntlm->request.sessionkey->data, sessionkey, length); 1121178825Sdfr ntlm->request.sessionkey->length = length; 1122178825Sdfr return 0; 1123178825Sdfr} 1124178825Sdfr 1125178825Sdfrkrb5_boolean 1126178825Sdfrkrb5_ntlm_rep_get_status(krb5_context context, 1127178825Sdfr krb5_ntlm ntlm) 1128178825Sdfr{ 1129178825Sdfr return ntlm->response.success ? TRUE : FALSE; 1130178825Sdfr} 1131178825Sdfr 1132178825Sdfrkrb5_error_code 1133178825Sdfrkrb5_ntlm_rep_get_sessionkey(krb5_context context, 1134178825Sdfr krb5_ntlm ntlm, 1135178825Sdfr krb5_data *data) 1136178825Sdfr{ 1137178825Sdfr if (ntlm->response.sessionkey == NULL) { 1138178825Sdfr krb5_set_error_string(context, "no ntlm session key"); 1139178825Sdfr return EINVAL; 1140178825Sdfr } 1141178825Sdfr krb5_clear_error_string(context); 1142178825Sdfr return krb5_data_copy(data, 1143178825Sdfr ntlm->response.sessionkey->data, 1144178825Sdfr ntlm->response.sessionkey->length); 1145178825Sdfr} 1146178825Sdfr 1147178825Sdfr/** 1148178825Sdfr * Get the supported/allowed mechanism for this principal. 1149178825Sdfr * 1150178825Sdfr * @param context A Keberos context. 1151178825Sdfr * @param realm The realm of the KDC. 1152178825Sdfr * @param ccache The credential cache to use when talking to the KDC. 1153178825Sdfr * @param flags The supported mechanism. 1154178825Sdfr * 1155178825Sdfr * @return Return an error code or 0. 1156178825Sdfr * 1157178825Sdfr * @ingroup krb5_digest 1158178825Sdfr */ 1159178825Sdfr 1160178825Sdfrkrb5_error_code 1161178825Sdfrkrb5_digest_probe(krb5_context context, 1162178825Sdfr krb5_realm realm, 1163178825Sdfr krb5_ccache ccache, 1164178825Sdfr unsigned *flags) 1165178825Sdfr{ 1166178825Sdfr DigestReqInner ireq; 1167178825Sdfr DigestRepInner irep; 1168178825Sdfr krb5_error_code ret; 1169178825Sdfr 1170178825Sdfr memset(&ireq, 0, sizeof(ireq)); 1171178825Sdfr memset(&irep, 0, sizeof(irep)); 1172178825Sdfr 1173178825Sdfr ireq.element = choice_DigestReqInner_supportedMechs; 1174178825Sdfr 1175178825Sdfr ret = digest_request(context, realm, ccache, 1176178825Sdfr KRB5_KU_DIGEST_ENCRYPT, &ireq, &irep); 1177178825Sdfr if (ret) 1178178825Sdfr goto out; 1179178825Sdfr 1180178825Sdfr if (irep.element == choice_DigestRepInner_error) { 1181178825Sdfr krb5_set_error_string(context, "Digest probe error: %s", 1182178825Sdfr irep.u.error.reason); 1183178825Sdfr ret = irep.u.error.code; 1184178825Sdfr goto out; 1185178825Sdfr } 1186178825Sdfr 1187178825Sdfr if (irep.element != choice_DigestRepInner_supportedMechs) { 1188178825Sdfr krb5_set_error_string(context, "Digest reply not an probe"); 1189178825Sdfr ret = EINVAL; 1190178825Sdfr goto out; 1191178825Sdfr } 1192178825Sdfr 1193178825Sdfr *flags = DigestTypes2int(irep.u.supportedMechs); 1194178825Sdfr 1195178825Sdfrout: 1196178825Sdfr free_DigestRepInner(&irep); 1197178825Sdfr 1198178825Sdfr return ret; 1199178825Sdfr} 1200