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