1 /*
2 *
3 * Copyright 2018 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 <grpc/support/port_platform.h>
20
21 #include "src/core/lib/security/security_connector/local_security_connector.h"
22
23 #include <stdbool.h>
24 #include <string.h>
25
26 #include <grpc/grpc.h>
27 #include <grpc/support/alloc.h>
28 #include <grpc/support/log.h>
29 #include <grpc/support/string_util.h>
30
31 #include "src/core/ext/filters/client_channel/client_channel.h"
32 #include "src/core/lib/channel/channel_args.h"
33 #include "src/core/lib/security/credentials/local/local_credentials.h"
34 #include "src/core/lib/security/transport/security_handshaker.h"
35 #include "src/core/tsi/local_transport_security.h"
36
37 #define GRPC_UDS_URI_PATTERN "unix:"
38 #define GRPC_UDS_URL_SCHEME "unix"
39 #define GRPC_LOCAL_TRANSPORT_SECURITY_TYPE "local"
40
41 typedef struct {
42 grpc_channel_security_connector base;
43 char* target_name;
44 } grpc_local_channel_security_connector;
45
46 typedef struct {
47 grpc_server_security_connector base;
48 } grpc_local_server_security_connector;
49
local_channel_destroy(grpc_security_connector * sc)50 static void local_channel_destroy(grpc_security_connector* sc) {
51 if (sc == nullptr) {
52 return;
53 }
54 auto c = reinterpret_cast<grpc_local_channel_security_connector*>(sc);
55 grpc_call_credentials_unref(c->base.request_metadata_creds);
56 grpc_channel_credentials_unref(c->base.channel_creds);
57 gpr_free(c->target_name);
58 gpr_free(sc);
59 }
60
local_server_destroy(grpc_security_connector * sc)61 static void local_server_destroy(grpc_security_connector* sc) {
62 if (sc == nullptr) {
63 return;
64 }
65 auto c = reinterpret_cast<grpc_local_server_security_connector*>(sc);
66 grpc_server_credentials_unref(c->base.server_creds);
67 gpr_free(sc);
68 }
69
local_channel_add_handshakers(grpc_channel_security_connector * sc,grpc_handshake_manager * handshake_manager)70 static void local_channel_add_handshakers(
71 grpc_channel_security_connector* sc,
72 grpc_handshake_manager* handshake_manager) {
73 tsi_handshaker* handshaker = nullptr;
74 GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) ==
75 TSI_OK);
76 grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
77 handshaker, &sc->base));
78 }
79
local_server_add_handshakers(grpc_server_security_connector * sc,grpc_handshake_manager * handshake_manager)80 static void local_server_add_handshakers(
81 grpc_server_security_connector* sc,
82 grpc_handshake_manager* handshake_manager) {
83 tsi_handshaker* handshaker = nullptr;
84 GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */, &handshaker) ==
85 TSI_OK);
86 grpc_handshake_manager_add(handshake_manager, grpc_security_handshaker_create(
87 handshaker, &sc->base));
88 }
89
local_channel_cmp(grpc_security_connector * sc1,grpc_security_connector * sc2)90 static int local_channel_cmp(grpc_security_connector* sc1,
91 grpc_security_connector* sc2) {
92 grpc_local_channel_security_connector* c1 =
93 reinterpret_cast<grpc_local_channel_security_connector*>(sc1);
94 grpc_local_channel_security_connector* c2 =
95 reinterpret_cast<grpc_local_channel_security_connector*>(sc2);
96 int c = grpc_channel_security_connector_cmp(&c1->base, &c2->base);
97 if (c != 0) return c;
98 return strcmp(c1->target_name, c2->target_name);
99 }
100
local_server_cmp(grpc_security_connector * sc1,grpc_security_connector * sc2)101 static int local_server_cmp(grpc_security_connector* sc1,
102 grpc_security_connector* sc2) {
103 grpc_local_server_security_connector* c1 =
104 reinterpret_cast<grpc_local_server_security_connector*>(sc1);
105 grpc_local_server_security_connector* c2 =
106 reinterpret_cast<grpc_local_server_security_connector*>(sc2);
107 return grpc_server_security_connector_cmp(&c1->base, &c2->base);
108 }
109
local_auth_context_create(grpc_auth_context ** ctx)110 static grpc_security_status local_auth_context_create(grpc_auth_context** ctx) {
111 if (ctx == nullptr) {
112 gpr_log(GPR_ERROR, "Invalid arguments to local_auth_context_create()");
113 return GRPC_SECURITY_ERROR;
114 }
115 /* Create auth context. */
116 *ctx = grpc_auth_context_create(nullptr);
117 grpc_auth_context_add_cstring_property(
118 *ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
119 GRPC_LOCAL_TRANSPORT_SECURITY_TYPE);
120 GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
121 *ctx, GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1);
122 return GRPC_SECURITY_OK;
123 }
124
local_check_peer(grpc_security_connector * sc,tsi_peer peer,grpc_auth_context ** auth_context,grpc_closure * on_peer_checked)125 static void local_check_peer(grpc_security_connector* sc, tsi_peer peer,
126 grpc_auth_context** auth_context,
127 grpc_closure* on_peer_checked) {
128 grpc_security_status status;
129 /* Create an auth context which is necessary to pass the santiy check in
130 * {client, server}_auth_filter that verifies if the peer's auth context is
131 * obtained during handshakes. The auth context is only checked for its
132 * existence and not actually used.
133 */
134 status = local_auth_context_create(auth_context);
135 grpc_error* error = status == GRPC_SECURITY_OK
136 ? GRPC_ERROR_NONE
137 : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
138 "Could not create local auth context");
139 GRPC_CLOSURE_SCHED(on_peer_checked, error);
140 }
141
142 static grpc_security_connector_vtable local_channel_vtable = {
143 local_channel_destroy, local_check_peer, local_channel_cmp};
144
145 static grpc_security_connector_vtable local_server_vtable = {
146 local_server_destroy, local_check_peer, local_server_cmp};
147
local_check_call_host(grpc_channel_security_connector * sc,const char * host,grpc_auth_context * auth_context,grpc_closure * on_call_host_checked,grpc_error ** error)148 static bool local_check_call_host(grpc_channel_security_connector* sc,
149 const char* host,
150 grpc_auth_context* auth_context,
151 grpc_closure* on_call_host_checked,
152 grpc_error** error) {
153 grpc_local_channel_security_connector* local_sc =
154 reinterpret_cast<grpc_local_channel_security_connector*>(sc);
155 if (host == nullptr || local_sc == nullptr ||
156 strcmp(host, local_sc->target_name) != 0) {
157 *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
158 "local call host does not match target name");
159 }
160 return true;
161 }
162
local_cancel_check_call_host(grpc_channel_security_connector * sc,grpc_closure * on_call_host_checked,grpc_error * error)163 static void local_cancel_check_call_host(grpc_channel_security_connector* sc,
164 grpc_closure* on_call_host_checked,
165 grpc_error* error) {
166 GRPC_ERROR_UNREF(error);
167 }
168
grpc_local_channel_security_connector_create(grpc_channel_credentials * channel_creds,grpc_call_credentials * request_metadata_creds,const grpc_channel_args * args,const char * target_name,grpc_channel_security_connector ** sc)169 grpc_security_status grpc_local_channel_security_connector_create(
170 grpc_channel_credentials* channel_creds,
171 grpc_call_credentials* request_metadata_creds,
172 const grpc_channel_args* args, const char* target_name,
173 grpc_channel_security_connector** sc) {
174 if (channel_creds == nullptr || sc == nullptr || target_name == nullptr) {
175 gpr_log(
176 GPR_ERROR,
177 "Invalid arguments to grpc_local_channel_security_connector_create()");
178 return GRPC_SECURITY_ERROR;
179 }
180 // Check if local_connect_type is UDS. Only UDS is supported for now.
181 grpc_local_credentials* creds =
182 reinterpret_cast<grpc_local_credentials*>(channel_creds);
183 if (creds->connect_type != UDS) {
184 gpr_log(GPR_ERROR,
185 "Invalid local channel type to "
186 "grpc_local_channel_security_connector_create()");
187 return GRPC_SECURITY_ERROR;
188 }
189 // Check if target_name is a valid UDS address.
190 const grpc_arg* server_uri_arg =
191 grpc_channel_args_find(args, GRPC_ARG_SERVER_URI);
192 const char* server_uri_str = grpc_channel_arg_get_string(server_uri_arg);
193 if (strncmp(GRPC_UDS_URI_PATTERN, server_uri_str,
194 strlen(GRPC_UDS_URI_PATTERN)) != 0) {
195 gpr_log(GPR_ERROR,
196 "Invalid target_name to "
197 "grpc_local_channel_security_connector_create()");
198 return GRPC_SECURITY_ERROR;
199 }
200 auto c = static_cast<grpc_local_channel_security_connector*>(
201 gpr_zalloc(sizeof(grpc_local_channel_security_connector)));
202 gpr_ref_init(&c->base.base.refcount, 1);
203 c->base.base.vtable = &local_channel_vtable;
204 c->base.add_handshakers = local_channel_add_handshakers;
205 c->base.channel_creds = grpc_channel_credentials_ref(channel_creds);
206 c->base.request_metadata_creds =
207 grpc_call_credentials_ref(request_metadata_creds);
208 c->base.check_call_host = local_check_call_host;
209 c->base.cancel_check_call_host = local_cancel_check_call_host;
210 c->base.base.url_scheme =
211 creds->connect_type == UDS ? GRPC_UDS_URL_SCHEME : nullptr;
212 c->target_name = gpr_strdup(target_name);
213 *sc = &c->base;
214 return GRPC_SECURITY_OK;
215 }
216
grpc_local_server_security_connector_create(grpc_server_credentials * server_creds,grpc_server_security_connector ** sc)217 grpc_security_status grpc_local_server_security_connector_create(
218 grpc_server_credentials* server_creds,
219 grpc_server_security_connector** sc) {
220 if (server_creds == nullptr || sc == nullptr) {
221 gpr_log(
222 GPR_ERROR,
223 "Invalid arguments to grpc_local_server_security_connector_create()");
224 return GRPC_SECURITY_ERROR;
225 }
226 // Check if local_connect_type is UDS. Only UDS is supported for now.
227 grpc_local_server_credentials* creds =
228 reinterpret_cast<grpc_local_server_credentials*>(server_creds);
229 if (creds->connect_type != UDS) {
230 gpr_log(GPR_ERROR,
231 "Invalid local server type to "
232 "grpc_local_server_security_connector_create()");
233 return GRPC_SECURITY_ERROR;
234 }
235 auto c = static_cast<grpc_local_server_security_connector*>(
236 gpr_zalloc(sizeof(grpc_local_server_security_connector)));
237 gpr_ref_init(&c->base.base.refcount, 1);
238 c->base.base.vtable = &local_server_vtable;
239 c->base.server_creds = grpc_server_credentials_ref(server_creds);
240 c->base.base.url_scheme =
241 creds->connect_type == UDS ? GRPC_UDS_URL_SCHEME : nullptr;
242 c->base.add_handshakers = local_server_add_handshakers;
243 *sc = &c->base;
244 return GRPC_SECURITY_OK;
245 }
246