]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - crypto/heimdal/lib/gssapi/ntlm/accept_sec_context.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / crypto / heimdal / lib / gssapi / ntlm / accept_sec_context.c
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 }