Remove building with NOCRYPTO option
[minix.git] / crypto / external / bsd / heimdal / dist / lib / gssapi / ntlm / kdc.c
blobcb2de8b8f35372e59b48a7b5b715ea476af49712
1 /* $NetBSD: kdc.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $ */
3 /*
4 * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include "ntlm.h"
38 #ifdef DIGEST
44 struct ntlmkrb5 {
45 krb5_context context;
46 krb5_ntlm ntlm;
47 krb5_realm kerberos_realm;
48 krb5_ccache id;
49 krb5_data opaque;
50 int destroy;
51 OM_uint32 flags;
52 struct ntlm_buf key;
53 krb5_data sessionkey;
56 static OM_uint32 kdc_destroy(OM_uint32 *, void *);
59 * Get credential cache that the ntlm code can use to talk to the KDC
60 * using the digest API.
63 static krb5_error_code
64 get_ccache(krb5_context context, int *destroy, krb5_ccache *id)
66 krb5_principal principal = NULL;
67 krb5_error_code ret;
68 krb5_keytab kt = NULL;
70 *id = NULL;
72 if (!issuid()) {
73 const char *cache;
75 cache = getenv("NTLM_ACCEPTOR_CCACHE");
76 if (cache) {
77 ret = krb5_cc_resolve(context, cache, id);
78 if (ret)
79 goto out;
80 return 0;
84 ret = krb5_sname_to_principal(context, NULL, "host",
85 KRB5_NT_SRV_HST, &principal);
86 if (ret)
87 goto out;
89 ret = krb5_cc_cache_match(context, principal, id);
90 if (ret == 0)
91 return 0;
93 /* did not find in default credcache, lets try default keytab */
94 ret = krb5_kt_default(context, &kt);
95 if (ret)
96 goto out;
98 /* XXX check in keytab */
100 krb5_get_init_creds_opt *opt;
101 krb5_creds cred;
103 memset(&cred, 0, sizeof(cred));
105 ret = krb5_cc_new_unique(context, "MEMORY", NULL, id);
106 if (ret)
107 goto out;
108 *destroy = 1;
109 ret = krb5_get_init_creds_opt_alloc(context, &opt);
110 if (ret)
111 goto out;
112 ret = krb5_get_init_creds_keytab (context,
113 &cred,
114 principal,
117 NULL,
118 opt);
119 krb5_get_init_creds_opt_free(context, opt);
120 if (ret)
121 goto out;
122 ret = krb5_cc_initialize (context, *id, cred.client);
123 if (ret) {
124 krb5_free_cred_contents (context, &cred);
125 goto out;
127 ret = krb5_cc_store_cred (context, *id, &cred);
128 krb5_free_cred_contents (context, &cred);
129 if (ret)
130 goto out;
133 krb5_kt_close(context, kt);
135 return 0;
137 out:
138 if (*id) {
139 if (*destroy)
140 krb5_cc_destroy(context, *id);
141 else
142 krb5_cc_close(context, *id);
143 *id = NULL;
146 if (kt)
147 krb5_kt_close(context, kt);
149 if (principal)
150 krb5_free_principal(context, principal);
151 return ret;
158 static OM_uint32
159 kdc_alloc(OM_uint32 *minor, void **ctx)
161 krb5_error_code ret;
162 struct ntlmkrb5 *c;
163 OM_uint32 junk;
165 c = calloc(1, sizeof(*c));
166 if (c == NULL) {
167 *minor = ENOMEM;
168 return GSS_S_FAILURE;
171 ret = krb5_init_context(&c->context);
172 if (ret) {
173 kdc_destroy(&junk, c);
174 *minor = ret;
175 return GSS_S_FAILURE;
178 ret = get_ccache(c->context, &c->destroy, &c->id);
179 if (ret) {
180 kdc_destroy(&junk, c);
181 *minor = ret;
182 return GSS_S_FAILURE;
185 ret = krb5_ntlm_alloc(c->context, &c->ntlm);
186 if (ret) {
187 kdc_destroy(&junk, c);
188 *minor = ret;
189 return GSS_S_FAILURE;
192 *ctx = c;
194 return GSS_S_COMPLETE;
197 static int
198 kdc_probe(OM_uint32 *minor, void *ctx, const char *realm)
200 struct ntlmkrb5 *c = ctx;
201 krb5_error_code ret;
202 unsigned flags;
204 ret = krb5_digest_probe(c->context, rk_UNCONST(realm), c->id, &flags);
205 if (ret)
206 return ret;
208 if ((flags & (1|2|4)) == 0)
209 return EINVAL;
211 return 0;
218 static OM_uint32
219 kdc_destroy(OM_uint32 *minor, void *ctx)
221 struct ntlmkrb5 *c = ctx;
222 krb5_data_free(&c->opaque);
223 krb5_data_free(&c->sessionkey);
224 if (c->ntlm)
225 krb5_ntlm_free(c->context, c->ntlm);
226 if (c->id) {
227 if (c->destroy)
228 krb5_cc_destroy(c->context, c->id);
229 else
230 krb5_cc_close(c->context, c->id);
232 if (c->context)
233 krb5_free_context(c->context);
234 memset(c, 0, sizeof(*c));
235 free(c);
237 return GSS_S_COMPLETE;
244 static OM_uint32
245 kdc_type2(OM_uint32 *minor_status,
246 void *ctx,
247 uint32_t flags,
248 const char *hostname,
249 const char *domain,
250 uint32_t *ret_flags,
251 struct ntlm_buf *out)
253 struct ntlmkrb5 *c = ctx;
254 krb5_error_code ret;
255 struct ntlm_type2 type2;
256 krb5_data challange;
257 struct ntlm_buf data;
258 krb5_data ti;
260 memset(&type2, 0, sizeof(type2));
263 * Request data for type 2 packet from the KDC.
265 ret = krb5_ntlm_init_request(c->context,
266 c->ntlm,
267 NULL,
268 c->id,
269 flags,
270 hostname,
271 domain);
272 if (ret) {
273 *minor_status = ret;
274 return GSS_S_FAILURE;
281 ret = krb5_ntlm_init_get_opaque(c->context, c->ntlm, &c->opaque);
282 if (ret) {
283 *minor_status = ret;
284 return GSS_S_FAILURE;
291 ret = krb5_ntlm_init_get_flags(c->context, c->ntlm, &type2.flags);
292 if (ret) {
293 *minor_status = ret;
294 return GSS_S_FAILURE;
296 *ret_flags = type2.flags;
298 ret = krb5_ntlm_init_get_challange(c->context, c->ntlm, &challange);
299 if (ret) {
300 *minor_status = ret;
301 return GSS_S_FAILURE;
304 if (challange.length != sizeof(type2.challenge)) {
305 *minor_status = EINVAL;
306 return GSS_S_FAILURE;
308 memcpy(type2.challenge, challange.data, sizeof(type2.challenge));
309 krb5_data_free(&challange);
311 ret = krb5_ntlm_init_get_targetname(c->context, c->ntlm,
312 &type2.targetname);
313 if (ret) {
314 *minor_status = ret;
315 return GSS_S_FAILURE;
318 ret = krb5_ntlm_init_get_targetinfo(c->context, c->ntlm, &ti);
319 if (ret) {
320 free(type2.targetname);
321 *minor_status = ret;
322 return GSS_S_FAILURE;
325 type2.targetinfo.data = ti.data;
326 type2.targetinfo.length = ti.length;
328 ret = heim_ntlm_encode_type2(&type2, &data);
329 free(type2.targetname);
330 krb5_data_free(&ti);
331 if (ret) {
332 *minor_status = ret;
333 return GSS_S_FAILURE;
336 out->data = data.data;
337 out->length = data.length;
339 return GSS_S_COMPLETE;
346 static OM_uint32
347 kdc_type3(OM_uint32 *minor_status,
348 void *ctx,
349 const struct ntlm_type3 *type3,
350 struct ntlm_buf *sessionkey)
352 struct ntlmkrb5 *c = ctx;
353 krb5_error_code ret;
355 sessionkey->data = NULL;
356 sessionkey->length = 0;
358 ret = krb5_ntlm_req_set_flags(c->context, c->ntlm, type3->flags);
359 if (ret) goto out;
360 ret = krb5_ntlm_req_set_username(c->context, c->ntlm, type3->username);
361 if (ret) goto out;
362 ret = krb5_ntlm_req_set_targetname(c->context, c->ntlm,
363 type3->targetname);
364 if (ret) goto out;
365 ret = krb5_ntlm_req_set_lm(c->context, c->ntlm,
366 type3->lm.data, type3->lm.length);
367 if (ret) goto out;
368 ret = krb5_ntlm_req_set_ntlm(c->context, c->ntlm,
369 type3->ntlm.data, type3->ntlm.length);
370 if (ret) goto out;
371 ret = krb5_ntlm_req_set_opaque(c->context, c->ntlm, &c->opaque);
372 if (ret) goto out;
374 if (type3->sessionkey.length) {
375 ret = krb5_ntlm_req_set_session(c->context, c->ntlm,
376 type3->sessionkey.data,
377 type3->sessionkey.length);
378 if (ret) goto out;
382 * Verify with the KDC the type3 packet is ok
384 ret = krb5_ntlm_request(c->context,
385 c->ntlm,
386 NULL,
387 c->id);
388 if (ret)
389 goto out;
391 if (krb5_ntlm_rep_get_status(c->context, c->ntlm) != TRUE) {
392 ret = EINVAL;
393 goto out;
396 if (type3->sessionkey.length) {
397 ret = krb5_ntlm_rep_get_sessionkey(c->context,
398 c->ntlm,
399 &c->sessionkey);
400 if (ret)
401 goto out;
403 sessionkey->data = c->sessionkey.data;
404 sessionkey->length = c->sessionkey.length;
407 return 0;
409 out:
410 *minor_status = ret;
411 return GSS_S_FAILURE;
418 static void
419 kdc_free_buffer(struct ntlm_buf *sessionkey)
421 if (sessionkey->data)
422 free(sessionkey->data);
423 sessionkey->data = NULL;
424 sessionkey->length = 0;
431 struct ntlm_server_interface ntlmsspi_kdc_digest = {
432 kdc_alloc,
433 kdc_destroy,
434 kdc_probe,
435 kdc_type2,
436 kdc_type3,
437 kdc_free_buffer
440 #endif /* DIGEST */