1/* 2 * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 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 "ntlm.h" 37#include <gssapi_spi.h> 38 39OM_uint32 40_gss_ntlm_have_cred(OM_uint32 *minor, 41 const ntlm_name target_name, 42 ntlm_cred *rcred) 43{ 44 krb5_context context; 45 krb5_error_code ret; 46 krb5_storage *request, *response; 47 krb5_data response_data; 48 OM_uint32 major; 49 ntlm_name cred; 50 kcmuuid_t uuid; 51 ssize_t sret; 52 53 ret = krb5_init_context(&context); 54 if (ret) { 55 *minor = ret; 56 return GSS_S_FAILURE; 57 } 58 59 ret = krb5_kcm_storage_request(context, KCM_OP_HAVE_NTLM_CRED, &request); 60 if (ret) 61 goto out; 62 63 ret = krb5_store_stringz(request, target_name->user); 64 if (ret) 65 goto out; 66 67 ret = krb5_store_stringz(request, target_name->domain); 68 if (ret) 69 goto out; 70 71 ret = krb5_kcm_call(context, request, &response, &response_data); 72 krb5_storage_free(request); 73 if (ret) 74 goto out; 75 76 sret = krb5_storage_read(response, uuid, sizeof(uuid)); 77 78 krb5_storage_free(response); 79 krb5_data_free(&response_data); 80 81 if (sret != sizeof(uuid)) { 82 krb5_clear_error_message(context); 83 return KRB5_CC_IO; 84 } 85 86 major = _gss_ntlm_duplicate_name(minor, (gss_name_t)target_name, 87 (gss_name_t *)&cred); 88 if (major) 89 return major; 90 91 cred->flags |= NTLM_UUID; 92 memcpy(cred->uuid, uuid, sizeof(cred->uuid)); 93 94 *rcred = (ntlm_cred)cred; 95 out: 96 krb5_free_context(context); 97 if (ret) { 98 *minor = ret; 99 major = GSS_S_FAILURE; 100 } 101 102 return major; 103} 104 105OM_uint32 106_gss_ntlm_acquire_cred(OM_uint32 * min_stat, 107 const gss_name_t desired_name, 108 OM_uint32 time_req, 109 const gss_OID_set desired_mechs, 110 gss_cred_usage_t cred_usage, 111 gss_cred_id_t * output_cred_handle, 112 gss_OID_set * actual_mechs, 113 OM_uint32 * time_rec) 114{ 115 ntlm_name name = (ntlm_name) desired_name; 116 OM_uint32 maj_stat, junk; 117 ntlm_ctx ctx; 118 119 *min_stat = 0; 120 *output_cred_handle = GSS_C_NO_CREDENTIAL; 121 if (actual_mechs) 122 *actual_mechs = GSS_C_NO_OID_SET; 123 if (time_rec) 124 *time_rec = GSS_C_INDEFINITE; 125 126 if (desired_name == NULL) 127 return GSS_S_NO_CRED; 128 129 if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_ACCEPT) { 130 gss_ctx_id_t gctx; 131 132 maj_stat = _gss_ntlm_allocate_ctx(min_stat, name->domain, &ctx); 133 if (maj_stat != GSS_S_COMPLETE) 134 return maj_stat; 135 136 gctx = (gss_ctx_id_t)ctx; 137 _gss_ntlm_delete_sec_context(&junk, &gctx, NULL); 138 } 139 if (cred_usage == GSS_C_BOTH || cred_usage == GSS_C_INITIATE) { 140 ntlm_cred cred; 141 142 /* if we have a anon name, lets dup it directly */ 143 if ((name->flags & NTLM_ANON_NAME) != 0) { 144 maj_stat = _gss_ntlm_duplicate_name(min_stat, 145 (gss_name_t)name, 146 (gss_name_t *)&cred); 147 if (maj_stat) 148 return maj_stat; 149 } else { 150 maj_stat = _gss_ntlm_have_cred(min_stat, name, &cred); 151 if (maj_stat) 152 return maj_stat; 153 } 154 *output_cred_handle = (gss_cred_id_t)cred; 155 } 156 157 return (GSS_S_COMPLETE); 158} 159 160OM_uint32 161_gss_ntlm_acquire_cred_ext(OM_uint32 * minor_status, 162 const gss_name_t desired_name, 163 gss_const_OID credential_type, 164 const void *credential_data, 165 OM_uint32 time_req, 166 gss_const_OID desired_mech, 167 gss_cred_usage_t cred_usage, 168 gss_cred_id_t * output_cred_handle) 169{ 170 ntlm_name name = (ntlm_name) desired_name; 171 OM_uint32 major; 172 krb5_storage *request, *response; 173 krb5_data response_data; 174 krb5_context context; 175 krb5_error_code ret; 176 struct ntlm_buf buf; 177 krb5_data data; 178 ntlm_cred dn; 179 kcmuuid_t uuid; 180 ssize_t sret; 181 182 if (credential_data == NULL) 183 return GSS_S_FAILURE; 184 185 if (!gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) 186 return GSS_S_FAILURE; 187 188 if (name == NULL) 189 return GSS_S_FAILURE; 190 191 ret = krb5_init_context(&context); 192 if (ret) 193 return GSS_S_FAILURE; 194 195 { 196 gss_buffer_t buffer; 197 char *password; 198 199 buffer = (gss_buffer_t)credential_data; 200 password = malloc(buffer->length + 1); 201 if (password == NULL) { 202 ret = ENOMEM; 203 goto out; 204 } 205 memcpy(password, buffer->value, buffer->length); 206 password[buffer->length] = '\0'; 207 208 heim_ntlm_nt_key(password, &buf); 209 memset(password, 0, strlen(password)); 210 free(password); 211 } 212 213 data.data = buf.data; 214 data.length = buf.length; 215 216 krb5_kcm_storage_request(context, KCM_OP_ADD_NTLM_CRED, &request); 217 218 krb5_store_stringz(request, name->user); 219 krb5_store_stringz(request, name->domain); 220 krb5_store_data(request, data); 221 222 ret = krb5_kcm_call(context, request, &response, &response_data); 223 krb5_storage_free(request); 224 if (ret) 225 goto out; 226 227 sret = krb5_storage_read(response, &uuid, sizeof(uuid)); 228 229 krb5_storage_free(response); 230 krb5_data_free(&response_data); 231 232 if (sret != sizeof(uuid)) { 233 ret = KRB5_CC_IO; 234 goto out; 235 } 236 237 heim_ntlm_free_buf(&buf); 238 239 dn = calloc(1, sizeof(*dn)); 240 if (dn == NULL) { 241 major = GSS_S_FAILURE; 242 goto out; 243 } 244 245 dn->user = strdup(name->user); 246 dn->domain = strdup(name->domain); 247 dn->flags = NTLM_UUID; 248 memcpy(dn->uuid, uuid, sizeof(dn->uuid)); 249 250 *output_cred_handle = (gss_cred_id_t)dn; 251 252 major = GSS_S_COMPLETE; 253 out: 254 255 krb5_free_context(context); 256 if (ret) 257 major = GSS_S_FAILURE; 258 259 return major; 260} 261