OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * |
| 3 * Copyright 2015-2016, Google Inc. |
| 4 * 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 |
| 36 #include "src/core/security/security_context.h" |
| 37 #include "src/core/surface/api_trace.h" |
| 38 #include "src/core/surface/call.h" |
| 39 #include "src/core/support/string.h" |
| 40 |
| 41 #include <grpc/grpc_security.h> |
| 42 #include <grpc/support/alloc.h> |
| 43 #include <grpc/support/log.h> |
| 44 #include <grpc/support/string_util.h> |
| 45 |
| 46 /* --- grpc_call --- */ |
| 47 |
| 48 grpc_call_error grpc_call_set_credentials(grpc_call *call, |
| 49 grpc_call_credentials *creds) { |
| 50 grpc_client_security_context *ctx = NULL; |
| 51 GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2, |
| 52 (call, creds)); |
| 53 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 } |
| 57 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(); |
| 61 ctx->creds = grpc_call_credentials_ref(creds); |
| 62 grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx, |
| 63 grpc_client_security_context_destroy); |
| 64 } else { |
| 65 grpc_call_credentials_unref(ctx->creds); |
| 66 ctx->creds = grpc_call_credentials_ref(creds); |
| 67 } |
| 68 return GRPC_CALL_OK; |
| 69 } |
| 70 |
| 71 grpc_auth_context *grpc_call_auth_context(grpc_call *call) { |
| 72 void *sec_ctx = grpc_call_context_get(call, GRPC_CONTEXT_SECURITY); |
| 73 GRPC_API_TRACE("grpc_call_auth_context(call=%p)", 1, (call)); |
| 74 if (sec_ctx == NULL) return NULL; |
| 75 return grpc_call_is_client(call) |
| 76 ? 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 |
| 84 void grpc_auth_context_release(grpc_auth_context *context) { |
| 85 GRPC_API_TRACE("grpc_auth_context_release(context=%p)", 1, (context)); |
| 86 GRPC_AUTH_CONTEXT_UNREF(context, "grpc_auth_context_unref"); |
| 87 } |
| 88 |
| 89 /* --- grpc_client_security_context --- */ |
| 90 |
| 91 grpc_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 |
| 98 void grpc_client_security_context_destroy(void *ctx) { |
| 99 grpc_client_security_context *c = (grpc_client_security_context *)ctx; |
| 100 grpc_call_credentials_unref(c->creds); |
| 101 GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context"); |
| 102 gpr_free(ctx); |
| 103 } |
| 104 |
| 105 /* --- grpc_server_security_context --- */ |
| 106 |
| 107 grpc_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 |
| 114 void grpc_server_security_context_destroy(void *ctx) { |
| 115 grpc_server_security_context *c = (grpc_server_security_context *)ctx; |
| 116 GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "server_security_context"); |
| 117 gpr_free(ctx); |
| 118 } |
| 119 |
| 120 /* --- grpc_auth_context --- */ |
| 121 |
| 122 static grpc_auth_property_iterator empty_iterator = {NULL, 0, NULL}; |
| 123 |
| 124 grpc_auth_context *grpc_auth_context_create(grpc_auth_context *chained) { |
| 125 grpc_auth_context *ctx = gpr_malloc(sizeof(grpc_auth_context)); |
| 126 memset(ctx, 0, sizeof(grpc_auth_context)); |
| 127 gpr_ref_init(&ctx->refcount, 1); |
| 128 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 } |
| 133 return ctx; |
| 134 } |
| 135 |
| 136 #ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG |
| 137 grpc_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 |
| 145 grpc_auth_context *grpc_auth_context_ref(grpc_auth_context *ctx) { |
| 146 if (ctx == NULL) return NULL; |
| 147 #endif |
| 148 gpr_ref(&ctx->refcount); |
| 149 return ctx; |
| 150 } |
| 151 |
| 152 #ifdef GRPC_AUTH_CONTEXT_REFCOUNT_DEBUG |
| 153 void 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 |
| 160 void grpc_auth_context_unref(grpc_auth_context *ctx) { |
| 161 if (ctx == NULL) return; |
| 162 #endif |
| 163 if (gpr_unref(&ctx->refcount)) { |
| 164 size_t i; |
| 165 GRPC_AUTH_CONTEXT_UNREF(ctx->chained, "chained"); |
| 166 if (ctx->properties.array != NULL) { |
| 167 for (i = 0; i < ctx->properties.count; i++) { |
| 168 grpc_auth_property_reset(&ctx->properties.array[i]); |
| 169 } |
| 170 gpr_free(ctx->properties.array); |
| 171 } |
| 172 gpr_free(ctx); |
| 173 } |
| 174 } |
| 175 |
| 176 const char *grpc_auth_context_peer_identity_property_name( |
| 177 const grpc_auth_context *ctx) { |
| 178 GRPC_API_TRACE("grpc_auth_context_peer_identity_property_name(ctx=%p)", 1, |
| 179 (ctx)); |
| 180 return ctx->peer_identity_property_name; |
| 181 } |
| 182 |
| 183 int 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); |
| 188 GRPC_API_TRACE( |
| 189 "grpc_auth_context_set_peer_identity_property_name(ctx=%p, name=%s)", 2, |
| 190 (ctx, name)); |
| 191 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 |
| 200 int grpc_auth_context_peer_is_authenticated(const grpc_auth_context *ctx) { |
| 201 GRPC_API_TRACE("grpc_auth_context_peer_is_authenticated(ctx=%p)", 1, (ctx)); |
| 202 return ctx->peer_identity_property_name == NULL ? 0 : 1; |
| 203 } |
| 204 |
| 205 grpc_auth_property_iterator grpc_auth_context_property_iterator( |
| 206 const grpc_auth_context *ctx) { |
| 207 grpc_auth_property_iterator it = empty_iterator; |
| 208 GRPC_API_TRACE("grpc_auth_context_property_iterator(ctx=%p)", 1, (ctx)); |
| 209 if (ctx == NULL) return it; |
| 210 it.ctx = ctx; |
| 211 return it; |
| 212 } |
| 213 |
| 214 const grpc_auth_property *grpc_auth_property_iterator_next( |
| 215 grpc_auth_property_iterator *it) { |
| 216 GRPC_API_TRACE("grpc_auth_property_iterator_next(it=%p)", 1, (it)); |
| 217 if (it == NULL || it->ctx == NULL) return NULL; |
| 218 while (it->index == it->ctx->properties.count) { |
| 219 if (it->ctx->chained == NULL) return NULL; |
| 220 it->ctx = it->ctx->chained; |
| 221 it->index = 0; |
| 222 } |
| 223 if (it->name == NULL) { |
| 224 return &it->ctx->properties.array[it->index++]; |
| 225 } else { |
| 226 while (it->index < it->ctx->properties.count) { |
| 227 const grpc_auth_property *prop = &it->ctx->properties.array[it->index++]; |
| 228 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 |
| 238 grpc_auth_property_iterator grpc_auth_context_find_properties_by_name( |
| 239 const grpc_auth_context *ctx, const char *name) { |
| 240 grpc_auth_property_iterator it = empty_iterator; |
| 241 GRPC_API_TRACE("grpc_auth_context_find_properties_by_name(ctx=%p, name=%s)", |
| 242 2, (ctx, name)); |
| 243 if (ctx == NULL || name == NULL) return empty_iterator; |
| 244 it.ctx = ctx; |
| 245 it.name = name; |
| 246 return it; |
| 247 } |
| 248 |
| 249 grpc_auth_property_iterator grpc_auth_context_peer_identity( |
| 250 const grpc_auth_context *ctx) { |
| 251 GRPC_API_TRACE("grpc_auth_context_peer_identity(ctx=%p)", 1, (ctx)); |
| 252 if (ctx == NULL) return empty_iterator; |
| 253 return grpc_auth_context_find_properties_by_name( |
| 254 ctx, ctx->peer_identity_property_name); |
| 255 } |
| 256 |
| 257 static 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 } |
| 265 } |
| 266 |
| 267 void 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; |
| 270 GRPC_API_TRACE( |
| 271 "grpc_auth_context_add_property(ctx=%p, name=%s, value=%*.*s, " |
| 272 "value_length=%lu)", |
| 273 6, (ctx, name, (int)value_length, (int)value_length, value, |
| 274 (unsigned long)value_length)); |
| 275 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 |
| 284 void grpc_auth_context_add_cstring_property(grpc_auth_context *ctx, |
| 285 const char *name, |
| 286 const char *value) { |
| 287 grpc_auth_property *prop; |
| 288 GRPC_API_TRACE( |
| 289 "grpc_auth_context_add_cstring_property(ctx=%p, name=%s, value=%s)", 3, |
| 290 (ctx, name, value)); |
| 291 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); |
| 296 } |
| 297 |
| 298 void grpc_auth_property_reset(grpc_auth_property *property) { |
| 299 gpr_free(property->name); |
| 300 gpr_free(property->value); |
| 301 memset(property, 0, sizeof(grpc_auth_property)); |
| 302 } |
| 303 |
| 304 static void auth_context_pointer_arg_destroy(void *p) { |
| 305 GRPC_AUTH_CONTEXT_UNREF(p, "auth_context_pointer_arg"); |
| 306 } |
| 307 |
| 308 static void *auth_context_pointer_arg_copy(void *p) { |
| 309 return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg"); |
| 310 } |
| 311 |
| 312 static int auth_context_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } |
| 313 |
| 314 static const grpc_arg_pointer_vtable auth_context_pointer_vtable = { |
| 315 auth_context_pointer_arg_copy, auth_context_pointer_arg_destroy, |
| 316 auth_context_pointer_cmp}; |
| 317 |
| 318 grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) { |
| 319 grpc_arg arg; |
| 320 memset(&arg, 0, sizeof(grpc_arg)); |
| 321 arg.type = GRPC_ARG_POINTER; |
| 322 arg.key = GRPC_AUTH_CONTEXT_ARG; |
| 323 arg.value.pointer.p = p; |
| 324 arg.value.pointer.vtable = &auth_context_pointer_vtable; |
| 325 return arg; |
| 326 } |
| 327 |
| 328 grpc_auth_context *grpc_auth_context_from_arg(const grpc_arg *arg) { |
| 329 if (strcmp(arg->key, GRPC_AUTH_CONTEXT_ARG) != 0) return NULL; |
| 330 if (arg->type != GRPC_ARG_POINTER) { |
| 331 gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type, |
| 332 GRPC_AUTH_CONTEXT_ARG); |
| 333 return NULL; |
| 334 } |
| 335 return arg->value.pointer.p; |
| 336 } |
| 337 |
| 338 grpc_auth_context *grpc_find_auth_context_in_args( |
| 339 const grpc_channel_args *args) { |
| 340 size_t i; |
| 341 if (args == NULL) return NULL; |
| 342 for (i = 0; i < args->num_args; i++) { |
| 343 grpc_auth_context *p = grpc_auth_context_from_arg(&args->args[i]); |
| 344 if (p != NULL) return p; |
| 345 } |
| 346 return NULL; |
| 347 } |
OLD | NEW |