1/* 2 * Copyright (c) 2009 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 KTH nor the names of its contributors may be 18 * used to endorse or promote products derived from this software without 19 * specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY 22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34#include "mech_locl.h" 35#include <krb5.h> 36 37/* 38 * format: any number of: 39 * mech-len: int32 40 * mech-data: char * (not alligned) 41 * cred-len: int32 42 * cred-data char * (not alligned) 43*/ 44 45GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 46gss_export_cred(OM_uint32 * minor_status, 47 gss_cred_id_t cred_handle, 48 gss_buffer_t token) 49{ 50 struct _gss_cred *cred = (struct _gss_cred *)cred_handle; 51 struct _gss_mechanism_cred *mc; 52 gss_buffer_desc buffer; 53 krb5_error_code ret; 54 krb5_storage *sp; 55 OM_uint32 major; 56 krb5_data data; 57 58 _mg_buffer_zero(token); 59 60 if (cred == NULL) { 61 *minor_status = 0; 62 return GSS_S_NO_CRED; 63 } 64 65 HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { 66 if (mc->gmc_mech->gm_export_cred == NULL) { 67 *minor_status = 0; 68 gss_mg_set_error_string(&mc->gmc_mech->gm_mech_oid, 69 GSS_S_NO_CRED, *minor_status, 70 "Credential doesn't support exporting"); 71 return GSS_S_NO_CRED; 72 } 73 } 74 75 sp = krb5_storage_emem(); 76 if (sp == NULL) { 77 *minor_status = ENOMEM; 78 return GSS_S_FAILURE; 79 } 80 81 HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { 82 krb5_ssize_t sret; 83 84 major = mc->gmc_mech->gm_export_cred(minor_status, 85 mc->gmc_cred, &buffer); 86 if (major) { 87 krb5_storage_free(sp); 88 return major; 89 } 90 91 if (buffer.length) { 92 sret = krb5_storage_write(sp, buffer.value, buffer.length); 93 if (sret < 0 || (size_t)sret != buffer.length) { 94 gss_release_buffer(minor_status, &buffer); 95 krb5_storage_free(sp); 96 *minor_status = EINVAL; 97 return GSS_S_FAILURE; 98 } 99 } 100 gss_release_buffer(minor_status, &buffer); 101 } 102 103 ret = krb5_storage_to_data(sp, &data); 104 krb5_storage_free(sp); 105 if (ret) { 106 *minor_status = ret; 107 return GSS_S_FAILURE; 108 } 109 110 if (data.length == 0) { 111 *minor_status = 0; 112 gss_mg_set_error_string(GSS_C_NO_OID, 113 GSS_S_NO_CRED, *minor_status, 114 "Credential was not exportable"); 115 return GSS_S_NO_CRED; 116 } 117 118 token->value = data.data; 119 token->length = data.length; 120 121 return GSS_S_COMPLETE; 122} 123 124GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 125gss_import_cred(OM_uint32 * minor_status, 126 gss_buffer_t token, 127 gss_cred_id_t * cred_handle) 128{ 129 gssapi_mech_interface m; 130 krb5_error_code ret; 131 struct _gss_cred *cred; 132 krb5_storage *sp = NULL; 133 OM_uint32 major, junk; 134 krb5_data data; 135 136 *cred_handle = GSS_C_NO_CREDENTIAL; 137 138 if (token->length == 0) { 139 *minor_status = ENOMEM; 140 return GSS_S_FAILURE; 141 } 142 143 sp = krb5_storage_from_readonly_mem(token->value, token->length); 144 if (sp == NULL) { 145 *minor_status = ENOMEM; 146 return GSS_S_FAILURE; 147 } 148 149 cred = _gss_mg_alloc_cred(); 150 if (cred == NULL) { 151 krb5_storage_free(sp); 152 *minor_status = ENOMEM; 153 return GSS_S_FAILURE; 154 } 155 156 *cred_handle = (gss_cred_id_t)cred; 157 158 while(1) { 159 struct _gss_mechanism_cred *mc; 160 gss_buffer_desc buffer; 161 gss_cred_id_t mcred; 162 gss_OID_desc oid; 163 164 ret = krb5_ret_data(sp, &data); 165 if (ret == HEIM_ERR_EOF) { 166 break; 167 } else if (ret) { 168 *minor_status = ret; 169 major = GSS_S_FAILURE; 170 goto out; 171 } 172 oid.elements = data.data; 173 oid.length = (OM_uint32)data.length; 174 175 m = __gss_get_mechanism(&oid); 176 krb5_data_free(&data); 177 if (!m) { 178 *minor_status = 0; 179 major = GSS_S_BAD_MECH; 180 goto out; 181 } 182 183 if (m->gm_import_cred == NULL) { 184 *minor_status = 0; 185 major = GSS_S_BAD_MECH; 186 goto out; 187 } 188 189 ret = krb5_ret_data(sp, &data); 190 if (ret) { 191 *minor_status = ret; 192 major = GSS_S_FAILURE; 193 goto out; 194 } 195 196 buffer.value = data.data; 197 buffer.length = data.length; 198 199 major = m->gm_import_cred(minor_status, 200 &buffer, &mcred); 201 krb5_data_free(&data); 202 if (major) { 203 goto out; 204 } 205 206 mc = malloc(sizeof(struct _gss_mechanism_cred)); 207 if (mc == NULL) { 208 *minor_status = EINVAL; 209 major = GSS_S_FAILURE; 210 goto out; 211 } 212 213 mc->gmc_mech = m; 214 mc->gmc_mech_oid = &m->gm_mech_oid; 215 mc->gmc_cred = mcred; 216 217 HEIM_SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link); 218 } 219 krb5_storage_free(sp); 220 sp = NULL; 221 222 if (HEIM_SLIST_EMPTY(&cred->gc_mc)) { 223 major = GSS_S_NO_CRED; 224 goto out; 225 } 226 227 return GSS_S_COMPLETE; 228 229 out: 230 if (sp) 231 krb5_storage_free(sp); 232 233 gss_release_cred(&junk, cred_handle); 234 235 return major; 236 237} 238 239OM_uint32 240gss_cred_label_get(OM_uint32 * min_stat, 241 gss_cred_id_t cred_handle, 242 const char * label, 243 gss_buffer_t value) 244{ 245 struct _gss_cred *cred = (struct _gss_cred *)cred_handle; 246 struct _gss_mechanism_cred *mc; 247 OM_uint32 maj_stat; 248 249 *min_stat = 0; 250 _mg_buffer_zero(value); 251 252 HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { 253 254 if (mc->gmc_mech->gm_cred_label_get == NULL) 255 continue; 256 257 maj_stat = mc->gmc_mech->gm_cred_label_get(min_stat, mc->gmc_cred, 258 label, value); 259 if (maj_stat == GSS_S_COMPLETE) 260 return GSS_S_COMPLETE; 261 } 262 263 return GSS_S_UNAVAILABLE; 264} 265 266OM_uint32 267gss_cred_label_set(OM_uint32 * min_stat, 268 gss_cred_id_t cred_handle, 269 const char * label, 270 gss_buffer_t value) 271{ 272 struct _gss_cred *cred = (struct _gss_cred *)cred_handle; 273 struct _gss_mechanism_cred *mc; 274 275 *min_stat = 0; 276 277 HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) { 278 279 if (mc->gmc_mech->gm_cred_label_set == NULL) 280 continue; 281 282 (void)mc->gmc_mech->gm_cred_label_set(min_stat, mc->gmc_cred, 283 label, value); 284 } 285 286 return GSS_S_COMPLETE; 287} 288