xref: /freebsd/crypto/heimdal/lib/gssapi/ntlm/init_sec_context.c (revision ed549cb0c53f8438c52593ce811f6fcc812248e9)
1c19800e8SDoug Rabson /*
2ae771770SStanislav Sedov  * Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan
3c19800e8SDoug Rabson  * (Royal Institute of Technology, Stockholm, Sweden).
4c19800e8SDoug Rabson  * All rights reserved.
5c19800e8SDoug Rabson  *
6c19800e8SDoug Rabson  * Redistribution and use in source and binary forms, with or without
7c19800e8SDoug Rabson  * modification, are permitted provided that the following conditions
8c19800e8SDoug Rabson  * are met:
9c19800e8SDoug Rabson  *
10c19800e8SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12c19800e8SDoug Rabson  *
13c19800e8SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
14c19800e8SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
15c19800e8SDoug Rabson  *    documentation and/or other materials provided with the distribution.
16c19800e8SDoug Rabson  *
17c19800e8SDoug Rabson  * 3. Neither the name of the Institute nor the names of its contributors
18c19800e8SDoug Rabson  *    may be used to endorse or promote products derived from this software
19c19800e8SDoug Rabson  *    without specific prior written permission.
20c19800e8SDoug Rabson  *
21c19800e8SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22c19800e8SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c19800e8SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c19800e8SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25c19800e8SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c19800e8SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c19800e8SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c19800e8SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c19800e8SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c19800e8SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c19800e8SDoug Rabson  * SUCH DAMAGE.
32c19800e8SDoug Rabson  */
33c19800e8SDoug Rabson 
34ae771770SStanislav Sedov #include "ntlm.h"
35c19800e8SDoug Rabson 
36c19800e8SDoug Rabson static int
from_file(const char * fn,const char * target_domain,char ** username,struct ntlm_buf * key)37c19800e8SDoug Rabson from_file(const char *fn, const char *target_domain,
38c19800e8SDoug Rabson 	  char **username, struct ntlm_buf *key)
39c19800e8SDoug Rabson {
40c19800e8SDoug Rabson     char *str, buf[1024];
41c19800e8SDoug Rabson     FILE *f;
42c19800e8SDoug Rabson 
43c19800e8SDoug Rabson     f = fopen(fn, "r");
44c19800e8SDoug Rabson     if (f == NULL)
45c19800e8SDoug Rabson 	return ENOENT;
46ae771770SStanislav Sedov     rk_cloexec_file(f);
47c19800e8SDoug Rabson 
48c19800e8SDoug Rabson     while (fgets(buf, sizeof(buf), f) != NULL) {
49c19800e8SDoug Rabson 	char *d, *u, *p;
50c19800e8SDoug Rabson 	buf[strcspn(buf, "\r\n")] = '\0';
51c19800e8SDoug Rabson 	if (buf[0] == '#')
52c19800e8SDoug Rabson 	    continue;
53c19800e8SDoug Rabson 	str = NULL;
54c19800e8SDoug Rabson 	d = strtok_r(buf, ":", &str);
55*ed549cb0SCy Schubert 	if (!d)
56*ed549cb0SCy Schubert 	    continue;
57c19800e8SDoug Rabson 	if (d && strcasecmp(target_domain, d) != 0)
58c19800e8SDoug Rabson 	    continue;
59c19800e8SDoug Rabson 	u = strtok_r(NULL, ":", &str);
60c19800e8SDoug Rabson 	p = strtok_r(NULL, ":", &str);
61c19800e8SDoug Rabson 	if (u == NULL || p == NULL)
62c19800e8SDoug Rabson 	    continue;
63c19800e8SDoug Rabson 
64c19800e8SDoug Rabson 	*username = strdup(u);
65c19800e8SDoug Rabson 
66c19800e8SDoug Rabson 	heim_ntlm_nt_key(p, key);
67c19800e8SDoug Rabson 
68c19800e8SDoug Rabson 	memset(buf, 0, sizeof(buf));
69c19800e8SDoug Rabson 	fclose(f);
70c19800e8SDoug Rabson 	return 0;
71c19800e8SDoug Rabson     }
72c19800e8SDoug Rabson     memset(buf, 0, sizeof(buf));
73c19800e8SDoug Rabson     fclose(f);
74c19800e8SDoug Rabson     return ENOENT;
75c19800e8SDoug Rabson }
76c19800e8SDoug Rabson 
77c19800e8SDoug Rabson static int
get_user_file(const ntlm_name target_name,char ** username,struct ntlm_buf * key)78c19800e8SDoug Rabson get_user_file(const ntlm_name target_name,
79c19800e8SDoug Rabson 	      char **username, struct ntlm_buf *key)
80c19800e8SDoug Rabson {
81c19800e8SDoug Rabson     const char *fn;
82c19800e8SDoug Rabson 
83c19800e8SDoug Rabson     if (issuid())
84c19800e8SDoug Rabson 	return ENOENT;
85c19800e8SDoug Rabson 
86c19800e8SDoug Rabson     fn = getenv("NTLM_USER_FILE");
87c19800e8SDoug Rabson     if (fn == NULL)
88c19800e8SDoug Rabson 	return ENOENT;
89c19800e8SDoug Rabson     if (from_file(fn, target_name->domain, username, key) == 0)
90c19800e8SDoug Rabson 	return 0;
91c19800e8SDoug Rabson 
92c19800e8SDoug Rabson     return ENOENT;
93c19800e8SDoug Rabson }
94c19800e8SDoug Rabson 
95c19800e8SDoug Rabson /*
96c19800e8SDoug Rabson  * Pick up the ntlm cred from the default krb5 credential cache.
97c19800e8SDoug Rabson  */
98c19800e8SDoug Rabson 
99c19800e8SDoug Rabson static int
get_user_ccache(const ntlm_name name,char ** username,struct ntlm_buf * key)100c19800e8SDoug Rabson get_user_ccache(const ntlm_name name, char **username, struct ntlm_buf *key)
101c19800e8SDoug Rabson {
102c19800e8SDoug Rabson     krb5_context context = NULL;
103ae771770SStanislav Sedov     krb5_principal client;
104c19800e8SDoug Rabson     krb5_ccache id = NULL;
105ae771770SStanislav Sedov     krb5_error_code ret;
106ae771770SStanislav Sedov     char *confname;
107ae771770SStanislav Sedov     krb5_data data;
108c19800e8SDoug Rabson 
109c19800e8SDoug Rabson     *username = NULL;
110ae771770SStanislav Sedov     krb5_data_zero(&data);
111c19800e8SDoug Rabson     key->length = 0;
112c19800e8SDoug Rabson     key->data = NULL;
113c19800e8SDoug Rabson 
114c19800e8SDoug Rabson     ret = krb5_init_context(&context);
115c19800e8SDoug Rabson     if (ret)
116c19800e8SDoug Rabson 	return ret;
117c19800e8SDoug Rabson 
118c19800e8SDoug Rabson     ret = krb5_cc_default(context, &id);
119c19800e8SDoug Rabson     if (ret)
120c19800e8SDoug Rabson 	goto out;
121c19800e8SDoug Rabson 
122c19800e8SDoug Rabson     ret = krb5_cc_get_principal(context, id, &client);
123c19800e8SDoug Rabson     if (ret)
124c19800e8SDoug Rabson 	goto out;
125c19800e8SDoug Rabson 
126c19800e8SDoug Rabson     ret = krb5_unparse_name_flags(context, client,
127c19800e8SDoug Rabson 				  KRB5_PRINCIPAL_UNPARSE_NO_REALM,
128c19800e8SDoug Rabson 				  username);
129c19800e8SDoug Rabson     krb5_free_principal(context, client);
130c19800e8SDoug Rabson     if (ret)
131c19800e8SDoug Rabson 	goto out;
132c19800e8SDoug Rabson 
133ae771770SStanislav Sedov     asprintf(&confname, "ntlm-key-%s", name->domain);
134ae771770SStanislav Sedov     if (confname == NULL) {
135ae771770SStanislav Sedov 	krb5_clear_error_message(context);
136ae771770SStanislav Sedov 	ret = ENOMEM;
137c19800e8SDoug Rabson 	goto out;
138c19800e8SDoug Rabson     }
139c19800e8SDoug Rabson 
140ae771770SStanislav Sedov     ret = krb5_cc_get_config(context, id, NULL,
141ae771770SStanislav Sedov 			     confname, &data);
142ae771770SStanislav Sedov     if (ret)
143c19800e8SDoug Rabson 	goto out;
144c19800e8SDoug Rabson 
145ae771770SStanislav Sedov     key->data = malloc(data.length);
146ae771770SStanislav Sedov     if (key->data == NULL) {
147ae771770SStanislav Sedov 	ret = ENOMEM;
148ae771770SStanislav Sedov 	goto out;
149ae771770SStanislav Sedov     }
150ae771770SStanislav Sedov     key->length = data.length;
151ae771770SStanislav Sedov     memcpy(key->data, data.data, data.length);
152c19800e8SDoug Rabson 
153c19800e8SDoug Rabson  out:
154ae771770SStanislav Sedov     krb5_data_free(&data);
155c19800e8SDoug Rabson     if (id)
156c19800e8SDoug Rabson 	krb5_cc_close(context, id);
157ae771770SStanislav Sedov 
158c19800e8SDoug Rabson     krb5_free_context(context);
159c19800e8SDoug Rabson 
160c19800e8SDoug Rabson     return ret;
161c19800e8SDoug Rabson }
162c19800e8SDoug Rabson 
163c19800e8SDoug Rabson int
_gss_ntlm_get_user_cred(const ntlm_name target_name,ntlm_cred * rcred)164c19800e8SDoug Rabson _gss_ntlm_get_user_cred(const ntlm_name target_name,
165c19800e8SDoug Rabson 			ntlm_cred *rcred)
166c19800e8SDoug Rabson {
167c19800e8SDoug Rabson     ntlm_cred cred;
168c19800e8SDoug Rabson     int ret;
169c19800e8SDoug Rabson 
170c19800e8SDoug Rabson     cred = calloc(1, sizeof(*cred));
171c19800e8SDoug Rabson     if (cred == NULL)
172c19800e8SDoug Rabson 	return ENOMEM;
173c19800e8SDoug Rabson 
174c19800e8SDoug Rabson     ret = get_user_file(target_name, &cred->username, &cred->key);
175c19800e8SDoug Rabson     if (ret)
176c19800e8SDoug Rabson 	ret = get_user_ccache(target_name, &cred->username, &cred->key);
177c19800e8SDoug Rabson     if (ret) {
178c19800e8SDoug Rabson 	free(cred);
179c19800e8SDoug Rabson 	return ret;
180c19800e8SDoug Rabson     }
181c19800e8SDoug Rabson 
182c19800e8SDoug Rabson     cred->domain = strdup(target_name->domain);
183c19800e8SDoug Rabson     *rcred = cred;
184c19800e8SDoug Rabson 
185c19800e8SDoug Rabson     return ret;
186c19800e8SDoug Rabson }
187c19800e8SDoug Rabson 
188c19800e8SDoug Rabson static int
_gss_copy_cred(ntlm_cred from,ntlm_cred * to)189c19800e8SDoug Rabson _gss_copy_cred(ntlm_cred from, ntlm_cred *to)
190c19800e8SDoug Rabson {
191ae771770SStanislav Sedov     *to = calloc(1, sizeof(**to));
192c19800e8SDoug Rabson     if (*to == NULL)
193c19800e8SDoug Rabson 	return ENOMEM;
194c19800e8SDoug Rabson     (*to)->username = strdup(from->username);
195c19800e8SDoug Rabson     if ((*to)->username == NULL) {
196c19800e8SDoug Rabson 	free(*to);
197c19800e8SDoug Rabson 	return ENOMEM;
198c19800e8SDoug Rabson     }
199c19800e8SDoug Rabson     (*to)->domain = strdup(from->domain);
200c19800e8SDoug Rabson     if ((*to)->domain == NULL) {
201c19800e8SDoug Rabson 	free((*to)->username);
202c19800e8SDoug Rabson 	free(*to);
203c19800e8SDoug Rabson 	return ENOMEM;
204c19800e8SDoug Rabson     }
205c19800e8SDoug Rabson     (*to)->key.data = malloc(from->key.length);
206c19800e8SDoug Rabson     if ((*to)->key.data == NULL) {
207c19800e8SDoug Rabson 	free((*to)->domain);
208c19800e8SDoug Rabson 	free((*to)->username);
209c19800e8SDoug Rabson 	free(*to);
210c19800e8SDoug Rabson 	return ENOMEM;
211c19800e8SDoug Rabson     }
212c19800e8SDoug Rabson     memcpy((*to)->key.data, from->key.data, from->key.length);
213c19800e8SDoug Rabson     (*to)->key.length = from->key.length;
214c19800e8SDoug Rabson 
215c19800e8SDoug Rabson     return 0;
216c19800e8SDoug Rabson }
217c19800e8SDoug Rabson 
218ae771770SStanislav Sedov OM_uint32 GSSAPI_CALLCONV
_gss_ntlm_init_sec_context(OM_uint32 * minor_status,const gss_cred_id_t initiator_cred_handle,gss_ctx_id_t * context_handle,const gss_name_t target_name,const gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,const gss_channel_bindings_t input_chan_bindings,const gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec)219c19800e8SDoug Rabson _gss_ntlm_init_sec_context
220c19800e8SDoug Rabson            (OM_uint32 * minor_status,
221c19800e8SDoug Rabson             const gss_cred_id_t initiator_cred_handle,
222c19800e8SDoug Rabson             gss_ctx_id_t * context_handle,
223c19800e8SDoug Rabson             const gss_name_t target_name,
224c19800e8SDoug Rabson             const gss_OID mech_type,
225c19800e8SDoug Rabson             OM_uint32 req_flags,
226c19800e8SDoug Rabson             OM_uint32 time_req,
227c19800e8SDoug Rabson             const gss_channel_bindings_t input_chan_bindings,
228c19800e8SDoug Rabson             const gss_buffer_t input_token,
229c19800e8SDoug Rabson             gss_OID * actual_mech_type,
230c19800e8SDoug Rabson             gss_buffer_t output_token,
231c19800e8SDoug Rabson             OM_uint32 * ret_flags,
232c19800e8SDoug Rabson             OM_uint32 * time_rec
233c19800e8SDoug Rabson 	   )
234c19800e8SDoug Rabson {
235c19800e8SDoug Rabson     ntlm_ctx ctx;
236c19800e8SDoug Rabson     ntlm_name name = (ntlm_name)target_name;
237c19800e8SDoug Rabson 
238c19800e8SDoug Rabson     *minor_status = 0;
239c19800e8SDoug Rabson 
240c19800e8SDoug Rabson     if (ret_flags)
241c19800e8SDoug Rabson 	*ret_flags = 0;
242c19800e8SDoug Rabson     if (time_rec)
243c19800e8SDoug Rabson 	*time_rec = 0;
244c19800e8SDoug Rabson     if (actual_mech_type)
245c19800e8SDoug Rabson 	*actual_mech_type = GSS_C_NO_OID;
246c19800e8SDoug Rabson 
247c19800e8SDoug Rabson     if (*context_handle == GSS_C_NO_CONTEXT) {
248c19800e8SDoug Rabson 	struct ntlm_type1 type1;
249c19800e8SDoug Rabson 	struct ntlm_buf data;
250c19800e8SDoug Rabson 	uint32_t flags = 0;
251c19800e8SDoug Rabson 	int ret;
252c19800e8SDoug Rabson 
253c19800e8SDoug Rabson 	ctx = calloc(1, sizeof(*ctx));
254c19800e8SDoug Rabson 	if (ctx == NULL) {
255c19800e8SDoug Rabson 	    *minor_status = EINVAL;
256c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
257c19800e8SDoug Rabson 	}
258c19800e8SDoug Rabson 	*context_handle = (gss_ctx_id_t)ctx;
259c19800e8SDoug Rabson 
260c19800e8SDoug Rabson 	if (initiator_cred_handle != GSS_C_NO_CREDENTIAL) {
261c19800e8SDoug Rabson 	    ntlm_cred cred = (ntlm_cred)initiator_cred_handle;
262c19800e8SDoug Rabson 	    ret = _gss_copy_cred(cred, &ctx->client);
263c19800e8SDoug Rabson 	} else
264c19800e8SDoug Rabson 	    ret = _gss_ntlm_get_user_cred(name, &ctx->client);
265c19800e8SDoug Rabson 
266c19800e8SDoug Rabson 	if (ret) {
267c19800e8SDoug Rabson 	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
268c19800e8SDoug Rabson 	    *minor_status = ret;
269c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
270c19800e8SDoug Rabson 	}
271c19800e8SDoug Rabson 
272c19800e8SDoug Rabson 	if (req_flags & GSS_C_CONF_FLAG)
273c19800e8SDoug Rabson 	    flags |= NTLM_NEG_SEAL;
274c19800e8SDoug Rabson 	if (req_flags & GSS_C_INTEG_FLAG)
275c19800e8SDoug Rabson 	    flags |= NTLM_NEG_SIGN;
276c19800e8SDoug Rabson 	else
277c19800e8SDoug Rabson 	    flags |= NTLM_NEG_ALWAYS_SIGN;
278c19800e8SDoug Rabson 
279c19800e8SDoug Rabson 	flags |= NTLM_NEG_UNICODE;
280c19800e8SDoug Rabson 	flags |= NTLM_NEG_NTLM;
281c19800e8SDoug Rabson 	flags |= NTLM_NEG_NTLM2_SESSION;
282c19800e8SDoug Rabson 	flags |= NTLM_NEG_KEYEX;
283c19800e8SDoug Rabson 
284c19800e8SDoug Rabson 	memset(&type1, 0, sizeof(type1));
285c19800e8SDoug Rabson 
286c19800e8SDoug Rabson 	type1.flags = flags;
287c19800e8SDoug Rabson 	type1.domain = name->domain;
288c19800e8SDoug Rabson 	type1.hostname = NULL;
289c19800e8SDoug Rabson 	type1.os[0] = 0;
290c19800e8SDoug Rabson 	type1.os[1] = 0;
291c19800e8SDoug Rabson 
292c19800e8SDoug Rabson 	ret = heim_ntlm_encode_type1(&type1, &data);
293c19800e8SDoug Rabson 	if (ret) {
294c19800e8SDoug Rabson 	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
295c19800e8SDoug Rabson 	    *minor_status = ret;
296c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
297c19800e8SDoug Rabson 	}
298c19800e8SDoug Rabson 
299c19800e8SDoug Rabson 	output_token->value = data.data;
300c19800e8SDoug Rabson 	output_token->length = data.length;
301c19800e8SDoug Rabson 
302c19800e8SDoug Rabson 	return GSS_S_CONTINUE_NEEDED;
303c19800e8SDoug Rabson     } else {
304c19800e8SDoug Rabson 	krb5_error_code ret;
305c19800e8SDoug Rabson 	struct ntlm_type2 type2;
306c19800e8SDoug Rabson 	struct ntlm_type3 type3;
307c19800e8SDoug Rabson 	struct ntlm_buf data;
308c19800e8SDoug Rabson 
309c19800e8SDoug Rabson 	ctx = (ntlm_ctx)*context_handle;
310c19800e8SDoug Rabson 
311c19800e8SDoug Rabson 	data.data = input_token->value;
312c19800e8SDoug Rabson 	data.length = input_token->length;
313c19800e8SDoug Rabson 
314c19800e8SDoug Rabson 	ret = heim_ntlm_decode_type2(&data, &type2);
315c19800e8SDoug Rabson 	if (ret) {
316c19800e8SDoug Rabson 	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
317c19800e8SDoug Rabson 	    *minor_status = ret;
318c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
319c19800e8SDoug Rabson 	}
320c19800e8SDoug Rabson 
321c19800e8SDoug Rabson 	ctx->flags = type2.flags;
322c19800e8SDoug Rabson 
323ae771770SStanislav Sedov 	/* XXX check that type2.targetinfo matches `target_name´ */
324c19800e8SDoug Rabson 	/* XXX check verify targetinfo buffer */
325c19800e8SDoug Rabson 
326c19800e8SDoug Rabson 	memset(&type3, 0, sizeof(type3));
327c19800e8SDoug Rabson 
328c19800e8SDoug Rabson 	type3.username = ctx->client->username;
329c19800e8SDoug Rabson 	type3.flags = type2.flags;
330c19800e8SDoug Rabson 	type3.targetname = type2.targetname;
331c19800e8SDoug Rabson 	type3.ws = rk_UNCONST("workstation");
332c19800e8SDoug Rabson 
333c19800e8SDoug Rabson 	/*
334c19800e8SDoug Rabson 	 * NTLM Version 1 if no targetinfo buffer.
335c19800e8SDoug Rabson 	 */
336c19800e8SDoug Rabson 
337c19800e8SDoug Rabson 	if (1 || type2.targetinfo.length == 0) {
338c19800e8SDoug Rabson 	    struct ntlm_buf sessionkey;
339c19800e8SDoug Rabson 
340c19800e8SDoug Rabson 	    if (type2.flags & NTLM_NEG_NTLM2_SESSION) {
341c19800e8SDoug Rabson 		unsigned char nonce[8];
342c19800e8SDoug Rabson 
343c19800e8SDoug Rabson 		if (RAND_bytes(nonce, sizeof(nonce)) != 1) {
344c19800e8SDoug Rabson 		    _gss_ntlm_delete_sec_context(minor_status,
345c19800e8SDoug Rabson 						 context_handle, NULL);
346c19800e8SDoug Rabson 		    *minor_status = EINVAL;
347c19800e8SDoug Rabson 		    return GSS_S_FAILURE;
348c19800e8SDoug Rabson 		}
349c19800e8SDoug Rabson 
350c19800e8SDoug Rabson 		ret = heim_ntlm_calculate_ntlm2_sess(nonce,
351ae771770SStanislav Sedov 						     type2.challenge,
352c19800e8SDoug Rabson 						     ctx->client->key.data,
353c19800e8SDoug Rabson 						     &type3.lm,
354c19800e8SDoug Rabson 						     &type3.ntlm);
355c19800e8SDoug Rabson 	    } else {
356c19800e8SDoug Rabson 		ret = heim_ntlm_calculate_ntlm1(ctx->client->key.data,
357c19800e8SDoug Rabson 						ctx->client->key.length,
358ae771770SStanislav Sedov 						type2.challenge,
359c19800e8SDoug Rabson 						&type3.ntlm);
360c19800e8SDoug Rabson 
361c19800e8SDoug Rabson 	    }
362c19800e8SDoug Rabson 	    if (ret) {
363c19800e8SDoug Rabson 		_gss_ntlm_delete_sec_context(minor_status,context_handle,NULL);
364c19800e8SDoug Rabson 		*minor_status = ret;
365c19800e8SDoug Rabson 		return GSS_S_FAILURE;
366c19800e8SDoug Rabson 	    }
367c19800e8SDoug Rabson 
368c19800e8SDoug Rabson 	    ret = heim_ntlm_build_ntlm1_master(ctx->client->key.data,
369c19800e8SDoug Rabson 					       ctx->client->key.length,
370c19800e8SDoug Rabson 					       &sessionkey,
371c19800e8SDoug Rabson 					       &type3.sessionkey);
372c19800e8SDoug Rabson 	    if (ret) {
373c19800e8SDoug Rabson 		if (type3.lm.data)
374c19800e8SDoug Rabson 		    free(type3.lm.data);
375c19800e8SDoug Rabson 		if (type3.ntlm.data)
376c19800e8SDoug Rabson 		    free(type3.ntlm.data);
377c19800e8SDoug Rabson 		_gss_ntlm_delete_sec_context(minor_status,context_handle,NULL);
378c19800e8SDoug Rabson 		*minor_status = ret;
379c19800e8SDoug Rabson 		return GSS_S_FAILURE;
380c19800e8SDoug Rabson 	    }
381c19800e8SDoug Rabson 
382c19800e8SDoug Rabson 	    ret = krb5_data_copy(&ctx->sessionkey,
383c19800e8SDoug Rabson 				 sessionkey.data, sessionkey.length);
384c19800e8SDoug Rabson 	    free(sessionkey.data);
385c19800e8SDoug Rabson 	    if (ret) {
386c19800e8SDoug Rabson 		if (type3.lm.data)
387c19800e8SDoug Rabson 		    free(type3.lm.data);
388c19800e8SDoug Rabson 		if (type3.ntlm.data)
389c19800e8SDoug Rabson 		    free(type3.ntlm.data);
390c19800e8SDoug Rabson 		_gss_ntlm_delete_sec_context(minor_status,context_handle,NULL);
391c19800e8SDoug Rabson 		*minor_status = ret;
392c19800e8SDoug Rabson 		return GSS_S_FAILURE;
393c19800e8SDoug Rabson 	    }
394c19800e8SDoug Rabson 	    ctx->status |= STATUS_SESSIONKEY;
395c19800e8SDoug Rabson 
396c19800e8SDoug Rabson 	} else {
397c19800e8SDoug Rabson 	    struct ntlm_buf sessionkey;
398c19800e8SDoug Rabson 	    unsigned char ntlmv2[16];
399c19800e8SDoug Rabson 	    struct ntlm_targetinfo ti;
400c19800e8SDoug Rabson 
401c19800e8SDoug Rabson 	    /* verify infotarget */
402c19800e8SDoug Rabson 
403c19800e8SDoug Rabson 	    ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti);
404c19800e8SDoug Rabson 	    if(ret) {
405c19800e8SDoug Rabson 		_gss_ntlm_delete_sec_context(minor_status,
406c19800e8SDoug Rabson 					     context_handle, NULL);
407c19800e8SDoug Rabson 		*minor_status = ret;
408c19800e8SDoug Rabson 		return GSS_S_FAILURE;
409c19800e8SDoug Rabson 	    }
410c19800e8SDoug Rabson 
411c19800e8SDoug Rabson 	    if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) {
412c19800e8SDoug Rabson 		_gss_ntlm_delete_sec_context(minor_status,
413c19800e8SDoug Rabson 					     context_handle, NULL);
414c19800e8SDoug Rabson 		*minor_status = EINVAL;
415c19800e8SDoug Rabson 		return GSS_S_FAILURE;
416c19800e8SDoug Rabson 	    }
417c19800e8SDoug Rabson 
418c19800e8SDoug Rabson 	    ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data,
419c19800e8SDoug Rabson 					    ctx->client->key.length,
420c19800e8SDoug Rabson 					    ctx->client->username,
421c19800e8SDoug Rabson 					    name->domain,
422ae771770SStanislav Sedov 					    type2.challenge,
423c19800e8SDoug Rabson 					    &type2.targetinfo,
424c19800e8SDoug Rabson 					    ntlmv2,
425c19800e8SDoug Rabson 					    &type3.ntlm);
426c19800e8SDoug Rabson 	    if (ret) {
427c19800e8SDoug Rabson 		_gss_ntlm_delete_sec_context(minor_status,
428c19800e8SDoug Rabson 					     context_handle, NULL);
429c19800e8SDoug Rabson 		*minor_status = ret;
430c19800e8SDoug Rabson 		return GSS_S_FAILURE;
431c19800e8SDoug Rabson 	    }
432c19800e8SDoug Rabson 
433c19800e8SDoug Rabson 	    ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2),
434c19800e8SDoug Rabson 					       &sessionkey,
435c19800e8SDoug Rabson 					       &type3.sessionkey);
436c19800e8SDoug Rabson 	    memset(ntlmv2, 0, sizeof(ntlmv2));
437c19800e8SDoug Rabson 	    if (ret) {
438c19800e8SDoug Rabson 		_gss_ntlm_delete_sec_context(minor_status,
439c19800e8SDoug Rabson 					     context_handle, NULL);
440c19800e8SDoug Rabson 		*minor_status = ret;
441c19800e8SDoug Rabson 		return GSS_S_FAILURE;
442c19800e8SDoug Rabson 	    }
443c19800e8SDoug Rabson 
444c19800e8SDoug Rabson 	    ctx->flags |= NTLM_NEG_NTLM2_SESSION;
445c19800e8SDoug Rabson 
446c19800e8SDoug Rabson 	    ret = krb5_data_copy(&ctx->sessionkey,
447c19800e8SDoug Rabson 				 sessionkey.data, sessionkey.length);
448c19800e8SDoug Rabson 	    free(sessionkey.data);
449ae771770SStanislav Sedov 	    if (ret) {
450ae771770SStanislav Sedov 		_gss_ntlm_delete_sec_context(minor_status,
451ae771770SStanislav Sedov 					     context_handle, NULL);
452ae771770SStanislav Sedov 		*minor_status = ret;
453ae771770SStanislav Sedov 		return GSS_S_FAILURE;
454ae771770SStanislav Sedov 	    }
455c19800e8SDoug Rabson 	}
456c19800e8SDoug Rabson 
457c19800e8SDoug Rabson 	if (ctx->flags & NTLM_NEG_NTLM2_SESSION) {
458c19800e8SDoug Rabson 	    ctx->status |= STATUS_SESSIONKEY;
459c19800e8SDoug Rabson 	    _gss_ntlm_set_key(&ctx->u.v2.send, 0, (ctx->flags & NTLM_NEG_KEYEX),
460c19800e8SDoug Rabson 			      ctx->sessionkey.data,
461c19800e8SDoug Rabson 			      ctx->sessionkey.length);
462c19800e8SDoug Rabson 	    _gss_ntlm_set_key(&ctx->u.v2.recv, 1, (ctx->flags & NTLM_NEG_KEYEX),
463c19800e8SDoug Rabson 			      ctx->sessionkey.data,
464c19800e8SDoug Rabson 			      ctx->sessionkey.length);
465c19800e8SDoug Rabson 	} else {
466c19800e8SDoug Rabson 	    ctx->status |= STATUS_SESSIONKEY;
467c19800e8SDoug Rabson 	    RC4_set_key(&ctx->u.v1.crypto_recv.key,
468c19800e8SDoug Rabson 			ctx->sessionkey.length,
469c19800e8SDoug Rabson 			ctx->sessionkey.data);
470c19800e8SDoug Rabson 	    RC4_set_key(&ctx->u.v1.crypto_send.key,
471c19800e8SDoug Rabson 			ctx->sessionkey.length,
472c19800e8SDoug Rabson 			ctx->sessionkey.data);
473c19800e8SDoug Rabson 	}
474c19800e8SDoug Rabson 
475c19800e8SDoug Rabson 
476c19800e8SDoug Rabson 
477c19800e8SDoug Rabson 	ret = heim_ntlm_encode_type3(&type3, &data);
478c19800e8SDoug Rabson 	free(type3.sessionkey.data);
479c19800e8SDoug Rabson 	if (type3.lm.data)
480c19800e8SDoug Rabson 	    free(type3.lm.data);
481c19800e8SDoug Rabson 	if (type3.ntlm.data)
482c19800e8SDoug Rabson 	    free(type3.ntlm.data);
483c19800e8SDoug Rabson 	if (ret) {
484c19800e8SDoug Rabson 	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
485c19800e8SDoug Rabson 	    *minor_status = ret;
486c19800e8SDoug Rabson 	    return GSS_S_FAILURE;
487c19800e8SDoug Rabson 	}
488c19800e8SDoug Rabson 
489c19800e8SDoug Rabson 	output_token->length = data.length;
490c19800e8SDoug Rabson 	output_token->value = data.data;
491c19800e8SDoug Rabson 
492c19800e8SDoug Rabson 	if (actual_mech_type)
493c19800e8SDoug Rabson 	    *actual_mech_type = GSS_NTLM_MECHANISM;
494c19800e8SDoug Rabson 	if (ret_flags)
495c19800e8SDoug Rabson 	    *ret_flags = 0;
496c19800e8SDoug Rabson 	if (time_rec)
497c19800e8SDoug Rabson 	    *time_rec = GSS_C_INDEFINITE;
498c19800e8SDoug Rabson 
499c19800e8SDoug Rabson 	ctx->status |= STATUS_OPEN;
500c19800e8SDoug Rabson 
501c19800e8SDoug Rabson 	return GSS_S_COMPLETE;
502c19800e8SDoug Rabson     }
503c19800e8SDoug Rabson }
504