Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/gssapi/ntlm/kdc.c
34914 views
1
/*
2
* Copyright (c) 2006 - 2007 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 "ntlm.h"
35
36
#ifdef DIGEST
37
38
/*
39
*
40
*/
41
42
struct ntlmkrb5 {
43
krb5_context context;
44
krb5_ntlm ntlm;
45
krb5_realm kerberos_realm;
46
krb5_ccache id;
47
krb5_data opaque;
48
int destroy;
49
OM_uint32 flags;
50
struct ntlm_buf key;
51
krb5_data sessionkey;
52
};
53
54
static OM_uint32 kdc_destroy(OM_uint32 *, void *);
55
56
/*
57
* Get credential cache that the ntlm code can use to talk to the KDC
58
* using the digest API.
59
*/
60
61
static krb5_error_code
62
get_ccache(krb5_context context, int *destroy, krb5_ccache *id)
63
{
64
krb5_principal principal = NULL;
65
krb5_error_code ret;
66
krb5_keytab kt = NULL;
67
68
*id = NULL;
69
70
if (!issuid()) {
71
const char *cache;
72
73
cache = getenv("NTLM_ACCEPTOR_CCACHE");
74
if (cache) {
75
ret = krb5_cc_resolve(context, cache, id);
76
if (ret)
77
goto out;
78
return 0;
79
}
80
}
81
82
ret = krb5_sname_to_principal(context, NULL, "host",
83
KRB5_NT_SRV_HST, &principal);
84
if (ret)
85
goto out;
86
87
ret = krb5_cc_cache_match(context, principal, id);
88
if (ret == 0)
89
return 0;
90
91
/* did not find in default credcache, lets try default keytab */
92
ret = krb5_kt_default(context, &kt);
93
if (ret)
94
goto out;
95
96
/* XXX check in keytab */
97
{
98
krb5_get_init_creds_opt *opt;
99
krb5_creds cred;
100
101
memset(&cred, 0, sizeof(cred));
102
103
ret = krb5_cc_new_unique(context, "MEMORY", NULL, id);
104
if (ret)
105
goto out;
106
*destroy = 1;
107
ret = krb5_get_init_creds_opt_alloc(context, &opt);
108
if (ret)
109
goto out;
110
ret = krb5_get_init_creds_keytab (context,
111
&cred,
112
principal,
113
kt,
114
0,
115
NULL,
116
opt);
117
krb5_get_init_creds_opt_free(context, opt);
118
if (ret)
119
goto out;
120
ret = krb5_cc_initialize (context, *id, cred.client);
121
if (ret) {
122
krb5_free_cred_contents (context, &cred);
123
goto out;
124
}
125
ret = krb5_cc_store_cred (context, *id, &cred);
126
krb5_free_cred_contents (context, &cred);
127
if (ret)
128
goto out;
129
}
130
131
krb5_kt_close(context, kt);
132
133
return 0;
134
135
out:
136
if (*id) {
137
if (*destroy)
138
krb5_cc_destroy(context, *id);
139
else
140
krb5_cc_close(context, *id);
141
*id = NULL;
142
}
143
144
if (kt)
145
krb5_kt_close(context, kt);
146
147
if (principal)
148
krb5_free_principal(context, principal);
149
return ret;
150
}
151
152
/*
153
*
154
*/
155
156
static OM_uint32
157
kdc_alloc(OM_uint32 *minor, void **ctx)
158
{
159
krb5_error_code ret;
160
struct ntlmkrb5 *c;
161
OM_uint32 junk;
162
163
c = calloc(1, sizeof(*c));
164
if (c == NULL) {
165
*minor = ENOMEM;
166
return GSS_S_FAILURE;
167
}
168
169
ret = krb5_init_context(&c->context);
170
if (ret) {
171
kdc_destroy(&junk, c);
172
*minor = ret;
173
return GSS_S_FAILURE;
174
}
175
176
ret = get_ccache(c->context, &c->destroy, &c->id);
177
if (ret) {
178
kdc_destroy(&junk, c);
179
*minor = ret;
180
return GSS_S_FAILURE;
181
}
182
183
ret = krb5_ntlm_alloc(c->context, &c->ntlm);
184
if (ret) {
185
kdc_destroy(&junk, c);
186
*minor = ret;
187
return GSS_S_FAILURE;
188
}
189
190
*ctx = c;
191
192
return GSS_S_COMPLETE;
193
}
194
195
static int
196
kdc_probe(OM_uint32 *minor, void *ctx, const char *realm)
197
{
198
struct ntlmkrb5 *c = ctx;
199
krb5_error_code ret;
200
unsigned flags;
201
202
ret = krb5_digest_probe(c->context, rk_UNCONST(realm), c->id, &flags);
203
if (ret)
204
return ret;
205
206
if ((flags & (1|2|4)) == 0)
207
return EINVAL;
208
209
return 0;
210
}
211
212
/*
213
*
214
*/
215
216
static OM_uint32
217
kdc_destroy(OM_uint32 *minor, void *ctx)
218
{
219
struct ntlmkrb5 *c = ctx;
220
krb5_data_free(&c->opaque);
221
krb5_data_free(&c->sessionkey);
222
if (c->ntlm)
223
krb5_ntlm_free(c->context, c->ntlm);
224
if (c->id) {
225
if (c->destroy)
226
krb5_cc_destroy(c->context, c->id);
227
else
228
krb5_cc_close(c->context, c->id);
229
}
230
if (c->context)
231
krb5_free_context(c->context);
232
memset(c, 0, sizeof(*c));
233
free(c);
234
235
return GSS_S_COMPLETE;
236
}
237
238
/*
239
*
240
*/
241
242
static OM_uint32
243
kdc_type2(OM_uint32 *minor_status,
244
void *ctx,
245
uint32_t flags,
246
const char *hostname,
247
const char *domain,
248
uint32_t *ret_flags,
249
struct ntlm_buf *out)
250
{
251
struct ntlmkrb5 *c = ctx;
252
krb5_error_code ret;
253
struct ntlm_type2 type2;
254
krb5_data challange;
255
struct ntlm_buf data;
256
krb5_data ti;
257
258
memset(&type2, 0, sizeof(type2));
259
260
/*
261
* Request data for type 2 packet from the KDC.
262
*/
263
ret = krb5_ntlm_init_request(c->context,
264
c->ntlm,
265
NULL,
266
c->id,
267
flags,
268
hostname,
269
domain);
270
if (ret) {
271
*minor_status = ret;
272
return GSS_S_FAILURE;
273
}
274
275
/*
276
*
277
*/
278
279
ret = krb5_ntlm_init_get_opaque(c->context, c->ntlm, &c->opaque);
280
if (ret) {
281
*minor_status = ret;
282
return GSS_S_FAILURE;
283
}
284
285
/*
286
*
287
*/
288
289
ret = krb5_ntlm_init_get_flags(c->context, c->ntlm, &type2.flags);
290
if (ret) {
291
*minor_status = ret;
292
return GSS_S_FAILURE;
293
}
294
*ret_flags = type2.flags;
295
296
ret = krb5_ntlm_init_get_challange(c->context, c->ntlm, &challange);
297
if (ret) {
298
*minor_status = ret;
299
return GSS_S_FAILURE;
300
}
301
302
if (challange.length != sizeof(type2.challenge)) {
303
*minor_status = EINVAL;
304
return GSS_S_FAILURE;
305
}
306
memcpy(type2.challenge, challange.data, sizeof(type2.challenge));
307
krb5_data_free(&challange);
308
309
ret = krb5_ntlm_init_get_targetname(c->context, c->ntlm,
310
&type2.targetname);
311
if (ret) {
312
*minor_status = ret;
313
return GSS_S_FAILURE;
314
}
315
316
ret = krb5_ntlm_init_get_targetinfo(c->context, c->ntlm, &ti);
317
if (ret) {
318
free(type2.targetname);
319
*minor_status = ret;
320
return GSS_S_FAILURE;
321
}
322
323
type2.targetinfo.data = ti.data;
324
type2.targetinfo.length = ti.length;
325
326
ret = heim_ntlm_encode_type2(&type2, &data);
327
free(type2.targetname);
328
krb5_data_free(&ti);
329
if (ret) {
330
*minor_status = ret;
331
return GSS_S_FAILURE;
332
}
333
334
out->data = data.data;
335
out->length = data.length;
336
337
return GSS_S_COMPLETE;
338
}
339
340
/*
341
*
342
*/
343
344
static OM_uint32
345
kdc_type3(OM_uint32 *minor_status,
346
void *ctx,
347
const struct ntlm_type3 *type3,
348
struct ntlm_buf *sessionkey)
349
{
350
struct ntlmkrb5 *c = ctx;
351
krb5_error_code ret;
352
353
sessionkey->data = NULL;
354
sessionkey->length = 0;
355
356
ret = krb5_ntlm_req_set_flags(c->context, c->ntlm, type3->flags);
357
if (ret) goto out;
358
ret = krb5_ntlm_req_set_username(c->context, c->ntlm, type3->username);
359
if (ret) goto out;
360
ret = krb5_ntlm_req_set_targetname(c->context, c->ntlm,
361
type3->targetname);
362
if (ret) goto out;
363
ret = krb5_ntlm_req_set_lm(c->context, c->ntlm,
364
type3->lm.data, type3->lm.length);
365
if (ret) goto out;
366
ret = krb5_ntlm_req_set_ntlm(c->context, c->ntlm,
367
type3->ntlm.data, type3->ntlm.length);
368
if (ret) goto out;
369
ret = krb5_ntlm_req_set_opaque(c->context, c->ntlm, &c->opaque);
370
if (ret) goto out;
371
372
if (type3->sessionkey.length) {
373
ret = krb5_ntlm_req_set_session(c->context, c->ntlm,
374
type3->sessionkey.data,
375
type3->sessionkey.length);
376
if (ret) goto out;
377
}
378
379
/*
380
* Verify with the KDC the type3 packet is ok
381
*/
382
ret = krb5_ntlm_request(c->context,
383
c->ntlm,
384
NULL,
385
c->id);
386
if (ret)
387
goto out;
388
389
if (krb5_ntlm_rep_get_status(c->context, c->ntlm) != TRUE) {
390
ret = EINVAL;
391
goto out;
392
}
393
394
if (type3->sessionkey.length) {
395
ret = krb5_ntlm_rep_get_sessionkey(c->context,
396
c->ntlm,
397
&c->sessionkey);
398
if (ret)
399
goto out;
400
401
sessionkey->data = c->sessionkey.data;
402
sessionkey->length = c->sessionkey.length;
403
}
404
405
return 0;
406
407
out:
408
*minor_status = ret;
409
return GSS_S_FAILURE;
410
}
411
412
/*
413
*
414
*/
415
416
static void
417
kdc_free_buffer(struct ntlm_buf *sessionkey)
418
{
419
if (sessionkey->data)
420
free(sessionkey->data);
421
sessionkey->data = NULL;
422
sessionkey->length = 0;
423
}
424
425
/*
426
*
427
*/
428
429
struct ntlm_server_interface ntlmsspi_kdc_digest = {
430
kdc_alloc,
431
kdc_destroy,
432
kdc_probe,
433
kdc_type2,
434
kdc_type3,
435
kdc_free_buffer
436
};
437
438
#endif /* DIGEST */
439
440