• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include "src/core/lib/security/context/security_context.h"
20 
21 #include <grpc/credentials.h>
22 #include <grpc/grpc_security.h>
23 #include <grpc/support/alloc.h>
24 #include <grpc/support/port_platform.h>
25 #include <grpc/support/string_util.h>
26 #include <string.h>
27 
28 #include <algorithm>
29 
30 #include "absl/log/check.h"
31 #include "absl/log/log.h"
32 #include "src/core/lib/channel/channel_args.h"
33 #include "src/core/lib/debug/trace.h"
34 #include "src/core/lib/iomgr/exec_ctx.h"
35 #include "src/core/lib/resource_quota/arena.h"
36 #include "src/core/lib/security/credentials/credentials.h"
37 #include "src/core/lib/surface/call.h"
38 #include "src/core/util/ref_counted_ptr.h"
39 
40 // --- grpc_call ---
41 
grpc_call_set_credentials(grpc_call * call,grpc_call_credentials * creds)42 grpc_call_error grpc_call_set_credentials(grpc_call* call,
43                                           grpc_call_credentials* creds) {
44   grpc_core::ExecCtx exec_ctx;
45   grpc_client_security_context* ctx = nullptr;
46   GRPC_TRACE_LOG(api, INFO) << "grpc_call_set_credentials(call=" << call
47                             << ", creds=" << creds << ")";
48   if (!grpc_call_is_client(call)) {
49     LOG(ERROR) << "Method is client-side only.";
50     return GRPC_CALL_ERROR_NOT_ON_SERVER;
51   }
52   auto* arena = grpc_call_get_arena(call);
53   ctx = grpc_core::DownCast<grpc_client_security_context*>(
54       arena->GetContext<grpc_core::SecurityContext>());
55   if (ctx == nullptr) {
56     ctx = grpc_client_security_context_create(arena, creds);
57     arena->SetContext<grpc_core::SecurityContext>(ctx);
58   } else {
59     ctx->creds = creds != nullptr ? creds->Ref() : nullptr;
60   }
61 
62   return GRPC_CALL_OK;
63 }
64 
grpc_call_auth_context(grpc_call * call)65 grpc_auth_context* grpc_call_auth_context(grpc_call* call) {
66   auto* sec_ctx =
67       grpc_call_get_arena(call)->GetContext<grpc_core::SecurityContext>();
68   GRPC_TRACE_LOG(api, INFO) << "grpc_call_auth_context(call=" << call << ")";
69   if (sec_ctx == nullptr) return nullptr;
70   if (grpc_call_is_client(call)) {
71     auto* sc = grpc_core::DownCast<grpc_client_security_context*>(sec_ctx);
72     if (sc->auth_context == nullptr) {
73       return nullptr;
74     } else {
75       return sc->auth_context
76           ->Ref(DEBUG_LOCATION, "grpc_call_auth_context client")
77           .release();
78     }
79   } else {
80     auto* sc = grpc_core::DownCast<grpc_server_security_context*>(sec_ctx);
81     if (sc->auth_context == nullptr) {
82       return nullptr;
83     } else {
84       return sc->auth_context
85           ->Ref(DEBUG_LOCATION, "grpc_call_auth_context server")
86           .release();
87     }
88   }
89 }
90 
grpc_auth_context_release(grpc_auth_context * context)91 void grpc_auth_context_release(grpc_auth_context* context) {
92   GRPC_TRACE_LOG(api, INFO)
93       << "grpc_auth_context_release(context=" << context << ")";
94   if (context == nullptr) return;
95   context->Unref(DEBUG_LOCATION, "grpc_auth_context_unref");
96 }
97 
98 // --- grpc_client_security_context ---
~grpc_client_security_context()99 grpc_client_security_context::~grpc_client_security_context() {
100   auth_context.reset(DEBUG_LOCATION, "client_security_context");
101   if (extension.instance != nullptr && extension.destroy != nullptr) {
102     extension.destroy(extension.instance);
103   }
104 }
105 
grpc_client_security_context_create(grpc_core::Arena * arena,grpc_call_credentials * creds)106 grpc_client_security_context* grpc_client_security_context_create(
107     grpc_core::Arena* arena, grpc_call_credentials* creds) {
108   return arena->New<grpc_client_security_context>(
109       creds != nullptr ? creds->Ref() : nullptr);
110 }
111 
grpc_client_security_context_destroy(void * ctx)112 void grpc_client_security_context_destroy(void* ctx) {
113   grpc_client_security_context* c =
114       static_cast<grpc_client_security_context*>(ctx);
115   c->~grpc_client_security_context();
116 }
117 
118 // --- grpc_server_security_context ---
~grpc_server_security_context()119 grpc_server_security_context::~grpc_server_security_context() {
120   auth_context.reset(DEBUG_LOCATION, "server_security_context");
121   if (extension.instance != nullptr && extension.destroy != nullptr) {
122     extension.destroy(extension.instance);
123   }
124 }
125 
grpc_server_security_context_create(grpc_core::Arena * arena)126 grpc_server_security_context* grpc_server_security_context_create(
127     grpc_core::Arena* arena) {
128   return arena->New<grpc_server_security_context>();
129 }
130 
grpc_server_security_context_destroy(void * ctx)131 void grpc_server_security_context_destroy(void* ctx) {
132   grpc_server_security_context* c =
133       static_cast<grpc_server_security_context*>(ctx);
134   c->~grpc_server_security_context();
135 }
136 
137 // --- grpc_auth_context ---
138 
139 static grpc_auth_property_iterator empty_iterator = {nullptr, 0, nullptr};
140 
grpc_auth_context_peer_identity_property_name(const grpc_auth_context * ctx)141 const char* grpc_auth_context_peer_identity_property_name(
142     const grpc_auth_context* ctx) {
143   GRPC_TRACE_LOG(api, INFO)
144       << "grpc_auth_context_peer_identity_property_name(ctx=" << ctx << ")";
145   return ctx->peer_identity_property_name();
146 }
147 
grpc_auth_context_set_peer_identity_property_name(grpc_auth_context * ctx,const char * name)148 int grpc_auth_context_set_peer_identity_property_name(grpc_auth_context* ctx,
149                                                       const char* name) {
150   grpc_auth_property_iterator it =
151       grpc_auth_context_find_properties_by_name(ctx, name);
152   const grpc_auth_property* prop = grpc_auth_property_iterator_next(&it);
153   GRPC_TRACE_LOG(api, INFO)
154       << "grpc_auth_context_set_peer_identity_property_name(ctx=" << ctx
155       << ", name=" << name << ")";
156   if (prop == nullptr) {
157     LOG(ERROR) << "Property name " << (name != nullptr ? name : "NULL")
158                << " not found in auth context.";
159     return 0;
160   }
161   ctx->set_peer_identity_property_name(prop->name);
162   return 1;
163 }
164 
grpc_auth_context_peer_is_authenticated(const grpc_auth_context * ctx)165 int grpc_auth_context_peer_is_authenticated(const grpc_auth_context* ctx) {
166   GRPC_TRACE_LOG(api, INFO)
167       << "grpc_auth_context_peer_is_authenticated(ctx=" << ctx << ")";
168   return ctx->is_authenticated();
169 }
170 
grpc_auth_context_property_iterator(const grpc_auth_context * ctx)171 grpc_auth_property_iterator grpc_auth_context_property_iterator(
172     const grpc_auth_context* ctx) {
173   grpc_auth_property_iterator it = empty_iterator;
174   GRPC_TRACE_LOG(api, INFO)
175       << "grpc_auth_context_property_iterator(ctx=" << ctx << ")";
176   if (ctx == nullptr) return it;
177   it.ctx = ctx;
178   return it;
179 }
180 
grpc_auth_property_iterator_next(grpc_auth_property_iterator * it)181 const grpc_auth_property* grpc_auth_property_iterator_next(
182     grpc_auth_property_iterator* it) {
183   GRPC_TRACE_LOG(api, INFO)
184       << "grpc_auth_property_iterator_next(it=" << it << ")";
185   if (it == nullptr || it->ctx == nullptr) return nullptr;
186   while (it->index == it->ctx->properties().count) {
187     if (it->ctx->chained() == nullptr) return nullptr;
188     it->ctx = it->ctx->chained();
189     it->index = 0;
190   }
191   if (it->name == nullptr) {
192     return &it->ctx->properties().array[it->index++];
193   } else {
194     while (it->index < it->ctx->properties().count) {
195       const grpc_auth_property* prop =
196           &it->ctx->properties().array[it->index++];
197       CHECK_NE(prop->name, nullptr);
198       if (strcmp(it->name, prop->name) == 0) {
199         return prop;
200       }
201     }
202     // We could not find the name, try another round.
203     return grpc_auth_property_iterator_next(it);
204   }
205 }
206 
grpc_auth_context_find_properties_by_name(const grpc_auth_context * ctx,const char * name)207 grpc_auth_property_iterator grpc_auth_context_find_properties_by_name(
208     const grpc_auth_context* ctx, const char* name) {
209   grpc_auth_property_iterator it = empty_iterator;
210   GRPC_TRACE_LOG(api, INFO)
211       << "grpc_auth_context_find_properties_by_name(ctx=" << ctx
212       << ", name=" << name << ")";
213   if (ctx == nullptr || name == nullptr) return empty_iterator;
214   it.ctx = ctx;
215   it.name = name;
216   return it;
217 }
218 
grpc_auth_context_peer_identity(const grpc_auth_context * ctx)219 grpc_auth_property_iterator grpc_auth_context_peer_identity(
220     const grpc_auth_context* ctx) {
221   GRPC_TRACE_LOG(api, INFO)
222       << "grpc_auth_context_peer_identity(ctx=" << ctx << ")";
223   if (ctx == nullptr) return empty_iterator;
224   return grpc_auth_context_find_properties_by_name(
225       ctx, ctx->peer_identity_property_name());
226 }
227 
ensure_capacity()228 void grpc_auth_context::ensure_capacity() {
229   if (properties_.count == properties_.capacity) {
230     properties_.capacity =
231         std::max(properties_.capacity + 8, properties_.capacity * 2);
232     properties_.array = static_cast<grpc_auth_property*>(gpr_realloc(
233         properties_.array, properties_.capacity * sizeof(grpc_auth_property)));
234   }
235 }
236 
add_property(const char * name,const char * value,size_t value_length)237 void grpc_auth_context::add_property(const char* name, const char* value,
238                                      size_t value_length) {
239   ensure_capacity();
240   grpc_auth_property* prop = &properties_.array[properties_.count++];
241   prop->name = gpr_strdup(name);
242   prop->value = static_cast<char*>(gpr_malloc(value_length + 1));
243   if (value != nullptr) {
244     memcpy(prop->value, value, value_length);
245   }
246   prop->value[value_length] = '\0';
247   prop->value_length = value_length;
248 }
249 
grpc_auth_context_add_property(grpc_auth_context * ctx,const char * name,const char * value,size_t value_length)250 void grpc_auth_context_add_property(grpc_auth_context* ctx, const char* name,
251                                     const char* value, size_t value_length) {
252   GRPC_TRACE_LOG(api, INFO) << absl::StrFormat(
253       "grpc_auth_context_add_property(ctx=%p, name=%s, value=%*.*s, "
254       "value_length=%lu)",
255       ctx, name, (int)value_length, (int)value_length, value,
256       (unsigned long)value_length);
257   ctx->add_property(name, value, value_length);
258 }
259 
add_cstring_property(const char * name,const char * value)260 void grpc_auth_context::add_cstring_property(const char* name,
261                                              const char* value) {
262   ensure_capacity();
263   grpc_auth_property* prop = &properties_.array[properties_.count++];
264   prop->name = gpr_strdup(name);
265   prop->value = gpr_strdup(value);
266   prop->value_length = strlen(value);
267 }
268 
grpc_auth_context_add_cstring_property(grpc_auth_context * ctx,const char * name,const char * value)269 void grpc_auth_context_add_cstring_property(grpc_auth_context* ctx,
270                                             const char* name,
271                                             const char* value) {
272   GRPC_TRACE_LOG(api, INFO)
273       << "grpc_auth_context_add_cstring_property(ctx=" << ctx
274       << ", name=" << name << ", value=" << value << ")";
275   ctx->add_cstring_property(name, value);
276 }
277 
grpc_auth_property_reset(grpc_auth_property * property)278 void grpc_auth_property_reset(grpc_auth_property* property) {
279   gpr_free(property->name);
280   gpr_free(property->value);
281   memset(property, 0, sizeof(grpc_auth_property));
282 }
283 
auth_context_pointer_arg_destroy(void * p)284 static void auth_context_pointer_arg_destroy(void* p) {
285   if (p != nullptr) {
286     static_cast<grpc_auth_context*>(p)->Unref(DEBUG_LOCATION,
287                                               "auth_context_pointer_arg");
288   }
289 }
290 
auth_context_pointer_arg_copy(void * p)291 static void* auth_context_pointer_arg_copy(void* p) {
292   auto* ctx = static_cast<grpc_auth_context*>(p);
293   return ctx == nullptr
294              ? nullptr
295              : ctx->Ref(DEBUG_LOCATION, "auth_context_pointer_arg").release();
296 }
297 
auth_context_pointer_cmp(void * a,void * b)298 static int auth_context_pointer_cmp(void* a, void* b) {
299   return grpc_core::QsortCompare(a, b);
300 }
301 
302 static const grpc_arg_pointer_vtable auth_context_pointer_vtable = {
303     auth_context_pointer_arg_copy, auth_context_pointer_arg_destroy,
304     auth_context_pointer_cmp};
305 
grpc_auth_context_to_arg(grpc_auth_context * c)306 grpc_arg grpc_auth_context_to_arg(grpc_auth_context* c) {
307   return grpc_channel_arg_pointer_create(
308       const_cast<char*>(GRPC_AUTH_CONTEXT_ARG), c,
309       &auth_context_pointer_vtable);
310 }
311 
grpc_auth_context_from_arg(const grpc_arg * arg)312 grpc_auth_context* grpc_auth_context_from_arg(const grpc_arg* arg) {
313   if (strcmp(arg->key, GRPC_AUTH_CONTEXT_ARG) != 0) return nullptr;
314   if (arg->type != GRPC_ARG_POINTER) {
315     LOG(ERROR) << "Invalid type " << arg->type << " for arg "
316                << GRPC_AUTH_CONTEXT_ARG;
317     return nullptr;
318   }
319   return static_cast<grpc_auth_context*>(arg->value.pointer.p);
320 }
321 
grpc_find_auth_context_in_args(const grpc_channel_args * args)322 grpc_auth_context* grpc_find_auth_context_in_args(
323     const grpc_channel_args* args) {
324   size_t i;
325   if (args == nullptr) return nullptr;
326   for (i = 0; i < args->num_args; i++) {
327     grpc_auth_context* p = grpc_auth_context_from_arg(&args->args[i]);
328     if (p != nullptr) return p;
329   }
330   return nullptr;
331 }
332