1/*	$NetBSD: accept_sec_context.c,v 1.1.1.1 2011/04/13 18:14:47 elric Exp $	*/
2
3/*
4 * Copyright (c) 2006 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "ntlm.h"
37
38/*
39 *
40 */
41
42OM_uint32
43_gss_ntlm_allocate_ctx(OM_uint32 *minor_status, ntlm_ctx *ctx)
44{
45    OM_uint32 maj_stat;
46    struct ntlm_server_interface *ns_interface = NULL;
47
48#ifdef DIGEST
49    ns_interface = &ntlmsspi_kdc_digest;
50#endif
51    if (ns_interface == NULL)
52	return GSS_S_FAILURE;
53
54    *ctx = calloc(1, sizeof(**ctx));
55
56    (*ctx)->server = ns_interface;
57
58    maj_stat = (*(*ctx)->server->nsi_init)(minor_status, &(*ctx)->ictx);
59    if (maj_stat != GSS_S_COMPLETE)
60	return maj_stat;
61
62    return GSS_S_COMPLETE;
63}
64
65/*
66 *
67 */
68
69OM_uint32 GSSAPI_CALLCONV
70_gss_ntlm_accept_sec_context
71(OM_uint32 * minor_status,
72 gss_ctx_id_t * context_handle,
73 const gss_cred_id_t acceptor_cred_handle,
74 const gss_buffer_t input_token_buffer,
75 const gss_channel_bindings_t input_chan_bindings,
76 gss_name_t * src_name,
77 gss_OID * mech_type,
78 gss_buffer_t output_token,
79 OM_uint32 * ret_flags,
80 OM_uint32 * time_rec,
81 gss_cred_id_t * delegated_cred_handle
82    )
83{
84    krb5_error_code ret;
85    struct ntlm_buf data;
86    OM_uint32 junk;
87    ntlm_ctx ctx;
88
89    output_token->value = NULL;
90    output_token->length = 0;
91
92    *minor_status = 0;
93
94    if (context_handle == NULL)
95	return GSS_S_FAILURE;
96
97    if (input_token_buffer == GSS_C_NO_BUFFER)
98	return GSS_S_FAILURE;
99
100    if (src_name)
101	*src_name = GSS_C_NO_NAME;
102    if (mech_type)
103	*mech_type = GSS_C_NO_OID;
104    if (ret_flags)
105	*ret_flags = 0;
106    if (time_rec)
107	*time_rec = 0;
108    if (delegated_cred_handle)
109	*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
110
111    if (*context_handle == GSS_C_NO_CONTEXT) {
112	struct ntlm_type1 type1;
113	OM_uint32 major_status;
114	OM_uint32 retflags;
115	struct ntlm_buf out;
116
117	major_status = _gss_ntlm_allocate_ctx(minor_status, &ctx);
118	if (major_status)
119	    return major_status;
120	*context_handle = (gss_ctx_id_t)ctx;
121
122	/* check if the mechs is allowed by remote service */
123	major_status = (*ctx->server->nsi_probe)(minor_status, ctx->ictx, NULL);
124	if (major_status) {
125	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
126	    return major_status;
127	}
128
129	data.data = input_token_buffer->value;
130	data.length = input_token_buffer->length;
131
132	ret = heim_ntlm_decode_type1(&data, &type1);
133	if (ret) {
134	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
135	    *minor_status = ret;
136	    return GSS_S_FAILURE;
137	}
138
139	if ((type1.flags & NTLM_NEG_UNICODE) == 0) {
140	    heim_ntlm_free_type1(&type1);
141	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
142	    *minor_status = EINVAL;
143	    return GSS_S_FAILURE;
144	}
145
146	if (type1.flags & NTLM_NEG_SIGN)
147	    ctx->gssflags |= GSS_C_CONF_FLAG;
148	if (type1.flags & NTLM_NEG_SIGN)
149	    ctx->gssflags |= GSS_C_INTEG_FLAG;
150
151	major_status = (*ctx->server->nsi_type2)(minor_status,
152						 ctx->ictx,
153						 type1.flags,
154						 type1.hostname,
155						 type1.domain,
156						 &retflags,
157						 &out);
158	heim_ntlm_free_type1(&type1);
159	if (major_status != GSS_S_COMPLETE) {
160	    OM_uint32 junk;
161	    _gss_ntlm_delete_sec_context(&junk, context_handle, NULL);
162	    return major_status;
163	}
164
165	output_token->value = malloc(out.length);
166	if (output_token->value == NULL && out.length != 0) {
167	    OM_uint32 junk;
168	    _gss_ntlm_delete_sec_context(&junk, context_handle, NULL);
169	    *minor_status = ENOMEM;
170	    return GSS_S_FAILURE;
171	}
172	memcpy(output_token->value, out.data, out.length);
173	output_token->length = out.length;
174
175	ctx->flags = retflags;
176
177	return GSS_S_CONTINUE_NEEDED;
178    } else {
179	OM_uint32 maj_stat;
180	struct ntlm_type3 type3;
181	struct ntlm_buf session;
182
183	ctx = (ntlm_ctx)*context_handle;
184
185	data.data = input_token_buffer->value;
186	data.length = input_token_buffer->length;
187
188	ret = heim_ntlm_decode_type3(&data, 1, &type3);
189	if (ret) {
190	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
191	    *minor_status = ret;
192	    return GSS_S_FAILURE;
193	}
194
195	maj_stat = (*ctx->server->nsi_type3)(minor_status,
196					     ctx->ictx,
197					     &type3,
198					     &session);
199	if (maj_stat) {
200	    heim_ntlm_free_type3(&type3);
201	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
202	    return maj_stat;
203	}
204
205	if (src_name) {
206	    ntlm_name n = calloc(1, sizeof(*n));
207	    if (n) {
208		n->user = strdup(type3.username);
209		n->domain = strdup(type3.targetname);
210	    }
211	    if (n == NULL || n->user == NULL || n->domain == NULL) {
212		gss_name_t tempn =  (gss_name_t)n;
213		_gss_ntlm_release_name(&junk, &tempn);
214		heim_ntlm_free_type3(&type3);
215		_gss_ntlm_delete_sec_context(minor_status,
216					     context_handle, NULL);
217		return maj_stat;
218	    }
219	    *src_name = (gss_name_t)n;
220	}
221
222	heim_ntlm_free_type3(&type3);
223
224	ret = krb5_data_copy(&ctx->sessionkey,
225			     session.data, session.length);
226	if (ret) {
227	    if (src_name)
228		_gss_ntlm_release_name(&junk, src_name);
229	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
230	    *minor_status = ret;
231	    return GSS_S_FAILURE;
232	}
233
234	if (session.length != 0) {
235
236	    ctx->status |= STATUS_SESSIONKEY;
237
238	    if (ctx->flags & NTLM_NEG_NTLM2_SESSION) {
239		_gss_ntlm_set_key(&ctx->u.v2.send, 1,
240				  (ctx->flags & NTLM_NEG_KEYEX),
241				  ctx->sessionkey.data,
242				  ctx->sessionkey.length);
243		_gss_ntlm_set_key(&ctx->u.v2.recv, 0,
244				  (ctx->flags & NTLM_NEG_KEYEX),
245				  ctx->sessionkey.data,
246				  ctx->sessionkey.length);
247	    } else {
248		RC4_set_key(&ctx->u.v1.crypto_send.key,
249			    ctx->sessionkey.length,
250			    ctx->sessionkey.data);
251		RC4_set_key(&ctx->u.v1.crypto_recv.key,
252			    ctx->sessionkey.length,
253			    ctx->sessionkey.data);
254	    }
255	}
256
257	if (mech_type)
258	    *mech_type = GSS_NTLM_MECHANISM;
259	if (time_rec)
260	    *time_rec = GSS_C_INDEFINITE;
261
262	ctx->status |= STATUS_OPEN;
263
264	if (ret_flags)
265	    *ret_flags = ctx->gssflags;
266
267	return GSS_S_COMPLETE;
268    }
269}
270