• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/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/gprpp/ref_counted_ptr.h"
34 #include "src/core/lib/iomgr/pollset.h"
35 #include "src/core/lib/iomgr/resolve_address.h"
36 #include "src/core/lib/iomgr/sockaddr.h"
37 #include "src/core/lib/iomgr/sockaddr_utils.h"
38 #include "src/core/lib/iomgr/socket_utils.h"
39 #include "src/core/lib/iomgr/unix_sockets_posix.h"
40 #include "src/core/lib/security/credentials/local/local_credentials.h"
41 #include "src/core/lib/security/transport/security_handshaker.h"
42 #include "src/core/tsi/local_transport_security.h"
43 
44 #define GRPC_UDS_URI_PATTERN "unix:"
45 #define GRPC_LOCAL_TRANSPORT_SECURITY_TYPE "local"
46 
47 namespace {
48 
local_auth_context_create(const tsi_peer * peer)49 grpc_core::RefCountedPtr<grpc_auth_context> local_auth_context_create(
50     const tsi_peer* peer) {
51   /* Create auth context. */
52   grpc_core::RefCountedPtr<grpc_auth_context> ctx =
53       grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
54   grpc_auth_context_add_cstring_property(
55       ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
56       GRPC_LOCAL_TRANSPORT_SECURITY_TYPE);
57   GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
58                  ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1);
59   GPR_ASSERT(peer->property_count == 1);
60   const tsi_peer_property* prop = &peer->properties[0];
61   GPR_ASSERT(prop != nullptr);
62   GPR_ASSERT(strcmp(prop->name, TSI_SECURITY_LEVEL_PEER_PROPERTY) == 0);
63   grpc_auth_context_add_property(ctx.get(),
64                                  GRPC_TRANSPORT_SECURITY_LEVEL_PROPERTY_NAME,
65                                  prop->value.data, prop->value.length);
66   return ctx;
67 }
68 
local_check_peer(tsi_peer peer,grpc_endpoint * ep,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked,grpc_local_connect_type type)69 void local_check_peer(tsi_peer peer, grpc_endpoint* ep,
70                       grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
71                       grpc_closure* on_peer_checked,
72                       grpc_local_connect_type type) {
73   int fd = grpc_endpoint_get_fd(ep);
74   grpc_resolved_address resolved_addr;
75   memset(&resolved_addr, 0, sizeof(resolved_addr));
76   resolved_addr.len = GRPC_MAX_SOCKADDR_SIZE;
77   bool is_endpoint_local = false;
78   if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(resolved_addr.addr),
79                   &resolved_addr.len) == 0) {
80     grpc_resolved_address addr_normalized;
81     grpc_resolved_address* addr =
82         grpc_sockaddr_is_v4mapped(&resolved_addr, &addr_normalized)
83             ? &addr_normalized
84             : &resolved_addr;
85     grpc_sockaddr* sock_addr = reinterpret_cast<grpc_sockaddr*>(&addr->addr);
86     // UDS
87     if (type == UDS && grpc_is_unix_socket(addr)) {
88       is_endpoint_local = true;
89       // IPV4
90     } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET) {
91       const grpc_sockaddr_in* addr4 =
92           reinterpret_cast<const grpc_sockaddr_in*>(sock_addr);
93       if (grpc_htonl(addr4->sin_addr.s_addr) == INADDR_LOOPBACK) {
94         is_endpoint_local = true;
95       }
96       // IPv6
97     } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET6) {
98       const grpc_sockaddr_in6* addr6 =
99           reinterpret_cast<const grpc_sockaddr_in6*>(addr);
100       if (memcmp(&addr6->sin6_addr, &in6addr_loopback,
101                  sizeof(in6addr_loopback)) == 0) {
102         is_endpoint_local = true;
103       }
104     }
105   }
106   grpc_error* error = GRPC_ERROR_NONE;
107   if (!is_endpoint_local) {
108     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
109         "Endpoint is neither UDS or TCP loopback address.");
110     grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
111     return;
112   }
113   // Add TSI_SECURITY_LEVEL_PEER_PROPERTY type peer property.
114   size_t new_property_count = peer.property_count + 1;
115   tsi_peer_property* new_properties = static_cast<tsi_peer_property*>(
116       gpr_zalloc(sizeof(*new_properties) * new_property_count));
117   for (size_t i = 0; i < peer.property_count; i++) {
118     new_properties[i] = peer.properties[i];
119   }
120   if (peer.properties != nullptr) gpr_free(peer.properties);
121   peer.properties = new_properties;
122   // TODO(yihuazhang): Set security level of local TCP to TSI_SECURITY_NONE.
123   const char* security_level =
124       tsi_security_level_to_string(TSI_PRIVACY_AND_INTEGRITY);
125   tsi_result result = tsi_construct_string_peer_property_from_cstring(
126       TSI_SECURITY_LEVEL_PEER_PROPERTY, security_level,
127       &peer.properties[peer.property_count]);
128   if (result != TSI_OK) return;
129   peer.property_count++;
130   /* Create an auth context which is necessary to pass the santiy check in
131    * {client, server}_auth_filter that verifies if the peer's auth context is
132    * obtained during handshakes. The auth context is only checked for its
133    * existence and not actually used.
134    */
135   *auth_context = local_auth_context_create(&peer);
136   tsi_peer_destruct(&peer);
137   error = *auth_context != nullptr ? GRPC_ERROR_NONE
138                                    : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
139                                          "Could not create local auth context");
140   grpc_core::ExecCtx::Run(DEBUG_LOCATION, on_peer_checked, error);
141 }
142 
143 class grpc_local_channel_security_connector final
144     : public grpc_channel_security_connector {
145  public:
grpc_local_channel_security_connector(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const char * target_name)146   grpc_local_channel_security_connector(
147       grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
148       grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
149       const char* target_name)
150       : grpc_channel_security_connector(nullptr, std::move(channel_creds),
151                                         std::move(request_metadata_creds)),
152         target_name_(gpr_strdup(target_name)) {}
153 
~grpc_local_channel_security_connector()154   ~grpc_local_channel_security_connector() override { gpr_free(target_name_); }
155 
add_handshakers(const grpc_channel_args * args,grpc_pollset_set *,grpc_core::HandshakeManager * handshake_manager)156   void add_handshakers(
157       const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
158       grpc_core::HandshakeManager* handshake_manager) override {
159     tsi_handshaker* handshaker = nullptr;
160     GPR_ASSERT(tsi_local_handshaker_create(true /* is_client */, &handshaker) ==
161                TSI_OK);
162     handshake_manager->Add(
163         grpc_core::SecurityHandshakerCreate(handshaker, this, args));
164   }
165 
cmp(const grpc_security_connector * other_sc) const166   int cmp(const grpc_security_connector* other_sc) const override {
167     auto* other =
168         reinterpret_cast<const grpc_local_channel_security_connector*>(
169             other_sc);
170     int c = channel_security_connector_cmp(other);
171     if (c != 0) return c;
172     return strcmp(target_name_, other->target_name_);
173   }
174 
check_peer(tsi_peer peer,grpc_endpoint * ep,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)175   void check_peer(tsi_peer peer, grpc_endpoint* ep,
176                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
177                   grpc_closure* on_peer_checked) override {
178     grpc_local_credentials* creds =
179         reinterpret_cast<grpc_local_credentials*>(mutable_channel_creds());
180     local_check_peer(peer, ep, auth_context, on_peer_checked,
181                      creds->connect_type());
182   }
183 
check_call_host(absl::string_view host,grpc_auth_context *,grpc_closure *,grpc_error ** error)184   bool check_call_host(absl::string_view host,
185                        grpc_auth_context* /*auth_context*/,
186                        grpc_closure* /*on_call_host_checked*/,
187                        grpc_error** error) override {
188     if (host.empty() || host != target_name_) {
189       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
190           "local call host does not match target name");
191     }
192     return true;
193   }
194 
cancel_check_call_host(grpc_closure *,grpc_error * error)195   void cancel_check_call_host(grpc_closure* /*on_call_host_checked*/,
196                               grpc_error* error) override {
197     GRPC_ERROR_UNREF(error);
198   }
199 
target_name() const200   const char* target_name() const { return target_name_; }
201 
202  private:
203   char* target_name_;
204 };
205 
206 class grpc_local_server_security_connector final
207     : public grpc_server_security_connector {
208  public:
grpc_local_server_security_connector(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)209   explicit grpc_local_server_security_connector(
210       grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
211       : grpc_server_security_connector(nullptr, std::move(server_creds)) {}
212   ~grpc_local_server_security_connector() override = default;
213 
add_handshakers(const grpc_channel_args * args,grpc_pollset_set *,grpc_core::HandshakeManager * handshake_manager)214   void add_handshakers(
215       const grpc_channel_args* args, grpc_pollset_set* /*interested_parties*/,
216       grpc_core::HandshakeManager* handshake_manager) override {
217     tsi_handshaker* handshaker = nullptr;
218     GPR_ASSERT(tsi_local_handshaker_create(false /* is_client */,
219                                            &handshaker) == TSI_OK);
220     handshake_manager->Add(
221         grpc_core::SecurityHandshakerCreate(handshaker, this, args));
222   }
223 
check_peer(tsi_peer peer,grpc_endpoint * ep,grpc_core::RefCountedPtr<grpc_auth_context> * auth_context,grpc_closure * on_peer_checked)224   void check_peer(tsi_peer peer, grpc_endpoint* ep,
225                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
226                   grpc_closure* on_peer_checked) override {
227     grpc_local_server_credentials* creds =
228         static_cast<grpc_local_server_credentials*>(mutable_server_creds());
229     local_check_peer(peer, ep, auth_context, on_peer_checked,
230                      creds->connect_type());
231   }
232 
cmp(const grpc_security_connector * other) const233   int cmp(const grpc_security_connector* other) const override {
234     return server_security_connector_cmp(
235         static_cast<const grpc_server_security_connector*>(other));
236   }
237 };
238 }  // namespace
239 
240 grpc_core::RefCountedPtr<grpc_channel_security_connector>
grpc_local_channel_security_connector_create(grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,const grpc_channel_args * args,const char * target_name)241 grpc_local_channel_security_connector_create(
242     grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
243     grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
244     const grpc_channel_args* args, const char* target_name) {
245   if (channel_creds == nullptr || target_name == nullptr) {
246     gpr_log(
247         GPR_ERROR,
248         "Invalid arguments to grpc_local_channel_security_connector_create()");
249     return nullptr;
250   }
251   // Perform sanity check on UDS address. For TCP local connection, the check
252   // will be done during check_peer procedure.
253   grpc_local_credentials* creds =
254       static_cast<grpc_local_credentials*>(channel_creds.get());
255   const grpc_arg* server_uri_arg =
256       grpc_channel_args_find(args, GRPC_ARG_SERVER_URI);
257   const char* server_uri_str = grpc_channel_arg_get_string(server_uri_arg);
258   if (creds->connect_type() == UDS &&
259       strncmp(GRPC_UDS_URI_PATTERN, server_uri_str,
260               strlen(GRPC_UDS_URI_PATTERN)) != 0) {
261     gpr_log(GPR_ERROR,
262             "Invalid UDS target name to "
263             "grpc_local_channel_security_connector_create()");
264     return nullptr;
265   }
266   return grpc_core::MakeRefCounted<grpc_local_channel_security_connector>(
267       channel_creds, request_metadata_creds, target_name);
268 }
269 
270 grpc_core::RefCountedPtr<grpc_server_security_connector>
grpc_local_server_security_connector_create(grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)271 grpc_local_server_security_connector_create(
272     grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
273   if (server_creds == nullptr) {
274     gpr_log(
275         GPR_ERROR,
276         "Invalid arguments to grpc_local_server_security_connector_create()");
277     return nullptr;
278   }
279   return grpc_core::MakeRefCounted<grpc_local_server_security_connector>(
280       std::move(server_creds));
281 }
282