1/* 2 * Copyright (c) 2009 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 - 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 "mech_locl.h" 37#include <gssapi_spi.h> 38#include <heim_threads.h> 39 40 41struct _gss_iter { 42 HEIMDAL_MUTEX mutex; 43 unsigned int count; 44 void *userctx; 45 void (*iter)(void *, gss_const_OID, gss_cred_id_t); 46}; 47 48static void 49iter_deref(struct _gss_iter *ctx) 50{ 51 HEIMDAL_MUTEX_lock(&ctx->mutex); 52 if (--ctx->count == 0) { 53 (ctx->iter)(ctx->userctx, NULL, NULL); 54 HEIMDAL_MUTEX_unlock(&ctx->mutex); 55 HEIMDAL_MUTEX_destroy(&ctx->mutex); 56 free(ctx); 57 } else 58 HEIMDAL_MUTEX_unlock(&ctx->mutex); 59} 60 61 62static void 63iterate(void *cctx, gss_OID mech, gss_cred_id_t cred) 64{ 65 struct _gss_iter *ctx = cctx; 66 if (cred) { 67 struct _gss_mechanism_cred *mc; 68 struct _gss_cred *c; 69 70 c = _gss_mg_alloc_cred(); 71 if (!c) 72 return; 73 74 mc = malloc(sizeof(struct _gss_mechanism_cred)); 75 if (!mc) { 76 free(c); 77 return; 78 } 79 80 mc->gmc_mech = __gss_get_mechanism(mech); 81 mc->gmc_mech_oid = mech; 82 mc->gmc_cred = cred; 83 HEIM_SLIST_INSERT_HEAD(&c->gc_mc, mc, gmc_link); 84 85 ctx->iter(ctx->userctx, mech, (gss_cred_id_t)c); 86 } else { 87 /* 88 * Now that we reach the end of this mechs credentials, 89 * release the context, only one ref per mech. 90 */ 91 iter_deref(ctx); 92 } 93} 94 95/** 96 * Iterate over all credentials 97 * 98 * @param min_stat set to minor status in case of an error 99 * @param flags flags argument, no flags currently defined, pass in 0 (zero) 100 * @param mech the mechanism type of credentials to iterate over, by passing in GSS_C_NO_OID, the function will iterate over all credentails 101 * @param userctx user context passed to the useriter funcion 102 * @param useriter function that will be called on each gss_cred_id_t, when NULL is passed the list is completed. Must free the credential with gss_release_cred(). 103 * 104 * @ingroup gssapi 105 */ 106 107OM_uint32 GSSAPI_LIB_FUNCTION 108gss_iter_creds_f(OM_uint32 *min_stat, 109 OM_uint32 flags, 110 gss_const_OID mech, 111 void * userctx, 112 void (*useriter)(void *, gss_iter_OID, gss_cred_id_t)) 113{ 114 struct _gss_iter *ctx; 115 gss_OID_set mechs; 116 gssapi_mech_interface m; 117 size_t i; 118 119 if (useriter == NULL) 120 return GSS_S_CALL_INACCESSIBLE_READ; 121 122 _gss_load_mech(); 123 124 /* 125 * First make sure that at least one of the requested 126 * mechanisms is one that we support. 127 */ 128 mechs = _gss_mech_oids; 129 130 ctx = malloc(sizeof(struct _gss_iter)); 131 if (ctx == NULL) { 132 if (min_stat) 133 *min_stat = ENOMEM; 134 return GSS_S_FAILURE; 135 } 136 137 HEIMDAL_MUTEX_init(&ctx->mutex); 138 ctx->count = 1; 139 ctx->userctx = userctx; 140 ctx->iter = useriter; 141 142 for (i = 0; i < mechs->count; i++) { 143 144 if (mech && !gss_oid_equal(mech, &mechs->elements[i])) 145 continue; 146 147 m = __gss_get_mechanism(&mechs->elements[i]); 148 if (!m) 149 continue; 150 151 if (m->gm_iter_creds == NULL) 152 continue; 153 154 HEIMDAL_MUTEX_lock(&ctx->mutex); 155 ctx->count += 1; 156 HEIMDAL_MUTEX_unlock(&ctx->mutex); 157 158 m->gm_iter_creds(flags, ctx, iterate); 159 } 160 161 iter_deref(ctx); 162 163 return GSS_S_COMPLETE; 164} 165 166#ifdef __BLOCKS__ 167 168#include <Block.h> 169 170static void 171useriter_block(void *ctx, gss_const_OID mech, gss_cred_id_t cred) 172{ 173 void (^u)(gss_const_OID, gss_cred_id_t) = ctx; 174 175 u(mech, cred); 176 177 if (cred == NULL) 178 Block_release(u); 179 180} 181 182/** 183 * Iterate over all credentials 184 * 185 * @param min_stat set to minor status in case of an error 186 * @param flags flags argument, no flags currently defined, pass in 0 (zero) 187 * @param mech the mechanism type of credentials to iterate over, by passing in GSS_C_NO_OID, the function will iterate over all credentails 188 * @param useriter block that will be called on each gss_cred_id_t, when NULL is passed the list is completed. Must free the credential with gss_release_cred(). 189 * 190 * @ingroup gssapi 191 */ 192 193 194OM_uint32 GSSAPI_LIB_FUNCTION 195gss_iter_creds(OM_uint32 *min_stat, 196 OM_uint32 flags, 197 gss_const_OID mech, 198 void (^useriter)(gss_iter_OID, gss_cred_id_t)) 199{ 200 void (^u)(gss_const_OID, gss_cred_id_t) = (void (^)(gss_const_OID, gss_cred_id_t))Block_copy(useriter); 201 202 return gss_iter_creds_f(min_stat, flags, mech, u, useriter_block); 203} 204 205#endif 206