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