gss_iter_cred.c   [plain text]


/*
 * Copyright (c) 2009 Kungliga Tekniska Högskolan
 * (Royal Institute of Technology, Stockholm, Sweden).
 * All rights reserved.
 *
 * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "mech_locl.h"
#include <gssapi_spi.h>
#include <heim_threads.h>


struct _gss_iter {
    HEIMDAL_MUTEX mutex;
    unsigned int count;
    void *userctx;
    void (*iter)(void *, gss_const_OID, gss_cred_id_t);
};

static void
iter_deref(struct _gss_iter *ctx)
{
    HEIMDAL_MUTEX_lock(&ctx->mutex);
    if (--ctx->count == 0) {
	(ctx->iter)(ctx->userctx, NULL, NULL);
	HEIMDAL_MUTEX_unlock(&ctx->mutex);
	HEIMDAL_MUTEX_destroy(&ctx->mutex);
	free(ctx);
    } else
	HEIMDAL_MUTEX_unlock(&ctx->mutex);
}


static void
iterate(void *cctx, gss_OID mech, gss_cred_id_t cred)
{
    struct _gss_iter *ctx = cctx;
    if (cred) {
	struct _gss_mechanism_cred *mc;
	struct _gss_cred *c;

	c = _gss_mg_alloc_cred();
	if (!c)
	    return;

	mc = malloc(sizeof(struct _gss_mechanism_cred));
	if (!mc) {
	    free(c);
	    return;
	}

	mc->gmc_mech = __gss_get_mechanism(mech);
	mc->gmc_mech_oid = mech;
	mc->gmc_cred = cred;
	HEIM_SLIST_INSERT_HEAD(&c->gc_mc, mc, gmc_link);

	ctx->iter(ctx->userctx, mech, (gss_cred_id_t)c);
    } else {
	/*
	 * Now that we reach the end of this mechs credentials,
	 * release the context, only one ref per mech.
	 */
	iter_deref(ctx);
    }
}

/**
 * Iterate over all credentials
 *
 * @param min_stat set to minor status in case of an error
 * @param flags flags argument, no flags currently defined, pass in 0 (zero)
 * @param mech the mechanism type of credentials to iterate over, by passing in GSS_C_NO_OID, the function will iterate over all credentails
 * @param userctx user context passed to the useriter funcion
 * @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().
 *
 * @ingroup gssapi
 */

OM_uint32 GSSAPI_LIB_FUNCTION
gss_iter_creds_f(OM_uint32 *min_stat,
		 OM_uint32 flags,
		 gss_const_OID mech,
		 void * userctx,
		 void (*useriter)(void *, gss_iter_OID, gss_cred_id_t))
{
    struct _gss_iter *ctx;
    gss_OID_set mechs;
    gssapi_mech_interface m;
    int i;

    if (useriter == NULL)
	return GSS_S_CALL_INACCESSIBLE_READ;
    
    _gss_load_mech();
    
    /*
     * First make sure that at least one of the requested
     * mechanisms is one that we support.
     */
    mechs = _gss_mech_oids;
    
    ctx = malloc(sizeof(struct _gss_iter));
    if (ctx == NULL) {
	if (min_stat)
	    *min_stat = ENOMEM;
	return GSS_S_FAILURE;
    }
    
    HEIMDAL_MUTEX_init(&ctx->mutex);
    ctx->count = 1;
    ctx->userctx = userctx;
    ctx->iter = useriter;
    
    for (i = 0; i < mechs->count; i++) {
	
	if (mech && !gss_oid_equal(mech, &mechs->elements[i]))
	    continue;
	
	m = __gss_get_mechanism(&mechs->elements[i]);
	if (!m)
	    continue;
	
	if (m->gm_iter_creds == NULL)
	    continue;
	
	HEIMDAL_MUTEX_lock(&ctx->mutex);
	ctx->count += 1;
	HEIMDAL_MUTEX_unlock(&ctx->mutex);
	
	m->gm_iter_creds(flags, ctx, iterate);
    }
    
    iter_deref(ctx);
    
    return GSS_S_COMPLETE;
}

#ifdef __BLOCKS__

#include <Block.h>

static void
useriter_block(void *ctx, gss_const_OID mech, gss_cred_id_t cred)
{
    void (^u)(gss_const_OID, gss_cred_id_t) = ctx;

    u(mech, cred);

    if (cred == NULL)
	Block_release(u);
	
}

/**
 * Iterate over all credentials
 *
 * @param min_stat set to minor status in case of an error
 * @param flags flags argument, no flags currently defined, pass in 0 (zero)
 * @param mech the mechanism type of credentials to iterate over, by passing in GSS_C_NO_OID, the function will iterate over all credentails
 * @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().
 *
 * @ingroup gssapi
 */


OM_uint32 GSSAPI_LIB_FUNCTION
gss_iter_creds(OM_uint32 *min_stat,
	       OM_uint32 flags,
	       gss_const_OID mech,
	       void (^useriter)(gss_iter_OID, gss_cred_id_t))
{
    void (^u)(gss_const_OID, gss_cred_id_t) = (void (^)(gss_const_OID, gss_cred_id_t))Block_copy(useriter);

    return gss_iter_creds_f(min_stat, flags, mech, u, useriter_block);
}

#endif