Home | History | Annotate | Download | only in security_connector
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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