1/* 2 * Copyright (c) 2010 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2010 Apple Inc. 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 "netlogon.h" 37#include <nameser.h> 38 39static OM_uint32 40_netlogon_encode_dns_string(OM_uint32 *minor_status, 41 const gss_buffer_t str, 42 gss_buffer_t buffer) 43{ 44 int ret; 45 46 memset(buffer->value, 0, buffer->length); 47 48 ret = ns_name_compress((const char *)str->value, 49 (uint8_t *)buffer->value, buffer->length, 50 NULL, NULL); 51 if (ret < 0) { 52 *minor_status = errno; 53 return GSS_S_FAILURE; 54 } 55 56 buffer->length = ret; 57 58 *minor_status = 0; 59 return GSS_S_COMPLETE; 60} 61 62static OM_uint32 63_netlogon_make_initial_auth_message(OM_uint32 *minor_status, 64 gssnetlogon_ctx ctx, 65 gss_buffer_t output_token) 66{ 67 uint32_t flags = 0; 68#define MAX_NL_NAMES 5 69 gss_buffer_desc names[MAX_NL_NAMES]; 70 uint8_t comp_names[3][MAXHOSTNAMELEN * 2]; 71 size_t n = 0, i __attribute__((__unused__)) = 0 , len; 72 OM_uint32 ret; 73 uint8_t *p; 74 75 if (ctx->TargetName->NetbiosName.length) { 76 flags |= NL_FLAG_NETBIOS_DOMAIN_NAME; 77 names[n] = ctx->TargetName->NetbiosName; /* OEM encoding */ 78 names[n].length++; 79 n++; 80 } 81 if (ctx->SourceName->NetbiosName.length) { 82 flags |= NL_FLAG_NETBIOS_COMPUTER_NAME; 83 names[n] = ctx->SourceName->NetbiosName; /* OEM encoding */ 84 names[n].length++; 85 n++; 86 } 87 if (ctx->TargetName->DnsName.length) { 88 flags |= NL_FLAG_DNS_DOMAIN_NAME; 89 names[n].value = comp_names[i++]; 90 names[n].length = MAXHOSTNAMELEN * 2; 91 ret = _netlogon_encode_dns_string(minor_status, 92 &ctx->TargetName->DnsName, 93 &names[n]); 94 if (GSS_ERROR(ret)) 95 return ret; 96 n++; 97 } 98 if (ctx->SourceName->DnsName.length) { 99 flags |= NL_FLAG_DNS_HOST_NAME; 100 names[n].value = comp_names[i++]; 101 names[n].length = MAXHOSTNAMELEN * 2; 102 ret = _netlogon_encode_dns_string(minor_status, 103 &ctx->SourceName->DnsName, 104 &names[n]); 105 if (GSS_ERROR(ret)) 106 return ret; 107 n++; 108 } 109 if (ctx->SourceName->NetbiosName.length) { 110 flags |= NL_FLAG_UTF8_COMPUTER_NAME; 111 names[n].value = comp_names[i++]; 112 names[n].length = MAXHOSTNAMELEN * 2; 113 ret = _netlogon_encode_dns_string(minor_status, 114 &ctx->SourceName->NetbiosName, 115 &names[n]); 116 if (GSS_ERROR(ret)) 117 return ret; 118 n++; 119 } 120 121 for (i = 0, len = NL_AUTH_MESSAGE_LENGTH; i < n; i++) { 122 len += names[i].length; 123 } 124 125 output_token->value = malloc(len); 126 if (output_token->value == NULL) { 127 *minor_status = ENOMEM; 128 return GSS_S_FAILURE; 129 } 130 131 p = (uint8_t *)output_token->value; 132 _gss_mg_encode_le_uint32(NL_NEGOTIATE_REQUEST_MESSAGE, p); 133 _gss_mg_encode_le_uint32(flags, p + 4); 134 p += 8; 135 136 for (i = 0; i < n; i++) { 137 assert(names[i].length != 0); 138 assert(((char *)names[i].value)[names[i].length - 1] == '\0'); 139 memcpy(p, names[i].value, names[i].length); 140 p += names[i].length; 141 } 142 143 output_token->length = len; 144 assert(p == (uint8_t *)output_token->value + len); 145 146 *minor_status = 0; 147 return GSS_S_CONTINUE_NEEDED; 148} 149 150static OM_uint32 151_netlogon_read_initial_auth_message(OM_uint32 *minor_status, 152 gssnetlogon_ctx ctx, 153 const gss_buffer_t input_token) 154{ 155 NL_AUTH_MESSAGE msg; 156 const uint8_t *p = (const uint8_t *)input_token->value; 157 158 if (ctx->State != NL_AUTH_NEGOTIATE) { 159 *minor_status = EINVAL; 160 return GSS_S_FAILURE; 161 } 162 163 if (input_token->length < NL_AUTH_MESSAGE_LENGTH) 164 return GSS_S_DEFECTIVE_TOKEN; 165 166 _gss_mg_decode_le_uint32(&p[0], &msg.MessageType); 167 _gss_mg_decode_le_uint32(&p[4], &msg.Flags); 168 169 if (msg.MessageType != NL_NEGOTIATE_RESPONSE_MESSAGE || 170 msg.Flags != 0) 171 return GSS_S_DEFECTIVE_TOKEN; 172 173 ctx->State = NL_AUTH_ESTABLISHED; 174 175 *minor_status = 0; 176 return GSS_S_COMPLETE; 177} 178 179static OM_uint32 180_netlogon_alloc_context(OM_uint32 *minor_status, 181 gssnetlogon_ctx *pContext) 182{ 183 gssnetlogon_ctx ctx; 184 185 ctx = (gssnetlogon_ctx)calloc(1, sizeof(*ctx)); 186 if (ctx == NULL) { 187 *minor_status = ENOMEM; 188 return GSS_S_FAILURE; 189 } 190 191 ctx->State = NL_AUTH_NEGOTIATE; 192 ctx->LocallyInitiated = 1; 193 ctx->MessageBlockSize = 1; 194 195 HEIMDAL_MUTEX_init(&ctx->Mutex); 196 197 *pContext = ctx; 198 199 return GSS_S_COMPLETE; 200} 201 202OM_uint32 203_netlogon_init_sec_context(OM_uint32 * minor_status, 204 const gss_cred_id_t initiator_cred_handle, 205 gss_ctx_id_t * context_handle, 206 const gss_name_t target_name, 207 const gss_OID mech_type, 208 OM_uint32 req_flags, 209 OM_uint32 time_req, 210 const gss_channel_bindings_t input_chan_bindings, 211 const gss_buffer_t input_token, 212 gss_OID * actual_mech_type, 213 gss_buffer_t output_token, 214 OM_uint32 * ret_flags, 215 OM_uint32 * time_rec) 216{ 217 const gssnetlogon_cred cred = (const gssnetlogon_cred)initiator_cred_handle; 218 gssnetlogon_ctx ctx = (gssnetlogon_ctx)*context_handle; 219 const gssnetlogon_name target = (const gssnetlogon_name)target_name; 220 OM_uint32 ret; 221 222 *minor_status = 0; 223 224 output_token->value = NULL; 225 output_token->length = 0; 226 227 /* Validate arguments */ 228 if (cred == NULL) 229 return GSS_S_NO_CRED; 230 else if (target == NULL) 231 return GSS_S_BAD_NAME; 232 233 if (ctx == NULL) { 234 if (input_token->length != 0) 235 return GSS_S_DEFECTIVE_TOKEN; 236 237 ret = _netlogon_alloc_context(minor_status, &ctx); 238 if (GSS_ERROR(ret)) 239 goto cleanup; 240 241 HEIMDAL_MUTEX_lock(&ctx->Mutex); 242 *context_handle = (gss_ctx_id_t)ctx; 243 244 ctx->GssFlags = req_flags & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | 245 GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | 246 GSS_C_INTEG_FLAG | GSS_C_DCE_STYLE); 247 ctx->SignatureAlgorithm = cred->SignatureAlgorithm; 248 ctx->SealAlgorithm = cred->SealAlgorithm; 249 250 ret = _netlogon_duplicate_name(minor_status, (gss_name_t)cred->Name, 251 (gss_name_t *)&ctx->SourceName); 252 if (GSS_ERROR(ret)) 253 goto cleanup; 254 255 ret = _netlogon_duplicate_name(minor_status, (gss_name_t)target, 256 (gss_name_t *)&ctx->TargetName); 257 if (GSS_ERROR(ret)) 258 goto cleanup; 259 260 memcpy(ctx->SessionKey, cred->SessionKey, sizeof(cred->SessionKey)); 261 262 ret = _netlogon_make_initial_auth_message(minor_status, ctx, 263 output_token); 264 if (GSS_ERROR(ret)) 265 goto cleanup; 266 } else { 267 HEIMDAL_MUTEX_lock(&ctx->Mutex); 268 ret = _netlogon_read_initial_auth_message(minor_status, ctx, 269 input_token); 270 } 271 272 if (ret_flags != NULL) 273 *ret_flags = ctx->GssFlags; 274 if (time_rec != NULL) 275 *time_rec = GSS_C_INDEFINITE; 276 if (actual_mech_type != NULL) 277 *actual_mech_type = GSS_NETLOGON_MECHANISM; 278 279cleanup: 280 HEIMDAL_MUTEX_unlock(&ctx->Mutex); 281 282 if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) { 283 OM_uint32 tmp; 284 _netlogon_delete_sec_context(&tmp, context_handle, NULL); 285 } 286 287 return ret; 288} 289 290