xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/gssapi/ntlm/accept_sec_context.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
1 /*	$NetBSD: accept_sec_context.c,v 1.2 2017/01/28 21:31:46 christos 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 
42 OM_uint32
_gss_ntlm_allocate_ctx(OM_uint32 * minor_status,ntlm_ctx * ctx)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 
69 OM_uint32 GSSAPI_CALLCONV
_gss_ntlm_accept_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_const_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token_buffer,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)70 _gss_ntlm_accept_sec_context
71 (OM_uint32 * minor_status,
72  gss_ctx_id_t * context_handle,
73  gss_const_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 gunk;
161 	    _gss_ntlm_delete_sec_context(&gunk, 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 gunk;
168 	    _gss_ntlm_delete_sec_context(&gunk, 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