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 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 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