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