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