1 /* $NetBSD: tls_proxy_clnt.c,v 1.1.1.1 2011/03/02 19:32:27 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* tlsproxy_clnt 3 6 /* SUMMARY 7 /* postscreen TLS proxy support 8 /* SYNOPSIS 9 /* #include <tlsproxy_clnt.h> 10 /* 11 /* VSTREAM *tls_proxy_open(service, flags, peer_stream, peer_addr, 12 /* peer_port, timeout) 13 /* const char *service; 14 /* int flags; 15 /* VSTREAM *peer_stream; 16 /* const char *peer_addr; 17 /* const char *peer_port; 18 /* int timeout; 19 /* 20 /* TLS_SESS_STATE *tls_proxy_context_receive(proxy_stream) 21 /* VSTREAM *proxy_stream; 22 /* 23 /* void tls_proxy_context_free(tls_context) 24 /* TLS_SESS_STATE *tls_context; 25 /* DESCRIPTION 26 /* tls_proxy_open() prepares for inserting the tlsproxy(8) 27 /* daemon between the current process and a remote peer (the 28 /* actual insert operation is described in the next paragraph). 29 /* The result value is a null pointer on failure. The peer_stream 30 /* is not closed. The resulting proxy stream is single-buffered. 31 /* 32 /* After this, it is a good idea to use the VSTREAM_CTL_SWAP_FD 33 /* request to swap the file descriptors between the plaintext 34 /* peer_stream and the proxy stream from tls_proxy_open(). 35 /* This avoids the loss of application-configurable VSTREAM 36 /* attributes on the plaintext peer_stream (such as longjmp 37 /* buffer, timeout, etc.). Once the file descriptors are 38 /* swapped, the proxy stream should be closed. 39 /* 40 /* tls_proxy_context_receive() receives the TLS context object 41 /* for the named proxy stream. This function must be called 42 /* only if the TLS_PROXY_SEND_CONTEXT flag was specified in 43 /* the tls_proxy_open() call. Note that this TLS context object 44 /* is not compatible with tls_session_free(). It must be given 45 /* to tls_proxy_context_free() instead. 46 /* 47 /* After this, the proxy_stream is ready for plain-text I/O. 48 /* 49 /* tls_proxy_context_free() destroys a TLS context object that 50 /* was received with tls_proxy_context_receive(). 51 /* 52 /* Arguments: 53 /* .IP service 54 /* The (base) name of the tlsproxy service. 55 /* .IP flags 56 /* Bit-wise OR of: 57 /* .RS 58 /* .IP TLS_PROXY_FLAG_ROLE_SERVER 59 /* Request the TLS server proxy role. 60 /* .IP TLS_PROXY_FLAG_ROLE_CLIENT 61 /* Request the TLS client proxy role. 62 /* .IP TLS_PROXY_FLAG_SEND_CONTEXT 63 /* Send the TLS context object. 64 /* .RE 65 /* .IP peer_stream 66 /* Stream that connects the current process to a remote peer. 67 /* .IP peer_addr 68 /* Printable IP address of the remote peer_stream endpoint. 69 /* .IP peer_port 70 /* Printable TCP port of the remote peer_stream endpoint. 71 /* .IP timeout 72 /* Time limit that the tlsproxy(8) daemon should use. 73 /* .IP proxy_stream 74 /* Stream from tls_proxy_open(). 75 /* .IP tls_context 76 /* TLS session object from tls_proxy_context_receive(). 77 /* LICENSE 78 /* .ad 79 /* .fi 80 /* The Secure Mailer license must be distributed with this software. 81 /* AUTHOR(S) 82 /* Wietse Venema 83 /* IBM T.J. Watson Research 84 /* P.O. Box 704 85 /* Yorktown Heights, NY 10598, USA 86 /*--*/ 87 88 #ifdef USE_TLS 89 90 /* System library. */ 91 92 #include <sys_defs.h> 93 94 /* Utility library. */ 95 96 #include <msg.h> 97 #include <mymalloc.h> 98 #include <connect.h> 99 #include <stringops.h> 100 #include <vstring.h> 101 102 /* Global library. */ 103 104 #include <mail_proto.h> 105 #include <mail_params.h> 106 107 /* TLS library-specific. */ 108 109 #include <tls.h> 110 #include <tls_proxy.h> 111 112 #define TLSPROXY_INIT_TIMEOUT 10 113 114 /* SLMs. */ 115 116 #define STR vstring_str 117 118 /* tls_proxy_open - open negotiations with TLS proxy */ 119 120 VSTREAM *tls_proxy_open(const char *service, int flags, 121 VSTREAM *peer_stream, 122 const char *peer_addr, 123 const char *peer_port, 124 int timeout) 125 { 126 VSTREAM *tlsproxy_stream; 127 int status; 128 int fd; 129 static VSTRING *tlsproxy_service = 0; 130 static VSTRING *remote_endpt = 0; 131 132 /* 133 * Initialize. 134 */ 135 if (tlsproxy_service == 0) { 136 tlsproxy_service = vstring_alloc(20); 137 remote_endpt = vstring_alloc(20); 138 } 139 140 /* 141 * Connect to the tlsproxy(8) daemon. 142 */ 143 vstring_sprintf(tlsproxy_service, "%s/%s", MAIL_CLASS_PRIVATE, service); 144 if ((fd = LOCAL_CONNECT(STR(tlsproxy_service), BLOCKING, 145 TLSPROXY_INIT_TIMEOUT)) < 0) { 146 msg_warn("connect to %s service: %m", STR(tlsproxy_service)); 147 return (0); 148 } 149 150 /* 151 * Initial handshake. Send the data attributes now, and send the client 152 * file descriptor in a later transaction. 153 * 154 * XXX The formatted endpoint should be a state member. Then, we can 155 * simplify all the format strings throughout the program. 156 */ 157 tlsproxy_stream = vstream_fdopen(fd, O_RDWR); 158 vstring_sprintf(remote_endpt, "[%s]:%s", peer_addr, peer_port); 159 attr_print(tlsproxy_stream, ATTR_FLAG_NONE, 160 ATTR_TYPE_STR, MAIL_ATTR_REMOTE_ENDPT, STR(remote_endpt), 161 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, 162 ATTR_TYPE_INT, MAIL_ATTR_TIMEOUT, timeout, 163 ATTR_TYPE_END); 164 if (vstream_fflush(tlsproxy_stream) != 0) { 165 msg_warn("error sending request to %s service: %m", 166 STR(tlsproxy_service)); 167 vstream_fclose(tlsproxy_stream); 168 return (0); 169 } 170 171 /* 172 * Receive the "TLS is available" indication. 173 * 174 * This may seem out of order, but we must have a read transaction between 175 * sending the request attributes and sending the SMTP client file 176 * descriptor. We can't assume UNIX-domain socket semantics here. 177 */ 178 if (attr_scan(tlsproxy_stream, ATTR_FLAG_STRICT, 179 ATTR_TYPE_INT, MAIL_ATTR_STATUS, &status, 180 ATTR_TYPE_END) != 1 || status == 0) { 181 182 /* 183 * The TLS proxy reports that the TLS engine is not available (due to 184 * configuration error, or other causes). 185 */ 186 msg_warn("%s service role \"%s\" is not available", 187 STR(tlsproxy_service), 188 (flags & TLS_PROXY_FLAG_ROLE_SERVER) ? "server" : 189 (flags & TLS_PROXY_FLAG_ROLE_CLIENT) ? "client" : 190 "bogus role"); 191 vstream_fclose(tlsproxy_stream); 192 return (0); 193 } 194 195 /* 196 * Send the remote SMTP client file descriptor. 197 */ 198 if (LOCAL_SEND_FD(vstream_fileno(tlsproxy_stream), 199 vstream_fileno(peer_stream)) < 0) { 200 201 /* 202 * Some error: drop the TLS proxy stream. 203 */ 204 msg_warn("sending file handle to %s service: %m", 205 STR(tlsproxy_service)); 206 vstream_fclose(tlsproxy_stream); 207 return (0); 208 } 209 return (tlsproxy_stream); 210 } 211 212 /* tls_proxy_context_receive - receive TLS session object from tlsproxy(8) */ 213 214 TLS_SESS_STATE *tls_proxy_context_receive(VSTREAM *proxy_stream) 215 { 216 TLS_SESS_STATE *tls_context; 217 218 tls_context = (TLS_SESS_STATE *) mymalloc(sizeof(*tls_context)); 219 220 if (attr_scan(proxy_stream, ATTR_FLAG_STRICT, 221 ATTR_TYPE_FUNC, tls_proxy_context_scan, (char *) tls_context, 222 ATTR_TYPE_END) != 1) { 223 tls_proxy_context_free(tls_context); 224 return (0); 225 } else { 226 return (tls_context); 227 } 228 } 229 230 /* tls_proxy_context_free - destroy object from tls_proxy_context_receive() */ 231 232 void tls_proxy_context_free(TLS_SESS_STATE *tls_context) 233 { 234 if (tls_context->peer_CN) 235 myfree(tls_context->peer_CN); 236 if (tls_context->issuer_CN) 237 myfree(tls_context->issuer_CN); 238 if (tls_context->peer_fingerprint) 239 myfree(tls_context->peer_fingerprint); 240 if (tls_context->protocol) 241 myfree((char *) tls_context->protocol); 242 if (tls_context->cipher_name) 243 myfree((char *) tls_context->cipher_name); 244 myfree((char *) tls_context); 245 } 246 247 #endif 248