1 /* $NetBSD: tls_proxy_clnt.c,v 1.3 2020/03/18 19:05:21 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* tlsproxy_clnt 3 6 /* SUMMARY 7 /* tlsproxy(8) client support 8 /* SYNOPSIS 9 /* #include <tlsproxy_clnt.h> 10 /* 11 /* VSTREAM *tls_proxy_open(service, flags, peer_stream, peer_addr, 12 /* peer_port, handshake_timeout, session_timeout, 13 /* serverid, tls_params, init_props, start_props) 14 /* const char *service; 15 /* int flags; 16 /* VSTREAM *peer_stream; 17 /* const char *peer_addr; 18 /* const char *peer_port; 19 /* int handshake_timeout; 20 /* int session_timeout; 21 /* const char *serverid; 22 /* void *tls_params; 23 /* void *init_props; 24 /* void *start_props; 25 /* 26 /* TLS_SESS_STATE *tls_proxy_context_receive(proxy_stream) 27 /* VSTREAM *proxy_stream; 28 /* AUXILIARY FUNCTIONS 29 /* VSTREAM *tls_proxy_legacy_open(service, flags, peer_stream, 30 /* peer_addr, peer_port, 31 /* timeout, serverid) 32 /* const char *service; 33 /* int flags; 34 /* VSTREAM *peer_stream; 35 /* const char *peer_addr; 36 /* const char *peer_port; 37 /* int timeout; 38 /* const char *serverid; 39 /* DESCRIPTION 40 /* tls_proxy_open() prepares for inserting the tlsproxy(8) 41 /* daemon between the current process and a remote peer (the 42 /* actual insert operation is described in the next paragraph). 43 /* The result value is a null pointer on failure. The peer_stream 44 /* is not closed. The resulting proxy stream is single-buffered. 45 /* 46 /* After this, it is a good idea to use the CA_VSTREAM_CTL_SWAP_FD 47 /* request to swap the file descriptors between the plaintext 48 /* peer_stream and the proxy stream from tls_proxy_open(). 49 /* This avoids the loss of application-configurable VSTREAM 50 /* attributes on the plaintext peer_stream (such as longjmp 51 /* buffer, timeout, etc.). Once the file descriptors are 52 /* swapped, the proxy stream should be closed. 53 /* 54 /* tls_proxy_context_receive() receives the TLS context object 55 /* for the named proxy stream. This function must be called 56 /* only if the TLS_PROXY_SEND_CONTEXT flag was specified in 57 /* the tls_proxy_open() call. Note that this TLS context object 58 /* is not compatible with tls_session_free(). It must be given 59 /* to tls_proxy_context_free() instead. 60 /* 61 /* After this, the proxy_stream is ready for plain-text I/O. 62 /* 63 /* tls_proxy_legacy_open() is a backwards-compatibility feature 64 /* that provides a historical interface. 65 /* 66 /* Arguments: 67 /* .IP service 68 /* The (base) name of the tlsproxy service. 69 /* .IP flags 70 /* Bit-wise OR of: 71 /* .RS 72 /* .IP TLS_PROXY_FLAG_ROLE_SERVER 73 /* Request the TLS server proxy role. 74 /* .IP TLS_PROXY_FLAG_ROLE_CLIENT 75 /* Request the TLS client proxy role. 76 /* .IP TLS_PROXY_FLAG_SEND_CONTEXT 77 /* Send the TLS context object. 78 /* .RE 79 /* .IP peer_stream 80 /* Stream that connects the current process to a remote peer. 81 /* .IP peer_addr 82 /* Printable IP address of the remote peer_stream endpoint. 83 /* .IP peer_port 84 /* Printable TCP port of the remote peer_stream endpoint. 85 /* .IP handshake_timeout 86 /* Time limit that the tlsproxy(8) daemon should use during 87 /* the TLS handshake. 88 /* .IP session_timeout 89 /* Time limit that the tlsproxy(8) daemon should use after the 90 /* TLS handshake. 91 /* .IP serverid 92 /* Unique service identifier. 93 /* .IP tls_params 94 /* Pointer to TLS_CLIENT_PARAMS or TLS_SERVER_PARAMS. 95 /* .IP init_props 96 /* Pointer to TLS_CLIENT_INIT_PROPS or TLS_SERVER_INIT_PROPS. 97 /* .IP start_props 98 /* Pointer to TLS_CLIENT_START_PROPS or TLS_SERVER_START_PROPS. 99 /* .IP proxy_stream 100 /* Stream from tls_proxy_open(). 101 /* .IP tls_context 102 /* TLS session object from tls_proxy_context_receive(). 103 /* LICENSE 104 /* .ad 105 /* .fi 106 /* The Secure Mailer license must be distributed with this software. 107 /* AUTHOR(S) 108 /* Wietse Venema 109 /* IBM T.J. Watson Research 110 /* P.O. Box 704 111 /* Yorktown Heights, NY 10598, USA 112 /* 113 /* Wietse Venema 114 /* Google, Inc. 115 /* 111 8th Avenue 116 /* New York, NY 10011, USA 117 /*--*/ 118 119 #ifdef USE_TLS 120 121 /* System library. */ 122 123 #include <sys_defs.h> 124 125 /* Utility library. */ 126 127 #include <msg.h> 128 #include <mymalloc.h> 129 #include <connect.h> 130 #include <stringops.h> 131 #include <vstring.h> 132 133 /* Global library. */ 134 135 #include <mail_proto.h> 136 #include <mail_params.h> 137 138 /* TLS library-specific. */ 139 140 #include <tls.h> 141 #include <tls_proxy.h> 142 143 #define TLSPROXY_INIT_TIMEOUT 10 144 145 /* SLMs. */ 146 147 #define STR vstring_str 148 149 /* tls_proxy_open - open negotiations with TLS proxy */ 150 151 VSTREAM *tls_proxy_open(const char *service, int flags, 152 VSTREAM *peer_stream, 153 const char *peer_addr, 154 const char *peer_port, 155 int handshake_timeout, 156 int session_timeout, 157 const char *serverid, 158 void *tls_params, 159 void *init_props, 160 void *start_props) 161 { 162 const char myname[] = "tls_proxy_open"; 163 VSTREAM *tlsproxy_stream; 164 int status; 165 int fd; 166 static VSTRING *tlsproxy_service = 0; 167 static VSTRING *remote_endpt = 0; 168 169 /* 170 * Initialize. 171 */ 172 if (tlsproxy_service == 0) { 173 tlsproxy_service = vstring_alloc(20); 174 remote_endpt = vstring_alloc(20); 175 } 176 177 /* 178 * Connect to the tlsproxy(8) daemon. 179 */ 180 vstring_sprintf(tlsproxy_service, "%s/%s", MAIL_CLASS_PRIVATE, service); 181 if ((fd = LOCAL_CONNECT(STR(tlsproxy_service), BLOCKING, 182 TLSPROXY_INIT_TIMEOUT)) < 0) { 183 msg_warn("connect to %s service: %m", STR(tlsproxy_service)); 184 return (0); 185 } 186 187 /* 188 * Initial handshake. Send common data attributes now, and send the 189 * remote peer file descriptor in a later transaction. 190 */ 191 tlsproxy_stream = vstream_fdopen(fd, O_RDWR); 192 vstring_sprintf(remote_endpt, "[%s]:%s", peer_addr, peer_port); 193 attr_print(tlsproxy_stream, ATTR_FLAG_NONE, 194 SEND_ATTR_STR(TLS_ATTR_REMOTE_ENDPT, STR(remote_endpt)), 195 SEND_ATTR_INT(TLS_ATTR_FLAGS, flags), 196 SEND_ATTR_INT(TLS_ATTR_TIMEOUT, handshake_timeout), 197 SEND_ATTR_INT(TLS_ATTR_TIMEOUT, session_timeout), 198 SEND_ATTR_STR(TLS_ATTR_SERVERID, serverid), 199 ATTR_TYPE_END); 200 /* Do not flush the stream yet. */ 201 if (vstream_ferror(tlsproxy_stream) != 0) { 202 msg_warn("error sending request to %s service: %m", 203 STR(tlsproxy_service)); 204 vstream_fclose(tlsproxy_stream); 205 return (0); 206 } 207 switch (flags & (TLS_PROXY_FLAG_ROLE_CLIENT | TLS_PROXY_FLAG_ROLE_SERVER)) { 208 case TLS_PROXY_FLAG_ROLE_CLIENT: 209 attr_print(tlsproxy_stream, ATTR_FLAG_NONE, 210 SEND_ATTR_FUNC(tls_proxy_client_param_print, tls_params), 211 SEND_ATTR_FUNC(tls_proxy_client_init_print, init_props), 212 SEND_ATTR_FUNC(tls_proxy_client_start_print, start_props), 213 ATTR_TYPE_END); 214 break; 215 case TLS_PROXY_FLAG_ROLE_SERVER: 216 #if 0 217 attr_print(tlsproxy_stream, ATTR_FLAG_NONE, 218 SEND_ATTR_FUNC(tls_proxy_server_param_print, tls_params), 219 SEND_ATTR_FUNC(tls_proxy_server_init_print, init_props), 220 SEND_ATTR_FUNC(tls_proxy_server_start_print, start_props), 221 ATTR_TYPE_END); 222 #endif 223 break; 224 default: 225 msg_panic("%s: bad flags: 0x%x", myname, flags); 226 } 227 if (vstream_fflush(tlsproxy_stream) != 0) { 228 msg_warn("error sending request to %s service: %m", 229 STR(tlsproxy_service)); 230 vstream_fclose(tlsproxy_stream); 231 return (0); 232 } 233 234 /* 235 * Receive the "TLS is available" indication. 236 * 237 * This may seem out of order, but we must have a read transaction between 238 * sending the request attributes and sending the plaintext file 239 * descriptor. We can't assume UNIX-domain socket semantics here. 240 */ 241 if (attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT, 242 RECV_ATTR_INT(MAIL_ATTR_STATUS, &status), 243 /* TODO: informative message. */ 244 ATTR_TYPE_END) != 1 || status == 0) { 245 246 /* 247 * The TLS proxy reports that the TLS engine is not available (due to 248 * configuration error, or other causes). 249 */ 250 msg_warn("%s service role \"%s\" is not available", 251 STR(tlsproxy_service), 252 (flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "server" : 253 (flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "client" : 254 "bogus role"); 255 vstream_fclose(tlsproxy_stream); 256 return (0); 257 } 258 259 /* 260 * Send the remote peer file descriptor. 261 */ 262 if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream), 263 vstream_fileno(peer_stream)) < 0) { 264 265 /* 266 * Some error: drop the TLS proxy stream. 267 */ 268 msg_warn("sending file handle to %s service: %m", 269 STR(tlsproxy_service)); 270 vstream_fclose(tlsproxy_stream); 271 return (0); 272 } 273 return (tlsproxy_stream); 274 } 275 276 277 /* tls_proxy_context_receive - receive TLS session object from tlsproxy(8) */ 278 279 TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *proxy_stream) 280 { 281 TLS_SESS_STATE *tls_context = 0; 282 283 if (attr_scan(proxy_stream, ATTR_FLAG_STRICT, 284 RECV_ATTR_FUNC(tls_proxy_context_scan, (void *) &tls_context), 285 ATTR_TYPE_END) != 1) { 286 if (tls_context) 287 tls_proxy_context_free(tls_context); 288 return (0); 289 } else { 290 return (tls_context); 291 } 292 } 293 294 #endif 295