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