2 * Copyright (c) 2012, 2013, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <murphy/common/macros.h>
33 #include <murphy/common/mm.h>
34 #include <murphy/common/log.h>
36 #include <murphy/core/context.h>
37 #include <murphy/core/auth.h>
41 char *name; /* backend name */
42 mrp_auth_cb_t cb; /* backend method */
43 void *auth_data; /* backend data */
44 mrp_list_hook_t hook; /* to list of backends */
48 static MRP_LIST_HOOK(pending);
51 static auth_backend_t *find_auth(mrp_list_hook_t *backends, const char *name)
53 mrp_list_hook_t *p, *n;
56 mrp_list_foreach(backends, p, n) {
57 auth = mrp_list_entry(p, typeof(*auth), hook);
59 if (!strcmp(auth->name, name))
67 static int register_auth(mrp_list_hook_t *backends, const char *name,
68 mrp_auth_cb_t cb, void *auth_data)
72 if (find_auth(backends, name) != NULL)
75 auth = mrp_allocz(sizeof(*auth));
78 mrp_list_init(&auth->hook);
80 auth->name = mrp_strdup(name);
82 auth->auth_data = auth_data;
84 if (auth->name != NULL) {
87 * Prepending here is a crude hack to make sure the first
88 * registered backend, which is 'deny', ends up being the
89 * last in the list of authenticators. Maybe we should add
90 * a priority to the backend registration interface and
91 * use it to make this more explicit...
94 mrp_list_prepend(backends, &auth->hook);
96 mrp_debug("registered authentication backend %s", auth->name);
108 static void unregister_auth(mrp_list_hook_t *backends, const char *name)
110 auth_backend_t *auth;
112 auth = find_auth(backends, name);
115 mrp_list_delete(&auth->hook);
116 mrp_free(auth->name);
122 int mrp_register_authenticator(mrp_context_t *ctx, const char *name,
123 mrp_auth_cb_t cb, void *auth_data)
125 mrp_list_hook_t *backends;
128 if (MRP_UNLIKELY(!mrp_list_empty(&pending)))
129 mrp_list_move(&ctx->auth, &pending);
131 backends = &ctx->auth;
136 if (register_auth(backends, name, cb, auth_data) == 0)
143 void mrp_unregister_authenticator(mrp_context_t *ctx, const char *name)
145 mrp_list_hook_t *backends = ctx ? &ctx->auth : &pending;
147 unregister_auth(backends, name);
151 int mrp_authenticate(mrp_context_t *ctx, const char *backend,
152 const char *target, mrp_auth_mode_t mode,
153 const char *id, const char *token)
155 auth_backend_t *auth;
156 mrp_list_hook_t *p, *n;
159 if (MRP_UNLIKELY(!mrp_list_empty(&pending)))
160 mrp_list_move(&ctx->auth, &pending);
165 * Currently we let the caller request authentication by any available
166 * backend by using MRP_AUTH_ANY. If requested so, access is granted
167 * if any of the backends grants access.
169 * We might want to change this in the future, probably by either
170 * requiring the caller to always specify a valid authentication backend,
171 * or by having one of the backends be marked as default which then would
172 * be used for authentication in these cases. Either of those would make
173 * it more difficult to grant unwanted access accidentially in the case
174 * of multiple available backends.
177 result = MRP_AUTH_RESULT_ERROR;
179 mrp_list_foreach(&ctx->auth, p, n) {
180 auth = mrp_list_entry(p, typeof(*auth), hook);
182 if (backend == MRP_AUTH_ANY || !strcmp(backend, auth->name)) {
183 status = auth->cb(target, mode, id, token, auth->auth_data);
185 mrp_debug("backend %s, access 0x%x of %s/%s to %s: %d", auth->name,
186 mode, id, token ? token : "<none>", target, status);
188 if (backend != MRP_AUTH_ANY)
192 case MRP_AUTH_RESULT_GRANT:
193 return MRP_AUTH_RESULT_GRANT;
194 case MRP_AUTH_RESULT_DENY:
195 result = MRP_AUTH_RESULT_DENY;