1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 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
36178825Sdfr/*
37178825Sdfr *
38178825Sdfr */
39178825Sdfr
40178825SdfrOM_uint32
41178825Sdfr_gss_ntlm_allocate_ctx(OM_uint32 *minor_status, ntlm_ctx *ctx)
42178825Sdfr{
43178825Sdfr    OM_uint32 maj_stat;
44233294Sstas    struct ntlm_server_interface *ns_interface = NULL;
45178825Sdfr
46233294Sstas#ifdef DIGEST
47233294Sstas    ns_interface = &ntlmsspi_kdc_digest;
48233294Sstas#endif
49233294Sstas    if (ns_interface == NULL)
50233294Sstas	return GSS_S_FAILURE;
51233294Sstas
52178825Sdfr    *ctx = calloc(1, sizeof(**ctx));
53178825Sdfr
54233294Sstas    (*ctx)->server = ns_interface;
55178825Sdfr
56178825Sdfr    maj_stat = (*(*ctx)->server->nsi_init)(minor_status, &(*ctx)->ictx);
57178825Sdfr    if (maj_stat != GSS_S_COMPLETE)
58178825Sdfr	return maj_stat;
59178825Sdfr
60178825Sdfr    return GSS_S_COMPLETE;
61178825Sdfr}
62178825Sdfr
63178825Sdfr/*
64178825Sdfr *
65178825Sdfr */
66178825Sdfr
67233294SstasOM_uint32 GSSAPI_CALLCONV
68178825Sdfr_gss_ntlm_accept_sec_context
69178825Sdfr(OM_uint32 * minor_status,
70178825Sdfr gss_ctx_id_t * context_handle,
71178825Sdfr const gss_cred_id_t acceptor_cred_handle,
72178825Sdfr const gss_buffer_t input_token_buffer,
73178825Sdfr const gss_channel_bindings_t input_chan_bindings,
74178825Sdfr gss_name_t * src_name,
75178825Sdfr gss_OID * mech_type,
76178825Sdfr gss_buffer_t output_token,
77178825Sdfr OM_uint32 * ret_flags,
78178825Sdfr OM_uint32 * time_rec,
79178825Sdfr gss_cred_id_t * delegated_cred_handle
80178825Sdfr    )
81178825Sdfr{
82178825Sdfr    krb5_error_code ret;
83178825Sdfr    struct ntlm_buf data;
84233294Sstas    OM_uint32 junk;
85178825Sdfr    ntlm_ctx ctx;
86178825Sdfr
87178825Sdfr    output_token->value = NULL;
88178825Sdfr    output_token->length = 0;
89178825Sdfr
90178825Sdfr    *minor_status = 0;
91178825Sdfr
92178825Sdfr    if (context_handle == NULL)
93178825Sdfr	return GSS_S_FAILURE;
94233294Sstas
95178825Sdfr    if (input_token_buffer == GSS_C_NO_BUFFER)
96178825Sdfr	return GSS_S_FAILURE;
97178825Sdfr
98178825Sdfr    if (src_name)
99178825Sdfr	*src_name = GSS_C_NO_NAME;
100178825Sdfr    if (mech_type)
101178825Sdfr	*mech_type = GSS_C_NO_OID;
102178825Sdfr    if (ret_flags)
103178825Sdfr	*ret_flags = 0;
104178825Sdfr    if (time_rec)
105178825Sdfr	*time_rec = 0;
106178825Sdfr    if (delegated_cred_handle)
107178825Sdfr	*delegated_cred_handle = GSS_C_NO_CREDENTIAL;
108178825Sdfr
109178825Sdfr    if (*context_handle == GSS_C_NO_CONTEXT) {
110178825Sdfr	struct ntlm_type1 type1;
111178825Sdfr	OM_uint32 major_status;
112178825Sdfr	OM_uint32 retflags;
113178825Sdfr	struct ntlm_buf out;
114178825Sdfr
115178825Sdfr	major_status = _gss_ntlm_allocate_ctx(minor_status, &ctx);
116178825Sdfr	if (major_status)
117178825Sdfr	    return major_status;
118178825Sdfr	*context_handle = (gss_ctx_id_t)ctx;
119233294Sstas
120178825Sdfr	/* check if the mechs is allowed by remote service */
121178825Sdfr	major_status = (*ctx->server->nsi_probe)(minor_status, ctx->ictx, NULL);
122178825Sdfr	if (major_status) {
123178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
124178825Sdfr	    return major_status;
125178825Sdfr	}
126178825Sdfr
127178825Sdfr	data.data = input_token_buffer->value;
128178825Sdfr	data.length = input_token_buffer->length;
129233294Sstas
130178825Sdfr	ret = heim_ntlm_decode_type1(&data, &type1);
131178825Sdfr	if (ret) {
132178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
133178825Sdfr	    *minor_status = ret;
134178825Sdfr	    return GSS_S_FAILURE;
135178825Sdfr	}
136178825Sdfr
137178825Sdfr	if ((type1.flags & NTLM_NEG_UNICODE) == 0) {
138178825Sdfr	    heim_ntlm_free_type1(&type1);
139178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
140178825Sdfr	    *minor_status = EINVAL;
141178825Sdfr	    return GSS_S_FAILURE;
142178825Sdfr	}
143178825Sdfr
144178825Sdfr	if (type1.flags & NTLM_NEG_SIGN)
145178825Sdfr	    ctx->gssflags |= GSS_C_CONF_FLAG;
146178825Sdfr	if (type1.flags & NTLM_NEG_SIGN)
147178825Sdfr	    ctx->gssflags |= GSS_C_INTEG_FLAG;
148178825Sdfr
149178825Sdfr	major_status = (*ctx->server->nsi_type2)(minor_status,
150178825Sdfr						 ctx->ictx,
151178825Sdfr						 type1.flags,
152178825Sdfr						 type1.hostname,
153178825Sdfr						 type1.domain,
154178825Sdfr						 &retflags,
155178825Sdfr						 &out);
156178825Sdfr	heim_ntlm_free_type1(&type1);
157178825Sdfr	if (major_status != GSS_S_COMPLETE) {
158233294Sstas	    OM_uint32 gunk;
159233294Sstas	    _gss_ntlm_delete_sec_context(&gunk, context_handle, NULL);
160178825Sdfr	    return major_status;
161178825Sdfr	}
162178825Sdfr
163178825Sdfr	output_token->value = malloc(out.length);
164233294Sstas	if (output_token->value == NULL && out.length != 0) {
165233294Sstas	    OM_uint32 gunk;
166233294Sstas	    _gss_ntlm_delete_sec_context(&gunk, context_handle, NULL);
167178825Sdfr	    *minor_status = ENOMEM;
168178825Sdfr	    return GSS_S_FAILURE;
169178825Sdfr	}
170178825Sdfr	memcpy(output_token->value, out.data, out.length);
171178825Sdfr	output_token->length = out.length;
172178825Sdfr
173178825Sdfr	ctx->flags = retflags;
174178825Sdfr
175178825Sdfr	return GSS_S_CONTINUE_NEEDED;
176178825Sdfr    } else {
177178825Sdfr	OM_uint32 maj_stat;
178178825Sdfr	struct ntlm_type3 type3;
179178825Sdfr	struct ntlm_buf session;
180178825Sdfr
181178825Sdfr	ctx = (ntlm_ctx)*context_handle;
182178825Sdfr
183178825Sdfr	data.data = input_token_buffer->value;
184178825Sdfr	data.length = input_token_buffer->length;
185178825Sdfr
186178825Sdfr	ret = heim_ntlm_decode_type3(&data, 1, &type3);
187178825Sdfr	if (ret) {
188178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
189178825Sdfr	    *minor_status = ret;
190178825Sdfr	    return GSS_S_FAILURE;
191178825Sdfr	}
192178825Sdfr
193178825Sdfr	maj_stat = (*ctx->server->nsi_type3)(minor_status,
194178825Sdfr					     ctx->ictx,
195178825Sdfr					     &type3,
196178825Sdfr					     &session);
197178825Sdfr	if (maj_stat) {
198178825Sdfr	    heim_ntlm_free_type3(&type3);
199178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
200178825Sdfr	    return maj_stat;
201178825Sdfr	}
202178825Sdfr
203178825Sdfr	if (src_name) {
204178825Sdfr	    ntlm_name n = calloc(1, sizeof(*n));
205178825Sdfr	    if (n) {
206178825Sdfr		n->user = strdup(type3.username);
207178825Sdfr		n->domain = strdup(type3.targetname);
208178825Sdfr	    }
209178825Sdfr	    if (n == NULL || n->user == NULL || n->domain == NULL) {
210233294Sstas		gss_name_t tempn =  (gss_name_t)n;
211233294Sstas		_gss_ntlm_release_name(&junk, &tempn);
212178825Sdfr		heim_ntlm_free_type3(&type3);
213233294Sstas		_gss_ntlm_delete_sec_context(minor_status,
214178825Sdfr					     context_handle, NULL);
215178825Sdfr		return maj_stat;
216178825Sdfr	    }
217178825Sdfr	    *src_name = (gss_name_t)n;
218233294Sstas	}
219178825Sdfr
220178825Sdfr	heim_ntlm_free_type3(&type3);
221178825Sdfr
222233294Sstas	ret = krb5_data_copy(&ctx->sessionkey,
223178825Sdfr			     session.data, session.length);
224233294Sstas	if (ret) {
225233294Sstas	    if (src_name)
226233294Sstas		_gss_ntlm_release_name(&junk, src_name);
227178825Sdfr	    _gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);
228178825Sdfr	    *minor_status = ret;
229178825Sdfr	    return GSS_S_FAILURE;
230178825Sdfr	}
231233294Sstas
232178825Sdfr	if (session.length != 0) {
233178825Sdfr
234233294Sstas	    ctx->status |= STATUS_SESSIONKEY;
235178825Sdfr
236178825Sdfr	    if (ctx->flags & NTLM_NEG_NTLM2_SESSION) {
237178825Sdfr		_gss_ntlm_set_key(&ctx->u.v2.send, 1,
238178825Sdfr				  (ctx->flags & NTLM_NEG_KEYEX),
239178825Sdfr				  ctx->sessionkey.data,
240178825Sdfr				  ctx->sessionkey.length);
241178825Sdfr		_gss_ntlm_set_key(&ctx->u.v2.recv, 0,
242178825Sdfr				  (ctx->flags & NTLM_NEG_KEYEX),
243178825Sdfr				  ctx->sessionkey.data,
244178825Sdfr				  ctx->sessionkey.length);
245178825Sdfr	    } else {
246233294Sstas		RC4_set_key(&ctx->u.v1.crypto_send.key,
247178825Sdfr			    ctx->sessionkey.length,
248178825Sdfr			    ctx->sessionkey.data);
249233294Sstas		RC4_set_key(&ctx->u.v1.crypto_recv.key,
250178825Sdfr			    ctx->sessionkey.length,
251178825Sdfr			    ctx->sessionkey.data);
252178825Sdfr	    }
253178825Sdfr	}
254178825Sdfr
255178825Sdfr	if (mech_type)
256178825Sdfr	    *mech_type = GSS_NTLM_MECHANISM;
257178825Sdfr	if (time_rec)
258178825Sdfr	    *time_rec = GSS_C_INDEFINITE;
259178825Sdfr
260178825Sdfr	ctx->status |= STATUS_OPEN;
261178825Sdfr
262178825Sdfr	if (ret_flags)
263178825Sdfr	    *ret_flags = ctx->gssflags;
264178825Sdfr
265178825Sdfr	return GSS_S_COMPLETE;
266178825Sdfr    }
267178825Sdfr}
268