1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 - 2008 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34233294Sstas#include "ntlm.h"
35178825Sdfr
36178825Sdfrstatic int
37233294Sstasfrom_file(const char *fn, const char *target_domain,
38178825Sdfr	  char **username, struct ntlm_buf *key)
39233294Sstas{
40178825Sdfr    char *str, buf[1024];
41178825Sdfr    FILE *f;
42178825Sdfr
43178825Sdfr    f = fopen(fn, "r");
44178825Sdfr    if (f == NULL)
45178825Sdfr	return ENOENT;
46233294Sstas    rk_cloexec_file(f);
47178825Sdfr
48178825Sdfr    while (fgets(buf, sizeof(buf), f) != NULL) {
49178825Sdfr	char *d, *u, *p;
50178825Sdfr	buf[strcspn(buf, "\r\n")] = '\0';
51178825Sdfr	if (buf[0] == '#')
52178825Sdfr	    continue;
53178825Sdfr	str = NULL;
54178825Sdfr	d = strtok_r(buf, ":", &str);
55178825Sdfr	if (d && strcasecmp(target_domain, d) != 0)
56178825Sdfr	    continue;
57178825Sdfr	u = strtok_r(NULL, ":", &str);
58178825Sdfr	p = strtok_r(NULL, ":", &str);
59178825Sdfr	if (u == NULL || p == NULL)
60178825Sdfr	    continue;
61178825Sdfr
62178825Sdfr	*username = strdup(u);
63178825Sdfr
64178825Sdfr	heim_ntlm_nt_key(p, key);
65178825Sdfr
66178825Sdfr	memset(buf, 0, sizeof(buf));
67178825Sdfr	fclose(f);
68178825Sdfr	return 0;
69178825Sdfr    }
70178825Sdfr    memset(buf, 0, sizeof(buf));
71178825Sdfr    fclose(f);
72178825Sdfr    return ENOENT;
73178825Sdfr}
74178825Sdfr
75178825Sdfrstatic int
76233294Sstasget_user_file(const ntlm_name target_name,
77178825Sdfr	      char **username, struct ntlm_buf *key)
78178825Sdfr{
79178825Sdfr    const char *fn;
80178825Sdfr
81178825Sdfr    if (issuid())
82178825Sdfr	return ENOENT;
83178825Sdfr
84178825Sdfr    fn = getenv("NTLM_USER_FILE");
85178825Sdfr    if (fn == NULL)
86178825Sdfr	return ENOENT;
87178825Sdfr    if (from_file(fn, target_name->domain, username, key) == 0)
88178825Sdfr	return 0;
89178825Sdfr
90178825Sdfr    return ENOENT;
91178825Sdfr}
92178825Sdfr
93178825Sdfr/*
94178825Sdfr * Pick up the ntlm cred from the default krb5 credential cache.
95178825Sdfr */
96178825Sdfr
97178825Sdfrstatic int
98178825Sdfrget_user_ccache(const ntlm_name name, char **username, struct ntlm_buf *key)
99178825Sdfr{
100233294Sstas    krb5_context context = NULL;
101178825Sdfr    krb5_principal client;
102233294Sstas    krb5_ccache id = NULL;
103178825Sdfr    krb5_error_code ret;
104233294Sstas    char *confname;
105233294Sstas    krb5_data data;
106178825Sdfr
107178825Sdfr    *username = NULL;
108233294Sstas    krb5_data_zero(&data);
109178825Sdfr    key->length = 0;
110178825Sdfr    key->data = NULL;
111178825Sdfr
112178825Sdfr    ret = krb5_init_context(&context);
113178825Sdfr    if (ret)
114178825Sdfr	return ret;
115178825Sdfr
116178825Sdfr    ret = krb5_cc_default(context, &id);
117178825Sdfr    if (ret)
118178825Sdfr	goto out;
119178825Sdfr
120178825Sdfr    ret = krb5_cc_get_principal(context, id, &client);
121178825Sdfr    if (ret)
122178825Sdfr	goto out;
123178825Sdfr
124178825Sdfr    ret = krb5_unparse_name_flags(context, client,
125178825Sdfr				  KRB5_PRINCIPAL_UNPARSE_NO_REALM,
126178825Sdfr				  username);
127178825Sdfr    krb5_free_principal(context, client);
128178825Sdfr    if (ret)
129178825Sdfr	goto out;
130178825Sdfr
131233294Sstas    asprintf(&confname, "ntlm-key-%s", name->domain);
132233294Sstas    if (confname == NULL) {
133233294Sstas	krb5_clear_error_message(context);
134233294Sstas	ret = ENOMEM;
135178825Sdfr	goto out;
136178825Sdfr    }
137178825Sdfr
138233294Sstas    ret = krb5_cc_get_config(context, id, NULL,
139233294Sstas			     confname, &data);
140233294Sstas    if (ret)
141178825Sdfr	goto out;
142178825Sdfr
143233294Sstas    key->data = malloc(data.length);
144233294Sstas    if (key->data == NULL) {
145233294Sstas	ret = ENOMEM;
146233294Sstas	goto out;
147233294Sstas    }
148233294Sstas    key->length = data.length;
149233294Sstas    memcpy(key->data, data.data, data.length);
150178825Sdfr
151233294Sstas out:
152233294Sstas    krb5_data_free(&data);
153178825Sdfr    if (id)
154178825Sdfr	krb5_cc_close(context, id);
155178825Sdfr
156233294Sstas    krb5_free_context(context);
157233294Sstas
158178825Sdfr    return ret;
159178825Sdfr}
160178825Sdfr
161178825Sdfrint
162178825Sdfr_gss_ntlm_get_user_cred(const ntlm_name target_name,
163178825Sdfr			ntlm_cred *rcred)
164178825Sdfr{
165178825Sdfr    ntlm_cred cred;
166178825Sdfr    int ret;
167233294Sstas
168178825Sdfr    cred = calloc(1, sizeof(*cred));
169178825Sdfr    if (cred == NULL)
170178825Sdfr	return ENOMEM;
171233294Sstas
172178825Sdfr    ret = get_user_file(target_name, &cred->username, &cred->key);
173178825Sdfr    if (ret)
174178825Sdfr	ret = get_user_ccache(target_name, &cred->username, &cred->key);
175178825Sdfr    if (ret) {
176178825Sdfr	free(cred);
177178825Sdfr	return ret;
178178825Sdfr    }
179233294Sstas
180178825Sdfr    cred->domain = strdup(target_name->domain);
181178825Sdfr    *rcred = cred;
182178825Sdfr
183178825Sdfr    return ret;
184178825Sdfr}
185178825Sdfr
186178825Sdfrstatic int
187178825Sdfr_gss_copy_cred(ntlm_cred from, ntlm_cred *to)
188178825Sdfr{
189233294Sstas    *to = calloc(1, sizeof(**to));
190178825Sdfr    if (*to == NULL)
191178825Sdfr	return ENOMEM;
192178825Sdfr    (*to)->username = strdup(from->username);
193178825Sdfr    if ((*to)->username == NULL) {
194178825Sdfr	free(*to);
195178825Sdfr	return ENOMEM;
196178825Sdfr    }
197178825Sdfr    (*to)->domain = strdup(from->domain);
198178825Sdfr    if ((*to)->domain == NULL) {
199178825Sdfr	free((*to)->username);
200178825Sdfr	free(*to);
201178825Sdfr	return ENOMEM;
202178825Sdfr    }
203178825Sdfr    (*to)->key.data = malloc(from->key.length);
204178825Sdfr    if ((*to)->key.data == NULL) {
205178825Sdfr	free((*to)->domain);
206178825Sdfr	free((*to)->username);
207178825Sdfr	free(*to);
208178825Sdfr	return ENOMEM;
209178825Sdfr    }
210178825Sdfr    memcpy((*to)->key.data, from->key.data, from->key.length);
211178825Sdfr    (*to)->key.length = from->key.length;
212178825Sdfr
213178825Sdfr    return 0;
214178825Sdfr}
215178825Sdfr
216233294SstasOM_uint32 GSSAPI_CALLCONV
217178825Sdfr_gss_ntlm_init_sec_context
218178825Sdfr           (OM_uint32 * minor_status,
219178825Sdfr            const gss_cred_id_t initiator_cred_handle,
220178825Sdfr            gss_ctx_id_t * context_handle,
221178825Sdfr            const gss_name_t target_name,
222178825Sdfr            const gss_OID mech_type,
223178825Sdfr            OM_uint32 req_flags,
224178825Sdfr            OM_uint32 time_req,
225178825Sdfr            const gss_channel_bindings_t input_chan_bindings,
226178825Sdfr            const gss_buffer_t input_token,
227178825Sdfr            gss_OID * actual_mech_type,
228178825Sdfr            gss_buffer_t output_token,
229178825Sdfr            OM_uint32 * ret_flags,
230178825Sdfr            OM_uint32 * time_rec
231178825Sdfr	   )
232178825Sdfr{
233178825Sdfr    ntlm_ctx ctx;
234178825Sdfr    ntlm_name name = (ntlm_name)target_name;
235178825Sdfr
236178825Sdfr    *minor_status = 0;
237178825Sdfr
238178825Sdfr    if (ret_flags)
239178825Sdfr	*ret_flags = 0;
240178825Sdfr    if (time_rec)
241178825Sdfr	*time_rec = 0;
242178825Sdfr    if (actual_mech_type)
243178825Sdfr	*actual_mech_type = GSS_C_NO_OID;
244178825Sdfr
245178825Sdfr    if (*context_handle == GSS_C_NO_CONTEXT) {
246178825Sdfr	struct ntlm_type1 type1;
247178825Sdfr	struct ntlm_buf data;
248178825Sdfr	uint32_t flags = 0;
249178825Sdfr	int ret;
250233294Sstas
251178825Sdfr	ctx = calloc(1, sizeof(*ctx));
252178825Sdfr	if (ctx == NULL) {
253178825Sdfr	    *minor_status = EINVAL;
254178825Sdfr	    return GSS_S_FAILURE;
255178825Sdfr	}
256178825Sdfr	*context_handle = (gss_ctx_id_t)ctx;
257178825Sdfr
258178825Sdfr	if (initiator_cred_handle != GSS_C_NO_CREDENTIAL) {
259178825Sdfr	    ntlm_cred cred = (ntlm_cred)initiator_cred_handle;
260178825Sdfr	    ret = _gss_copy_cred(cred, &ctx->client);
261178825Sdfr	} else
262178825Sdfr	    ret = _gss_ntlm_get_user_cred(name, &ctx->client);
263178825Sdfr
264178825Sdfr	if (ret) {
265178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
266178825Sdfr	    *minor_status = ret;
267178825Sdfr	    return GSS_S_FAILURE;
268178825Sdfr	}
269178825Sdfr
270178825Sdfr	if (req_flags & GSS_C_CONF_FLAG)
271178825Sdfr	    flags |= NTLM_NEG_SEAL;
272178825Sdfr	if (req_flags & GSS_C_INTEG_FLAG)
273178825Sdfr	    flags |= NTLM_NEG_SIGN;
274178825Sdfr	else
275178825Sdfr	    flags |= NTLM_NEG_ALWAYS_SIGN;
276178825Sdfr
277178825Sdfr	flags |= NTLM_NEG_UNICODE;
278178825Sdfr	flags |= NTLM_NEG_NTLM;
279178825Sdfr	flags |= NTLM_NEG_NTLM2_SESSION;
280178825Sdfr	flags |= NTLM_NEG_KEYEX;
281178825Sdfr
282178825Sdfr	memset(&type1, 0, sizeof(type1));
283233294Sstas
284178825Sdfr	type1.flags = flags;
285178825Sdfr	type1.domain = name->domain;
286178825Sdfr	type1.hostname = NULL;
287178825Sdfr	type1.os[0] = 0;
288178825Sdfr	type1.os[1] = 0;
289233294Sstas
290178825Sdfr	ret = heim_ntlm_encode_type1(&type1, &data);
291178825Sdfr	if (ret) {
292178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
293178825Sdfr	    *minor_status = ret;
294178825Sdfr	    return GSS_S_FAILURE;
295178825Sdfr	}
296233294Sstas
297178825Sdfr	output_token->value = data.data;
298178825Sdfr	output_token->length = data.length;
299233294Sstas
300178825Sdfr	return GSS_S_CONTINUE_NEEDED;
301178825Sdfr    } else {
302178825Sdfr	krb5_error_code ret;
303178825Sdfr	struct ntlm_type2 type2;
304178825Sdfr	struct ntlm_type3 type3;
305178825Sdfr	struct ntlm_buf data;
306178825Sdfr
307178825Sdfr	ctx = (ntlm_ctx)*context_handle;
308178825Sdfr
309178825Sdfr	data.data = input_token->value;
310178825Sdfr	data.length = input_token->length;
311178825Sdfr
312178825Sdfr	ret = heim_ntlm_decode_type2(&data, &type2);
313178825Sdfr	if (ret) {
314178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
315178825Sdfr	    *minor_status = ret;
316178825Sdfr	    return GSS_S_FAILURE;
317178825Sdfr	}
318178825Sdfr
319178825Sdfr	ctx->flags = type2.flags;
320178825Sdfr
321233294Sstas	/* XXX check that type2.targetinfo matches `target_name�� */
322178825Sdfr	/* XXX check verify targetinfo buffer */
323178825Sdfr
324178825Sdfr	memset(&type3, 0, sizeof(type3));
325178825Sdfr
326178825Sdfr	type3.username = ctx->client->username;
327178825Sdfr	type3.flags = type2.flags;
328178825Sdfr	type3.targetname = type2.targetname;
329178825Sdfr	type3.ws = rk_UNCONST("workstation");
330178825Sdfr
331178825Sdfr	/*
332178825Sdfr	 * NTLM Version 1 if no targetinfo buffer.
333178825Sdfr	 */
334178825Sdfr
335178825Sdfr	if (1 || type2.targetinfo.length == 0) {
336178825Sdfr	    struct ntlm_buf sessionkey;
337178825Sdfr
338178825Sdfr	    if (type2.flags & NTLM_NEG_NTLM2_SESSION) {
339178825Sdfr		unsigned char nonce[8];
340178825Sdfr
341178825Sdfr		if (RAND_bytes(nonce, sizeof(nonce)) != 1) {
342233294Sstas		    _gss_ntlm_delete_sec_context(minor_status,
343178825Sdfr						 context_handle, NULL);
344178825Sdfr		    *minor_status = EINVAL;
345178825Sdfr		    return GSS_S_FAILURE;
346178825Sdfr		}
347178825Sdfr
348178825Sdfr		ret = heim_ntlm_calculate_ntlm2_sess(nonce,
349233294Sstas						     type2.challenge,
350178825Sdfr						     ctx->client->key.data,
351178825Sdfr						     &type3.lm,
352178825Sdfr						     &type3.ntlm);
353178825Sdfr	    } else {
354233294Sstas		ret = heim_ntlm_calculate_ntlm1(ctx->client->key.data,
355178825Sdfr						ctx->client->key.length,
356233294Sstas						type2.challenge,
357178825Sdfr						&type3.ntlm);
358178825Sdfr
359178825Sdfr	    }
360178825Sdfr	    if (ret) {
361178825Sdfr		_gss_ntlm_delete_sec_context(minor_status,context_handle,NULL);
362178825Sdfr		*minor_status = ret;
363178825Sdfr		return GSS_S_FAILURE;
364178825Sdfr	    }
365178825Sdfr
366233294Sstas	    ret = heim_ntlm_build_ntlm1_master(ctx->client->key.data,
367178825Sdfr					       ctx->client->key.length,
368178825Sdfr					       &sessionkey,
369178825Sdfr					       &type3.sessionkey);
370178825Sdfr	    if (ret) {
371178825Sdfr		if (type3.lm.data)
372178825Sdfr		    free(type3.lm.data);
373178825Sdfr		if (type3.ntlm.data)
374178825Sdfr		    free(type3.ntlm.data);
375178825Sdfr		_gss_ntlm_delete_sec_context(minor_status,context_handle,NULL);
376178825Sdfr		*minor_status = ret;
377178825Sdfr		return GSS_S_FAILURE;
378178825Sdfr	    }
379178825Sdfr
380233294Sstas	    ret = krb5_data_copy(&ctx->sessionkey,
381178825Sdfr				 sessionkey.data, sessionkey.length);
382178825Sdfr	    free(sessionkey.data);
383178825Sdfr	    if (ret) {
384178825Sdfr		if (type3.lm.data)
385178825Sdfr		    free(type3.lm.data);
386178825Sdfr		if (type3.ntlm.data)
387178825Sdfr		    free(type3.ntlm.data);
388178825Sdfr		_gss_ntlm_delete_sec_context(minor_status,context_handle,NULL);
389178825Sdfr		*minor_status = ret;
390178825Sdfr		return GSS_S_FAILURE;
391178825Sdfr	    }
392233294Sstas	    ctx->status |= STATUS_SESSIONKEY;
393178825Sdfr
394178825Sdfr	} else {
395178825Sdfr	    struct ntlm_buf sessionkey;
396178825Sdfr	    unsigned char ntlmv2[16];
397178825Sdfr	    struct ntlm_targetinfo ti;
398178825Sdfr
399178825Sdfr	    /* verify infotarget */
400233294Sstas
401178825Sdfr	    ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti);
402178825Sdfr	    if(ret) {
403233294Sstas		_gss_ntlm_delete_sec_context(minor_status,
404178825Sdfr					     context_handle, NULL);
405178825Sdfr		*minor_status = ret;
406178825Sdfr		return GSS_S_FAILURE;
407178825Sdfr	    }
408178825Sdfr
409178825Sdfr	    if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) {
410233294Sstas		_gss_ntlm_delete_sec_context(minor_status,
411178825Sdfr					     context_handle, NULL);
412178825Sdfr		*minor_status = EINVAL;
413178825Sdfr		return GSS_S_FAILURE;
414178825Sdfr	    }
415178825Sdfr
416178825Sdfr	    ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data,
417178825Sdfr					    ctx->client->key.length,
418178825Sdfr					    ctx->client->username,
419178825Sdfr					    name->domain,
420233294Sstas					    type2.challenge,
421178825Sdfr					    &type2.targetinfo,
422178825Sdfr					    ntlmv2,
423178825Sdfr					    &type3.ntlm);
424178825Sdfr	    if (ret) {
425233294Sstas		_gss_ntlm_delete_sec_context(minor_status,
426178825Sdfr					     context_handle, NULL);
427178825Sdfr		*minor_status = ret;
428178825Sdfr		return GSS_S_FAILURE;
429178825Sdfr	    }
430178825Sdfr
431178825Sdfr	    ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2),
432178825Sdfr					       &sessionkey,
433178825Sdfr					       &type3.sessionkey);
434178825Sdfr	    memset(ntlmv2, 0, sizeof(ntlmv2));
435178825Sdfr	    if (ret) {
436233294Sstas		_gss_ntlm_delete_sec_context(minor_status,
437178825Sdfr					     context_handle, NULL);
438178825Sdfr		*minor_status = ret;
439178825Sdfr		return GSS_S_FAILURE;
440178825Sdfr	    }
441233294Sstas
442178825Sdfr	    ctx->flags |= NTLM_NEG_NTLM2_SESSION;
443178825Sdfr
444233294Sstas	    ret = krb5_data_copy(&ctx->sessionkey,
445178825Sdfr				 sessionkey.data, sessionkey.length);
446178825Sdfr	    free(sessionkey.data);
447233294Sstas	    if (ret) {
448233294Sstas		_gss_ntlm_delete_sec_context(minor_status,
449233294Sstas					     context_handle, NULL);
450233294Sstas		*minor_status = ret;
451233294Sstas		return GSS_S_FAILURE;
452233294Sstas	    }
453178825Sdfr	}
454178825Sdfr
455178825Sdfr	if (ctx->flags & NTLM_NEG_NTLM2_SESSION) {
456233294Sstas	    ctx->status |= STATUS_SESSIONKEY;
457178825Sdfr	    _gss_ntlm_set_key(&ctx->u.v2.send, 0, (ctx->flags & NTLM_NEG_KEYEX),
458178825Sdfr			      ctx->sessionkey.data,
459178825Sdfr			      ctx->sessionkey.length);
460178825Sdfr	    _gss_ntlm_set_key(&ctx->u.v2.recv, 1, (ctx->flags & NTLM_NEG_KEYEX),
461178825Sdfr			      ctx->sessionkey.data,
462178825Sdfr			      ctx->sessionkey.length);
463178825Sdfr	} else {
464233294Sstas	    ctx->status |= STATUS_SESSIONKEY;
465233294Sstas	    RC4_set_key(&ctx->u.v1.crypto_recv.key,
466178825Sdfr			ctx->sessionkey.length,
467178825Sdfr			ctx->sessionkey.data);
468233294Sstas	    RC4_set_key(&ctx->u.v1.crypto_send.key,
469178825Sdfr			ctx->sessionkey.length,
470178825Sdfr			ctx->sessionkey.data);
471178825Sdfr	}
472178825Sdfr
473178825Sdfr
474233294Sstas
475178825Sdfr	ret = heim_ntlm_encode_type3(&type3, &data);
476178825Sdfr	free(type3.sessionkey.data);
477178825Sdfr	if (type3.lm.data)
478178825Sdfr	    free(type3.lm.data);
479178825Sdfr	if (type3.ntlm.data)
480178825Sdfr	    free(type3.ntlm.data);
481178825Sdfr	if (ret) {
482178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
483178825Sdfr	    *minor_status = ret;
484178825Sdfr	    return GSS_S_FAILURE;
485178825Sdfr	}
486178825Sdfr
487178825Sdfr	output_token->length = data.length;
488178825Sdfr	output_token->value = data.data;
489178825Sdfr
490178825Sdfr	if (actual_mech_type)
491178825Sdfr	    *actual_mech_type = GSS_NTLM_MECHANISM;
492178825Sdfr	if (ret_flags)
493178825Sdfr	    *ret_flags = 0;
494178825Sdfr	if (time_rec)
495178825Sdfr	    *time_rec = GSS_C_INDEFINITE;
496178825Sdfr
497178825Sdfr	ctx->status |= STATUS_OPEN;
498178825Sdfr
499178825Sdfr	return GSS_S_COMPLETE;
500178825Sdfr    }
501178825Sdfr}
502