summaryrefslogtreecommitdiff
path: root/imap
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2018-08-12 22:34:43 -0600
committerEduardo Chappa <chappa@washington.edu>2018-08-12 22:34:43 -0600
commit9449b23bbca71471a64f914b4bc7ec7d810e587f (patch)
tree12e119c0e389546892ae4bc4df82980cda4d6ffe /imap
parentabcd5fe37b31b2e13907893f70a9e411dcf5e295 (diff)
downloadalpine-9449b23bbca71471a64f914b4bc7ec7d810e587f.tar.xz
* Several changes to the compilation of Alpine in Windows to use
LibreSSL in connecting to external servers. This complements the changes to support S/MIME. In particular, we add support for validation of certificates by using C:\\libressl\ssl\certs as the place to save CA certificates. In order to help users, some certificates are distributed. TODO: Kerberos port, w2k.
Diffstat (limited to 'imap')
-rw-r--r--imap/src/c-client/imap4r1.c5
-rw-r--r--imap/src/c-client/mail.c2
-rw-r--r--imap/src/imapd/makefile.nt2
-rw-r--r--imap/src/imapd/makefile.ntk2
-rw-r--r--imap/src/ipopd/makefile.nt2
-rw-r--r--imap/src/ipopd/makefile.ntk2
-rw-r--r--imap/src/mailutil/mailutil.c3
-rw-r--r--imap/src/mailutil/makefile.nt6
-rw-r--r--imap/src/mailutil/makefile.ntk4
-rw-r--r--imap/src/mtest/makefile.nt2
-rw-r--r--imap/src/mtest/makefile.ntk2
-rw-r--r--imap/src/osdep/nt/makefile.nt21
-rw-r--r--imap/src/osdep/nt/makefile.ntk18
-rw-r--r--imap/src/osdep/nt/makefile.old2
-rw-r--r--imap/src/osdep/nt/makefile.w2k15
-rw-r--r--imap/src/osdep/nt/proc.c80
-rw-r--r--imap/src/osdep/nt/ssl_nt.c912
-rw-r--r--imap/src/osdep/nt/ssl_old.c4
-rw-r--r--imap/src/osdep/nt/sslstdio.c181
19 files changed, 1225 insertions, 40 deletions
diff --git a/imap/src/c-client/imap4r1.c b/imap/src/c-client/imap4r1.c
index b20453ee..abaddfe4 100644
--- a/imap/src/c-client/imap4r1.c
+++ b/imap/src/c-client/imap4r1.c
@@ -3363,13 +3363,12 @@ IMAPPARSEDREPLY *imap_send_literal (MAILSTREAM *stream,char *tag,char **s,
long imap_search_x_gm_ext1 (MAILSTREAM *stream, char *charset, SEARCHPGM *pgm, long flags)
{
char *cmd = (flags & SE_UID) ? "UID SEARCH X-GM-RAW" : "SEARCH X-GM-RAW";
- char *p, *t, s[MAILTMPLEN+1], u[MAILTMPLEN], v[MAILTMPLEN];
- IMAPARG *args[4],apgm,aatt,achs;;
+ char *t, s[MAILTMPLEN+1], u[MAILTMPLEN];
+ IMAPARG *args[4],apgm;
IMAPPARSEDREPLY *reply;
unsigned long i,j,k;
MESSAGECACHE *elt;
size_t remain = sizeof(s) - 1, len;
- NETMBX mb;
u[0] = s[0] = '\0';
t = s;
diff --git a/imap/src/c-client/mail.c b/imap/src/c-client/mail.c
index 3dd45eb5..43db47aa 100644
--- a/imap/src/c-client/mail.c
+++ b/imap/src/c-client/mail.c
@@ -2793,8 +2793,6 @@ BODY *mail_body_section (BODY *b, unsigned char *section)
BODY *mail_body (MAILSTREAM *stream,unsigned long msgno,unsigned char *section)
{
BODY *b = NIL;
- PART *pt;
- unsigned long i;
/* make sure have a body */
if (section && *section && mail_fetchstructure (stream,msgno,&b) && b)
return mail_body_section(b, section);
diff --git a/imap/src/imapd/makefile.nt b/imap/src/imapd/makefile.nt
index 41216701..9831ffea 100644
--- a/imap/src/imapd/makefile.nt
+++ b/imap/src/imapd/makefile.nt
@@ -34,7 +34,7 @@ NNTP=\\imapd.nntp
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
diff --git a/imap/src/imapd/makefile.ntk b/imap/src/imapd/makefile.ntk
index 5c5500e6..31d24d9f 100644
--- a/imap/src/imapd/makefile.ntk
+++ b/imap/src/imapd/makefile.ntk
@@ -37,7 +37,7 @@ CCLIENTLIB = $C\cclient.lib
K5 = \k5\lib
K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS) -DALERTFILE=\"$(ALERT)\" -DNNTPFILE=\"$(NNTP)\" -DUSERALERTFILE=\"$(USERALERT)\" -DANOFILE=\"$(ANO)\" -DSHUTDOWNFILE=\"$(SHUTDOWN)\"
diff --git a/imap/src/ipopd/makefile.nt b/imap/src/ipopd/makefile.nt
index ef32819b..88460f7b 100644
--- a/imap/src/ipopd/makefile.nt
+++ b/imap/src/ipopd/makefile.nt
@@ -28,7 +28,7 @@
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
diff --git a/imap/src/ipopd/makefile.ntk b/imap/src/ipopd/makefile.ntk
index 4a90a7a0..00782e4b 100644
--- a/imap/src/ipopd/makefile.ntk
+++ b/imap/src/ipopd/makefile.ntk
@@ -30,7 +30,7 @@ CCLIENTLIB = $C\cclient.lib
K5 = \k5\lib
K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
diff --git a/imap/src/mailutil/mailutil.c b/imap/src/mailutil/mailutil.c
index 15ae636b..d8faefa4 100644
--- a/imap/src/mailutil/mailutil.c
+++ b/imap/src/mailutil/mailutil.c
@@ -456,9 +456,8 @@ int main (int argc,char *argv[])
char *mailutil_string_sequence(MAILSTREAM *m)
{
char *rv = NULL;
- unsigned long i, j, count;
+ unsigned long i, j;
size_t len = 0;
- MESSAGECACHE elt;
if(m == NULL || m->nmsgs == 0L) return NULL;
diff --git a/imap/src/mailutil/makefile.nt b/imap/src/mailutil/makefile.nt
index 1a6eb515..97324350 100644
--- a/imap/src/mailutil/makefile.nt
+++ b/imap/src/mailutil/makefile.nt
@@ -27,9 +27,9 @@
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
-LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
-CFLAGS= -I$C /MT /W3 /DWIN32 /D_WIN32_WINNT=0x0400 -nologo $(EXTRACFLAGS)
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib $(LIBRESSLLIBS)
+CFLAGS= -I$C /MT /W3 /DWIN32 /D_WIN32_WINNT=0x0501 -nologo $(EXTRACFLAGS)
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
diff --git a/imap/src/mailutil/makefile.ntk b/imap/src/mailutil/makefile.ntk
index 42ae5185..f4cd28d4 100644
--- a/imap/src/mailutil/makefile.ntk
+++ b/imap/src/mailutil/makefile.ntk
@@ -29,8 +29,8 @@ C = ..\c-client
CCLIENTLIB = $C\cclient.lib
K5 = \k5\lib
K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
-LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib $(LIBRESSLLIBS)
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
diff --git a/imap/src/mtest/makefile.nt b/imap/src/mtest/makefile.nt
index 9486e42b..b3fcfeba 100644
--- a/imap/src/mtest/makefile.nt
+++ b/imap/src/mtest/makefile.nt
@@ -28,7 +28,7 @@
C = ..\c-client
CCLIENTLIB = $C\cclient.lib
LIBS = $(CCLIENTLIB) ws2_32.lib winmm.lib advapi32.lib
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
diff --git a/imap/src/mtest/makefile.ntk b/imap/src/mtest/makefile.ntk
index 91508162..0ddb50f5 100644
--- a/imap/src/mtest/makefile.ntk
+++ b/imap/src/mtest/makefile.ntk
@@ -30,7 +30,7 @@ CCLIENTLIB = $C\cclient.lib
K5 = \k5\lib
K5LIB = $(K5)\comerr32.lib $(K5)\gssapi32.lib $(K5)\krb5_32.lib
LIBS = $(CCLIENTLIB) $(K5LIB) ws2_32.lib winmm.lib advapi32.lib
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS= -I$C /MT /W3 $(OSCOMPAT) $(VSCOMPAT) -nologo $(EXTRACFLAGS)
diff --git a/imap/src/osdep/nt/makefile.nt b/imap/src/osdep/nt/makefile.nt
index a30dfc40..b56ed36c 100644
--- a/imap/src/osdep/nt/makefile.nt
+++ b/imap/src/osdep/nt/makefile.nt
@@ -1,4 +1,5 @@
# ========================================================================
+# Copyright 2018 Eduardo Chappa
# Copyright 1988-2007 University of Washington
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,6 +23,7 @@
#
# Date: 11 May 1989
# Last Edited: 23 May 2007
+# Last Edited 1 Aug 2018
EXTRAAUTHENTICATORS =
@@ -31,7 +33,7 @@ AUTHENTICATORS = ext md5 pla log
DRIVERS = imap nntp pop3 mbx mtx tenex unix
CREATEDRIVER = mbx
APPENDDRIVER = unix
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
CC = cl
@@ -44,15 +46,22 @@ all: $(CCLIENTLIB)
osdep.h: os_nt.h
copy os_nt.h osdep.h
- drivers $(EXTRADRIVERS) $(DRIVERS) dummy
- setproto $(CREATEDRIVER) $(APPENDDRIVER)
- echo ssl_onceonlyinit (); >> linkage.c
- mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
- echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
+ if exist linkage.c del linkage.c
+ if exist linkage.h del linkage.h
+ if exist auths.c del auths.c
+ $(CC) -c $(CFLAGS) proc.c
+ link /subsystem:console /out:proc.exe proc.obj
+ proc drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+ proc setproto $(CREATEDRIVER) $(APPENDDRIVER)
+ proc sslinit
+ proc mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
+ proc version
ip_nt.c: ip4_nt.c
copy ip4_nt.c ip_nt.c
+proc.obj: proc.c
+
mail.obj: mail.h misc.h osdep.h mail.c
misc.obj: mail.h misc.h misc.c
diff --git a/imap/src/osdep/nt/makefile.ntk b/imap/src/osdep/nt/makefile.ntk
index 507d7541..8ac5055e 100644
--- a/imap/src/osdep/nt/makefile.ntk
+++ b/imap/src/osdep/nt/makefile.ntk
@@ -22,6 +22,7 @@
#
# Date: 11 May 1989
# Last Edited: 23 May 2007
+# Last Edited: 1 Aug 2018
EXTRAAUTHENTICATORS =
@@ -31,7 +32,7 @@ AUTHENTICATORS = ext gss md5 pla log
DRIVERS = imap nntp pop3 mbx mtx tenex unix
CREATEDRIVER = mbx
APPENDDRIVER = unix
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400 /I\k5\include
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501 /I\k5\include
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
CC = cl
@@ -44,11 +45,16 @@ all: $(CCLIENTLIB)
osdep.h: os_nt.h
copy os_nt.h osdep.h
- drivers $(EXTRADRIVERS) $(DRIVERS) dummy
- setproto $(CREATEDRIVER) $(APPENDDRIVER)
- echo ssl_onceonlyinit (); >> linkage.c
- mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
- echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
+ if exist linkage.c del linkage.c
+ if exist linkage.h del linkage.h
+ if exist auths.c del auths.c
+ $(CC) -c $(CFLAGS) proc.c
+ link /subsystem:console /out:proc.exe proc.obj
+ proc drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+ proc setproto $(CREATEDRIVER) $(APPENDDRIVER)
+ proc sslinit
+ proc mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
+ proc version
ip_nt.c: ip4_nt.c
copy ip4_nt.c ip_nt.c
diff --git a/imap/src/osdep/nt/makefile.old b/imap/src/osdep/nt/makefile.old
index 028c98ba..5da00539 100644
--- a/imap/src/osdep/nt/makefile.old
+++ b/imap/src/osdep/nt/makefile.old
@@ -31,7 +31,7 @@ AUTHENTICATORS = ext md5 pla log
DRIVERS = imap nntp pop3 mbx mtx tenex unix
CREATEDRIVER = mbx
APPENDDRIVER = unix
-OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0400
+OSCOMPAT = /DWIN32 /D_WIN32_WINNT=0x0501
VSCOMPAT = /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE
CFLAGS = /MT /W3 /Ox /DCHUNKSIZE=65536 $(OSCOMPAT) $(VSCOMPAT) -nologo /I.. $(EXTRACFLAGS)
CC = cl
diff --git a/imap/src/osdep/nt/makefile.w2k b/imap/src/osdep/nt/makefile.w2k
index a58f0274..ba4a55fa 100644
--- a/imap/src/osdep/nt/makefile.w2k
+++ b/imap/src/osdep/nt/makefile.w2k
@@ -45,11 +45,16 @@ all: $(CCLIENTLIB)
osdep.h: os_nt.h
copy os_nt.h osdep.h
- drivers $(EXTRADRIVERS) $(DRIVERS) dummy
- setproto $(CREATEDRIVER) $(APPENDDRIVER)
- echo ssl_onceonlyinit (); >> linkage.c
- mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
- echo mail_versioncheck (CCLIENTVERSION); >> linkage.c
+ if exist linkage.c del linkage.c
+ if exist linkage.h del linkage.h
+ if exist auths.c del auths.c
+ $(CC) -c $(CFLAGS) proc.c
+ link /subsystem:console /out:proc.exe proc.obj
+ proc drivers $(EXTRADRIVERS) $(DRIVERS) dummy
+ proc setproto $(CREATEDRIVER) $(APPENDDRIVER)
+ proc sslinit
+ proc mkauths $(EXTRAAUTHENTICATORS) $(AUTHENTICATORS)
+ proc version
ip_nt.c: ip$(IP)_nt.c
copy ip$(IP)_nt.c ip_nt.c
diff --git a/imap/src/osdep/nt/proc.c b/imap/src/osdep/nt/proc.c
new file mode 100644
index 00000000..8fc3c4ee
--- /dev/null
+++ b/imap/src/osdep/nt/proc.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018 Eduardo Chappa
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+int main(int, char **);
+
+int
+main(int argc, char *argv[])
+{
+ int rv = 0, i;
+ FILE *fph, *fpc, *fpa;
+ char *opt;
+
+ fph = fpc = fpa = NULL;
+ if(argc < 2){
+ fprintf(stdout, "Not enough arguments.\n");
+ fprintf(stdout, "Usage: %s opt ...\n", argv[0]);
+ fprintf(stdout, "opt can be drivers, mkauths, version, setproto or sslinit\n");
+ exit(1);
+ }
+
+ opt = argv[1];
+ if(!strcmp(opt, "drivers")){
+ fph = fopen("linkage.h", "w");
+ fpc = fopen("linkage.c", "w");
+ for (i = 2; i < argc; i++){
+ fprintf(fph, "extern DRIVER %sdriver;\n", argv[i]);
+ fprintf(fpc, " mail_link (&%sdriver); /* link in the %s driver */\n",
+ argv[i], argv[i]);
+ }
+ }
+ else if(!strcmp(opt, "mkauths")){
+ fph = fopen("linkage.h", "a");
+ fpc = fopen("linkage.c", "a");
+ fpa = fopen("auths.c", "w");
+ for (i = 2; i < argc; i++){
+ fprintf(fph, "extern AUTHENTICATOR auth_%s;\n", argv[i]);
+ fprintf(fpc, " auth_link (&auth_%s); /* link in the %s authenticator */\n",
+ argv[i], argv[i]);
+ fprintf(fpa, "#include \"auth_%s.c\"\n", argv[i]);
+ }
+ }
+ else if(!strcmp(opt, "setproto")){
+ if(argc != 4){
+ fprintf(stdout, "setproto requires two additional arguments\n");
+ exit(1);
+ }
+ fph = fopen("linkage.h", "a");
+ fprintf(fph, "#define CREATEPROTO %sproto\n", argv[2]);
+ fprintf(fph, "#define APPENDPROTO %sproto\n", argv[3]);
+ }
+ else if(!strcmp(opt, "sslinit")){
+ fpc = fopen("linkage.c", "a");
+ fprintf(fpc, "%s\n", "ssl_onceonlyinit();");
+ }
+ else if(!strcmp(opt, "version")){
+ fpc = fopen("linkage.c", "a");
+ fprintf(fpc, "%s\n", "mail_versioncheck(CCLIENTVERSION);");
+ }
+ else {
+ fprintf(stdout, "Try: \"drivers\", \"mkauths\", \"setproto\", \"sslinit\", or \"version\".\n");
+ exit(1);
+ }
+ if(fpa != NULL) fclose(fpa);
+ if(fpc != NULL) fclose(fpc);
+ if(fph != NULL) fclose(fph);
+ exit(0);
+}
diff --git a/imap/src/osdep/nt/ssl_nt.c b/imap/src/osdep/nt/ssl_nt.c
index 7c2248d1..d352980e 100644
--- a/imap/src/osdep/nt/ssl_nt.c
+++ b/imap/src/osdep/nt/ssl_nt.c
@@ -1,4 +1,5 @@
/* ========================================================================
+ * Copyright 2018 Eduardo Chappa
* Copyright 2008-2009 Mark Crispin
* ========================================================================
*/
@@ -22,7 +23,916 @@
* http://www.apache.org/licenses/LICENSE-2.0
*
*/
+#ifdef ENABLE_WINDOWS_LIBRESSL
+#define crypt ssl_private_crypt
+#define STRING OPENSSL_STRING
+#include <x509v3.h>
+#include <ssl.h>
+#include <err.h>
+#include <pem.h>
+#include <buffer.h>
+#include <bio.h>
+#include <crypto.h>
+#include <rand.h>
+#ifdef OPENSSL_1_1_0
+#include <rsa.h>
+#include <bn.h>
+#ifdef TLSv1_1_client_method
+#undef TLSv1_1_client_method
+#endif /* TLSv1_1_client_method */
+#ifdef TLSv1_2_client_method
+#undef TLSv1_2_client_method
+#endif /* TLSv1_2_client_method */
+#define TLSv1_1_client_method TLS_client_method
+#define TLSv1_2_client_method TLS_client_method
+#endif /* OPENSSL_1_1_0 */
+#undef STRING
+#undef crypt
+
+#define SSLBUFLEN 8192
+
+/*
+ * PCI auditing compliance, disable:
+ * SSLv2
+ * anonymous D-H (no certificate
+ * export encryption ciphers (40 and 56 bits)
+ * low encryption cipher suites (40 and 56 bits, excluding export)
+ * null encryption (disabling implied by "ALL")
+ *
+ * UW imapd just disables low-grade and null ("ALL:!LOW"). This setting
+ * will break clients that attempt to use the newly-prohibited mechanisms.
+ *
+ * I question the value of disabling SSLv2, as opposed to disabling the SSL
+ * ports (e.g., 993 for IMAP, 995 for POP3) and using TLS exclusively.
+ */
+
+#define SSLCIPHERLIST "ALL:!SSLv2:!ADH:!EXP:!LOW"
+
+/* SSL I/O stream */
+
+typedef struct ssl_stream {
+ TCPSTREAM *tcpstream; /* TCP stream */
+ SSL_CTX *context; /* SSL context */
+ SSL *con; /* SSL connection */
+ int ictr; /* input counter */
+ char *iptr; /* input pointer */
+ char ibuf[SSLBUFLEN]; /* input buffer */
+} SSLSTREAM;
+
+#include "sslio.h"
+
+/* Function prototypes */
+const SSL_METHOD *ssl_connect_mthd(int flag);
+static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags);
+static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags);
+static int ssl_open_verify (int ok,X509_STORE_CTX *ctx);
+static char *ssl_validate_cert (X509 *cert,char *host);
+static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat);
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+ long *contd);
+static long ssl_abort (SSLSTREAM *stream);
+
+#ifdef OPENSSL_1_1_0
+#define SSL_CTX_TYPE SSL_CTX
+#else
+#define SSL_CTX_TYPE SSL
+#endif /* OPENSSL_1_1_0 */
+
+static RSA *ssl_genkey (SSL_CTX_TYPE *con,int export,int keylength);
+
+
+/* Secure Sockets Layer network driver dispatch */
+
+static struct ssl_driver ssldriver = {
+ ssl_open, /* open connection */
+ ssl_aopen, /* open preauthenticated connection */
+ ssl_getline, /* get a line */
+ ssl_getbuffer, /* get a buffer */
+ ssl_soutr, /* output pushed data */
+ ssl_sout, /* output string */
+ ssl_close, /* close connection */
+ ssl_host, /* return host name */
+ ssl_remotehost, /* return remote host name */
+ ssl_port, /* return port number */
+ ssl_localhost /* return local host name */
+};
+ /* non-NIL if doing SSL primary I/O */
+static SSLSTDIOSTREAM *sslstdio = NIL;
+static char *start_tls = NIL; /* non-NIL if start TLS requested */
+
+/* One-time SSL initialization */
+
+static int sslonceonly = 0;
+
+void ssl_onceonlyinit (void)
+{
+ if (!sslonceonly++) { /* only need to call it once */
+ int fd;
+ char tmp[MAILTMPLEN];
+ struct stat sbuf;
+ /* if system doesn't have /dev/urandom */
+ if (stat ("/dev/urandom",&sbuf)) {
+ strcpy(tmp, "SSLXXXXXX");
+ fd = fopen(tmp,"a");
+ unlink (tmp); /* don't need the file */
+ fstat (fd,&sbuf); /* get information about the file */
+ close (fd); /* flush descriptor */
+ /* not great but it'll have to do */
+ sprintf (tmp + strlen (tmp),"%.80s%lx%.80s%lx%lx%lx%lx%lx",
+ tcp_serveraddr (),(unsigned long) tcp_serverport (),
+ tcp_clientaddr (),(unsigned long) tcp_clientport (),
+ (unsigned long) sbuf.st_ino,(unsigned long) time (0),
+ (unsigned long) gethostid (),(unsigned long) getpid ());
+ RAND_seed (tmp,strlen (tmp));
+ }
+ /* apply runtime linkage */
+ mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver);
+ mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start);
+#ifdef OPENSSL_1_1_0
+ OPENSSL_init_ssl(0, NULL);
+#else
+ SSL_library_init (); /* add all algorithms */
+#endif /* OPENSSL_1_1_0 */
+ }
+}
+
+/* SSL open
+ * Accepts: host name
+ * contact service name
+ * contact port number
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_open (char *host,char *service,unsigned long port)
+{
+ TCPSTREAM *stream = tcp_open (host,service,port);
+ return stream ? ssl_start (stream,host,port) : NIL;
+}
+
+
+/* SSL authenticated open
+ * Accepts: host name
+ * service name
+ * returned user name buffer
+ * Returns: SSL stream if success else NIL
+ */
+
+SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf)
+{
+ return NIL; /* don't use this mechanism with SSL */
+}
+
+/* ssl_connect_mthd: returns a context pointer to the connection to
+ * a ssl server
+ */
+const SSL_METHOD *ssl_connect_mthd(int flag)
+{
+#ifdef OPENSSL_1_1_0
+ if(flag & NET_TRYTLS1)
+ return TLS_client_method();
+#else
+ if(flag & NET_TRYTLS1)
+ return TLSv1_client_method();
+#endif /* OPENSSL_1_1_0 */
+#ifdef TLSV1_2
+ else if(flag & NET_TRYTLS1_1)
+ return TLSv1_1_client_method();
+ else if(flag & NET_TRYTLS1_2)
+ return TLSv1_2_client_method();
+#endif /* TLSV1_2 */
+#ifdef OPENSSL_1_1_0
+ else if(flag & NET_TRYDTLS1)
+ return DTLS_client_method();
+#else
+ else if(flag & NET_TRYDTLS1)
+ return DTLSv1_client_method();
+#endif /* OPENSSL_1_1_0 */
+ else return SSLv23_client_method();
+}
+
+/* Start SSL/TLS negotiations
+ * Accepts: open TCP stream of session
+ * user's host name
+ * flags
+ * Returns: SSL stream if success else NIL
+ */
+
+static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags)
+{
+ char *reason,tmp[MAILTMPLEN];
+ sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL);
+ blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ void *data = (*bn) (BLOCK_SENSITIVE,NIL);
+ SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+ sizeof (SSLSTREAM));
+ stream->tcpstream = tstream; /* bind TCP stream */
+ /* do the work */
+ reason = ssl_start_work (stream,host,flags);
+ (*bn) (BLOCK_NONSENSITIVE,data);
+ if (reason) { /* failed? */
+ ssl_close (stream); /* failed to do SSL */
+ stream = NIL; /* no stream returned */
+ switch (*reason) { /* analyze reason */
+ case '*': /* certificate failure */
+ ++reason; /* skip over certificate failure indication */
+ /* pass to error callback */
+ if (sf) (*sf) (host,reason,flags);
+ else { /* no error callback, build error message */
+ sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason);
+ mm_log (tmp,ERROR);
+ }
+ case '\0': /* user answered no to certificate callback */
+ if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */
+ stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+ sizeof (SSLSTREAM));
+ break;
+ default: /* non-certificate failure */
+ if (flags & NET_TRYSSL); /* no error output if tryssl */
+ /* pass to error callback */
+ else if (sf) (*sf) (host,reason,flags);
+ else { /* no error callback, build error message */
+ sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason);
+ mm_log (tmp,ERROR);
+ }
+ break;
+ }
+ }
+ return stream;
+}
+
+/* Start SSL/TLS negotiations worker routine
+ * Accepts: SSL stream
+ * user's host name
+ * flags
+ * Returns: NIL if success, else error reason
+ */
+
+ /* evil but I had no choice */
+static char *ssl_last_error = NIL;
+static char *ssl_last_host = NIL;
+
+static char *ssl_start_work (SSLSTREAM *stream,char *host,unsigned long flags)
+{
+ BIO *bio;
+ X509 *cert;
+ unsigned long sl,tl;
+ char *s,*t,*err,tmp[MAILTMPLEN], buf[256];
+ sslcertificatequery_t scq =
+ (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
+ sslclientcert_t scc =
+ (sslclientcert_t) mail_parameters (NIL,GET_SSLCLIENTCERT,NIL);
+ sslclientkey_t sck =
+ (sslclientkey_t) mail_parameters (NIL,GET_SSLCLIENTKEY,NIL);
+ if (ssl_last_error) fs_give ((void **) &ssl_last_error);
+ ssl_last_host = host;
+ if (!(stream->context = SSL_CTX_new (ssl_connect_mthd(flags))))
+ return "SSL context failed";
+ SSL_CTX_set_options (stream->context,0);
+ /* disable certificate validation? */
+ if (flags & NET_NOVALIDATECERT)
+ SSL_CTX_set_verify (stream->context,SSL_VERIFY_NONE,NIL);
+ else SSL_CTX_set_verify (stream->context,SSL_VERIFY_PEER,ssl_open_verify);
+ /* set default paths to CAs... */
+ SSL_CTX_set_default_verify_paths (stream->context);
+ /* ...unless a non-standard path desired */
+ if ((s = (char *) mail_parameters (NIL,GET_SSLCAPATH,NIL)) != NULL)
+ SSL_CTX_load_verify_locations (stream->context,NIL,s);
+ /* want to send client certificate? */
+ if (scc && (s = (*scc) ()) && (sl = strlen (s))) {
+ if ((cert = PEM_read_bio_X509 (bio = BIO_new_mem_buf (s,sl),NIL,NIL,NIL)) != NULL) {
+ SSL_CTX_use_certificate (stream->context,cert);
+ X509_free (cert);
+ }
+ BIO_free (bio);
+ if (!cert) return "SSL client certificate failed";
+ /* want to supply private key? */
+ if ((t = (sck ? (*sck) () : s)) && (tl = strlen (t))) {
+ EVP_PKEY *key;
+ if ((key = PEM_read_bio_PrivateKey (bio = BIO_new_mem_buf (t,tl),
+ NIL,NIL,"")) != NULL) {
+ SSL_CTX_use_PrivateKey (stream->context,key);
+ EVP_PKEY_free (key);
+ }
+ BIO_free (bio);
+ memset (t,0,tl); /* erase key */
+ }
+ if (s != t) memset (s,0,sl);/* erase certificate if different from key */
+ }
+
+ /* create connection */
+ if (!(stream->con = (SSL *) SSL_new (stream->context)))
+ return "SSL connection failed";
+ bio = BIO_new_socket (stream->tcpstream->tcpsi,BIO_NOCLOSE);
+ SSL_set_bio (stream->con,bio,bio);
+ SSL_set_connect_state (stream->con);
+ if (SSL_in_init (stream->con)) SSL_total_renegotiations (stream->con);
+ /* now negotiate SSL */
+ if (SSL_write (stream->con,"",0) < 0)
+ return ssl_last_error ? ssl_last_error : "SSL negotiation failed";
+ /* need to validate host names? */
+ if (!(flags & NET_NOVALIDATECERT) &&
+ (err = ssl_validate_cert (cert = SSL_get_peer_certificate (stream->con),
+ host))) {
+ /* application callback */
+ X509_NAME_oneline (X509_get_subject_name(cert), buf, sizeof(buf));
+ if (scq) return (*scq) (err,host,cert ? buf : "???") ? NIL : "";
+ /* error message to return via mm_log() */
+ sprintf (tmp,"*%.128s: %.255s",err,cert ? buf : "???");
+ return ssl_last_error = cpystr (tmp);
+ }
+ return NIL;
+}
+
+/* SSL certificate verification callback
+ * Accepts: error flag
+ * X509 context
+ * Returns: error flag
+ */
+
+static int ssl_open_verify (int ok,X509_STORE_CTX *ctx)
+{
+ char *err,cert[256],tmp[MAILTMPLEN];
+ sslcertificatequery_t scq =
+ (sslcertificatequery_t) mail_parameters (NIL,GET_SSLCERTIFICATEQUERY,NIL);
+ if (!ok) { /* in case failure */
+ err = (char *) X509_verify_cert_error_string
+ (X509_STORE_CTX_get_error (ctx));
+ X509_NAME_oneline (X509_get_subject_name
+ (X509_STORE_CTX_get_current_cert (ctx)),cert,255);
+ if (!scq) { /* mm_log() error message if no callback */
+ sprintf (tmp,"*%.128s: %.255s",err,cert);
+ ssl_last_error = cpystr (tmp);
+ }
+ /* ignore error if application says to */
+ else if ((*scq) (err,ssl_last_host,cert)) ok = T;
+ /* application wants punt */
+ else ssl_last_error = cpystr ("");
+ }
+ return ok;
+}
+
+
+/* SSL validate certificate
+ * Accepts: certificate
+ * host to validate against
+ * Returns: NIL if validated, else string of error message
+ */
+
+static char *ssl_validate_cert (X509 *cert,char *host)
+{
+ int i,n;
+ char *s=NULL,*t,*ret;
+ void *ext;
+ GENERAL_NAME *name;
+ X509_NAME *cname;
+ X509_NAME_ENTRY *e;
+ char buf[256];
+ /* make sure have a certificate */
+ if (!cert) ret = "No certificate from server";
+ /* and that it has a name */
+ else if (!(cname = X509_get_subject_name(cert))) ret = "No name in certificate";
+ /* locate CN */
+ else{
+ if((e = X509_NAME_get_entry(cname, X509_NAME_entry_count(cname)-1)) != NULL){
+ X509_NAME_get_text_by_OBJ(cname, X509_NAME_ENTRY_get_object(e), buf, sizeof(buf));
+ s = (char *) buf;
+ }
+ else s = NULL;
+ }
+ if (s != NULL) {
+ /* host name matches pattern? */
+ ret = ssl_compare_hostnames (host,s) ? NIL :
+ "Server name does not match certificate";
+ /* if mismatch, see if in extensions */
+ if (ret && (ext = X509_get_ext_d2i (cert,NID_subject_alt_name,NIL,NIL)) &&
+ (n = sk_GENERAL_NAME_num (ext)))
+ /* older versions of OpenSSL use "ia5" instead of dNSName */
+ for (i = 0; ret && (i < n); i++)
+ if ((name = sk_GENERAL_NAME_value (ext,i)) &&
+ (name->type = GEN_DNS) && (s = name->d.ia5->data) &&
+ ssl_compare_hostnames (host,s)) ret = NIL;
+ }
+ else ret = "Unable to locate common name in certificate";
+ return ret;
+}
+
+/* Case-independent wildcard pattern match
+ * Accepts: base string
+ * pattern string
+ * Returns: T if pattern matches base, else NIL
+ */
+
+static long ssl_compare_hostnames (unsigned char *s,unsigned char *pat)
+{
+ long ret = NIL;
+ switch (*pat) {
+ case '*': /* wildcard */
+ if (pat[1]) { /* there must be a pattern suffix */
+ /* there is, scan base against it */
+ do if (ssl_compare_hostnames (s,pat+1)) ret = LONGT;
+ while (!ret && (*s != '.') && *s++);
+ }
+ break;
+ case '\0': /* end of pattern */
+ if (!*s) ret = LONGT; /* success if base is also at end */
+ break;
+ default: /* non-wildcard, recurse if match */
+ if (!compare_uchar (*pat,*s)) ret = ssl_compare_hostnames (s+1,pat+1);
+ break;
+ }
+ return ret;
+}
+
+/* SSL receive line
+ * Accepts: SSL stream
+ * Returns: text line string or NIL if failure
+ */
+
+char *ssl_getline (SSLSTREAM *stream)
+{
+ unsigned long n,contd;
+ char *ret = ssl_getline_work (stream,&n,&contd);
+ if (ret && contd) { /* got a line needing continuation? */
+ STRINGLIST *stl = mail_newstringlist ();
+ STRINGLIST *stc = stl;
+ do { /* collect additional lines */
+ stc->text.data = (unsigned char *) ret;
+ stc->text.size = n;
+ stc = stc->next = mail_newstringlist ();
+ ret = ssl_getline_work (stream,&n,&contd);
+ } while (ret && contd);
+ if (ret) { /* stash final part of line on list */
+ stc->text.data = (unsigned char *) ret;
+ stc->text.size = n;
+ /* determine how large a buffer we need */
+ for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
+ ret = fs_get (n + 1); /* copy parts into buffer */
+ for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
+ memcpy (ret + n,stc->text.data,stc->text.size);
+ ret[n] = '\0';
+ }
+ mail_free_stringlist (&stl);/* either way, done with list */
+ }
+ return ret;
+}
+
+/* SSL receive line or partial line
+ * Accepts: SSL stream
+ * pointer to return size
+ * pointer to return continuation flag
+ * Returns: text line string, size and continuation flag, or NIL if failure
+ */
+
+static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size,
+ long *contd)
+{
+ unsigned long n;
+ char *s,*ret,c,d;
+ *contd = NIL; /* assume no continuation */
+ /* make sure have data */
+ if (!ssl_getdata (stream)) return NIL;
+ for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
+ d = *stream->iptr++; /* slurp another character */
+ if ((c == '\015') && (d == '\012')) {
+ ret = (char *) fs_get (n--);
+ memcpy (ret,s,*size = n); /* copy into a free storage string */
+ ret[n] = '\0'; /* tie off string with null */
+ return ret;
+ }
+ }
+ /* copy partial string from buffer */
+ memcpy ((ret = (char *) fs_get (n)),s,*size = n);
+ /* get more data from the net */
+ if (!ssl_getdata (stream)) fs_give ((void **) &ret);
+ /* special case of newline broken by buffer */
+ else if ((c == '\015') && (*stream->iptr == '\012')) {
+ stream->iptr++; /* eat the line feed */
+ stream->ictr--;
+ ret[*size = --n] = '\0'; /* tie off string with null */
+ }
+ else *contd = LONGT; /* continuation needed */
+ return ret;
+}
+
+/* SSL receive buffer
+ * Accepts: SSL stream
+ * size in bytes
+ * buffer to read into
+ * Returns: T if success, NIL otherwise
+ */
+
+long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer)
+{
+ unsigned long n;
+ while (size > 0) { /* until request satisfied */
+ if (!ssl_getdata (stream)) return NIL;
+ n = min (size,stream->ictr);/* number of bytes to transfer */
+ /* do the copy */
+ memcpy (buffer,stream->iptr,n);
+ buffer += n; /* update pointer */
+ stream->iptr += n;
+ size -= n; /* update # of bytes to do */
+ stream->ictr -= n;
+ }
+ buffer[0] = '\0'; /* tie off string */
+ return T;
+}
+/* SSL receive data
+ * Accepts: TCP/IP stream
+ * Returns: T if success, NIL otherwise
+ */
+
+#ifdef FD_SETSIZE
+#undef FD_SETSIZE
+#endif /* FD_SETSIZE */
+#define FD_SETSIZE 16384
+
+long ssl_getdata (SSLSTREAM *stream)
+{
+ int i,sock;
+ fd_set fds,efds;
+ struct timeval tmo;
+ tcptimeout_t tmoh = (tcptimeout_t) mail_parameters (NIL,GET_TIMEOUT,NIL);
+ long ttmo_read = (long) mail_parameters (NIL,GET_READTIMEOUT,NIL);
+ time_t t = time (0);
+ blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ if (!stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return NIL;
+ /* tcp_unix should have prevented this */
+ if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");
+ (*bn) (BLOCK_TCPREAD,NIL);
+ while (stream->ictr < 1) { /* if nothing in the buffer */
+ time_t tl = time (0); /* start of request */
+ time_t now = tl;
+ int ti = ttmo_read ? now + ttmo_read : 0;
+ if (SSL_pending (stream->con)) i = 1;
+ else {
+ if (tcpdebug) mm_log ("Reading SSL data",TCPDEBUG);
+ tmo.tv_usec = 0;
+ FD_ZERO (&fds); /* initialize selection vector */
+ FD_ZERO (&efds); /* handle errors too */
+ FD_SET (sock,&fds); /* set bit in selection vector */
+ FD_SET (sock,&efds); /* set bit in error selection vector */
+ errno = NIL; /* block and read */
+ do { /* block under timeout */
+ tmo.tv_sec = ti ? ti - now : 0;
+ i = select (sock+1,&fds,0,&efds,ti ? &tmo : 0);
+ now = time (0); /* fake timeout if interrupt & time expired */
+ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0;
+ } while ((i < 0) && (errno == EINTR));
+ }
+ if (i) { /* non-timeout result from select? */
+ errno = 0; /* just in case */
+ if (i > 0) /* read what we can */
+ while (((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) < 0) &&
+ ((errno == EINTR) ||
+ (SSL_get_error (stream->con,i) == SSL_ERROR_WANT_READ)));
+ if (i <= 0) { /* error seen? */
+ if (tcpdebug) {
+ char *s,tmp[MAILTMPLEN];
+ if (i) sprintf (s = tmp,"SSL data read I/O error %d SSL error %d",
+ errno,SSL_get_error (stream->con,i));
+ else s = "SSL data read end of file";
+ mm_log (s,TCPDEBUG);
+ }
+ return ssl_abort (stream);
+ }
+ stream->iptr = stream->ibuf;/* point at TCP buffer */
+ stream->ictr = i; /* set new byte count */
+ if (tcpdebug) mm_log ("Successfully read SSL data",TCPDEBUG);
+ }
+ /* timeout, punt unless told not to */
+ else if (!tmoh || !(*tmoh) (now - t,now - tl, stream->tcpstream->host)) {
+ if (tcpdebug) mm_log ("SSL data read timeout",TCPDEBUG);
+ return ssl_abort (stream);
+ }
+ }
+ (*bn) (BLOCK_NONE,NIL);
+ return T;
+}
+
+/* SSL send string as record
+ * Accepts: SSL stream
+ * string pointer
+ * Returns: T if success else NIL
+ */
+
+long ssl_soutr (SSLSTREAM *stream,char *string)
+{
+ return ssl_sout (stream,string,(unsigned long) strlen (string));
+}
+
+
+/* SSL send string
+ * Accepts: SSL stream
+ * string pointer
+ * byte count
+ * Returns: T if success else NIL
+ */
+
+long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size)
+{
+ long i;
+ blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ if (!stream->con) return NIL;
+ (*bn) (BLOCK_TCPWRITE,NIL);
+ if (tcpdebug) mm_log ("Writing to SSL",TCPDEBUG);
+ /* until request satisfied */
+ for (i = 0; size > 0; string += i,size -= i)
+ /* write as much as we can */
+ if ((i = SSL_write (stream->con,string,(int) min (SSLBUFLEN,size))) < 0) {
+ if (tcpdebug) {
+ char tmp[MAILTMPLEN];
+ sprintf (tmp,"SSL data write I/O error %d SSL error %d",
+ errno,SSL_get_error (stream->con,i));
+ mm_log (tmp,TCPDEBUG);
+ }
+ return ssl_abort (stream);/* write failed */
+ }
+ if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
+ (*bn) (BLOCK_NONE,NIL);
+ return LONGT; /* all done */
+}
+
+/* SSL close
+ * Accepts: SSL stream
+ */
+
+void ssl_close (SSLSTREAM *stream)
+{
+ ssl_abort (stream); /* nuke the stream */
+ fs_give ((void **) &stream); /* flush the stream */
+}
+
+
+/* SSL abort stream
+ * Accepts: SSL stream
+ * Returns: NIL always
+ */
+
+static long ssl_abort (SSLSTREAM *stream)
+{
+ blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
+ if (stream->con) { /* close SSL connection */
+ SSL_shutdown (stream->con);
+ SSL_free (stream->con);
+ stream->con = NIL;
+ }
+ if (stream->context) { /* clean up context */
+ SSL_CTX_free (stream->context);
+ stream->context = NIL;
+ }
+ if (stream->tcpstream) { /* close TCP stream */
+ tcp_close (stream->tcpstream);
+ stream->tcpstream = NIL;
+ }
+ (*bn) (BLOCK_NONE,NIL);
+ return NIL;
+}
+
+/* SSL get host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_host (SSLSTREAM *stream)
+{
+ return stream ? tcp_host (stream->tcpstream) : "UNKNOWN";
+}
+
+
+/* SSL get remote host name
+ * Accepts: SSL stream
+ * Returns: host name for this stream
+ */
+
+char *ssl_remotehost (SSLSTREAM *stream)
+{
+ return tcp_remotehost (stream->tcpstream);
+}
+
+
+/* SSL return port for this stream
+ * Accepts: SSL stream
+ * Returns: port number for this stream
+ */
+
+unsigned long ssl_port (SSLSTREAM *stream)
+{
+ return tcp_port (stream->tcpstream);
+}
+
+
+/* SSL get local host name
+ * Accepts: SSL stream
+ * Returns: local host name
+ */
+
+char *ssl_localhost (SSLSTREAM *stream)
+{
+ return tcp_localhost (stream->tcpstream);
+}
+
+#ifdef SSL_CERT_DIRECTORY
+#undef SSL_CERT_DIRECTORY
+#endif /* SSL_CERT_DIRECTORY */
+#define SSL_CERT_DIRECTORY "C:\\\\libressl\\ssl\\certs"
+
+#ifdef SSL_KEY_DIRECTORY
+#undef SSL_KEY_DIRECTORY
+#endif /* SSL_KEY_DIRECTORY */
+#define SSL_KEY_DIRECTORY "C:\\\\libressl\\ssl\\private"
+
+
+/* Start TLS
+ * Accepts: /etc/services service name
+ * Returns: cpystr'd error string if TLS failed, else NIL for success
+ */
+char *ssl_start_tls (char *server)
+{
+ char tmp[MAILTMPLEN];
+ struct stat sbuf;
+ if (sslstdio) return cpystr ("Already in an SSL session");
+ if (start_tls) return cpystr ("TLS already started");
+ if (server) { /* build specific certificate/key file name */
+ sprintf (tmp,"%s\\%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());
+ if (stat (tmp,&sbuf)) { /* use non-specific name if no specific file */
+ sprintf (tmp,"%s\\%s.pem",SSL_CERT_DIRECTORY,server);
+ if (stat (tmp,&sbuf)) return cpystr ("Server certificate not installed");
+ }
+ start_tls = server; /* switch to STARTTLS mode */
+ }
+ return NIL;
+}
+
+/* Init server for SSL
+ * Accepts: server name
+ */
+
+void ssl_server_init (char *server)
+{
+ char cert[MAILTMPLEN],key[MAILTMPLEN];
+ unsigned long i;
+ struct stat sbuf;
+ SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0,
+ sizeof (SSLSTREAM));
+ ssl_onceonlyinit (); /* make sure algorithms added */
+#ifdef OPENSSL_1_1_0
+ OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
+ OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS|OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
+#else
+ ERR_load_crypto_strings ();
+ SSL_load_error_strings ();
+#endif /* OPENSSL_1_1_0 */
+ /* build specific certificate/key file names */
+ sprintf (cert,"%s\\%s-%s.pem",SSL_CERT_DIRECTORY,server,tcp_serveraddr ());
+ sprintf (key,"%s\\%s-%s.pem",SSL_KEY_DIRECTORY,server,tcp_serveraddr ());
+ /* use non-specific name if no specific cert */
+ if (stat (cert,&sbuf)) sprintf (cert,"%s\\%s.pem",SSL_CERT_DIRECTORY,server);
+ if (stat (key,&sbuf)) { /* use non-specific name if no specific key */
+ sprintf (key,"%s\\%s.pem",SSL_KEY_DIRECTORY,server);
+ /* use cert file as fallback for key */
+ if (stat (key,&sbuf)) strcpy (key,cert);
+ }
+ /* create context */
+#ifdef OPENSSL_1_1_0
+ if (!(stream->context = SSL_CTX_new (start_tls ?
+ TLS_server_method () :
+ SSLv23_server_method ())))
+#else
+ if (!(stream->context = SSL_CTX_new (start_tls ?
+ TLSv1_server_method () :
+ SSLv23_server_method ())))
+#endif /* OPENSSL_1_1_0 */
+ syslog (LOG_ALERT,"Unable to create SSL context, host=%.80s",
+ tcp_clienthost ());
+ else { /* set context options */
+ SSL_CTX_set_options (stream->context,SSL_OP_ALL);
+ /* set cipher list */
+ if (!SSL_CTX_set_cipher_list (stream->context,SSLCIPHERLIST))
+ syslog (LOG_ALERT,"Unable to set cipher list %.80s, host=%.80s",
+ SSLCIPHERLIST,tcp_clienthost ());
+ /* load certificate */
+ else if (!SSL_CTX_use_certificate_chain_file (stream->context,cert))
+ syslog (LOG_ALERT,"Unable to load certificate from %.80s, host=%.80s",
+ cert,tcp_clienthost ());
+ /* load key */
+ else if (!(SSL_CTX_use_RSAPrivateKey_file (stream->context,key,
+ SSL_FILETYPE_PEM)))
+ syslog (LOG_ALERT,"Unable to load private key from %.80s, host=%.80s",
+ key,tcp_clienthost ());
+
+ else { /* generate key if needed */
+#ifdef OPENSSL_1_1_0
+ if (0)
+ ssl_genkey(stream->context, 0, 0);
+#else
+ if (SSL_CTX_need_tmp_RSA (stream->context))
+ SSL_CTX_set_tmp_rsa_callback (stream->context,ssl_genkey);
+#endif /* OPENSSL_1_1_0 */
+ /* create new SSL connection */
+ if (!(stream->con = SSL_new (stream->context)))
+ syslog (LOG_ALERT,"Unable to create SSL connection, host=%.80s",
+ tcp_clienthost ());
+ else { /* set file descriptor */
+ SSL_set_fd (stream->con,0);
+ /* all OK if accepted */
+ if (SSL_accept (stream->con) < 0)
+ syslog (LOG_INFO,"Unable to accept SSL connection, host=%.80s",
+ tcp_clienthost ());
+ else { /* server set up */
+ sslstdio = (SSLSTDIOSTREAM *)
+ memset (fs_get (sizeof(SSLSTDIOSTREAM)),0,sizeof (SSLSTDIOSTREAM));
+ sslstdio->sslstream = stream;
+ /* available space in output buffer */
+ sslstdio->octr = SSLBUFLEN;
+ /* current output buffer pointer */
+ sslstdio->optr = sslstdio->obuf;
+ /* allow plaintext if disable value was 2 */
+ if ((long) mail_parameters (NIL,GET_DISABLEPLAINTEXT,NIL) > 1)
+ mail_parameters (NIL,SET_DISABLEPLAINTEXT,NIL);
+ /* unhide PLAIN SASL authenticator */
+ mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"PLAIN");
+ mail_parameters (NIL,UNHIDE_AUTHENTICATOR,"LOGIN");
+ return;
+ }
+ }
+ }
+ }
+ while ((i = ERR_get_error ()) != 0L) /* SSL failure */
+ syslog (LOG_ERR,"SSL error status: %.80s",ERR_error_string (i,NIL));
+ ssl_close (stream); /* punt stream */
+ exit (1); /* punt this program too */
+}
+
+/* Generate one-time key for server
+ * Accepts: SSL connection
+ * export flag
+ * keylength
+ * Returns: generated key, always
+ */
+
+static RSA *ssl_genkey (SSL_CTX_TYPE *con,int export,int keylength)
+{
+ unsigned long i;
+ static RSA *key = NIL;
+ if (!key) { /* if don't have a key already */
+ /* generate key */
+#ifdef OPENSSL_1_1_0
+ BIGNUM *e = BN_new();
+ if (!RSA_generate_key_ex (key, export ? keylength : 1024, e,NIL)) {
+#else
+ if (!(key = RSA_generate_key (export ? keylength : 1024,RSA_F4,NIL,NIL))) {
+#endif /* OPENSSL_1_1_0 */
+ syslog (LOG_ALERT,"Unable to generate temp key, host=%.80s",
+ tcp_clienthost ());
+ while ((i = ERR_get_error ()) != 0L)
+ syslog (LOG_ALERT,"SSL error status: %s",ERR_error_string (i,NIL));
+ exit (1);
+ }
+#ifdef OPENSSL_1_1_0
+ BN_free(e);
+ e = NULL;
+#endif /* OPENSSL_1_1_0 */
+ }
+ return key;
+}
+
+/* Wait for stdin input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long ssl_server_input_wait (long seconds)
+{
+ int i,sock;
+ fd_set fds,efd;
+ struct timeval tmo;
+ SSLSTREAM *stream;
+ if (!sslstdio) return server_input_wait (seconds);
+ /* input available in buffer */
+ if (((stream = sslstdio->sslstream)->ictr > 0) ||
+ !stream->con || ((sock = SSL_get_fd (stream->con)) < 0)) return LONGT;
+ /* sock ought to be 0 always */
+ if (sock >= FD_SETSIZE) fatal ("unselectable socket in ssl_getdata()");
+ /* input available from SSL */
+ if (SSL_pending (stream->con) &&
+ ((i = SSL_read (stream->con,stream->ibuf,SSLBUFLEN)) > 0)) {
+ stream->iptr = stream->ibuf;/* point at TCP buffer */
+ stream->ictr = i; /* set new byte count */
+ return LONGT;
+ }
+ FD_ZERO (&fds); /* initialize selection vector */
+ FD_ZERO (&efd); /* initialize selection vector */
+ FD_SET (sock,&fds); /* set bit in selection vector */
+ FD_SET (sock,&efd); /* set bit in selection vector */
+ tmo.tv_sec = seconds; tmo.tv_usec = 0;
+ /* see if input available from the socket */
+ return select (sock+1,&fds,0,&efd,&tmo) ? LONGT : NIL;
+}
+
+#include "sslstdio.c"
+#else /* ENABLE_WINDOWS_LIBRESSL */
#define SECURITY_WIN32
#include <sspi.h>
#include <schannel.h>
@@ -717,3 +1627,5 @@ char *ssl_localhost (SSLSTREAM *stream)
}
#include "ssl_none.c" /* currently no server support */
+
+#endif /* ENABLE_WINDOWS_LIBRESSL */
diff --git a/imap/src/osdep/nt/ssl_old.c b/imap/src/osdep/nt/ssl_old.c
index 5d00b48b..73a360df 100644
--- a/imap/src/osdep/nt/ssl_old.c
+++ b/imap/src/osdep/nt/ssl_old.c
@@ -25,12 +25,8 @@
#define SECURITY_WIN32
#include <sspi.h>
-#if(_WIN32_WINNT < 0x0400)
-typedef unsigned int ALG_ID;
-#else
#include <wincrypt.h>
ALGIDDEF
-#endif
#include <schnlsp.h>
#include <issperr.h>
diff --git a/imap/src/osdep/nt/sslstdio.c b/imap/src/osdep/nt/sslstdio.c
new file mode 100644
index 00000000..3d3b1e06
--- /dev/null
+++ b/imap/src/osdep/nt/sslstdio.c
@@ -0,0 +1,181 @@
+/* ========================================================================
+ * Copyright 2008 Mark Crispin
+ * ========================================================================
+ */
+
+/*
+ * Program: SSL standard I/O routines for server use
+ *
+ * Author: Mark Crispin
+ *
+ * Date: 22 September 1998
+ * Last Edited: 19 November 2008
+ *
+ * Previous versions of this file were
+ *
+ * Copyright 1988-2006 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ */
+
+/* Get character
+ * Returns: character or EOF
+ */
+
+int PBIN (void)
+{
+ if (!sslstdio) {
+ int ret;
+ do {
+ clearerr (stdin);
+ ret = getchar ();
+ } while ((ret == EOF) && !feof (stdin) && ferror (stdin) &&
+ (errno == EINTR));
+ return ret;
+ }
+ if (!ssl_getdata (sslstdio->sslstream)) return EOF;
+ /* one last byte available */
+ sslstdio->sslstream->ictr--;
+ return (int) *(sslstdio->sslstream->iptr)++;
+}
+
+
+/* Get string
+ * Accepts: destination string pointer
+ * number of bytes available
+ * Returns: destination string pointer or NIL if EOF
+ */
+
+char *PSIN (char *s,int n)
+{
+ int i,c;
+ if (start_tls) { /* doing a start TLS? */
+ ssl_server_init (start_tls);/* enter the mode */
+ start_tls = NIL; /* don't do this again */
+ }
+ if (!sslstdio) {
+ char *ret;
+ do {
+ clearerr (stdin);
+ ret = fgets (s,n,stdin);
+ } while (!ret && !feof (stdin) && ferror (stdin) && (errno == EINTR));
+ return ret;
+ }
+ for (i = c = 0, n-- ; (c != '\n') && (i < n); sslstdio->sslstream->ictr--) {
+ if ((sslstdio->sslstream->ictr <= 0) && !ssl_getdata (sslstdio->sslstream))
+ return NIL; /* read error */
+ c = s[i++] = *(sslstdio->sslstream->iptr)++;
+ }
+ s[i] = '\0'; /* tie off string */
+ return s;
+}
+
+
+/* Get record
+ * Accepts: destination string pointer
+ * number of bytes to read
+ * Returns: T if success, NIL otherwise
+ */
+
+long PSINR (char *s,unsigned long n)
+{
+ unsigned long i;
+ if (start_tls) { /* doing a start TLS? */
+ ssl_server_init (start_tls);/* enter the mode */
+ start_tls = NIL; /* don't do this again */
+ }
+ if (sslstdio) return ssl_getbuffer (sslstdio->sslstream,n,s);
+ /* non-SSL case */
+ while (n && ((i = fread (s,1,n,stdin)) || (errno == EINTR))) s += i,n -= i;
+ return n ? NIL : LONGT;
+}
+
+
+/* Wait for stdin input
+ * Accepts: timeout in seconds
+ * Returns: T if have input on stdin, else NIL
+ */
+
+long INWAIT (long seconds)
+{
+ return (sslstdio ? ssl_server_input_wait : server_input_wait) (seconds);
+}
+
+/* Put character
+ * Accepts: character
+ * Returns: character written or EOF
+ */
+
+int PBOUT (int c)
+{
+ if (!sslstdio) return putchar (c);
+ /* flush buffer if full */
+ if (!sslstdio->octr && PFLUSH ()) return EOF;
+ sslstdio->octr--; /* count down one character */
+ *sslstdio->optr++ = c; /* write character */
+ return c; /* return that character */
+}
+
+
+/* Put string
+ * Accepts: destination string pointer
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUT (char *s)
+{
+ if (!sslstdio) return fputs (s,stdout);
+ while (*s) { /* flush buffer if full */
+ if (!sslstdio->octr && PFLUSH ()) return EOF;
+ *sslstdio->optr++ = *s++; /* write one more character */
+ sslstdio->octr--; /* count down one character */
+ }
+ return 0; /* success */
+}
+
+/* Put record
+ * Accepts: source sized text
+ * Returns: 0 or EOF if error
+ */
+
+int PSOUTR (SIZEDTEXT *s)
+{
+ unsigned char *t = s->data;
+ unsigned long i = s->size;
+ unsigned long j;
+ if (sslstdio) while (i) { /* until request satisfied */
+ /* flush buffer if full */
+ if (!sslstdio->octr && PFLUSH ()) break;
+ /* blat as big a chucnk as we can */
+ memcpy (sslstdio->optr,t,j = min (i,sslstdio->octr));
+ sslstdio->optr += j; /* account for chunk */
+ sslstdio->octr -= j;
+ t += j;
+ i -= j;
+ }
+ else while (i && ((j = fwrite (t,1,i,stdout)) || (errno == EINTR)))
+ t += j,i -= j;
+ return i ? EOF : NIL;
+}
+
+
+/* Flush output
+ * Returns: 0 or EOF if error
+ */
+
+int PFLUSH (void)
+{
+ if (!sslstdio) return fflush (stdout);
+ /* force out buffer */
+ if (!ssl_sout (sslstdio->sslstream,sslstdio->obuf,
+ SSLBUFLEN - sslstdio->octr)) return EOF;
+ /* renew output buffer */
+ sslstdio->optr = sslstdio->obuf;
+ sslstdio->octr = SSLBUFLEN;
+ return 0; /* success */
+}