1 1.1 elric /* $NetBSD: kdc.c,v 1.2 2017/01/28 21:31:47 christos Exp $ */ 2 1.1 elric 3 1.1 elric /* 4 1.1 elric * Copyright (c) 2006 - 2007 Kungliga Tekniska Hgskolan 5 1.1 elric * (Royal Institute of Technology, Stockholm, Sweden). 6 1.1 elric * All rights reserved. 7 1.1 elric * 8 1.1 elric * Redistribution and use in source and binary forms, with or without 9 1.1 elric * modification, are permitted provided that the following conditions 10 1.1 elric * are met: 11 1.1 elric * 12 1.1 elric * 1. Redistributions of source code must retain the above copyright 13 1.1 elric * notice, this list of conditions and the following disclaimer. 14 1.1 elric * 15 1.1 elric * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 elric * notice, this list of conditions and the following disclaimer in the 17 1.1 elric * documentation and/or other materials provided with the distribution. 18 1.1 elric * 19 1.1 elric * 3. Neither the name of the Institute nor the names of its contributors 20 1.1 elric * may be used to endorse or promote products derived from this software 21 1.1 elric * without specific prior written permission. 22 1.1 elric * 23 1.1 elric * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 1.1 elric * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.1 elric * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.1 elric * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 1.1 elric * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.1 elric * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.1 elric * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.1 elric * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.1 elric * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.1 elric * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.1 elric * SUCH DAMAGE. 34 1.1 elric */ 35 1.1 elric 36 1.1 elric #include "ntlm.h" 37 1.1 elric 38 1.1 elric #ifdef DIGEST 39 1.1 elric 40 1.1 elric /* 41 1.1 elric * 42 1.1 elric */ 43 1.1 elric 44 1.1 elric struct ntlmkrb5 { 45 1.1 elric krb5_context context; 46 1.1 elric krb5_ntlm ntlm; 47 1.1 elric krb5_realm kerberos_realm; 48 1.1 elric krb5_ccache id; 49 1.1 elric krb5_data opaque; 50 1.1 elric int destroy; 51 1.1 elric OM_uint32 flags; 52 1.1 elric struct ntlm_buf key; 53 1.1 elric krb5_data sessionkey; 54 1.1 elric }; 55 1.1 elric 56 1.1 elric static OM_uint32 kdc_destroy(OM_uint32 *, void *); 57 1.1 elric 58 1.1 elric /* 59 1.1 elric * Get credential cache that the ntlm code can use to talk to the KDC 60 1.1 elric * using the digest API. 61 1.1 elric */ 62 1.1 elric 63 1.1 elric static krb5_error_code 64 1.1 elric get_ccache(krb5_context context, int *destroy, krb5_ccache *id) 65 1.1 elric { 66 1.1 elric krb5_principal principal = NULL; 67 1.1 elric krb5_error_code ret; 68 1.1 elric krb5_keytab kt = NULL; 69 1.1 elric 70 1.1 elric *id = NULL; 71 1.1 elric 72 1.1 elric if (!issuid()) { 73 1.1 elric const char *cache; 74 1.1 elric 75 1.1 elric cache = getenv("NTLM_ACCEPTOR_CCACHE"); 76 1.1 elric if (cache) { 77 1.1 elric ret = krb5_cc_resolve(context, cache, id); 78 1.1 elric if (ret) 79 1.1 elric goto out; 80 1.1 elric return 0; 81 1.1 elric } 82 1.1 elric } 83 1.1 elric 84 1.1 elric ret = krb5_sname_to_principal(context, NULL, "host", 85 1.1 elric KRB5_NT_SRV_HST, &principal); 86 1.1 elric if (ret) 87 1.1 elric goto out; 88 1.1 elric 89 1.1 elric ret = krb5_cc_cache_match(context, principal, id); 90 1.1 elric if (ret == 0) 91 1.1 elric return 0; 92 1.1 elric 93 1.1 elric /* did not find in default credcache, lets try default keytab */ 94 1.1 elric ret = krb5_kt_default(context, &kt); 95 1.1 elric if (ret) 96 1.1 elric goto out; 97 1.1 elric 98 1.1 elric /* XXX check in keytab */ 99 1.1 elric { 100 1.1 elric krb5_get_init_creds_opt *opt; 101 1.1 elric krb5_creds cred; 102 1.1 elric 103 1.1 elric memset(&cred, 0, sizeof(cred)); 104 1.1 elric 105 1.1 elric ret = krb5_cc_new_unique(context, "MEMORY", NULL, id); 106 1.1 elric if (ret) 107 1.1 elric goto out; 108 1.1 elric *destroy = 1; 109 1.1 elric ret = krb5_get_init_creds_opt_alloc(context, &opt); 110 1.1 elric if (ret) 111 1.1 elric goto out; 112 1.1 elric ret = krb5_get_init_creds_keytab (context, 113 1.1 elric &cred, 114 1.1 elric principal, 115 1.1 elric kt, 116 1.1 elric 0, 117 1.1 elric NULL, 118 1.1 elric opt); 119 1.1 elric krb5_get_init_creds_opt_free(context, opt); 120 1.1 elric if (ret) 121 1.1 elric goto out; 122 1.1 elric ret = krb5_cc_initialize (context, *id, cred.client); 123 1.1 elric if (ret) { 124 1.1 elric krb5_free_cred_contents (context, &cred); 125 1.1 elric goto out; 126 1.1 elric } 127 1.1 elric ret = krb5_cc_store_cred (context, *id, &cred); 128 1.1 elric krb5_free_cred_contents (context, &cred); 129 1.1 elric if (ret) 130 1.1 elric goto out; 131 1.1 elric } 132 1.1 elric 133 1.1 elric krb5_kt_close(context, kt); 134 1.1 elric 135 1.1 elric return 0; 136 1.1 elric 137 1.1 elric out: 138 1.1 elric if (*id) { 139 1.1 elric if (*destroy) 140 1.1 elric krb5_cc_destroy(context, *id); 141 1.1 elric else 142 1.1 elric krb5_cc_close(context, *id); 143 1.1 elric *id = NULL; 144 1.1 elric } 145 1.1 elric 146 1.1 elric if (kt) 147 1.1 elric krb5_kt_close(context, kt); 148 1.1 elric 149 1.1 elric if (principal) 150 1.1 elric krb5_free_principal(context, principal); 151 1.1 elric return ret; 152 1.1 elric } 153 1.1 elric 154 1.1 elric /* 155 1.1 elric * 156 1.1 elric */ 157 1.1 elric 158 1.1 elric static OM_uint32 159 1.1 elric kdc_alloc(OM_uint32 *minor, void **ctx) 160 1.1 elric { 161 1.1 elric krb5_error_code ret; 162 1.1 elric struct ntlmkrb5 *c; 163 1.1 elric OM_uint32 junk; 164 1.1 elric 165 1.1 elric c = calloc(1, sizeof(*c)); 166 1.1 elric if (c == NULL) { 167 1.1 elric *minor = ENOMEM; 168 1.1 elric return GSS_S_FAILURE; 169 1.1 elric } 170 1.1 elric 171 1.1 elric ret = krb5_init_context(&c->context); 172 1.1 elric if (ret) { 173 1.1 elric kdc_destroy(&junk, c); 174 1.1 elric *minor = ret; 175 1.1 elric return GSS_S_FAILURE; 176 1.1 elric } 177 1.1 elric 178 1.1 elric ret = get_ccache(c->context, &c->destroy, &c->id); 179 1.1 elric if (ret) { 180 1.1 elric kdc_destroy(&junk, c); 181 1.1 elric *minor = ret; 182 1.1 elric return GSS_S_FAILURE; 183 1.1 elric } 184 1.1 elric 185 1.1 elric ret = krb5_ntlm_alloc(c->context, &c->ntlm); 186 1.1 elric if (ret) { 187 1.1 elric kdc_destroy(&junk, c); 188 1.1 elric *minor = ret; 189 1.1 elric return GSS_S_FAILURE; 190 1.1 elric } 191 1.1 elric 192 1.1 elric *ctx = c; 193 1.1 elric 194 1.1 elric return GSS_S_COMPLETE; 195 1.1 elric } 196 1.1 elric 197 1.1 elric static int 198 1.1 elric kdc_probe(OM_uint32 *minor, void *ctx, const char *realm) 199 1.1 elric { 200 1.1 elric struct ntlmkrb5 *c = ctx; 201 1.1 elric krb5_error_code ret; 202 1.1 elric unsigned flags; 203 1.1 elric 204 1.1 elric ret = krb5_digest_probe(c->context, rk_UNCONST(realm), c->id, &flags); 205 1.1 elric if (ret) 206 1.1 elric return ret; 207 1.1 elric 208 1.1 elric if ((flags & (1|2|4)) == 0) 209 1.1 elric return EINVAL; 210 1.1 elric 211 1.1 elric return 0; 212 1.1 elric } 213 1.1 elric 214 1.1 elric /* 215 1.1 elric * 216 1.1 elric */ 217 1.1 elric 218 1.1 elric static OM_uint32 219 1.1 elric kdc_destroy(OM_uint32 *minor, void *ctx) 220 1.1 elric { 221 1.1 elric struct ntlmkrb5 *c = ctx; 222 1.1 elric krb5_data_free(&c->opaque); 223 1.1 elric krb5_data_free(&c->sessionkey); 224 1.1 elric if (c->ntlm) 225 1.1 elric krb5_ntlm_free(c->context, c->ntlm); 226 1.1 elric if (c->id) { 227 1.1 elric if (c->destroy) 228 1.1 elric krb5_cc_destroy(c->context, c->id); 229 1.1 elric else 230 1.1 elric krb5_cc_close(c->context, c->id); 231 1.1 elric } 232 1.1 elric if (c->context) 233 1.1 elric krb5_free_context(c->context); 234 1.1 elric memset(c, 0, sizeof(*c)); 235 1.1 elric free(c); 236 1.1 elric 237 1.1 elric return GSS_S_COMPLETE; 238 1.1 elric } 239 1.1 elric 240 1.1 elric /* 241 1.1 elric * 242 1.1 elric */ 243 1.1 elric 244 1.1 elric static OM_uint32 245 1.1 elric kdc_type2(OM_uint32 *minor_status, 246 1.1 elric void *ctx, 247 1.1 elric uint32_t flags, 248 1.1 elric const char *hostname, 249 1.1 elric const char *domain, 250 1.1 elric uint32_t *ret_flags, 251 1.1 elric struct ntlm_buf *out) 252 1.1 elric { 253 1.1 elric struct ntlmkrb5 *c = ctx; 254 1.1 elric krb5_error_code ret; 255 1.1 elric struct ntlm_type2 type2; 256 1.2 christos krb5_data challenge; 257 1.1 elric struct ntlm_buf data; 258 1.1 elric krb5_data ti; 259 1.1 elric 260 1.1 elric memset(&type2, 0, sizeof(type2)); 261 1.1 elric 262 1.1 elric /* 263 1.1 elric * Request data for type 2 packet from the KDC. 264 1.1 elric */ 265 1.1 elric ret = krb5_ntlm_init_request(c->context, 266 1.1 elric c->ntlm, 267 1.1 elric NULL, 268 1.1 elric c->id, 269 1.1 elric flags, 270 1.1 elric hostname, 271 1.1 elric domain); 272 1.1 elric if (ret) { 273 1.1 elric *minor_status = ret; 274 1.1 elric return GSS_S_FAILURE; 275 1.1 elric } 276 1.1 elric 277 1.1 elric /* 278 1.1 elric * 279 1.1 elric */ 280 1.1 elric 281 1.1 elric ret = krb5_ntlm_init_get_opaque(c->context, c->ntlm, &c->opaque); 282 1.1 elric if (ret) { 283 1.1 elric *minor_status = ret; 284 1.1 elric return GSS_S_FAILURE; 285 1.1 elric } 286 1.1 elric 287 1.1 elric /* 288 1.1 elric * 289 1.1 elric */ 290 1.1 elric 291 1.1 elric ret = krb5_ntlm_init_get_flags(c->context, c->ntlm, &type2.flags); 292 1.1 elric if (ret) { 293 1.1 elric *minor_status = ret; 294 1.1 elric return GSS_S_FAILURE; 295 1.1 elric } 296 1.1 elric *ret_flags = type2.flags; 297 1.1 elric 298 1.2 christos ret = krb5_ntlm_init_get_challenge(c->context, c->ntlm, &challenge); 299 1.1 elric if (ret) { 300 1.1 elric *minor_status = ret; 301 1.1 elric return GSS_S_FAILURE; 302 1.1 elric } 303 1.1 elric 304 1.2 christos if (challenge.length != sizeof(type2.challenge)) { 305 1.1 elric *minor_status = EINVAL; 306 1.1 elric return GSS_S_FAILURE; 307 1.1 elric } 308 1.2 christos memcpy(type2.challenge, challenge.data, sizeof(type2.challenge)); 309 1.2 christos krb5_data_free(&challenge); 310 1.1 elric 311 1.1 elric ret = krb5_ntlm_init_get_targetname(c->context, c->ntlm, 312 1.1 elric &type2.targetname); 313 1.1 elric if (ret) { 314 1.1 elric *minor_status = ret; 315 1.1 elric return GSS_S_FAILURE; 316 1.1 elric } 317 1.1 elric 318 1.1 elric ret = krb5_ntlm_init_get_targetinfo(c->context, c->ntlm, &ti); 319 1.1 elric if (ret) { 320 1.1 elric free(type2.targetname); 321 1.1 elric *minor_status = ret; 322 1.1 elric return GSS_S_FAILURE; 323 1.1 elric } 324 1.1 elric 325 1.1 elric type2.targetinfo.data = ti.data; 326 1.1 elric type2.targetinfo.length = ti.length; 327 1.2 christos 328 1.1 elric ret = heim_ntlm_encode_type2(&type2, &data); 329 1.1 elric free(type2.targetname); 330 1.1 elric krb5_data_free(&ti); 331 1.1 elric if (ret) { 332 1.1 elric *minor_status = ret; 333 1.1 elric return GSS_S_FAILURE; 334 1.1 elric } 335 1.2 christos 336 1.1 elric out->data = data.data; 337 1.1 elric out->length = data.length; 338 1.1 elric 339 1.1 elric return GSS_S_COMPLETE; 340 1.1 elric } 341 1.1 elric 342 1.1 elric /* 343 1.1 elric * 344 1.1 elric */ 345 1.1 elric 346 1.1 elric static OM_uint32 347 1.1 elric kdc_type3(OM_uint32 *minor_status, 348 1.1 elric void *ctx, 349 1.1 elric const struct ntlm_type3 *type3, 350 1.1 elric struct ntlm_buf *sessionkey) 351 1.1 elric { 352 1.1 elric struct ntlmkrb5 *c = ctx; 353 1.1 elric krb5_error_code ret; 354 1.1 elric 355 1.1 elric sessionkey->data = NULL; 356 1.1 elric sessionkey->length = 0; 357 1.1 elric 358 1.1 elric ret = krb5_ntlm_req_set_flags(c->context, c->ntlm, type3->flags); 359 1.1 elric if (ret) goto out; 360 1.1 elric ret = krb5_ntlm_req_set_username(c->context, c->ntlm, type3->username); 361 1.1 elric if (ret) goto out; 362 1.1 elric ret = krb5_ntlm_req_set_targetname(c->context, c->ntlm, 363 1.1 elric type3->targetname); 364 1.1 elric if (ret) goto out; 365 1.1 elric ret = krb5_ntlm_req_set_lm(c->context, c->ntlm, 366 1.1 elric type3->lm.data, type3->lm.length); 367 1.1 elric if (ret) goto out; 368 1.1 elric ret = krb5_ntlm_req_set_ntlm(c->context, c->ntlm, 369 1.1 elric type3->ntlm.data, type3->ntlm.length); 370 1.1 elric if (ret) goto out; 371 1.1 elric ret = krb5_ntlm_req_set_opaque(c->context, c->ntlm, &c->opaque); 372 1.1 elric if (ret) goto out; 373 1.1 elric 374 1.1 elric if (type3->sessionkey.length) { 375 1.1 elric ret = krb5_ntlm_req_set_session(c->context, c->ntlm, 376 1.1 elric type3->sessionkey.data, 377 1.1 elric type3->sessionkey.length); 378 1.1 elric if (ret) goto out; 379 1.1 elric } 380 1.1 elric 381 1.1 elric /* 382 1.1 elric * Verify with the KDC the type3 packet is ok 383 1.1 elric */ 384 1.1 elric ret = krb5_ntlm_request(c->context, 385 1.1 elric c->ntlm, 386 1.1 elric NULL, 387 1.1 elric c->id); 388 1.1 elric if (ret) 389 1.1 elric goto out; 390 1.1 elric 391 1.1 elric if (krb5_ntlm_rep_get_status(c->context, c->ntlm) != TRUE) { 392 1.1 elric ret = EINVAL; 393 1.1 elric goto out; 394 1.1 elric } 395 1.1 elric 396 1.1 elric if (type3->sessionkey.length) { 397 1.1 elric ret = krb5_ntlm_rep_get_sessionkey(c->context, 398 1.1 elric c->ntlm, 399 1.1 elric &c->sessionkey); 400 1.1 elric if (ret) 401 1.1 elric goto out; 402 1.1 elric 403 1.1 elric sessionkey->data = c->sessionkey.data; 404 1.1 elric sessionkey->length = c->sessionkey.length; 405 1.1 elric } 406 1.1 elric 407 1.1 elric return 0; 408 1.1 elric 409 1.1 elric out: 410 1.1 elric *minor_status = ret; 411 1.1 elric return GSS_S_FAILURE; 412 1.1 elric } 413 1.1 elric 414 1.1 elric /* 415 1.1 elric * 416 1.1 elric */ 417 1.1 elric 418 1.1 elric static void 419 1.1 elric kdc_free_buffer(struct ntlm_buf *sessionkey) 420 1.1 elric { 421 1.1 elric if (sessionkey->data) 422 1.1 elric free(sessionkey->data); 423 1.1 elric sessionkey->data = NULL; 424 1.1 elric sessionkey->length = 0; 425 1.1 elric } 426 1.1 elric 427 1.1 elric /* 428 1.1 elric * 429 1.1 elric */ 430 1.1 elric 431 1.1 elric struct ntlm_server_interface ntlmsspi_kdc_digest = { 432 1.1 elric kdc_alloc, 433 1.1 elric kdc_destroy, 434 1.1 elric kdc_probe, 435 1.1 elric kdc_type2, 436 1.1 elric kdc_type3, 437 1.1 elric kdc_free_buffer 438 1.1 elric }; 439 1.1 elric 440 1.1 elric #endif /* DIGEST */ 441