blob: f6afc0f633915db7b48628afabc8ff32ef811e05 [file] [log] [blame]
Julien Boeuf9f218dd2015-04-23 10:24:02 -07001/*
2 *
Craig Tiller19482442016-01-25 09:59:20 -08003 * Copyright 2015-2016, Google Inc.
Julien Boeuf9f218dd2015-04-23 10:24:02 -07004 * 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 are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#include <string.h>
35
Julien Boeufd7f768b2015-05-08 16:37:16 -070036#include "src/core/security/security_context.h"
Craig Tillerf40df232016-03-25 13:38:14 -070037#include "src/core/support/string.h"
Masood Malekghassemi76c3d742015-08-19 18:22:53 -070038#include "src/core/surface/api_trace.h"
Julien Boeuf9f218dd2015-04-23 10:24:02 -070039#include "src/core/surface/call.h"
40
41#include <grpc/grpc_security.h>
42#include <grpc/support/alloc.h>
43#include <grpc/support/log.h>
Masood Malekghassemi701af602015-06-03 15:01:17 -070044#include <grpc/support/string_util.h>
Julien Boeuf9f218dd2015-04-23 10:24:02 -070045
Julien Boeuf84d964a2015-04-29 11:31:06 -070046/* --- grpc_call --- */
47
Julien Boeuf9f218dd2015-04-23 10:24:02 -070048grpc_call_error grpc_call_set_credentials(grpc_call *call,
Julien Boeuf441176d2015-10-09 21:14:07 -070049 grpc_call_credentials *creds) {
Julien Boeuf9f218dd2015-04-23 10:24:02 -070050 grpc_client_security_context *ctx = NULL;
Masood Malekghassemi76c3d742015-08-19 18:22:53 -070051 GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2,
52 (call, creds));
Julien Boeuf9f218dd2015-04-23 10:24:02 -070053 if (!grpc_call_is_client(call)) {
54 gpr_log(GPR_ERROR, "Method is client-side only.");
55 return GRPC_CALL_ERROR_NOT_ON_SERVER;
56 }
Julien Boeuf9f218dd2015-04-23 10:24:02 -070057 ctx = (grpc_client_security_context *)grpc_call_context_get(
58 call, GRPC_CONTEXT_SECURITY);
59 if (ctx == NULL) {
60 ctx = grpc_client_security_context_create();
Julien Boeuf441176d2015-10-09 21:14:07 -070061 ctx->creds = grpc_call_credentials_ref(creds);
Julien Boeuf9f218dd2015-04-23 10:24:02 -070062 grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx,
63 grpc_client_security_context_destroy);
64 } else {
Julien Boeuf441176d2015-10-09 21:14:07 -070065 grpc_call_credentials_unref(ctx->creds);
66 ctx->creds = grpc_call_credentials_ref(creds);
Julien Boeuf9f218dd2015-04-23 10:24:02 -070067 }
68 return GRPC_CALL_OK;
69}
70
yang-gf9e8e592015-07-09 12:32:15 -070071grpc_auth_context *grpc_call_auth_context(grpc_call *call) {
Julien Boeuf84d964a2015-04-29 11:31:06 -070072 void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY);
Masood Malekghassemi76c3d742015-08-19 18:22:53 -070073 GRPC_API_TRACE("grpc_call_auth_context(call=%p)", 1, (call));
Julien Boeuf84d964a2015-04-29 11:31:06 -070074 if (sec_ctx == NULL) return NULL;
75 return grpc_call_is_client(call)
yang-gf9e8e592015-07-09 12:32:15 -070076 ? GRPC_AUTH_CONTEXT_REF(
77 ((grpc_client_security_context *)sec_ctx)->auth_context,
78 "grpc_call_auth_context client")
79 : GRPC_AUTH_CONTEXT_REF(
80 ((grpc_server_security_context *)sec_ctx)->auth_context,
81 "grpc_call_auth_context server");
82}
83
84void grpc_auth_context_release(grpc_auth_context *context) {
Masood Malekghassemi76c3d742015-08-19 18:22:53 -070085 GRPC_API_TRACE("grpc_auth_context_release(context=%p)", 1, (context));
yang-gf9e8e592015-07-09 12:32:15 -070086 GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref");
Julien Boeuf84d964a2015-04-29 11:31:06 -070087}
88
89/* --- grpc_client_security_context --- */
90
Julien Boeuf9f218dd2015-04-23 10:24:02 -070091grpc_client_security_context *grpc_client_security_context_create(void) {
92 grpc_client_security_context *ctx =
93 gpr_malloc(sizeof(grpc_client_security_context));
94 memset(ctx, 0, sizeof(grpc_client_security_context));
95 return ctx;
96}
97
98void grpc_client_security_context_destroy(void *ctx) {
99 grpc_client_security_context *c = (grpc_client_security_context *)ctx;
Julien Boeuf441176d2015-10-09 21:14:07 -0700100 grpc_call_credentials_unref(c->creds);
Craig Tiller991edad2015-06-30 11:40:41 -0700101 GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context");
Julien Boeuf9f218dd2015-04-23 10:24:02 -0700102 gpr_free(ctx);
103}
Julien Boeuf84d964a2015-04-29 11:31:06 -0700104
105/* --- grpc_server_security_context --- */
106
107grpc_server_security_context *grpc_server_security_context_create(void) {
108 grpc_server_security_context *ctx =
109 gpr_malloc(sizeof(grpc_server_security_context));
110 memset(ctx, 0, sizeof(grpc_server_security_context));
111 return ctx;
112}
113
114void grpc_server_security_context_destroy(void *ctx) {
115 grpc_server_security_context *c = (grpc_server_security_context *)ctx;
Craig Tiller991edad2015-06-30 11:40:41 -0700116 GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context");
Julien Boeuf84d964a2015-04-29 11:31:06 -0700117 gpr_free(ctx);
118}
119
120/* --- grpc_auth_context --- */
121
Julien Boeuf83b02972015-05-20 22:50:34 -0700122static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL};
123
Julien Boeufea456fc2015-07-07 15:23:30 -0700124grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) {
Julien Boeuf84d964a2015-04-29 11:31:06 -0700125 grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context));
126 memset(ctx, 0, sizeof(grpc_auth_context));
Julien Boeuf84d964a2015-04-29 11:31:06 -0700127 gpr_ref_init(&ctx->refcount, 1);
Julien Boeufea456fc2015-07-07 15:23:30 -0700128 if (chained != NULL) {
129 ctx->chained = GRPC_AUTH_CONTEXT_REF(chained, "chained");
130 ctx->peer_identity_property_name =
131 ctx->chained->peer_identity_property_name;
132 }
Julien Boeuf84d964a2015-04-29 11:31:06 -0700133 return ctx;
134}
135
Craig Tiller991edad2015-06-30 11:40:41 -0700136#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG
137grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx,
138 const char *file, int line,
139 const char *reason) {
140 if (ctx == NULL) return NULL;
141 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
142 "AUTH_CONTEXT:%p ref %d -> %d %s", ctx, (int)ctx->refcount.count,
143 (int)ctx->refcount.count + 1, reason);
144#else
Julien Boeuf84d964a2015-04-29 11:31:06 -0700145grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) {
146 if (ctx == NULL) return NULL;
Craig Tiller991edad2015-06-30 11:40:41 -0700147#endif
Julien Boeuf84d964a2015-04-29 11:31:06 -0700148 gpr_ref(&ctx->refcount);
149 return ctx;
150}
151
Craig Tiller991edad2015-06-30 11:40:41 -0700152#ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG
153void grpc_auth_context_unref(grpc_auth_context *ctx, const char *file, int line,
154 const char *reason) {
155 if (ctx == NULL) return;
156 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
157 "AUTH_CONTEXT:%p unref %d -> %d %s", ctx, (int)ctx->refcount.count,
158 (int)ctx->refcount.count - 1, reason);
159#else
Julien Boeuf84d964a2015-04-29 11:31:06 -0700160void grpc_auth_context_unref(grpc_auth_context *ctx) {
161 if (ctx == NULL) return;
Craig Tiller991edad2015-06-30 11:40:41 -0700162#endif
Julien Boeuf84d964a2015-04-29 11:31:06 -0700163 if (gpr_unref(&ctx->refcount)) {
164 size_t i;
Craig Tiller991edad2015-06-30 11:40:41 -0700165 GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained");
Julien Boeufea456fc2015-07-07 15:23:30 -0700166 if (ctx->properties.array != NULL) {
167 for (i = 0; i < ctx->properties.count; i++) {
168 grpc_auth_property_reset(&ctx->properties.array[i]);
Julien Boeuf84d964a2015-04-29 11:31:06 -0700169 }
Julien Boeufea456fc2015-07-07 15:23:30 -0700170 gpr_free(ctx->properties.array);
Julien Boeuf84d964a2015-04-29 11:31:06 -0700171 }
Julien Boeuf83b02972015-05-20 22:50:34 -0700172 gpr_free(ctx);
Julien Boeuf84d964a2015-04-29 11:31:06 -0700173 }
174}
175
176const char *grpc_auth_context_peer_identity_property_name(
177 const grpc_auth_context *ctx) {
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700178 GRPC_API_TRACE("grpc_auth_context_peer_identity_property_name(ctx=%p)", 1,
179 (ctx));
Julien Boeuf84d964a2015-04-29 11:31:06 -0700180 return ctx->peer_identity_property_name;
181}
182
Julien Boeufea456fc2015-07-07 15:23:30 -0700183int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context *ctx,
184 const char *name) {
185 grpc_auth_property_iterator it =
186 grpc_auth_context_find_properties_by_name(ctx, name);
187 const grpc_auth_property *prop = grpc_auth_property_iterator_next(&it);
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700188 GRPC_API_TRACE(
189 "grpc_auth_context_set_peer_identity_property_name(ctx=%p, name=%s)", 2,
190 (ctx, name));
Julien Boeufea456fc2015-07-07 15:23:30 -0700191 if (prop == NULL) {
192 gpr_log(GPR_ERROR, "Property name %s not found in auth context.",
193 name != NULL ? name : "NULL");
194 return 0;
195 }
196 ctx->peer_identity_property_name = prop->name;
197 return 1;
198}
199
Craig Tillerd6c98df2015-08-18 09:33:44 -0700200int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx) {
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700201 GRPC_API_TRACE("grpc_auth_context_peer_is_authenticated(ctx=%p)", 1, (ctx));
Julien Boeuf83b02972015-05-20 22:50:34 -0700202 return ctx->peer_identity_property_name == NULL ? 0 : 1;
203}
204
205grpc_auth_property_iterator grpc_auth_context_property_iterator(
206 const grpc_auth_context *ctx) {
207 grpc_auth_property_iterator it = empty_iterator;
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700208 GRPC_API_TRACE("grpc_auth_context_property_iterator(ctx=%p)", 1, (ctx));
Julien Boeuf83b02972015-05-20 22:50:34 -0700209 if (ctx == NULL) return it;
210 it.ctx = ctx;
Julien Boeuf84d964a2015-04-29 11:31:06 -0700211 return it;
212}
213
214const grpc_auth_property *grpc_auth_property_iterator_next(
215 grpc_auth_property_iterator *it) {
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700216 GRPC_API_TRACE("grpc_auth_property_iterator_next(it=%p)", 1, (it));
Julien Boeuf83b02972015-05-20 22:50:34 -0700217 if (it == NULL || it->ctx == NULL) return NULL;
Julien Boeufea456fc2015-07-07 15:23:30 -0700218 while (it->index == it->ctx->properties.count) {
Julien Boeuf84d964a2015-04-29 11:31:06 -0700219 if (it->ctx->chained == NULL) return NULL;
220 it->ctx = it->ctx->chained;
221 it->index = 0;
222 }
223 if (it->name == NULL) {
Julien Boeufea456fc2015-07-07 15:23:30 -0700224 return &it->ctx->properties.array[it->index++];
Julien Boeuf84d964a2015-04-29 11:31:06 -0700225 } else {
Julien Boeufea456fc2015-07-07 15:23:30 -0700226 while (it->index < it->ctx->properties.count) {
227 const grpc_auth_property *prop = &it->ctx->properties.array[it->index++];
Julien Boeuf84d964a2015-04-29 11:31:06 -0700228 GPR_ASSERT(prop->name != NULL);
229 if (strcmp(it->name, prop->name) == 0) {
230 return prop;
231 }
232 }
233 /* We could not find the name, try another round. */
234 return grpc_auth_property_iterator_next(it);
235 }
236}
237
Julien Boeuf83b02972015-05-20 22:50:34 -0700238grpc_auth_property_iterator grpc_auth_context_find_properties_by_name(
Julien Boeuf84d964a2015-04-29 11:31:06 -0700239 const grpc_auth_context *ctx, const char *name) {
Julien Boeuf83b02972015-05-20 22:50:34 -0700240 grpc_auth_property_iterator it = empty_iterator;
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700241 GRPC_API_TRACE("grpc_auth_context_find_properties_by_name(ctx=%p, name=%s)",
242 2, (ctx, name));
Julien Boeuf83b02972015-05-20 22:50:34 -0700243 if (ctx == NULL || name == NULL) return empty_iterator;
244 it.ctx = ctx;
245 it.name = name;
Julien Boeuf84d964a2015-04-29 11:31:06 -0700246 return it;
247}
248
Julien Boeuf83b02972015-05-20 22:50:34 -0700249grpc_auth_property_iterator grpc_auth_context_peer_identity(
Julien Boeuf84d964a2015-04-29 11:31:06 -0700250 const grpc_auth_context *ctx) {
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700251 GRPC_API_TRACE("grpc_auth_context_peer_identity(ctx=%p)", 1, (ctx));
Julien Boeuf83b02972015-05-20 22:50:34 -0700252 if (ctx == NULL) return empty_iterator;
Julien Boeuf84d964a2015-04-29 11:31:06 -0700253 return grpc_auth_context_find_properties_by_name(
254 ctx, ctx->peer_identity_property_name);
255}
256
Julien Boeufea456fc2015-07-07 15:23:30 -0700257static void ensure_auth_context_capacity(grpc_auth_context *ctx) {
258 if (ctx->properties.count == ctx->properties.capacity) {
259 ctx->properties.capacity =
260 GPR_MAX(ctx->properties.capacity + 8, ctx->properties.capacity * 2);
261 ctx->properties.array =
262 gpr_realloc(ctx->properties.array,
263 ctx->properties.capacity * sizeof(grpc_auth_property));
264 }
Julien Boeuf84d964a2015-04-29 11:31:06 -0700265}
266
Julien Boeufea456fc2015-07-07 15:23:30 -0700267void grpc_auth_context_add_property(grpc_auth_context *ctx, const char *name,
268 const char *value, size_t value_length) {
269 grpc_auth_property *prop;
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700270 GRPC_API_TRACE(
271 "grpc_auth_context_add_property(ctx=%p, name=%s, value=%*.*s, "
Craig Tiller4de3e4f2015-10-05 08:55:50 -0700272 "value_length=%lu)",
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700273 6, (ctx, name, (int)value_length, (int)value_length, value,
274 (unsigned long)value_length));
Julien Boeufea456fc2015-07-07 15:23:30 -0700275 ensure_auth_context_capacity(ctx);
276 prop = &ctx->properties.array[ctx->properties.count++];
277 prop->name = gpr_strdup(name);
278 prop->value = gpr_malloc(value_length + 1);
279 memcpy(prop->value, value, value_length);
280 prop->value[value_length] = '\0';
281 prop->value_length = value_length;
282}
283
284void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx,
285 const char *name,
286 const char *value) {
287 grpc_auth_property *prop;
Masood Malekghassemi76c3d742015-08-19 18:22:53 -0700288 GRPC_API_TRACE(
289 "grpc_auth_context_add_cstring_property(ctx=%p, name=%s, value=%s)", 3,
290 (ctx, name, value));
Julien Boeufea456fc2015-07-07 15:23:30 -0700291 ensure_auth_context_capacity(ctx);
292 prop = &ctx->properties.array[ctx->properties.count++];
293 prop->name = gpr_strdup(name);
294 prop->value = gpr_strdup(value);
295 prop->value_length = strlen(value);
Julien Boeuf84d964a2015-04-29 11:31:06 -0700296}
297
298void grpc_auth_property_reset(grpc_auth_property *property) {
Craig Tiller991edad2015-06-30 11:40:41 -0700299 gpr_free(property->name);
300 gpr_free(property->value);
Julien Boeuf84d964a2015-04-29 11:31:06 -0700301 memset(property, 0, sizeof(grpc_auth_property));
302}
303
Julien Boeuf9a529082015-10-08 13:12:14 -0700304static void auth_context_pointer_arg_destroy(void *p) {
305 GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg");
306}
307
308static void *auth_context_pointer_arg_copy(void *p) {
309 return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg");
310}
311
Craig Tiller5de79ee2016-01-25 08:16:02 -0800312static int auth_context_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); }
Craig Tilleredc2fff2016-01-13 06:54:27 -0800313
314static const grpc_arg_pointer_vtable auth_context_pointer_vtable = {
Craig Tiller5de79ee2016-01-25 08:16:02 -0800315 auth_context_pointer_arg_copy, auth_context_pointer_arg_destroy,
316 auth_context_pointer_cmp};
Craig Tilleredc2fff2016-01-13 06:54:27 -0800317
Julien Boeuf9a529082015-10-08 13:12:14 -0700318grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) {
Julien Boeuf66a27da2015-07-21 17:17:35 -0700319 grpc_arg arg;
320 memset(&arg, 0, sizeof(grpc_arg));
321 arg.type = GRPC_ARG_POINTER;
Julien Boeuf9a529082015-10-08 13:12:14 -0700322 arg.key = GRPC_AUTH_CONTEXT_ARG;
Julien Boeuf66a27da2015-07-21 17:17:35 -0700323 arg.value.pointer.p = p;
Craig Tilleredc2fff2016-01-13 06:54:27 -0800324 arg.value.pointer.vtable = &auth_context_pointer_vtable;
Julien Boeuf66a27da2015-07-21 17:17:35 -0700325 return arg;
326}
327
Craig Tiller0581d122015-11-02 14:09:40 -0800328grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg) {
Julien Boeuf9a529082015-10-08 13:12:14 -0700329 if (strcmp(arg->key, GRPC_AUTH_CONTEXT_ARG) != 0) return NULL;
Julien Boeuf66a27da2015-07-21 17:17:35 -0700330 if (arg->type != GRPC_ARG_POINTER) {
331 gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
Julien Boeuf9a529082015-10-08 13:12:14 -0700332 GRPC_AUTH_CONTEXT_ARG);
Julien Boeuf66a27da2015-07-21 17:17:35 -0700333 return NULL;
334 }
335 return arg->value.pointer.p;
336}
337
Julien Boeuf9a529082015-10-08 13:12:14 -0700338grpc_auth_context *grpc_find_auth_context_in_args(
Julien Boeuf66a27da2015-07-21 17:17:35 -0700339 const grpc_channel_args *args) {
340 size_t i;
341 if (args == NULL) return NULL;
342 for (i = 0; i < args->num_args; i++) {
Craig Tiller0581d122015-11-02 14:09:40 -0800343 grpc_auth_context *p = grpc_auth_context_from_arg(&args->args[i]);
Julien Boeuf66a27da2015-07-21 17:17:35 -0700344 if (p != NULL) return p;
345 }
346 return NULL;
347}