[tpop3d-discuss] SSL support

Angel Marin anmar at gmx.net
Sun, 16 Jun 2002 12:13:48 +0200


This is a multi-part message in MIME format.

------=_NextPart_000_0000_01C2152F.44CB5E20
Content-Type: text/plain;
	charset="iso-8859-1"
Content-Transfer-Encoding: 7bit

Hi,

I have started the development of the ssl support for tpop3d. I have a
working snapshot, but its only an starting point of what shoud be. So if
anybody whants to test it and send problems/bugs/suggestions I will do my
best to improve it.

What it does :
 - provides tls support to tpop3d

Requisites:
 - OpenSSL

How to compile:
 - It needs to be linked with -lssl

How to configure:

I added a three config params:

"enable-ssl:" boolean to activate ssl support
	enable-ssl: true

"ssl-cert:" path to ssl public key file (pem format)
	ssl-cert: /usr/share/ssl/certs/tpop3d.pem

"ssl-key:" path to ssl private key file (pem format)
	ssl-key: /usr/share/ssl/certs/tpop3d-key.pem

If ssl-key is not set ssl-cert is tried as the private key.

I also modified the listen-address param. Now to specify that a address is
an ssl listener you may config it as:

	listen-address: (hostname | IP number)[:port][(domain)][{ssl}]
	listen-address: 127.0.0.1:995(foo.bar)]{ssl}

How it works:

If it receives a connection on a ssl listener it starts an ssl handshake and
then all the comunication will be encrypted.

To do:

	1. Modify configure & makefile
      2. Implement an xread function (equivalent to xwrite) so we can
replace read in connection_sendresponse and connection_sendline. Then we may
have a xread_ssl similar to xwrite_ssl to handle propertly rehandshake
situations while reading as it is done while writting.
	3. Implement a cleanner solution to write_file.
	4. Check if we are in a system without /dev/uramdom and handle it.
	5. Add more logging info for better debugging ssl problems
	6. Check the use of modern OpenSSL functions and determine the minimun
OpenSSL version needed.
	7. Test that the patch has not broken any other functionality.
	8. Add more comments to the source :)
	9. Test everything.

Situations already tested:

	Its working well in a small production server with ~70 users. It has two
listening addresses, only one ssl enabled. Maildir support only and
auth-flatfile. OpenSSL 0.9.6b

The patch:

	Attachment: tpop3d-1.4.2pre3-ssl.patch

Angel.

------=_NextPart_000_0000_01C2152F.44CB5E20
Content-Type: application/octet-stream;
	name="tpop3d-1.4.2pre3-ssl.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="tpop3d-1.4.2pre3-ssl.patch"

diff -urN tpop3d-1.4.2pre3/cfgdirectives.c =
tpop3d-1.4.2pre3-ssl/cfgdirectives.c
--- tpop3d-1.4.2pre3/cfgdirectives.c	Sat Jun  8 21:41:38 2002
+++ tpop3d-1.4.2pre3-ssl/cfgdirectives.c	Sat Jun 15 12:29:58 2002
@@ -31,6 +31,13 @@
     "mailbox",
     "no-detach",
=20
+#ifdef HAVE_SSL
+    /* SSL options */
+    "enable-ssl",
+    "ssl-cert",
+    "ssl-key",
+#endif /* HAVE_SSL */
+
 #ifdef AUTH_PAM
     /* auth-pam options */
     "auth-pam-enable",
diff -urN tpop3d-1.4.2pre3/connection.c =
tpop3d-1.4.2pre3-ssl/connection.c
--- tpop3d-1.4.2pre3/connection.c	Sat Jun  8 11:50:04 2002
+++ tpop3d-1.4.2pre3-ssl/connection.c	Sun Jun 16 11:23:11 2002
@@ -31,9 +31,16 @@
=20
 #include "connection.h"
 #include "util.h"
+#ifdef HAVE_SSL
+#include "util_ssl.h"
+#endif /* HAVE_SSL */
=20
 extern int verbose;
=20
+#ifdef HAVE_SSL
+extern int enable_ssl;              /* Enable SSL */
+#endif /* HAVE_SSL */
+
 /* make_timestamp:
  * Create a timestamp string. */
 #define TIMESTAMP_LEN   32
@@ -88,7 +95,7 @@
=20
 /* connection_new:
  * Create a connection object from a socket. */
-connection connection_new(int s, const struct sockaddr_in *sin, const =
char *domain) {
+connection connection_new(int s, const struct sockaddr_in *sin, const =
char *domain, const int ssl_listener) {
     connection c =3D NULL;
=20
     c =3D xcalloc(1, sizeof *c);
@@ -111,6 +118,13 @@
     c->state =3D authorisation;
=20
     c->idlesince =3D time(NULL);
+#ifdef HAVE_SSL
+    if ((enable_ssl)&&(ssl_listener)) {
+        c->ssl=3Dinit_ssl (c->s);
+    } else {
+        c->ssl=3DNULL;
+    }
+#endif /* HAVE_SSL */
=20
     if (!connection_sendresponse(c, 1, c->timestamp)) {
         log_print(LOG_ERR, "connection_new: could not send timestamp to =
`%s'", c->idstr);
@@ -130,8 +144,19 @@
     if (!c) return;
=20
     if (c->s !=3D -1) {
+#ifdef HAVE_SSL
+        if (c->ssl) {
+            close_ssl (c->ssl);
+        }
+#endif /* HAVE_SSL */
         shutdown(c->s, 2);
         close(c->s);
+#ifdef HAVE_SSL
+    } else {
+        if (c->ssl) {
+            free_ssl (c->ssl);
+        }
+#endif /* HAVE_SSL */
     }
=20
     if (c->a) authcontext_delete(c->a);
@@ -158,7 +183,15 @@
         return -1;
     }
     do {
-        n =3D read(c->s, c->p, c->buffer + c->bufferlen - c->p);
+#ifdef HAVE_SSL
+        if (c->ssl) {
+            n =3D xread_ssl (c->ssl, c->p, c->buffer + c->bufferlen - =
c->p);
+        } else {
+#endif /* HAVE_SSL */
+            n =3D read(c->s, c->p, c->buffer + c->bufferlen - c->p);
+#ifdef HAVE_SSL
+        }
+#endif /* HAVE_SSL */
     } while (n =3D=3D -1 && errno =3D=3D EINTR);
     if (n > 0) {
         c->p +=3D n;
@@ -310,7 +343,15 @@
     x =3D xmalloc(l =3D (4 + strlen(s) + 3 + 1));
     if (!x) return 0;
     snprintf(x, l, "%s %s\r\n", success ? "+OK" : "-ERR", s);
-    m =3D xwrite(c->s, x, l =3D strlen(x));
+#ifdef HAVE_SSL
+    if (c->ssl) {
+        m =3D xwrite_ssl (c->ssl, x, l =3D strlen(x));
+    } else {
+#endif /* HAVE_SSL */
+        m =3D xwrite(c->s, x, l =3D strlen(x));
+#ifdef HAVE_SSL
+    }
+#endif /* HAVE_SSL */
     xfree(x);
     if (verbose)
         log_print(LOG_DEBUG, _("connection_sendresponse: client %s: =
sent `%s %s'"), c->idstr, success? "+OK" : "-ERR", s);
@@ -328,7 +369,15 @@
     x =3D xmalloc(l =3D (3 + strlen(s)));
     if (!x) return 0;
     snprintf(x, l, "%s\r\n", s);
-    m =3D xwrite(c->s, x, l =3D strlen(x));
+#ifdef HAVE_SSL
+    if (c->ssl) {
+        m =3D xwrite_ssl (c->ssl, x, l =3D strlen(x));   =20
+    } else {
+#endif /* HAVE_SSL */
+        m =3D xwrite(c->s, x, l =3D strlen(x));
+#ifdef HAVE_SSL
+    }
+#endif /* HAVE_SSL */
     xfree(x);
     if (m > 0)
         c->nwr +=3D m;
diff -urN tpop3d-1.4.2pre3/connection.h =
tpop3d-1.4.2pre3-ssl/connection.h
--- tpop3d-1.4.2pre3/connection.h	Sat Jun  8 11:50:04 2002
+++ tpop3d-1.4.2pre3-ssl/connection.h	Sat Jun 15 12:26:15 2002
@@ -16,6 +16,10 @@
 #include <sys/socket.h>
 #include <sys/types.h>
=20
+#ifdef HAVE_SSL
+#include <openssl/ssl.h>
+#endif /* HAVE_SSL */
+
 #include "authswitch.h"
 #include "mailbox.h"
 #include "tokenise.h"
@@ -49,6 +53,9 @@
     char *user, *pass;      /* state accumulated */
     authcontext a;
     mailbox m;
+#ifdef HAVE_SSL
+    SSL *ssl;
+#endif /* HAVE_SSL */
 } *connection;
=20
 /* From rfc1939 */
@@ -65,7 +72,7 @@
 } *pop3command;
=20
 /* Create/destroy connections */
-connection   connection_new(const int s, const struct sockaddr_in *sin, =
const char *domain);
+connection   connection_new(const int s, const struct sockaddr_in *sin, =
const char *domain, const int ssl_listener);
 void         connection_delete(connection c);
=20
 /* Read data out of the socket into the buffer */
diff -urN tpop3d-1.4.2pre3/listener.c tpop3d-1.4.2pre3-ssl/listener.c
--- tpop3d-1.4.2pre3/listener.c	Tue Mar 19 19:38:27 2002
+++ tpop3d-1.4.2pre3-ssl/listener.c	Sat Jun 15 12:44:56 2002
@@ -32,9 +32,13 @@
 #include "listener.h"
 #include "util.h"
=20
+#ifdef HAVE_SSL
+extern int enable_ssl;
+#endif /* HAVE_SSL */
+
 /* listener_new:
  * Create a new listener object, listening on the specified address. */
-listener listener_new(const struct sockaddr_in *addr, const char =
*domain) {
+listener listener_new(const struct sockaddr_in *addr, const char =
*domain, const char *ssl) {
     listener L;
     struct hostent *he;
    =20
@@ -104,7 +108,11 @@
             L->domain =3D xstrdup(u.nodename);
         }
     }
-
+#ifdef HAVE_SSL
+    if ((enable_ssl)&&(ssl)) {
+        L->ssl =3D !strncmp (ssl,"ssl",3);
+    }
+#endif /* HAVE_SSL */
     return L;
=20
 fail:
diff -urN tpop3d-1.4.2pre3/listener.h tpop3d-1.4.2pre3-ssl/listener.h
--- tpop3d-1.4.2pre3/listener.h	Wed Nov  7 19:58:10 2001
+++ tpop3d-1.4.2pre3-ssl/listener.h	Sat Jun 15 12:25:05 2002
@@ -17,10 +17,11 @@
 typedef struct _listener {
     struct sockaddr_in sin;
     char *domain;
+    int ssl;
     int s;
 } *listener;
=20
-listener listener_new(const struct sockaddr_in *addr, const char =
*domain);
+listener listener_new(const struct sockaddr_in *addr, const char =
*domain, const char *ssl);
 void listener_delete(listener L);
=20
=20
diff -urN tpop3d-1.4.2pre3/main.c tpop3d-1.4.2pre3-ssl/main.c
--- tpop3d-1.4.2pre3/main.c	Sat Jun  8 20:27:40 2002
+++ tpop3d-1.4.2pre3-ssl/main.c	Sat Jun 15 20:07:53 2002
@@ -47,6 +47,10 @@
 #include "vector.h"
 #include "util.h"
=20
+#ifdef HAVE_SSL
+#include "util_ssl.h"
+#endif /* HAVE_SSL */
+
 /* The socket send buffer is set to this, so that we don't end up in a
  * position that we send so much data that the client will not have =
received
  * all of it before we time them out. */
@@ -57,6 +61,9 @@
 stringmap config;
=20
 /* Various configuration options. */
+#ifdef HAVE_SSL
+extern int enable_ssl;					/* Enable SSL */
+#endif /* HAVE_SSL */
 extern int append_domain;           /* Do we automatically try =
user@domain if user alone fails to authenticate? In pop3.c. */
 extern int strip_domain;            /* Do we automatically try user if =
user@domain fails to authenticate? */
 extern int apop_only;               /* Quit after receiving USER. */
@@ -157,7 +164,7 @@
                     log_print(LOG_INFO, _("listeners_post_select: =
rejected connection from %s owing to high load"), =
inet_ntoa(sin.sin_addr));
                 } else {
                     /* Find a free connection slot. */
-                    *J =3D connection_new(s, &sin, L->domain);
+                    *J =3D connection_new(s, &sin, L->domain, L->ssl);
                     if (*J)
                         log_print(LOG_INFO, _("listeners_post_select: =
client %s: connected"), (*J)->idstr);
                     else
@@ -449,6 +456,10 @@
             if (*J) connection_delete(*J);
         xfree(connections);
     }
+#ifdef HAVE_SSL
+    if (enable_ssl)
+        free_ssl_context();
+#endif /* HAVE_SSL */
 }
=20
 #define EXIT_REMOVING_PIDFILE(n) do { if (pidfile) =
remove_pid_file(pidfile); exit((n)); } while (0)
@@ -620,6 +631,14 @@
         }
     }
=20
+#ifdef HAVE_SSL
+    /* Enable SSL */
+    if (config_get_bool("enable-ssl")) {
+        enable_ssl=3D1;
+        initialize_ssl ();
+    }
+#endif /* HAVE_SSL */
+
     /* Identify addresses on which to listen.
      * The syntax for these is <addr>[:port][(domain)]. */
     s =3D config_get_string("listen-address");
@@ -633,10 +652,25 @@
         for (J =3D t->toks; J < t->toks + t->num; ++J) {
             struct sockaddr_in sin =3D {0};
             listener L;
-            char *s =3D *J, *r =3D NULL, *domain =3D NULL;
+            char *s =3D *J, *r =3D NULL, *domain =3D NULL, *ssl =3D =
NULL;
=20
             sin.sin_family =3D AF_INET;
=20
+#ifdef HAVE_SSL
+            /* SSL listener. */
+            r =3D strchr(s, '{');
+            if (r) {
+                if (*(s + strlen(s) - 1) !=3D '}') {
+                    log_print(LOG_ERR, _("%s: syntax for listen address =
`%s' is incorrect"), configfile, s);
+                    continue;
+                }
+
+                *r++ =3D 0;
+                *(r + strlen(r) - 1) =3D 0;
+                ssl =3D r;
+            }
+#endif /* HAVE_SSL */
+
             /* Specified domain. */
             r =3D strchr(s, '(');
             if (r) {
@@ -675,10 +709,11 @@
                 } else memcpy(&(sin.sin_addr), he->h_addr, =
sizeof(struct in_addr));
             }
=20
-            L =3D listener_new(&sin, domain);
+            L =3D listener_new(&sin, domain, ssl);
+
             if (L) {
                 vector_push_back(listeners, item_ptr(L));
-                log_print(LOG_INFO, _("listening on address %s, port =
%d, domain %s"), inet_ntoa(L->sin.sin_addr), htons(L->sin.sin_port), =
(L->domain ? L->domain : _("(none)")));
+                log_print(LOG_INFO, _("listening on address %s, port =
%d, domain %s, ssl %s"), inet_ntoa(L->sin.sin_addr), =
htons(L->sin.sin_port), (L->domain ? L->domain : _("(none)")), (L->ssl ? =
_("on"):_("off")));
             }
         }
=20
diff -urN tpop3d-1.4.2pre3/pop3.c tpop3d-1.4.2pre3-ssl/pop3.c
--- tpop3d-1.4.2pre3/pop3.c	Sat Jun  8 11:50:04 2002
+++ tpop3d-1.4.2pre3-ssl/pop3.c	Sat Jun 15 19:21:05 2002
@@ -420,10 +420,21 @@
                         log_print(LOG_DEBUG, _("connection_do: client =
%s: sending message %d (%d bytes)"),
                                     c->idstr, msg_num + 1, =
(int)curmsg->msglength);
                     connection_sendresponse(c, 1, _("Message =
follows:"));
-                    if ((n =3D (curmbox)->send_message(curmbox, c->s, =
msg_num, -1)) =3D=3D -1) {
-                        connection_sendresponse(c, 0, _("Oops"));
-                        return close_connection;
+#ifdef HAVE_SSL
+                    if (c->ssl) {
+                        if ((n =3D (curmbox)->send_message(curmbox, -1, =
msg_num, -1)) =3D=3D -1) {
+                            connection_sendresponse(c, 0, _("Oops"));
+                            return close_connection;
+                        }
+                    } else {
+#endif /* HAVE_SSL */
+                        if ((n =3D (curmbox)->send_message(curmbox, =
c->s, msg_num, -1)) =3D=3D -1) {
+                            connection_sendresponse(c, 0, _("Oops"));
+                            return close_connection;
+                        }
+#ifdef HAVE_SSL
                     }
+#endif /* HAVE_SSL */
                     c->nwr +=3D n; /* Record bytes sent. */
                    =20
                     /* That might have taken a long time. */
@@ -455,11 +466,21 @@
                     log_print(LOG_DEBUG, _("connection_do: client %s: =
sending headers and up to %d lines of message %d (< %d bytes)"),
                                 c->idstr, arg2, msg_num + 1, =
(int)curmsg->msglength);
                 connection_sendresponse(c, 1, _("Message follows:"));
-
-                if ((n =3D (curmbox)->send_message(curmbox, c->s, =
msg_num, arg2)) =3D=3D -1) {
-                    connection_sendresponse(c, 0, _("Oops."));
-                    return close_connection;
-                }
+#ifdef HAVE_SSL
+                if (c->ssl) {
+                    if ((n =3D (curmbox)->send_message(curmbox, -1 , =
msg_num, arg2)) =3D=3D -1) {
+                        connection_sendresponse(c, 0, _("Oops"));
+                        return close_connection;
+                    }
+                } else {
+#endif /* HAVE_SSL */
+                    if ((n =3D (curmbox)->send_message(curmbox, c->s, =
msg_num, arg2)) =3D=3D -1) {
+                        connection_sendresponse(c, 0, _("Oops."));
+                        return close_connection;
+                    }
+#ifdef HAVE_SSL
+                 }
+#endif /* HAVE_SSL */
                 c->nwr +=3D n; /* Record bytes sent. */
=20
                 /* That might have taken a long time. */
diff -urN tpop3d-1.4.2pre3/util.c tpop3d-1.4.2pre3-ssl/util.c
--- tpop3d-1.4.2pre3/util.c	Sat Jun  8 11:50:04 2002
+++ tpop3d-1.4.2pre3-ssl/util.c	Sun Jun 16 11:34:08 2002
@@ -24,7 +24,17 @@
 #include <unistd.h>
 #include <sys/mman.h>
=20
+#ifdef HAVE_SSL
+#include "connection.h"
+#include <openssl/md5.h>
+#include "util_ssl.h"
+#define MD5Init MD5_Init
+#define MD5Update MD5_Update
+#define MD5Final MD5_Final
+extern connection this_child_connection;
+#else
 #include "md5.h"
+#endif /* HAVE_SSL */
 #include "util.h"
=20
 /* xwrite:
@@ -122,13 +132,31 @@
         errno =3D 0;
        =20
         /* Escape a leading ., if present. */
-        if (*p =3D=3D '.' && !try_write(sck, ".", 1))
-            goto write_failure;
+#ifdef HAVE_SSL=20
+        if (this_child_connection->ssl) {
+            if (*p =3D=3D '.' && =
!try_write_ssl(this_child_connection->ssl, ".", 1))
+                goto write_failure;
+        } else {
+#endif /* HAVE_SSL */
+            if (*p =3D=3D '.' && !try_write(sck, ".", 1))
+                goto write_failure;
+#ifdef HAVE_SSL
+        }
+#endif /* HAVE_SSL */
         ++nwritten;
        =20
         /* Send line itself. */
-        if (!try_write(sck, p, q - p) || !try_write(sck, "\r\n", 2))
-            goto write_failure;
+#ifdef HAVE_SSL
+        if (this_child_connection->ssl) {
+            if (!try_write_ssl(this_child_connection->ssl, p, q - p) || =
!try_write_ssl(this_child_connection->ssl, "\r\n", 2))
+                goto write_failure;
+        } else {
+#endif /* HAVE_SSL */
+            if (!try_write(sck, p, q - p) || !try_write(sck, "\r\n", =
2))
+                goto write_failure;
+#ifdef HAVE_SSL
+        }
+#endif /* HAVE_SSL */
         nwritten +=3D q - p + 2;
=20
         p =3D q + 1;
@@ -137,11 +165,17 @@
     ++p;
=20
     errno =3D 0;
-    if (!try_write(sck, "\r\n", 2)) {
-        log_print(LOG_ERR, "write_file: write: %m");
-        munmap(filemem, length);
-        return -1;
+#ifdef HAVE_SSL
+    if (this_child_connection->ssl) {
+        if (!try_write_ssl(this_child_connection->ssl, "\r\n", 2))
+            goto write_failure;
+    } else {
+#endif /* HAVE_SSL */
+        if (!try_write(sck, "\r\n", 2))
+            goto write_failure;
+#ifdef HAVE_SSL
     }
+#endif /* HAVE_SSL */
    =20
     /* Now send the message itself */
     while (p < r && n) {
@@ -152,13 +186,31 @@
         errno =3D 0;
=20
         /* Escape a leading ., if present. */
-        if (*p =3D=3D '.' && !try_write(sck, ".", 1))
-            goto write_failure;
+#ifdef HAVE_SSL  =20
+        if (this_child_connection->ssl) {
+            if (*p =3D=3D '.' && =
!try_write_ssl(this_child_connection->ssl, ".", 1))
+                goto write_failure;
+        } else {
+#endif /* HAVE_SSL */
+            if (*p =3D=3D '.' && !try_write(sck, ".", 1))
+                goto write_failure;
+#ifdef HAVE_SSL
+        }
+#endif /* HAVE_SSL */
         ++nwritten;
        =20
         /* Send line itself. */
-        if (!try_write(sck, p, q - p) || !try_write(sck, "\r\n", 2))
-            goto write_failure;
+#ifdef HAVE_SSL
+        if (this_child_connection->ssl) {
+            if (!try_write_ssl(this_child_connection->ssl, p, q - p) || =
!try_write_ssl(this_child_connection->ssl, "\r\n", 2))
+                goto write_failure;
+        } else {
+#endif /* HAVE_SSL */
+            if (!try_write(sck, p, q - p) || !try_write(sck, "\r\n", =
2))
+                goto write_failure;
+#ifdef HAVE_SSL
+        }
+#endif /* HAVE_SSL */
         nwritten +=3D q - p + 2;
=20
         p =3D q + 1;
@@ -167,10 +219,18 @@
         log_print(LOG_ERR, "write_file: munmap: %m");
    =20
     errno =3D 0;
-    if (!try_write(sck, ".\r\n", 3)) {
-        log_print(LOG_ERR, "write_file: write: %m");
-        return -1;
-    } else return nwritten + 3;
+#ifdef HAVE_SSL
+    if (this_child_connection->ssl)
+        if (!try_write_ssl(this_child_connection->ssl, ".\r\n", 3)) {
+            log_print(LOG_ERR, "write_file: write: %m");
+            return -1;
+        } else return nwritten + 3;
+    else
+#endif /* HAVE_SSL */
+        if (!try_write(sck, ".\r\n", 3)) {
+            log_print(LOG_ERR, "write_file: write: %m");
+            return -1;
+        } else return nwritten + 3;
=20
 write_failure:
     log_print(LOG_ERR, "write_file: write: %m");
diff -urN tpop3d-1.4.2pre3/util_ssl.c tpop3d-1.4.2pre3-ssl/util_ssl.c
--- tpop3d-1.4.2pre3/util_ssl.c	Thu Jan  1 01:00:00 1970
+++ tpop3d-1.4.2pre3-ssl/util_ssl.c	Sun Jun 16 11:31:38 2002
@@ -0,0 +1,200 @@
+/*
+ * ssl.c:
+ * Global SSL stuff for tpop3d.
+ *
+ * designed for tpop3d by Angel Marin <anmar@gmx.net>
+ * Copyright (c) 2002 Angel Marin, Chris Lightfoot. All rights =
reserved.
+ */
+
+static const char rcsid[] =3D "$Id: util.c,v 1.0 2002/06/16 11:35:13 =
anmar Exp $";
+
+#ifdef HAVE_CONFIG_H
+#include "configuration.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_SSL
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <syslog.h>
+#include <string.h>
+
+#include "config.h"
+#include "util.h"
+#include "util_ssl.h"
+
+extern int timeout_seconds;
+int enable_ssl;
+SSL_CTX *ctx;
+
+/* initialize_ssl:
+ * Initialize context, load cert, set options, etc. */
+void initialize_ssl () {
+    char *s;
+
+    OpenSSL_add_ssl_algorithms();
+    SSL_load_error_strings();
+
+    ctx=3DSSL_CTX_new(SSLv23_server_method());
+    if (!ctx) {
+        log_print(LOG_ERR, "unable to create SSL context");
+        free_ssl_context();
+        enable_ssl =3D 0;
+        return;
+    }
+
+    SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
+
+    SSL_CTX_set_session_id_context(ctx, (const unsigned char *)"tpop3d =
SID", 10);
+
+    SSL_CTX_set_timeout(ctx, timeout_seconds);
+
+    s =3D config_get_string("ssl-cert");
+    if(!s||!SSL_CTX_use_certificate_chain_file(ctx, s)) {
+        log_print(LOG_ERR, "Error reading certificate file: %s", s);
+        free_ssl_context();
+        enable_ssl =3D 0;
+        return;
+    }
+    s =3D config_get_string("ssl-key");
+    if (!s) {
+        s =3D config_get_string("ssl-cert");
+    }
+    if(!s||!SSL_CTX_use_PrivateKey_file(ctx, s, SSL_FILETYPE_PEM)) {
+        log_print(LOG_ERR, "Error reading private key file: %s", s);
+        free_ssl_context();
+        enable_ssl =3D 0;
+        return;
+    }
+    if(!SSL_CTX_check_private_key(ctx)) {
+        log_print(LOG_ERR, "Private key does not match certificate =
file");
+        free_ssl_context();
+        enable_ssl =3D 0;
+        return;
+    }
+}
+
+/* free_ssl_context:
+ * Free context resources */
+void free_ssl_context () {
+    SSL_CTX_free(ctx);
+}
+
+/* free_ssl:
+ * Free ssl resources */
+void free_ssl (SSL *ssl) {
+    SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN);
+    SSL_clear (ssl);
+    SSL_free(ssl);
+    ERR_remove_state(0);
+}
+
+/* init_ssl:
+ * Create SSL object for this connection */
+SSL *init_ssl (int sock){
+    SSL *ssl;
+
+    ssl =3D SSL_new(ctx);
+    if (!ssl) {
+        log_print(LOG_ERR, "SSL_new: %s", =
ERR_reason_error_string(ERR_get_error()));
+        return NULL;
+    }
+
+    if (!SSL_set_fd(ssl, sock)) {
+        log_print(LOG_ERR, "SSL_accept: %s", =
ERR_reason_error_string(ERR_get_error()));
+        free_ssl(ssl);
+        return NULL;
+    }
+
+    if (SSL_accept(ssl) <=3D 0) {
+        log_print(LOG_ERR, "SSL_accept: %s", =
ERR_reason_error_string(ERR_get_error()));
+        free_ssl(ssl);
+        return NULL;
+    }
+    return ssl;
+}
+
+/* close_ssl:
+ * Close SSL connection and free resources */
+void close_ssl (SSL *ssl) {
+    int r =3D SSL_shutdown (ssl);
+    SSL_get_error(ssl,r);
+    switch (SSL_get_error(ssl,r)) {
+        case SSL_ERROR_NONE:
+            break;
+        case SSL_ERROR_WANT_WRITE:
+        case SSL_ERROR_WANT_READ:
+        case SSL_ERROR_WANT_X509_LOOKUP:
+        case SSL_ERROR_ZERO_RETURN:
+            break;
+        case SSL_ERROR_SYSCALL:
+        case SSL_ERROR_SSL:
+        default:
+            break;
+    }
+    free_ssl (ssl);
+}
+
+/* xwrite_ssl:
+ * Write some data, checking SSL states */
+ssize_t xwrite_ssl(SSL *ssl, const void *buf, size_t count) {
+    size_t c =3D count;
+    const char *b =3D (const char*)buf;
+    while (c > 0) {
+        int e =3D SSL_write(ssl, b, c);
+        switch (SSL_get_error(ssl,e)) {
+            case SSL_ERROR_NONE:
+                c -=3D e;
+                b +=3D e;
+                break;
+            case SSL_ERROR_WANT_WRITE:
+            case SSL_ERROR_WANT_READ:
+            case SSL_ERROR_WANT_X509_LOOKUP:
+                break;
+            case SSL_ERROR_ZERO_RETURN:
+                log_print(LOG_ERR, "SSL_write: Close notify recived =
from client");
+                return e;
+            case SSL_ERROR_SYSCALL:
+                if (e<0){
+                    if (errno =3D=3D EINTR)
+                        break;
+                }
+                log_print(LOG_ERR, "SSL_write: %s", =
ERR_reason_error_string(ERR_get_error()));
+                return e;
+            case SSL_ERROR_SSL:
+                log_print(LOG_ERR, "SSL_write: %s", =
ERR_reason_error_string(ERR_get_error()));
+                return e;
+        }
+    } while (c > 0);
+    return count;
+}
+
+/* xread_ssl:
+ * Read from SSL channel */
+ssize_t xread_ssl(SSL *ssl, const void *buf, size_t count) {
+    const char *b =3D (const char*)buf;
+    int r =3D SSL_read (ssl, b, count);
+    switch (SSL_get_error(ssl,r)) {
+        case SSL_ERROR_NONE:
+            break;
+        case SSL_ERROR_WANT_WRITE:
+        case SSL_ERROR_WANT_READ:
+        case SSL_ERROR_WANT_X509_LOOKUP:
+            break;
+        case SSL_ERROR_ZERO_RETURN:
+            log_print(LOG_ERR, "SSL_write: Close notify recived from =
client");
+            return r;
+        case SSL_ERROR_SYSCALL:
+            if (r<0){
+                if (errno =3D=3D EINTR)
+                    break;
+            }
+            log_print(LOG_ERR, "SSL_read: %s", =
ERR_reason_error_string(ERR_get_error()));
+            return r;
+        case SSL_ERROR_SSL:
+            log_print(LOG_ERR, "SSL_read: %s", =
ERR_reason_error_string(ERR_get_error()));
+            return r;
+    }
+    return r;
+}
+#endif /* HAVE_SSL */
diff -urN tpop3d-1.4.2pre3/util_ssl.h tpop3d-1.4.2pre3-ssl/util_ssl.h
--- tpop3d-1.4.2pre3/util_ssl.h	Thu Jan  1 01:00:00 1970
+++ tpop3d-1.4.2pre3-ssl/util_ssl.h	Sat Jun 15 19:53:39 2002
@@ -0,0 +1,27 @@
+/*
+ * util_ssl.h:
+ * Global SSL stuff for tpop3d
+ *
+ * designed for tpop3d by Angel Marin <anmar@gmx.net>
+ * Copyright (c) 2002 Angel Marin, Chris Lightfoot. All rights =
reserved.
+ */
+
+#ifndef __UTIL_SSL_H_ /* include guard */
+#define __UTIL_SSL_H_
+
+#ifdef HAVE_CONFIG_H
+#include "configuration.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+
+void initialize_ssl ( void);
+SSL *init_ssl (int sock);
+void free_ssl_context (void);
+void free_ssl (SSL *ssl);
+void close_ssl (SSL *ssl);
+ssize_t xwrite_ssl (SSL *ssl, const void *buf, size_t count);
+#define try_write_ssl(a, b, c)      (xwrite_ssl((a), (b), (c)) =3D=3D =
(c))
+ssize_t xread_ssl(SSL *ssl, const void *buf, size_t count);
+
+#endif /* __UTIL_SSL_H_ */

------=_NextPart_000_0000_01C2152F.44CB5E20--