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));