2 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
45 krb5_realm kerberos_realm;
54 static OM_uint32 kdc_destroy(OM_uint32 *, void *);
57 * Get credential cache that the ntlm code can use to talk to the KDC
58 * using the digest API.
61 static krb5_error_code
62 get_ccache(krb5_context context, int *destroy, krb5_ccache *id)
64 krb5_principal principal = NULL;
66 krb5_keytab kt = NULL;
73 cache = getenv("NTLM_ACCEPTOR_CCACHE");
75 ret = krb5_cc_resolve(context, cache, id);
82 ret = krb5_sname_to_principal(context, NULL, "host",
83 KRB5_NT_SRV_HST, &principal);
87 ret = krb5_cc_cache_match(context, principal, id);
91 /* did not find in default credcache, lets try default keytab */
92 ret = krb5_kt_default(context, &kt);
96 /* XXX check in keytab */
98 krb5_get_init_creds_opt *opt;
101 memset(&cred, 0, sizeof(cred));
103 ret = krb5_cc_new_unique(context, "MEMORY", NULL, id);
107 ret = krb5_get_init_creds_opt_alloc(context, &opt);
110 ret = krb5_get_init_creds_keytab (context,
117 krb5_get_init_creds_opt_free(context, opt);
120 ret = krb5_cc_initialize (context, *id, cred.client);
122 krb5_free_cred_contents (context, &cred);
125 ret = krb5_cc_store_cred (context, *id, &cred);
126 krb5_free_cred_contents (context, &cred);
131 krb5_kt_close(context, kt);
138 krb5_cc_destroy(context, *id);
140 krb5_cc_close(context, *id);
145 krb5_kt_close(context, kt);
148 krb5_free_principal(context, principal);
157 kdc_alloc(OM_uint32 *minor, void **ctx)
163 c = calloc(1, sizeof(*c));
166 return GSS_S_FAILURE;
169 ret = krb5_init_context(&c->context);
171 kdc_destroy(&junk, c);
173 return GSS_S_FAILURE;
176 ret = get_ccache(c->context, &c->destroy, &c->id);
178 kdc_destroy(&junk, c);
180 return GSS_S_FAILURE;
183 ret = krb5_ntlm_alloc(c->context, &c->ntlm);
185 kdc_destroy(&junk, c);
187 return GSS_S_FAILURE;
192 return GSS_S_COMPLETE;
196 kdc_probe(OM_uint32 *minor, void *ctx, const char *realm)
198 struct ntlmkrb5 *c = ctx;
202 ret = krb5_digest_probe(c->context, rk_UNCONST(realm), c->id, &flags);
206 if ((flags & (1|2|4)) == 0)
217 kdc_destroy(OM_uint32 *minor, void *ctx)
219 struct ntlmkrb5 *c = ctx;
220 krb5_data_free(&c->opaque);
221 krb5_data_free(&c->sessionkey);
223 krb5_ntlm_free(c->context, c->ntlm);
226 krb5_cc_destroy(c->context, c->id);
228 krb5_cc_close(c->context, c->id);
231 krb5_free_context(c->context);
232 memset(c, 0, sizeof(*c));
235 return GSS_S_COMPLETE;
243 kdc_type2(OM_uint32 *minor_status,
246 const char *hostname,
249 struct ntlm_buf *out)
251 struct ntlmkrb5 *c = ctx;
253 struct ntlm_type2 type2;
255 struct ntlm_buf data;
258 memset(&type2, 0, sizeof(type2));
261 * Request data for type 2 packet from the KDC.
263 ret = krb5_ntlm_init_request(c->context,
272 return GSS_S_FAILURE;
279 ret = krb5_ntlm_init_get_opaque(c->context, c->ntlm, &c->opaque);
282 return GSS_S_FAILURE;
289 ret = krb5_ntlm_init_get_flags(c->context, c->ntlm, &type2.flags);
292 return GSS_S_FAILURE;
294 *ret_flags = type2.flags;
296 ret = krb5_ntlm_init_get_challange(c->context, c->ntlm, &challange);
299 return GSS_S_FAILURE;
302 if (challange.length != sizeof(type2.challenge)) {
303 *minor_status = EINVAL;
304 return GSS_S_FAILURE;
306 memcpy(type2.challenge, challange.data, sizeof(type2.challenge));
307 krb5_data_free(&challange);
309 ret = krb5_ntlm_init_get_targetname(c->context, c->ntlm,
313 return GSS_S_FAILURE;
316 ret = krb5_ntlm_init_get_targetinfo(c->context, c->ntlm, &ti);
318 free(type2.targetname);
320 return GSS_S_FAILURE;
323 type2.targetinfo.data = ti.data;
324 type2.targetinfo.length = ti.length;
326 ret = heim_ntlm_encode_type2(&type2, &data);
327 free(type2.targetname);
331 return GSS_S_FAILURE;
334 out->data = data.data;
335 out->length = data.length;
337 return GSS_S_COMPLETE;
345 kdc_type3(OM_uint32 *minor_status,
347 const struct ntlm_type3 *type3,
348 struct ntlm_buf *sessionkey)
350 struct ntlmkrb5 *c = ctx;
353 sessionkey->data = NULL;
354 sessionkey->length = 0;
356 ret = krb5_ntlm_req_set_flags(c->context, c->ntlm, type3->flags);
358 ret = krb5_ntlm_req_set_username(c->context, c->ntlm, type3->username);
360 ret = krb5_ntlm_req_set_targetname(c->context, c->ntlm,
363 ret = krb5_ntlm_req_set_lm(c->context, c->ntlm,
364 type3->lm.data, type3->lm.length);
366 ret = krb5_ntlm_req_set_ntlm(c->context, c->ntlm,
367 type3->ntlm.data, type3->ntlm.length);
369 ret = krb5_ntlm_req_set_opaque(c->context, c->ntlm, &c->opaque);
372 if (type3->sessionkey.length) {
373 ret = krb5_ntlm_req_set_session(c->context, c->ntlm,
374 type3->sessionkey.data,
375 type3->sessionkey.length);
380 * Verify with the KDC the type3 packet is ok
382 ret = krb5_ntlm_request(c->context,
389 if (krb5_ntlm_rep_get_status(c->context, c->ntlm) != TRUE) {
394 if (type3->sessionkey.length) {
395 ret = krb5_ntlm_rep_get_sessionkey(c->context,
401 sessionkey->data = c->sessionkey.data;
402 sessionkey->length = c->sessionkey.length;
409 return GSS_S_FAILURE;
417 kdc_free_buffer(struct ntlm_buf *sessionkey)
419 if (sessionkey->data)
420 free(sessionkey->data);
421 sessionkey->data = NULL;
422 sessionkey->length = 0;
429 struct ntlm_server_interface ntlmsspi_kdc_digest = {