3  * Copyright 2018 gRPC authors.
 
   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
 
   9  *     http://www.apache.org/licenses/LICENSE-2.0
 
  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.
 
  19 #include <grpc/support/port_platform.h>
 
  21 #include "src/core/lib/security/security_connector/local/local_security_connector.h"
 
  26 #include <grpc/grpc.h>
 
  27 #include <grpc/support/alloc.h>
 
  28 #include <grpc/support/log.h>
 
  29 #include <grpc/support/string_util.h>
 
  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"
 
  44 #define GRPC_UDS_URI_PATTERN "unix:"
 
  45 #define GRPC_LOCAL_TRANSPORT_SECURITY_TYPE "local"
 
  49 grpc_core::RefCountedPtr<grpc_auth_context> local_auth_context_create() {
 
  50   /* Create auth context. */
 
  51   grpc_core::RefCountedPtr<grpc_auth_context> ctx =
 
  52       grpc_core::MakeRefCounted<grpc_auth_context>(nullptr);
 
  53   grpc_auth_context_add_cstring_property(
 
  54       ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME,
 
  55       GRPC_LOCAL_TRANSPORT_SECURITY_TYPE);
 
  56   GPR_ASSERT(grpc_auth_context_set_peer_identity_property_name(
 
  57                  ctx.get(), GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME) == 1);
 
  61 void local_check_peer(grpc_security_connector* sc, tsi_peer peer,
 
  63                       grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
 
  64                       grpc_closure* on_peer_checked,
 
  65                       grpc_local_connect_type type) {
 
  66   int fd = grpc_endpoint_get_fd(ep);
 
  67   grpc_resolved_address resolved_addr;
 
  68   memset(&resolved_addr, 0, sizeof(resolved_addr));
 
  69   resolved_addr.len = GRPC_MAX_SOCKADDR_SIZE;
 
  70   bool is_endpoint_local = false;
 
  71   if (getsockname(fd, reinterpret_cast<grpc_sockaddr*>(resolved_addr.addr),
 
  72                   &resolved_addr.len) == 0) {
 
  73     grpc_resolved_address addr_normalized;
 
  74     grpc_resolved_address* addr =
 
  75         grpc_sockaddr_is_v4mapped(&resolved_addr, &addr_normalized)
 
  78     grpc_sockaddr* sock_addr = reinterpret_cast<grpc_sockaddr*>(&addr->addr);
 
  80     if (type == UDS && grpc_is_unix_socket(addr)) {
 
  81       is_endpoint_local = true;
 
  83     } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET) {
 
  84       const grpc_sockaddr_in* addr4 =
 
  85           reinterpret_cast<const grpc_sockaddr_in*>(sock_addr);
 
  86       if (grpc_htonl(addr4->sin_addr.s_addr) == INADDR_LOOPBACK) {
 
  87         is_endpoint_local = true;
 
  90     } else if (type == LOCAL_TCP && sock_addr->sa_family == GRPC_AF_INET6) {
 
  91       const grpc_sockaddr_in6* addr6 =
 
  92           reinterpret_cast<const grpc_sockaddr_in6*>(addr);
 
  93       if (memcmp(&addr6->sin6_addr, &in6addr_loopback,
 
  94                  sizeof(in6addr_loopback)) == 0) {
 
  95         is_endpoint_local = true;
 
  99   grpc_error* error = GRPC_ERROR_NONE;
 
 100   if (!is_endpoint_local) {
 
 101     error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 102         "Endpoint is neither UDS or TCP loopback address.");
 
 103     GRPC_CLOSURE_SCHED(on_peer_checked, error);
 
 106   /* Create an auth context which is necessary to pass the santiy check in
 
 107    * {client, server}_auth_filter that verifies if the peer's auth context is
 
 108    * obtained during handshakes. The auth context is only checked for its
 
 109    * existence and not actually used.
 
 111   *auth_context = local_auth_context_create();
 
 112   error = *auth_context != nullptr ? GRPC_ERROR_NONE
 
 113                                    : GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 114                                          "Could not create local auth context");
 
 115   GRPC_CLOSURE_SCHED(on_peer_checked, error);
 
 118 class grpc_local_channel_security_connector final
 
 119     : public grpc_channel_security_connector {
 
 121   grpc_local_channel_security_connector(
 
 122       grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
 
 123       grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
 
 124       const char* target_name)
 
 125       : grpc_channel_security_connector(nullptr, std::move(channel_creds),
 
 126                                         std::move(request_metadata_creds)),
 
 127         target_name_(gpr_strdup(target_name)) {}
 
 129   ~grpc_local_channel_security_connector() override { gpr_free(target_name_); }
 
 131   void add_handshakers(
 
 132       grpc_pollset_set* interested_parties,
 
 133       grpc_core::HandshakeManager* handshake_manager) override {
 
 134     tsi_handshaker* handshaker = nullptr;
 
 135     GPR_ASSERT(local_tsi_handshaker_create(true /* is_client */, &handshaker) ==
 
 137     handshake_manager->Add(
 
 138         grpc_core::SecurityHandshakerCreate(handshaker, this));
 
 141   int cmp(const grpc_security_connector* other_sc) const override {
 
 143         reinterpret_cast<const grpc_local_channel_security_connector*>(
 
 145     int c = channel_security_connector_cmp(other);
 
 146     if (c != 0) return c;
 
 147     return strcmp(target_name_, other->target_name_);
 
 150   void check_peer(tsi_peer peer, grpc_endpoint* ep,
 
 151                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
 
 152                   grpc_closure* on_peer_checked) override {
 
 153     grpc_local_credentials* creds =
 
 154         reinterpret_cast<grpc_local_credentials*>(mutable_channel_creds());
 
 155     local_check_peer(this, peer, ep, auth_context, on_peer_checked,
 
 156                      creds->connect_type());
 
 159   bool check_call_host(const char* host, grpc_auth_context* auth_context,
 
 160                        grpc_closure* on_call_host_checked,
 
 161                        grpc_error** error) override {
 
 162     if (host == nullptr || strcmp(host, target_name_) != 0) {
 
 163       *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 
 164           "local call host does not match target name");
 
 169   void cancel_check_call_host(grpc_closure* on_call_host_checked,
 
 170                               grpc_error* error) override {
 
 171     GRPC_ERROR_UNREF(error);
 
 174   const char* target_name() const { return target_name_; }
 
 180 class grpc_local_server_security_connector final
 
 181     : public grpc_server_security_connector {
 
 183   grpc_local_server_security_connector(
 
 184       grpc_core::RefCountedPtr<grpc_server_credentials> server_creds)
 
 185       : grpc_server_security_connector(nullptr, std::move(server_creds)) {}
 
 186   ~grpc_local_server_security_connector() override = default;
 
 188   void add_handshakers(
 
 189       grpc_pollset_set* interested_parties,
 
 190       grpc_core::HandshakeManager* handshake_manager) override {
 
 191     tsi_handshaker* handshaker = nullptr;
 
 192     GPR_ASSERT(local_tsi_handshaker_create(false /* is_client */,
 
 193                                            &handshaker) == TSI_OK);
 
 194     handshake_manager->Add(
 
 195         grpc_core::SecurityHandshakerCreate(handshaker, this));
 
 198   void check_peer(tsi_peer peer, grpc_endpoint* ep,
 
 199                   grpc_core::RefCountedPtr<grpc_auth_context>* auth_context,
 
 200                   grpc_closure* on_peer_checked) override {
 
 201     grpc_local_server_credentials* creds =
 
 202         static_cast<grpc_local_server_credentials*>(mutable_server_creds());
 
 203     local_check_peer(this, peer, ep, auth_context, on_peer_checked,
 
 204                      creds->connect_type());
 
 207   int cmp(const grpc_security_connector* other) const override {
 
 208     return server_security_connector_cmp(
 
 209         static_cast<const grpc_server_security_connector*>(other));
 
 214 grpc_core::RefCountedPtr<grpc_channel_security_connector>
 
 215 grpc_local_channel_security_connector_create(
 
 216     grpc_core::RefCountedPtr<grpc_channel_credentials> channel_creds,
 
 217     grpc_core::RefCountedPtr<grpc_call_credentials> request_metadata_creds,
 
 218     const grpc_channel_args* args, const char* target_name) {
 
 219   if (channel_creds == nullptr || target_name == nullptr) {
 
 222         "Invalid arguments to grpc_local_channel_security_connector_create()");
 
 225   // Perform sanity check on UDS address. For TCP local connection, the check
 
 226   // will be done during check_peer procedure.
 
 227   grpc_local_credentials* creds =
 
 228       static_cast<grpc_local_credentials*>(channel_creds.get());
 
 229   const grpc_arg* server_uri_arg =
 
 230       grpc_channel_args_find(args, GRPC_ARG_SERVER_URI);
 
 231   const char* server_uri_str = grpc_channel_arg_get_string(server_uri_arg);
 
 232   if (creds->connect_type() == UDS &&
 
 233       strncmp(GRPC_UDS_URI_PATTERN, server_uri_str,
 
 234               strlen(GRPC_UDS_URI_PATTERN)) != 0) {
 
 236             "Invalid UDS target name to "
 
 237             "grpc_local_channel_security_connector_create()");
 
 240   return grpc_core::MakeRefCounted<grpc_local_channel_security_connector>(
 
 241       channel_creds, request_metadata_creds, target_name);
 
 244 grpc_core::RefCountedPtr<grpc_server_security_connector>
 
 245 grpc_local_server_security_connector_create(
 
 246     grpc_core::RefCountedPtr<grpc_server_credentials> server_creds) {
 
 247   if (server_creds == nullptr) {
 
 250         "Invalid arguments to grpc_local_server_security_connector_create()");
 
 253   return grpc_core::MakeRefCounted<grpc_local_server_security_connector>(
 
 254       std::move(server_creds));