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