1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Authors: Jeffrey Stedfast <fejj@ximian.com>
5 * Copyright 2001 Ximian, Inc. (www.ximian.com)
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
36 #include <sys/types.h>
38 #include <openssl/err.h>
39 #include <openssl/ssl.h>
40 #include <openssl/x509.h>
42 #include "camel-certdb.h"
43 #include "camel-operation.h"
44 #include "camel-service.h"
45 #include "camel-session.h"
47 #include "camel-tcp-stream-ssl.h"
51 #define TIMEOUT_USEC (10000)
53 static CamelTcpStreamClass *parent_class = NULL;
55 /* Returns the class for a CamelTcpStreamSSL */
56 #define CTSR_CLASS(so) CAMEL_TCP_STREAM_SSL_CLASS (CAMEL_OBJECT_GET_CLASS (so))
58 static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n);
59 static ssize_t stream_write (CamelStream *stream, const char *buffer, size_t n);
60 static int stream_flush (CamelStream *stream);
61 static int stream_close (CamelStream *stream);
63 static int stream_connect (CamelTcpStream *stream, struct hostent *host, int port);
64 static int stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
65 static int stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
66 static CamelTcpAddress *stream_get_local_address (CamelTcpStream *stream);
67 static CamelTcpAddress *stream_get_remote_address (CamelTcpStream *stream);
69 static SSL *open_ssl_connection (CamelService *service, int sockfd, CamelTcpStreamSSL *openssl);
71 struct _CamelTcpStreamSSLPrivate {
75 CamelService *service;
82 camel_tcp_stream_ssl_class_init (CamelTcpStreamSSLClass *camel_tcp_stream_ssl_class)
84 CamelTcpStreamClass *camel_tcp_stream_class =
85 CAMEL_TCP_STREAM_CLASS (camel_tcp_stream_ssl_class);
86 CamelStreamClass *camel_stream_class =
87 CAMEL_STREAM_CLASS (camel_tcp_stream_ssl_class);
89 parent_class = CAMEL_TCP_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ()));
91 /* virtual method overload */
92 camel_stream_class->read = stream_read;
93 camel_stream_class->write = stream_write;
94 camel_stream_class->flush = stream_flush;
95 camel_stream_class->close = stream_close;
97 camel_tcp_stream_class->connect = stream_connect;
98 camel_tcp_stream_class->getsockopt = stream_getsockopt;
99 camel_tcp_stream_class->setsockopt = stream_setsockopt;
100 camel_tcp_stream_class->get_local_address = stream_get_local_address;
101 camel_tcp_stream_class->get_remote_address = stream_get_remote_address;
103 /* init OpenSSL stuff */
104 SSLeay_add_ssl_algorithms ();
105 SSL_load_error_strings ();
109 camel_tcp_stream_ssl_init (gpointer object, gpointer klass)
111 CamelTcpStreamSSL *stream = CAMEL_TCP_STREAM_SSL (object);
113 stream->priv = g_new0 (struct _CamelTcpStreamSSLPrivate, 1);
114 stream->priv->sockfd = -1;
118 camel_tcp_stream_ssl_finalize (CamelObject *object)
120 CamelTcpStreamSSL *stream = CAMEL_TCP_STREAM_SSL (object);
122 if (stream->priv->ssl) {
123 SSL_shutdown (stream->priv->ssl);
125 if (stream->priv->ssl->ctx) {
126 SSL_CTX_free (stream->priv->ssl->ctx);
129 SSL_free (stream->priv->ssl);
132 if (stream->priv->sockfd != -1)
133 close (stream->priv->sockfd);
135 g_free (stream->priv->expected_host);
137 g_free (stream->priv);
142 camel_tcp_stream_ssl_get_type (void)
144 static CamelType type = CAMEL_INVALID_TYPE;
146 if (type == CAMEL_INVALID_TYPE) {
147 type = camel_type_register (camel_tcp_stream_get_type (),
149 sizeof (CamelTcpStreamSSL),
150 sizeof (CamelTcpStreamSSLClass),
151 (CamelObjectClassInitFunc) camel_tcp_stream_ssl_class_init,
153 (CamelObjectInitFunc) camel_tcp_stream_ssl_init,
154 (CamelObjectFinalizeFunc) camel_tcp_stream_ssl_finalize);
162 * camel_tcp_stream_ssl_new:
163 * @service: camel service
164 * @expected_host: host that the stream is expecting to connect with.
167 * Since the SSL certificate authenticator may need to prompt the
168 * user, a CamelService is needed. @expected_host is needed as a
169 * protection against an MITM attack.
171 * Return value: a ssl stream (in ssl mode)
174 camel_tcp_stream_ssl_new (CamelService *service, const char *expected_host, guint32 flags)
176 CamelTcpStreamSSL *stream;
178 stream = CAMEL_TCP_STREAM_SSL (camel_object_new (camel_tcp_stream_ssl_get_type ()));
180 stream->priv->service = service;
181 stream->priv->expected_host = g_strdup (expected_host);
182 stream->priv->ssl_mode = TRUE;
183 stream->priv->flags = flags;
185 return CAMEL_STREAM (stream);
190 * camel_tcp_stream_ssl_new_raw:
191 * @service: camel service
192 * @expected_host: host that the stream is expecting to connect with.
195 * Since the SSL certificate authenticator may need to prompt the
196 * user, a CamelService is needed. @expected_host is needed as a
197 * protection against an MITM attack.
199 * Return value: a ssl-capable stream (in non ssl mode)
202 camel_tcp_stream_ssl_new_raw (CamelService *service, const char *expected_host, guint32 flags)
204 CamelTcpStreamSSL *stream;
206 stream = CAMEL_TCP_STREAM_SSL (camel_object_new (camel_tcp_stream_ssl_get_type ()));
208 stream->priv->service = service;
209 stream->priv->expected_host = g_strdup (expected_host);
210 stream->priv->ssl_mode = FALSE;
211 stream->priv->flags = flags;
213 return CAMEL_STREAM (stream);
218 ssl_errno (SSL *ssl, int ret)
220 switch (SSL_get_error (ssl, ret)) {
223 case SSL_ERROR_ZERO_RETURN:
224 /* this one does not map well at all */
225 d(printf ("ssl_errno: SSL_ERROR_ZERO_RETURN\n"));
227 case SSL_ERROR_WANT_READ: /* non-fatal; retry */
228 case SSL_ERROR_WANT_WRITE: /* non-fatal; retry */
229 d(printf ("ssl_errno: SSL_ERROR_WANT_[READ,WRITE]\n"));
231 case SSL_ERROR_SYSCALL:
232 d(printf ("ssl_errno: SSL_ERROR_SYSCALL\n"));
235 d(printf ("ssl_errno: SSL_ERROR_SSL <-- very useful error...riiiiight\n"));
238 d(printf ("ssl_errno: default error\n"));
245 * camel_tcp_stream_ssl_enable_ssl:
246 * @stream: ssl stream
248 * Toggles an ssl-capable stream into ssl mode (if it isn't already).
250 * Returns 0 on success or -1 on fail.
253 camel_tcp_stream_ssl_enable_ssl (CamelTcpStreamSSL *stream)
257 g_return_val_if_fail (CAMEL_IS_TCP_STREAM_SSL (stream), -1);
259 if (stream->priv->sockfd != -1 && !stream->priv->ssl_mode) {
260 ssl = open_ssl_connection (stream->priv->service, stream->priv->sockfd, stream);
262 stream->priv->sockfd = -1;
266 stream->priv->ssl = ssl;
269 stream->priv->ssl_mode = TRUE;
276 stream_read (CamelStream *stream, char *buffer, size_t n)
278 CamelTcpStreamSSL *openssl = CAMEL_TCP_STREAM_SSL (stream);
279 SSL *ssl = openssl->priv->ssl;
283 if (camel_operation_cancel_check (NULL)) {
288 cancel_fd = camel_operation_cancel_fd (NULL);
289 if (cancel_fd == -1) {
292 nread = SSL_read (ssl, buffer, n);
294 errno = ssl_errno (ssl, nread);
296 nread = read (openssl->priv->sockfd, buffer, n);
298 } while (nread < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
300 int error, flags, fdmax;
301 struct timeval timeout;
304 flags = fcntl (openssl->priv->sockfd, F_GETFL);
305 fcntl (openssl->priv->sockfd, F_SETFL, flags | O_NONBLOCK);
307 fdmax = MAX (openssl->priv->sockfd, cancel_fd) + 1;
311 FD_SET (openssl->priv->sockfd, &rdset);
312 FD_SET (cancel_fd, &rdset);
315 timeout.tv_usec = TIMEOUT_USEC;
316 select (fdmax, &rdset, 0, 0, &timeout);
317 if (FD_ISSET (cancel_fd, &rdset)) {
318 fcntl (openssl->priv->sockfd, F_SETFL, flags);
325 nread = SSL_read (ssl, buffer, n);
327 errno = ssl_errno (ssl, nread);
329 nread = read (openssl->priv->sockfd, buffer, n);
331 } while (nread < 0 && errno == EINTR);
332 } while (nread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK));
335 fcntl (openssl->priv->sockfd, F_SETFL, flags);
343 stream_write (CamelStream *stream, const char *buffer, size_t n)
345 CamelTcpStreamSSL *openssl = CAMEL_TCP_STREAM_SSL (stream);
346 SSL *ssl = openssl->priv->ssl;
347 ssize_t w, written = 0;
350 if (camel_operation_cancel_check (NULL)) {
355 cancel_fd = camel_operation_cancel_fd (NULL);
356 if (cancel_fd == -1) {
360 w = SSL_write (ssl, buffer + written, n - written);
362 errno = ssl_errno (ssl, w);
364 w = write (openssl->priv->sockfd, buffer + written, n - written);
366 } while (w < 0 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
370 } while (w != -1 && written < n);
372 int error, flags, fdmax;
373 struct timeval timeout;
376 flags = fcntl (openssl->priv->sockfd, F_GETFL);
377 fcntl (openssl->priv->sockfd, F_SETFL, flags | O_NONBLOCK);
379 fdmax = MAX (openssl->priv->sockfd, cancel_fd) + 1;
383 FD_SET (openssl->priv->sockfd, &wrset);
384 FD_SET (cancel_fd, &rdset);
387 timeout.tv_usec = TIMEOUT_USEC;
388 select (fdmax, &rdset, &wrset, 0, &timeout);
389 if (FD_ISSET (cancel_fd, &rdset)) {
390 fcntl (openssl->priv->sockfd, F_SETFL, flags);
397 w = SSL_write (ssl, buffer + written, n - written);
399 errno = ssl_errno (ssl, w);
401 w = write (openssl->priv->sockfd, buffer + written, n - written);
403 } while (w < 0 && errno == EINTR);
406 if (errno == EAGAIN || errno == EWOULDBLOCK) {
410 fcntl (openssl->priv->sockfd, F_SETFL, flags);
416 } while (w >= 0 && written < n);
418 fcntl (openssl->priv->sockfd, F_SETFL, flags);
425 stream_flush (CamelStream *stream)
432 close_ssl_connection (SSL *ssl)
438 SSL_CTX_free (ssl->ctx);
445 stream_close (CamelStream *stream)
447 close_ssl_connection (((CamelTcpStreamSSL *)stream)->priv->ssl);
448 ((CamelTcpStreamSSL *)stream)->priv->ssl = NULL;
450 if (close (((CamelTcpStreamSSL *)stream)->priv->sockfd) == -1)
453 ((CamelTcpStreamSSL *)stream)->priv->sockfd = -1;
457 /* this is a 'cancellable' connect, cancellable from camel_operation_cancel etc */
458 /* returns -1 & errno == EINTR if the connection was cancelled */
460 socket_connect (struct hostent *h, int port)
463 struct sockaddr_in6 sin6;
465 struct sockaddr_in sin;
466 struct sockaddr *saddr;
472 /* see if we're cancelled yet */
473 if (camel_operation_cancel_check (NULL)) {
478 /* setup connect, we do it using a nonblocking socket so we can poll it */
480 if (h->h_addrtype == AF_INET6) {
481 sin6.sin6_port = htons (port);
482 sin6.sin6_family = h->h_addrtype;
483 memcpy (&sin6.sin6_addr, h->h_addr, sizeof (sin6.sin6_addr));
484 saddr = (struct sockaddr *) &sin6;
488 sin.sin_port = htons (port);
489 sin.sin_family = h->h_addrtype;
490 memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr));
491 saddr = (struct sockaddr *) &sin;
497 fd = socket (h->h_addrtype, SOCK_STREAM, 0);
499 cancel_fd = camel_operation_cancel_fd (NULL);
500 if (cancel_fd == -1) {
501 ret = connect (fd, saddr, len);
512 flags = fcntl (fd, F_GETFL);
513 fcntl (fd, F_SETFL, flags | O_NONBLOCK);
515 ret = connect (fd, saddr, len);
517 fcntl (fd, F_SETFL, flags);
521 if (errno != EINPROGRESS) {
529 FD_SET (cancel_fd, &rdset);
530 fdmax = MAX (fd, cancel_fd) + 1;
534 if (select (fdmax, &rdset, &wrset, 0, &tv) == 0) {
540 if (cancel_fd != -1 && FD_ISSET (cancel_fd, &rdset)) {
547 if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &len) == -1) {
559 fcntl (fd, F_SETFL, flags);
566 x509_strerror (int err)
569 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
570 return _("Unable to get issuer's certificate");
571 case X509_V_ERR_UNABLE_TO_GET_CRL:
572 return _("Unable to get Certificate Revocation List");
573 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
574 return _("Unable to decrypt certificate signature");
575 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
576 return _("Unable to decrypt Certificate Revocation List signature");
577 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
578 return _("Unable to decode issuer's public key");
579 case X509_V_ERR_CERT_SIGNATURE_FAILURE:
580 return _("Certificate signature failure");
581 case X509_V_ERR_CRL_SIGNATURE_FAILURE:
582 return _("Certificate Revocation List signature failure");
583 case X509_V_ERR_CERT_NOT_YET_VALID:
584 return _("Certificate not yet valid");
585 case X509_V_ERR_CERT_HAS_EXPIRED:
586 return _("Certificate has expired");
587 case X509_V_ERR_CRL_NOT_YET_VALID:
588 return _("CRL not yet valid");
589 case X509_V_ERR_CRL_HAS_EXPIRED:
590 return _("CRL has expired");
591 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
592 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
593 case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
594 case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
595 return _("Error in CRL");
596 case X509_V_ERR_OUT_OF_MEM:
597 return _("Out of memory");
598 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
599 return _("Zero-depth self-signed certificate");
600 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
601 return _("Self-signed certificate in chain");
602 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
603 return _("Unable to get issuer's certificate locally");
604 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
605 return _("Unable to verify leaf signature");
606 case X509_V_ERR_CERT_CHAIN_TOO_LONG:
607 return _("Certificate chain too long");
608 case X509_V_ERR_CERT_REVOKED:
609 return _("Certificate Revoked");
610 case X509_V_ERR_INVALID_CA:
611 return _("Invalid Certificate Authority (CA)");
612 case X509_V_ERR_PATH_LENGTH_EXCEEDED:
613 return _("Path length exceeded");
614 case X509_V_ERR_INVALID_PURPOSE:
615 return _("Invalid purpose");
616 case X509_V_ERR_CERT_UNTRUSTED:
617 return _("Certificate untrusted");
618 case X509_V_ERR_CERT_REJECTED:
619 return _("Certificate rejected");
620 /* These are 'informational' when looking for issuer cert */
621 case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
622 return _("Subject/Issuer mismatch");
623 case X509_V_ERR_AKID_SKID_MISMATCH:
624 return _("AKID/SKID mismatch");
625 case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH:
626 return _("AKID/Issuer serial mismatch");
627 case X509_V_ERR_KEYUSAGE_NO_CERTSIGN:
628 return _("Key usage does not support certificate signing");
629 /* The application is not happy */
630 case X509_V_ERR_APPLICATION_VERIFICATION:
631 return _("Error in application verification");
638 ssl_verify (int ok, X509_STORE_CTX *ctx)
640 unsigned char md5sum[16], fingerprint[40], *f;
641 CamelTcpStreamSSL *stream;
642 CamelService *service;
643 CamelCertDB *certdb = NULL;
644 CamelCert *ccert = NULL;
645 char *prompt, *cert_str;
654 ssl = X509_STORE_CTX_get_ex_data (ctx, SSL_get_ex_data_X509_STORE_CTX_idx ());
656 stream = SSL_CTX_get_app_data (ssl->ctx);
660 service = stream->priv->service;
662 cert = X509_STORE_CTX_get_current_cert (ctx);
663 err = X509_STORE_CTX_get_error (ctx);
665 /* calculate the MD5 hash of the raw certificate */
666 md5len = sizeof (md5sum);
667 X509_digest (cert, EVP_md5 (), md5sum, &md5len);
668 for (i = 0, f = fingerprint; i < 16; i++, f += 3)
669 sprintf (f, "%.2x%c", md5sum[i], i != 15 ? ':' : '\0');
671 #define GET_STRING(name) X509_NAME_oneline (name, buf, 256)
673 certdb = camel_certdb_get_default ();
675 ccert = camel_certdb_get_cert (certdb, fingerprint);
677 if (ccert->trust != CAMEL_CERT_TRUST_UNKNOWN) {
678 ok = ccert->trust != CAMEL_CERT_TRUST_NEVER;
679 camel_certdb_cert_unref (certdb, ccert);
680 camel_object_unref (certdb);
685 /* create a new camel-cert */
686 ccert = camel_certdb_cert_new (certdb);
687 camel_cert_set_issuer (certdb, ccert, GET_STRING (X509_get_issuer_name (cert)));
688 camel_cert_set_subject (certdb, ccert, GET_STRING (X509_get_subject_name (cert)));
689 camel_cert_set_hostname (certdb, ccert, stream->priv->expected_host);
690 camel_cert_set_fingerprint (certdb, ccert, fingerprint);
691 camel_cert_set_trust (certdb, ccert, CAMEL_CERT_TRUST_UNKNOWN);
693 /* Add the certificate to our db */
694 camel_certdb_add (certdb, ccert);
698 cert_str = g_strdup_printf (_("Issuer: %s\n"
702 GET_STRING (X509_get_issuer_name (cert)),
703 GET_STRING (X509_get_subject_name (cert)),
704 fingerprint, cert->valid ? _("GOOD") : _("BAD"));
706 prompt = g_strdup_printf (_("Bad certificate from %s:\n\n%s\n\n%s\n\n"
707 "Do you wish to accept anyway?"),
708 service->url->host, cert_str, x509_strerror (err));
710 ok = camel_session_alert_user (service->session, CAMEL_SESSION_ALERT_WARNING, prompt, TRUE);
714 camel_cert_set_trust (certdb, ccert, CAMEL_CERT_TRUST_FULLY);
715 camel_certdb_touch (certdb);
719 camel_certdb_cert_unref (certdb, ccert);
720 camel_object_unref (certdb);
727 open_ssl_connection (CamelService *service, int sockfd, CamelTcpStreamSSL *openssl)
729 SSL_CTX *ssl_ctx = NULL;
733 /* SSLv23_client_method will negotiate with SSL v2, v3, or TLS v1 */
734 ssl_ctx = SSL_CTX_new (SSLv23_client_method ());
735 g_return_val_if_fail (ssl_ctx != NULL, NULL);
737 SSL_CTX_set_default_verify_paths (ssl_ctx);
738 SSL_CTX_set_verify (ssl_ctx, SSL_VERIFY_PEER, &ssl_verify);
739 ssl = SSL_new (ssl_ctx);
740 SSL_set_fd (ssl, sockfd);
742 SSL_CTX_set_app_data (ssl_ctx, openssl);
744 n = SSL_connect (ssl);
746 int errnosave = ssl_errno (ssl, n);
751 SSL_CTX_free (ssl->ctx);
765 stream_connect (CamelTcpStream *stream, struct hostent *host, int port)
767 CamelTcpStreamSSL *openssl = CAMEL_TCP_STREAM_SSL (stream);
771 g_return_val_if_fail (host != NULL, -1);
773 fd = socket_connect (host, port);
777 if (openssl->priv->ssl_mode) {
778 ssl = open_ssl_connection (openssl->priv->service, fd, openssl);
783 openssl->priv->sockfd = fd;
784 openssl->priv->ssl = ssl;
791 get_sockopt_level (const CamelSockOptData *data)
793 switch (data->option) {
794 case CAMEL_SOCKOPT_MAXSEGMENT:
795 case CAMEL_SOCKOPT_NODELAY:
803 get_sockopt_optname (const CamelSockOptData *data)
805 switch (data->option) {
806 case CAMEL_SOCKOPT_MAXSEGMENT:
808 case CAMEL_SOCKOPT_NODELAY:
810 case CAMEL_SOCKOPT_BROADCAST:
812 case CAMEL_SOCKOPT_KEEPALIVE:
814 case CAMEL_SOCKOPT_LINGER:
816 case CAMEL_SOCKOPT_RECVBUFFERSIZE:
818 case CAMEL_SOCKOPT_SENDBUFFERSIZE:
820 case CAMEL_SOCKOPT_REUSEADDR:
822 case CAMEL_SOCKOPT_IPTYPEOFSERVICE:
830 stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data)
834 if ((optname = get_sockopt_optname (data)) == -1)
837 if (data->option == CAMEL_SOCKOPT_NONBLOCKING) {
840 flags = fcntl (((CamelTcpStreamSSL *) stream)->priv->sockfd, F_GETFL);
844 data->value.non_blocking = flags & O_NONBLOCK ? TRUE : FALSE;
849 return getsockopt (((CamelTcpStreamSSL *) stream)->priv->sockfd,
850 get_sockopt_level (data),
852 (void *) &data->value,
857 stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data)
861 if ((optname = get_sockopt_optname (data)) == -1)
864 if (data->option == CAMEL_SOCKOPT_NONBLOCKING) {
867 flags = fcntl (((CamelTcpStreamSSL *) stream)->priv->sockfd, F_GETFL);
871 set = data->value.non_blocking ? O_NONBLOCK : 0;
872 flags = (flags & ~O_NONBLOCK) | set;
874 if (fcntl (((CamelTcpStreamSSL *) stream)->priv->sockfd, F_SETFL, flags) == -1)
880 return setsockopt (((CamelTcpStreamSSL *) stream)->priv->sockfd,
881 get_sockopt_level (data),
883 (void *) &data->value,
884 sizeof (data->value));
888 #define MIN_SOCKADDR_BUFLEN (sizeof (struct sockaddr_in6))
890 #define MIN_SOCKADDR_BUFLEN (sizeof (struct sockaddr_in))
893 static CamelTcpAddress *
894 stream_get_local_address (CamelTcpStream *stream)
896 unsigned char buf[MIN_SOCKADDR_BUFLEN];
898 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) buf;
900 struct sockaddr_in *sin = (struct sockaddr_in *) buf;
901 struct sockaddr *saddr = (struct sockaddr *) buf;
906 len = MIN_SOCKADDR_BUFLEN;
908 if (getsockname (CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd, saddr, &len) == -1)
911 if (saddr->sa_family == AF_INET) {
912 family = CAMEL_TCP_ADDRESS_IPv4;
913 address = &sin->sin_addr;
915 } else if (saddr->sa_family == AF_INET6) {
916 family = CAMEL_TCP_ADDRESS_IPv6;
917 address = &sin6->sin6_addr;
922 return camel_tcp_address_new (family, sin->sin_port, len, address);
925 static CamelTcpAddress *
926 stream_get_remote_address (CamelTcpStream *stream)
928 unsigned char buf[MIN_SOCKADDR_BUFLEN];
930 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) buf;
932 struct sockaddr_in *sin = (struct sockaddr_in *) buf;
933 struct sockaddr *saddr = (struct sockaddr *) buf;
938 len = MIN_SOCKADDR_BUFLEN;
940 if (getpeername (CAMEL_TCP_STREAM_SSL (stream)->priv->sockfd, saddr, &len) == -1)
943 if (saddr->sa_family == AF_INET) {
944 family = CAMEL_TCP_ADDRESS_IPv4;
945 address = &sin->sin_addr;
947 } else if (saddr->sa_family == AF_INET6) {
948 family = CAMEL_TCP_ADDRESS_IPv6;
949 address = &sin6->sin6_addr;
954 return camel_tcp_address_new (family, sin->sin_port, len, address);
957 #endif /* HAVE_OPENSSL */