]> code.citadel.org Git - citadel.git/commitdiff
Remove preprocessor tests for OpenSSL. It's a requirement. master
authorArt Cancro <ajc@citadel.org>
Wed, 22 May 2024 03:24:53 +0000 (03:24 +0000)
committerArt Cancro <ajc@citadel.org>
Wed, 22 May 2024 03:24:53 +0000 (03:24 +0000)
36 files changed:
citadel/configure
citadel/dumploadtest.sh
citadel/server/citadel_defs.h
citadel/server/context.c
citadel/server/context.h
citadel/server/control.c
citadel/server/modules/autocompletion/serv_autocompletion.c
citadel/server/modules/bio/serv_bio.c
citadel/server/modules/crypto/serv_crypto.c
citadel/server/modules/crypto/serv_crypto.h
citadel/server/modules/ctdlproto/serv_ctdlproto.c
citadel/server/modules/expire/expire_policy.c
citadel/server/modules/expire/serv_expire.c
citadel/server/modules/imap/serv_imap.c
citadel/server/modules/inetcfg/serv_inetcfg.c
citadel/server/modules/listdeliver/serv_listdeliver.c
citadel/server/modules/nntp/serv_nntp.c
citadel/server/modules/pop3/serv_pop3.c
citadel/server/modules/smtp/dkim.c
citadel/server/modules/smtp/dkim_bindings.c [new file with mode: 0644]
citadel/server/modules/smtp/serv_smtp.c
citadel/server/modules/smtp/serv_smtpclient.c
citadel/server/modules/smtp/smtp_util.h
citadel/server/modules/xmpp/serv_xmpp.c
citadel/server/modules/xmpp/xmpp_queue.c
citadel/server/msgbase.c
citadel/server/serv_extensions.c
citadel/server/server.h
citadel/server/sysdep.c
citadel/tests/dkimtester/README.md
citadel/tests/dkimtester/dkimtester.c
citadel/utils/ctdlload.c
libcitadel/lib/libcitadel.h
release_version.txt
textclient/textclient.h
webcit/webcit.h

index ad136e3ac1b2ed79061c1688d1e648c2efc7e43b..381a2544c14090f781953154938489a6bf6ab279 100755 (executable)
@@ -74,7 +74,6 @@ int main(int argc, char **argv) {
 }
 !
 $CC $CFLAGS $CPPFLAGS $tempcc -o $tempfile $LDFLAGS -lssl -lcrypto && $tempfile >/dev/null 2>&1 && {
-       CFLAGS=${CFLAGS}' -DHAVE_OPENSSL'
        LDFLAGS=${LDFLAGS}' -lssl -lcrypto -lz'
 } || {
        echo Citadel Server requires OpenSSL which is not present.
index 7179f399180e853ec0f8a55db8c27197b979139c..835986ec79463d7cc3e2af079a5837991d8bfb18 100755 (executable)
@@ -1,20 +1,31 @@
 #!/bin/bash
 
-
 # This script dumps the database, deletes the database, loads the database, dumps it again...
 # ...and then compares the two dumps to see if we have full fidelity between them.
 #
 # Did you read that correctly?  Yes, it will DELETE your database.  So don't run this.
 
-exit 0         # In fact, here's an exit statement you must delete before you can even run it.
+
+if [ "${YES_DELETE_MY_DATABASE}" != '' ] ; then
+       echo Ah, I see you have set YES_DELETE_MY_DATABASE to a non-empty value.
+       echo The dump and load test will now proceed.
+else
+       echo 'This script dumps the database, deletes the database, loads the database, dumps it again...'
+       echo '...and then compares the two dumps to see if we have full fidelity between them.'
+       echo 'Did you read that correctly?  Yes, it will DELETE your database.'
+       echo 'If this is really what you want, set the environment variable YES_DELETE_MY_DATABASE'
+       echo 'to a non-empty value, and run it again.'
+       exit 0
+fi
 
 ps ax | grep citserver | grep -v grep >/dev/null 2>/dev/null && {
-       echo dont do this while the server is running
+       echo Do not do this while the server is running.
        exit 1
 }
 
 ./ctdldump -y >dump.dat
 first=$(md5sum dump.dat | awk ' { print $1 } ' )
+
 rm -fv data/*
 ./ctdlload -y <dump.dat
 ./ctdldump -y >dump.dat
index 4ee0cd060f18792fdc85f9cf48abe7d6fc6bbaf7..0ed7a5a630fd7418a1d589f46107fb7407ce0795 100644 (file)
@@ -21,7 +21,7 @@
 #include "typesize.h"
 #include "ipcdef.h"
 
-#define REV_LEVEL 999          // This version
+#define REV_LEVEL 1000         // This version
 #define REV_MIN                591     // Oldest compatible database
 #define EXPORT_REV_MIN 931     // Oldest compatible export files
 #define LIBCITADEL_MIN 951     // Minimum required version of libcitadel
index 6415ce12abd290ea52e8d846fd4dc252701195a3..81709b5b59e81ee0056bb9301df2f149e1953e33 100644 (file)
@@ -318,10 +318,7 @@ CitContext *CloneContext(CitContext *CloneMe) {
        me->MigrateBuf = NULL;
        me->sMigrateBuf = NULL;
        me->redirect_buffer = NULL;
-#ifdef HAVE_OPENSSL
        me->ssl = NULL;
-#endif
-
        me->download_fp = NULL;
        me->upload_fp = NULL;
        me->ma = NULL;
index d28dff7a7f59dadf481957b5bf65d9c8947c7245..1b207b64527b9a5349ea812ec26fe641f79c0370 100644 (file)
@@ -56,10 +56,8 @@ struct CitContext {
        // Redirect this session's output to a memory buffer?
        StrBuf *redirect_buffer;                // the buffer
        StrBuf *StatusMessage;
-#ifdef HAVE_OPENSSL
        SSL *ssl;
        int redirect_ssl;
-#endif
 
        char curr_user[USERNAME_SIZE];  // name of current user
        int logged_in;          // logged in?
index b3df0ae3fbf97dd78beddf0302c493a67926413a..9be3addeb75cd95d36e9116308711f9360f86c94 100644 (file)
@@ -636,7 +636,7 @@ void cmd_conf(char *argbuf) {
                        char *valbuf = malloc(bytes + 1);
                        cprintf("%d %d\n", SEND_BINARY, bytes);
                        client_read(valbuf, bytes);
-                       valbuf[bytes+1] = 0;
+                       valbuf[bytes] = 0;
                        CtdlSetConfigStr(confname, valbuf);
                        free(valbuf);
                }
index 413bf472b739920999baeff92ae7e3768206cecb..822e01aac6ec869e7fa6a478272071f5afb01ca9 100644 (file)
@@ -1,9 +1,6 @@
 // Autocompletion of email recipients, etc.
-//
 // Copyright (c) 1987-2023 by the citadel.org team
-//
-// This program is open source software.  Use, duplication, or disclosure
-// is subject to the terms of the GNU General Public License version 3.
+// This program is open source software.  Use, duplication, or disclosure is subject to the GNU General Public License version 3.
 
 #include "../../ctdl_module.h"
 #include "serv_autocompletion.h"
index 8be817ae687dbcdf7f999b1ad7aee2290347747d..6ff861551dd0cbbba682c10023ea51ec6f30e894 100644 (file)
@@ -3,9 +3,7 @@
 //
 // Copyright (c) 1987-2022 by the citadel.org team
 //
-// This program is open source software.  Use, duplication, or disclosure
-// is subject to the terms of the GNU General Public License, version 3.
-// The program is distributed without any warranty, expressed or implied.
+// This program is open source software.  Use, duplication, or disclosure is subject to the GNU General Public License, version 3.
 
 #include <sys/types.h>
 #include <sys/stat.h>
index 5d41fa27c924817cb29cc58c517417ba7daf996c..541479af14c73f4848cc789b46fd27a80f30470d 100644 (file)
@@ -7,11 +7,9 @@
 #include <sys/types.h>
 #include "../../sysdep.h"
 
-#ifdef HAVE_OPENSSL
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/rand.h>
-#endif
 
 #include <time.h>
 
@@ -32,8 +30,6 @@
 #include "../../config.h"
 #include "../../ctdl_module.h"
 
-#ifdef HAVE_OPENSSL
-
 SSL_CTX *ssl_ctx = NULL;               // This SSL context is used for all sessions.
 char *ssl_cipher_list = CIT_CIPHERS;
 
@@ -609,5 +605,3 @@ void endtls(void) {
        CC->ssl = NULL;
        CC->redirect_ssl = 0;
 }
-
-#endif // HAVE_OPENSSL
index b5ee85d53bd970058333422d20ce73e017134254..4ef8033d531d393b5220858171f9a48198a9e2b8 100644 (file)
@@ -7,7 +7,6 @@
 // Which ciphers will be offered; see https://www.openssl.org/docs/manmaster/man1/ciphers.html
 #define CIT_CIPHERS    "ALL:RC4+RSA:+SSLv2:+TLSv1:!MD5:@STRENGTH"
 
-#ifdef HAVE_OPENSSL
 #define OPENSSL_NO_KRB5                /* work around redhat b0rken ssl headers */
 void init_ssl(void);
 void client_write_ssl (const char *buf, int nbytes);
@@ -19,5 +18,3 @@ void cmd_gtls(char *params);
 void endtls(void);
 void CtdlStartTLS(char *ok_response, char *nosup_response, char *error_response);
 extern SSL_CTX *ssl_ctx;  
-
-#endif
index ae267b596fc5645f1a662b159c87066f32a803c3..d5e7ffe61b0c1bf8a634a9d2acec5fe7f2207f43 100644 (file)
@@ -1,72 +1,56 @@
-/* 
- * Citadel protocol main dispatcher
- *
- * Copyright (c) 1987-2017 by the citadel.org team
- *
- * This program is open source software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
+// Citadel protocol main dispatcher
+// Copyright (c) 1987-2024 by the citadel.org team
+// This program is open source software.  Use, duplication, or disclosure are subject to the GNU General Public License v3.
 
 #include <stdio.h>
 #include <libcitadel.h>
-
 #include "../../citserver.h"
 #include "../../ctdl_module.h"
 #include "../../config.h"
-/*
- * This loop recognizes all server commands.
- */
+
+// This loop recognizes all server commands.
 void do_command_loop(void) {
-       struct CitContext *CCC = CC;
        char cmdbuf[SIZ];
        
-       time(&CCC->lastcmd);
-       memset(cmdbuf, 0, sizeof cmdbuf); /* Clear it, just in case */
+       time(&CC->lastcmd);
+       memset(cmdbuf, 0, sizeof cmdbuf); // Clear it, just in case
        if (client_getln(cmdbuf, sizeof cmdbuf) < 1) {
                syslog(LOG_INFO, "Citadel client disconnected: ending session.");
-               CCC->kill_me = KILLME_CLIENT_DISCONNECTED;
+               CC->kill_me = KILLME_CLIENT_DISCONNECTED;
                return;
        }
 
-       /* Log the server command, but don't show passwords... */
-       if ( (strncasecmp(cmdbuf, "PASS", 4)) && (strncasecmp(cmdbuf, "SETP", 4)) ) {
-               syslog(LOG_DEBUG, "[%s(%ld)] %s",
-                       CCC->curr_user, CCC->user.usernum, cmdbuf
-               );
+       // Log the server command, but don't show passwords...
+       if (    (strncasecmp(cmdbuf, "PASS", 4))
+               && (strncasecmp(cmdbuf, "SETP", 4))
+       ) {
+               syslog(LOG_DEBUG, "[%s(%ld)] %s", CC->curr_user, CC->user.usernum, cmdbuf);
        }
        else {
-               syslog(LOG_DEBUG, "[%s(%ld)] <password command hidden from log>",
-                           CCC->curr_user, CCC->user.usernum
-               );
+               syslog(LOG_DEBUG, "[%s(%ld)] <password command hidden from log>", CC->curr_user, CC->user.usernum);
        }
 
        buffer_output();
 
-       /*
-        * Let other clients see the last command we executed, and
-        * update the idle time, but not NOOP, QNOP, PEXP, GEXP, RWHO, or TIME.
-        */
-       if ( (strncasecmp(cmdbuf, "NOOP", 4))
-          && (strncasecmp(cmdbuf, "QNOP", 4))
-          && (strncasecmp(cmdbuf, "PEXP", 4))
-          && (strncasecmp(cmdbuf, "GEXP", 4))
-          && (strncasecmp(cmdbuf, "RWHO", 4))
-          && (strncasecmp(cmdbuf, "TIME", 4)) ) {
-               strcpy(CCC->lastcmdname, "    ");
-               safestrncpy(CCC->lastcmdname, cmdbuf, sizeof(CCC->lastcmdname));
-               time(&CCC->lastidle);
+       // Let other clients see the last command we executed, and
+       // update the idle time, but not NOOP, QNOP, PEXP, GEXP, RWHO, or TIME.
+       if (    (strncasecmp(cmdbuf, "NOOP", 4))
+               && (strncasecmp(cmdbuf, "QNOP", 4))
+               && (strncasecmp(cmdbuf, "PEXP", 4))
+               && (strncasecmp(cmdbuf, "GEXP", 4))
+               && (strncasecmp(cmdbuf, "RWHO", 4))
+               && (strncasecmp(cmdbuf, "TIME", 4))
+       ) {
+               strcpy(CC->lastcmdname, "    ");
+               safestrncpy(CC->lastcmdname, cmdbuf, sizeof(CC->lastcmdname));
+               time(&CC->lastidle);
        }
        
-       if ((strncasecmp(cmdbuf, "ENT0", 4))
-          && (strncasecmp(cmdbuf, "MESG", 4))
-          && (strncasecmp(cmdbuf, "MSGS", 4)))
-       {
-          CCC->cs_flags &= ~CS_POSTING;
+       if (    (strncasecmp(cmdbuf, "ENT0", 4))
+               && (strncasecmp(cmdbuf, "MESG", 4))
+               && (strncasecmp(cmdbuf, "MSGS", 4))
+       {
+               CC->cs_flags &= ~CS_POSTING;
        }
                   
        if (!DLoader_Exec_Cmd(cmdbuf)) {
@@ -75,7 +59,7 @@ void do_command_loop(void) {
 
        unbuffer_output();
 
-       /* Run any after-each-command routines registered by modules */
+       // Run any after-each-command routines registered by modules
        PerformSessionHooks(EVT_CMD);
 }
 
index 32db98ad2ccc62b5b4d4849b59fc19afa122c5a6..ce302a6b310dd83265c36a1957ebbc2418848f40 100644 (file)
@@ -1,15 +1,6 @@
-/* 
- * Functions which manage expire policy for rooms
- * Copyright (c) 1987-2015 by the citadel.org team
- *
- * This program is open source software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
+// Functions which manage expire policy for rooms
+// Copyright (c) 1987-2024 by citadel.org (Art Cancro et al.)
+// This program is open source software.  Use, duplication, or disclosure is subject to the GNU General Public License, version 3.
 
 #include "../../sysdep.h"
 #include <stdlib.h>
@@ -17,7 +8,6 @@
 #include <stdio.h>
 #include <sys/stat.h>
 #include <string.h>
-
 #include <time.h>
 #include <limits.h>
 #include <libcitadel.h>
 #include "../../ctdl_module.h"
 #include "../../user_ops.h"
 
-/*
- * Retrieve the applicable expire policy for a specific room
- */
+// Retrieve the applicable expire policy for a specific room
 void GetExpirePolicy(struct ExpirePolicy *epbuf, struct ctdlroom *qrbuf) {
        struct floor *fl;
 
-       /* If the room has its own policy, return it */ 
+       // If the room has its own policy, return it 
        if (qrbuf->QRep.expire_mode != 0) {
                memcpy(epbuf, &qrbuf->QRep, sizeof(struct ExpirePolicy));
                return;
        }
 
-       /* (non-mailbox rooms)
-        * If the floor has its own policy, return it
-        */
+       // (non-mailbox rooms)
+       // If the floor has its own policy, return it
        if ( (qrbuf->QRflags & QR_MAILBOX) == 0) {
                fl = CtdlGetCachedFloor(qrbuf->QRfloor);
                if (fl->f_ep.expire_mode != 0) {
@@ -56,9 +43,8 @@ void GetExpirePolicy(struct ExpirePolicy *epbuf, struct ctdlroom *qrbuf) {
                }
        }
 
-       /* (Mailbox rooms)
-        * If there is a default policy for mailbox rooms, return it
-        */
+       // (Mailbox rooms)
+       // If there is a default policy for mailbox rooms, return it
        if (qrbuf->QRflags & QR_MAILBOX) {
                if (CtdlGetConfigInt("c_mbxep_mode") != 0) {
                        epbuf->expire_mode = CtdlGetConfigInt("c_mbxep_mode");
@@ -67,15 +53,13 @@ void GetExpirePolicy(struct ExpirePolicy *epbuf, struct ctdlroom *qrbuf) {
                }
        }
 
-       /* Otherwise, fall back on the system default */
+       // Otherwise, fall back on the system default
        epbuf->expire_mode = CtdlGetConfigInt("c_ep_mode");
        epbuf->expire_value = CtdlGetConfigInt("c_ep_value");
 }
 
 
-/*
- * Get Policy EXpire
- */
+// Get Policy EXpire
 void cmd_gpex(char *argbuf) {
        struct ExpirePolicy exp;
        struct floor *fl;
@@ -107,9 +91,7 @@ void cmd_gpex(char *argbuf) {
 }
 
 
-/*
- * Set Policy EXpire
- */
+// Set Policy EXpire
 void cmd_spex(char *argbuf) {
        struct ExpirePolicy exp;
        struct floor flbuf;
@@ -125,8 +107,7 @@ void cmd_spex(char *argbuf) {
                return;
        }
 
-       if ((!strcasecmp(which, strof(roompolicy))) || (!strcasecmp(which, "room")))
-       {
+       if ((!strcasecmp(which, strof(roompolicy))) || (!strcasecmp(which, "room"))) {
                if (!is_room_aide()) {
                        cprintf("%d Higher access required.\n", ERROR + HIGHER_ACCESS_REQUIRED);
                        return;
@@ -148,8 +129,7 @@ void cmd_spex(char *argbuf) {
                return;
        }
 
-       if ((!strcasecmp(which, strof(floorpolicy))) || (!strcasecmp(which, "floor")))
-       {
+       if ((!strcasecmp(which, strof(floorpolicy))) || (!strcasecmp(which, "floor"))) {
                lgetfloor(&flbuf, CC->room.QRfloor);
                memcpy(&flbuf.f_ep, &exp, sizeof(struct ExpirePolicy));
                lputfloor(&flbuf, CC->room.QRfloor);
@@ -157,16 +137,14 @@ void cmd_spex(char *argbuf) {
                return;
        }
 
-       else if ((!strcasecmp(which, strof(mailboxespolicy))) || (!strcasecmp(which, "mailboxes")))
-       {
+       else if ((!strcasecmp(which, strof(mailboxespolicy))) || (!strcasecmp(which, "mailboxes"))) {
                CtdlSetConfigInt("c_mbxep_mode", exp.expire_mode);
                CtdlSetConfigInt("c_mbxep_value", exp.expire_value);
                cprintf("%d Default expire policy for mailboxes set.\n", CIT_OK);
                return;
        }
 
-       else if ((!strcasecmp(which, strof(sitepolicy))) || (!strcasecmp(which, "site")))
-       {
+       else if ((!strcasecmp(which, strof(sitepolicy))) || (!strcasecmp(which, "site"))) {
                if (exp.expire_mode == EXPIRE_NEXTLEVEL) {
                        cprintf("%d Invalid policy (no higher level)\n", ERROR + ILLEGAL_VALUE);
                        return;
index fe4b60b4a20375610c7d1b60954bae7e4dce4221..63b8fc19173bc8fefcca5db2fabaefaa8104a281 100644 (file)
@@ -2,10 +2,9 @@
 //
 // You might also see this module affectionately referred to as TDAP (The Dreaded Auto-Purger).
 //
-// Copyright (c) 1988-2023 by citadel.org (Art Cancro, Wilifried Goesgens, and others)
+// Copyright (c) 1988-2024 by citadel.org (Art Cancro et al.)
 //
-// This program is open source software.  Use, duplication, or disclosure
-// is subject to the terms of the GNU General Public License, version 3.
+// This program is open source software.  Use, duplication, or disclosure is subject to the GNU General Public License, version 3.
 
 
 #include "../../sysdep.h"
index d55971bb5f76de414b88cd4122b3bf9ad3ea2d8a..b9d2a41af95b0efdaef904e38f40b740718a4e32 100644 (file)
@@ -429,9 +429,7 @@ void imap_cleanup_function(void) {
 void imap_output_capability_string(void) {
        IAPuts("CAPABILITY IMAP4REV1 NAMESPACE ID AUTH=PLAIN AUTH=LOGIN UIDPLUS");
 
-#ifdef HAVE_OPENSSL
        if (!CC->redirect_ssl) IAPuts(" STARTTLS");
-#endif
 
 #ifndef DISABLE_IMAP_ACL
        IAPuts(" ACL");
@@ -516,9 +514,7 @@ void imap_greeting(void) {
  */
 void imaps_greeting(void) {
        CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);
-#ifdef HAVE_OPENSSL
        if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO;          /* kill session if no crypto */
-#endif
        imap_greeting();
 }
 
@@ -1544,9 +1540,7 @@ char *ctdl_module_init_imap(void) {
        RegisterImapCMD("LOGIN", "", imap_login, I_FLAG_NONE);
        RegisterImapCMD("AUTHENTICATE", "", imap_authenticate, I_FLAG_NONE);
        RegisterImapCMD("CAPABILITY", "", imap_capability, I_FLAG_NONE);
-#ifdef HAVE_OPENSSL
        RegisterImapCMD("STARTTLS", "", imap_starttls, I_FLAG_NONE);
-#endif
 
        /* The commans below require a logged-in state */
        RegisterImapCMD("SELECT", "", imap_select, I_FLAG_LOGGED_IN);
@@ -1584,9 +1578,7 @@ char *ctdl_module_init_imap(void) {
 
        if (!threading) {
                CtdlRegisterServiceHook(CtdlGetConfigInt("c_imap_port"), NULL, imap_greeting, imap_command_loop, NULL, CitadelServiceIMAP);
-#ifdef HAVE_OPENSSL
                CtdlRegisterServiceHook(CtdlGetConfigInt("c_imaps_port"), NULL, imaps_greeting, imap_command_loop, NULL, CitadelServiceIMAPS);
-#endif
                CtdlRegisterSessionHook(imap_cleanup_function, EVT_STOP, PRIO_STOP + 30);
        }
        
index 19e5fd9f4eff5be15ec26db09dd32a8d5d9d40cd..1691f0f107a4587ec97961974bcfbd56129f6922 100644 (file)
 #include "../../genstamp.h"
 #include "../../domain.h"
 #include "../../ctdl_module.h"
+#include "../smtp/smtp_util.h"
 
 
 void inetcfg_setTo(struct CtdlMessage *msg) {
        char *conf;
        char buf[SIZ];
-       
+
        if (CM_IsEmpty(msg, eMessageText)) return;
        conf = strdup(msg->cm_fields[eMessageText]);
 
@@ -51,6 +52,7 @@ void inetcfg_setTo(struct CtdlMessage *msg) {
 
                if (inetcfg != NULL) free(inetcfg);
                inetcfg = conf;
+               dkim_check_advisory(inetcfg);           // this will check to see if we have to advise the admin about dkim
        }
 }
 
index fd1356079f104eaa907075af27275336949b8442..a6cb74ad40da811b5bbf406b5e674930e070abb1 100644 (file)
@@ -1,14 +1,6 @@
 // This module delivers messages to mailing lists.
-//
-// Copyright (c) 2002-2024 by the citadel.org team
-//
-// This program is open source software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License version 3.
-//  
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
+// Copyright (c) 2002-2024 by the citadel.org team (Art Cancro et al.)
+// This program is open source software.  Use, duplication, or disclosure are subject to the GNU General Public License v3.
 
 #include "../../sysdep.h"
 #include <stdlib.h>
@@ -40,7 +32,6 @@
 
 int doing_listdeliver = 0;
 
-
 // data passed back and forth between listdeliver_do_msg() and listdeliver_sweep_room()
 struct lddata {
        long msgnum;            // number of most recent message processed
@@ -48,7 +39,6 @@ struct lddata {
 };
 
 
-
 void listdeliver_do_msg(long msgnum, void *userdata) {
        struct lddata *ld = (struct lddata *) userdata;
        if (!ld) return;
@@ -63,6 +53,8 @@ void listdeliver_do_msg(long msgnum, void *userdata) {
        struct CtdlMessage *TheMessage = CtdlFetchMessage(msgnum, 1);
        if (!TheMessage) return;
 
+       // FIXME add the list unsubscribe instructions directly to the message text.  Do it right here.
+
        // If the subject line does not contain the name of the room, add it now.
        if (!bmstrcasestr(TheMessage->cm_fields[eMsgSubject], CC->room.QRname)) {
                snprintf(buf, sizeof buf, "[%s] %s", CC->room.QRname, TheMessage->cm_fields[eMsgSubject]);
@@ -78,6 +70,13 @@ void listdeliver_do_msg(long msgnum, void *userdata) {
        CM_SetField(TheMessage, erFc822Addr, buf);
        CM_SetField(TheMessage, eReplyTo, buf);
 
+       // To: likewise needs to have something in it, definitely not the name of an actual mailing list member.
+       // Let's use the address and name of the room.
+       strcat(buf, " (");
+       strcat(buf, CC->room.QRname);
+       strcat(buf, " )");
+       CM_SetField(TheMessage, eRecipient, buf);
+
        // With that out of the way, let's figure out who this message needs to be sent to.
        char *recipients = malloc(strlen(ld->netconf));
        if (recipients) {
index 4c581db632432c11313da844022969afb446807d..231b694cddb1c8a310767d4794e1219669169ee8 100644 (file)
@@ -175,9 +175,7 @@ void nntp_greeting(void) {
 // NNTPS is just like NNTP, except it goes crypto right away.
 void nntps_greeting(void) {
        CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);
-#ifdef HAVE_OPENSSL
        if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO;          // kill session if no crypto
-#endif
        nntp_greeting();
 }
 
@@ -204,9 +202,7 @@ void nntp_capabilities(void) {
        cprintf("MODE-READER\r\n");
        cprintf("LIST ACTIVE NEWSGROUPS\r\n");
        cprintf("OVER\r\n");
-#ifdef HAVE_OPENSSL
        cprintf("STARTTLS\r\n");
-#endif
        if (!CC->logged_in) {
                cprintf("AUTHINFO USER\r\n");
        }
@@ -1070,14 +1066,12 @@ char *ctdl_module_init_nntp(void) {
                                        NULL, 
                                        CitadelServiceNNTP);
 
-#ifdef HAVE_OPENSSL
                CtdlRegisterServiceHook(CtdlGetConfigInt("c_nntps_port"),
                                        NULL,
                                        nntps_greeting,
                                        nntp_command_loop,
                                        NULL,
                                        CitadelServiceNNTPS);
-#endif
 
                CtdlRegisterSessionHook(nntp_cleanup_function, EVT_STOP, PRIO_STOP + 250);
        }
index 322f2d826038834c47f55d21ef714339a75c98e9..d624cfe9e07ebf749efb40e488e42b3f2e04f84a 100644 (file)
 #include "../../ctdl_module.h"
 
 
-// This cleanup function blows away the temporary memory and files used by
-// the POP3 server.
+// This cleanup function blows away the temporary memory and files used by the POP3 server.
 void pop3_cleanup_function(void) {
-       /* Don't do this stuff if this is not a POP3 session! */
+       // Don't do this stuff if this is not a POP3 session!
        if (CC->h_command_function != pop3_command_loop) return;
 
        struct citpop3 *pop3 = ((struct citpop3 *)CC->session_specific_data);
@@ -78,13 +77,10 @@ void pop3_greeting(void) {
 void pop3s_greeting(void) {
        CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);
 
-/* kill session if no crypto */
-#ifdef HAVE_OPENSSL
-       if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO;
-#else
-       CC->kill_me = KILLME_NO_CRYPTO;
-#endif
-
+       // kill the session if TLS is not running by now
+       if (!CC->redirect_ssl) {
+               CC->kill_me = KILLME_NO_CRYPTO;
+       }
        pop3_greeting();
 }
 
@@ -149,10 +145,10 @@ int pop3_grab_mailbox(void) {
 
        if (CtdlGetRoom(&CC->room, MAILROOM) != 0) return(-1);
 
-       /* Load up the messages */
+       // Load up the messages
        CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL, pop3_add_message, NULL);
 
-       /* Figure out which are old and which are new */
+       // Figure out which are old and which are new
         CtdlGetRelationship(&vbuf, &CC->user, &CC->room);
        POP3->lastseen = (-1);
        if (POP3->num_msgs) for (i=0; i<POP3->num_msgs; ++i) {
@@ -516,11 +512,9 @@ void pop3_command_loop(void) {
                pop3_pass(&cmdbuf[5]);
        }
 
-#ifdef HAVE_OPENSSL
        else if (!strncasecmp(cmdbuf, "STLS", 4)) {
                pop3_stls();
        }
-#endif
 
        else if (!CC->logged_in) {
                cprintf("-ERR Not logged in.\r\n");
@@ -582,17 +576,15 @@ char *ctdl_module_init_pop3(void) {
                                        pop3_command_loop,
                                        NULL,
                                        CitadelServicePop3);
-#ifdef HAVE_OPENSSL
                CtdlRegisterServiceHook(CtdlGetConfigInt("c_pop3s_port"),
                                        NULL,
                                        pop3s_greeting,
                                        pop3_command_loop,
                                        NULL,
                                        CitadelServicePop3S);
-#endif
                CtdlRegisterSessionHook(pop3_cleanup_function, EVT_STOP, PRIO_STOP + 30);
        }
        
-       /* return our module name for the log */
+       // return our module name for the log
        return "pop3";
 }
index 248a89564182c8a0fb81fdd6a7b7debbbf032c2d..76a7a61122f1a55f77938df50cf0f4edf532cda8 100644 (file)
@@ -30,7 +30,7 @@
 #include <openssl/evp.h>
 #include <libcitadel.h>
 
-
+// This utility function is used by the body canonicalizer
 char *dkim_rtrim(char *str) {
        char *end;
        int len = strlen(str);
@@ -85,6 +85,7 @@ void dkim_wrap_header_strbuf(StrBuf *header_in) {
 }
 
 
+// This utility function is used by the body canonicalizer
 char *dkim_rtrim_lines(char *str) {
        char *end;
        int len = strlen(str);
@@ -209,7 +210,7 @@ char *dkim_canonicalize_body(char *body) {
 }
 
 
-// Second step to canonicalize a block of headers as per the "relaxed" algorithm.
+// First step to canonicalize a block of headers as per the "relaxed" algorithm.
 // Unfold all headers onto single lines.
 void dkim_unfold_headers(StrBuf *unfolded_headers) {
        char *headers_start = (char *)ChrPtr(unfolded_headers);
@@ -255,6 +256,39 @@ void dkim_canonicalize_unfolded_headers(StrBuf *headers) {
                }
                char *end_of_this_line = strstr(ptr, "\r\n");
 
+               // replace all multiple whitespace runs with a single space
+               int replaced_something;
+               do {
+                       replaced_something = 0;
+                       char *double_space = strstr(ptr, "  ");                 // space-space?
+                       if (!double_space) {
+                               double_space = strstr(ptr, " \t");              // space-tab?
+                       }
+                       if (!double_space) {
+                               double_space = strstr(ptr, "\t ");              // tab-space?
+                       }
+                       if (!double_space) {
+                               double_space = strstr(ptr, "\t\t");             // tab-tab?
+                       }
+                       if (double_space) {
+                               StrBufReplaceToken(headers, (long)(double_space-cheaders), 2, HKEY(" "));
+                               ++replaced_something;
+                       }
+               } while (replaced_something);
+
+               // remove whitespace at the end of the line
+               do {
+                       replaced_something = 0;
+                       char *trailing_space = strstr(ptr, " \r\n");            // line ends in a space?
+                       if (!trailing_space) {                                  // no?
+                               trailing_space = strstr(ptr, "\t\r\n");         // how about a tab?
+                       }
+                       if (trailing_space) {
+                               StrBufReplaceToken(headers, (long)(trailing_space-cheaders), 3, HKEY("\r\n"));
+                               ++replaced_something;
+                       }
+               } while (replaced_something);
+
                // Convert header field names to all lower case
                for (char *c = start_of_this_line; c<colon; ++c) {
                        cheaders[c-cheaders] = tolower(cheaders[c-cheaders]);
@@ -325,6 +359,94 @@ void dkim_final_header_list(char *header_list, size_t header_list_size, StrBuf *
 }
 
 
+// Supplied with a PEM-encoded PKCS#7 private key, that might also have newlines replaced with underscores, return an EVP_PKEY.
+// Caller is responsible for freeing it.
+EVP_PKEY *dkim_import_key(char *pkey_in) {
+
+       if (!pkey_in) {
+               return(NULL);
+       }
+
+       // Citadel Server stores the private key in PEM-encoded PKCS#7 format, but with all newlines replaced by underscores.
+       // Fix that before we try to decode it.
+       char *pkey_with_newlines = strdup(pkey_in);
+       if (!pkey_with_newlines) {
+               return(NULL);
+       }
+       char *sp;
+       while (sp = strchr(pkey_with_newlines, '_')) {
+               *sp = '\n';
+       }
+
+       // Load the private key into an OpenSSL "BIO" structure
+       BIO *bufio = BIO_new_mem_buf((void *)pkey_with_newlines, strlen(pkey_with_newlines));
+       if (bufio == NULL) {
+               syslog(LOG_ERR, "dkim: BIO_new_mem_buf() failed");
+               free(pkey_with_newlines);
+               return(NULL);
+       }
+
+       // Now import the private key
+       EVP_PKEY *pkey = NULL;                  // Don't combine this line with the next one.  It will barf.
+       pkey = PEM_read_bio_PrivateKey(
+               bufio,                          // BIO to read the private key from
+               &pkey,                          // pointer to EVP_PKEY structure
+               NULL,                           // password callback - can be NULL
+               NULL                            // parameter passed to callback or password if callback is NULL
+       );
+
+       free(pkey_with_newlines);
+       BIO_free(bufio);
+
+       if (pkey == NULL) {
+               syslog(LOG_ERR, "dkim: PEM_read_bio_PrivateKey() failed with error 0x%lx", ERR_get_error());
+       }
+
+       return(pkey);
+}
+
+
+// Get the public key from our DKIM signing pair.
+// Returns a string that must be freed by the caller.
+char *dkim_get_public_key(EVP_PKEY *pkey) {
+       char *b64key = NULL;
+       EVP_PKEY_CTX *ctx;
+       ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
+       if (ctx) {
+               BIO *bio = NULL;
+               bio = BIO_new(BIO_s_mem());
+               if (bio) {
+                       PEM_write_bio_PUBKEY(bio, pkey);
+                       b64key = malloc(4096);
+                       if (b64key) {
+                               size_t readbytes;
+                               BIO_read_ex(bio, b64key, 4096, &readbytes);
+                               b64key[readbytes] = 0;
+       
+                               // strip the header
+                               if (!strncasecmp(b64key, HKEY("-----BEGIN PUBLIC KEY-----\n"))) {
+                                       strcpy(b64key, &b64key[27]);
+                               }
+       
+                               // strip the footer
+                               char *foot = strstr(b64key, "\n-----END PUBLIC KEY-----");
+                               if (foot) {
+                                       *foot = 0;
+                               }
+       
+                               // remove newlines
+                               char *nl;
+                               while (nl = strchr(b64key, '\n')) {
+                                       strcpy(nl, nl+1);
+                               }
+                       }
+                       BIO_free(bio);
+               }
+               EVP_PKEY_CTX_free(ctx);
+       }
+       return(b64key);
+}
+
 // DKIM-sign an email, supplied as a full RFC2822-compliant message stored in a StrBuf
 void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
        int i = 0;
@@ -333,6 +455,12 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
                return;
        }
 
+       // Import the private key
+       EVP_PKEY *pkey = dkim_import_key(pkey_in);
+       if (pkey == NULL) {
+               return;
+       }
+
        // find the break between headers and body
        size_t msglen = StrLength(email);                                       // total length of message (headers + body)
 
@@ -354,7 +482,7 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
 
        // hash of the canonicalized body
        unsigned char *body_hash = malloc(SHA256_DIGEST_LENGTH);
-       SHA256((unsigned char*)relaxed_body, relaxed_body_len, body_hash);
+       SHA256((unsigned char *)relaxed_body, relaxed_body_len, body_hash);
        free(relaxed_body);                                                     // all we need now is the hash
        relaxed_body = NULL;
 
@@ -399,27 +527,6 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
        // Compute a hash of the canonicalized headers, and then sign that hash with our private key.
        // RFC6376 says that we hash and sign everything up to the "b=" and then we'll add the rest at the end.
 
-       // Load the private key into an OpenSSL "BIO" structure
-       BIO *bufio = BIO_new_mem_buf((void*)pkey_in, strlen(pkey_in));
-       if (bufio == NULL) {
-               syslog(LOG_ERR, "dkim: BIO_new_mem_buf() failed");
-               abort();
-       }
-
-       // Now import the private key
-       EVP_PKEY *pkey = NULL;                  // Don't combine this line with the next one.  It will barf.
-       pkey = PEM_read_bio_PrivateKey(
-               bufio,                          // BIO to read the private key from
-               &pkey,                          // pointer to EVP_PKEY structure
-               NULL,                           // password callback - can be NULL
-               NULL                            // parameter passed to callback or password if callback is NULL
-       );
-       if (pkey == NULL) {
-               syslog(LOG_ERR, "dkim: PEM_read_bio_PrivateKey() failed");
-               abort();
-       }
-       BIO_free(bufio);                        // Don't need this anymore, we have `pkey` now
-
        // The hashing/signing library calls are documented at https://wiki.openssl.org/index.php/EVP_Signing_and_Verifying
        // NOTE: EVP_DigestSign*() functions are supplied with the actual data to be hashed and signed.
        // That means we don't hash it first, otherwise we would be signing double-hashed (and therefore wrong) data.
@@ -470,7 +577,7 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
        EVP_MD_CTX_free(mdctx);
 
        // This is an optional routine to verify our own signature.
-       // The test program in tests/dkimtester enables it.  It is not enabled during server operation.
+       // The test program in tests/dkimtester enables it.  It is not enabled in Citadel Server.
 #ifdef DKIM_VERIFY_SIGNATURE
        mdctx = EVP_MD_CTX_new();
        if (mdctx) {
@@ -510,3 +617,5 @@ void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector) {
 
        // And we're done!
 }
+
+
diff --git a/citadel/server/modules/smtp/dkim_bindings.c b/citadel/server/modules/smtp/dkim_bindings.c
new file mode 100644 (file)
index 0000000..340e574
--- /dev/null
@@ -0,0 +1,192 @@
+// DKIM bindings to Citadel Server
+//
+// (C) 2024 by Art Cancro
+//
+// This program is open source software.  Use, duplication, or disclosure is subject to the GNU General Public License v3.
+
+// Make sure we don't accidentally use any deprecated API calls
+#define OPENSSL_NO_DEPRECATED_3_0
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+#include <syslog.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/engine.h>
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/buffer.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <libcitadel.h>
+#include "../../config.h"
+#include "../../msgbase.h"
+#include "smtp_util.h"
+
+
+// Generate a private key and selector for DKIM if needed.  This is called during server startup.
+void dkim_init(void) {
+
+       char *dkim_private_key = CtdlGetConfigStr("dkim_private_key");
+       if (!IsEmptyStr(dkim_private_key)) {
+               syslog(LOG_DEBUG, "dkim: private key exists and will continue to be used.");
+       }
+       else {
+               EVP_PKEY_CTX *ctx;
+               EVP_PKEY *pkey = NULL;  
+               BIO *bio = NULL;
+               ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
+               if (ctx) {
+                       if (
+                               (EVP_PKEY_keygen_init(ctx) == 1)
+                               && (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048) == 1)
+                               && (EVP_PKEY_keygen(ctx, &pkey) == 1)
+                       ) {
+                               syslog(LOG_DEBUG, "dkim: generated private key");
+                               bio = BIO_new(BIO_s_mem());
+                               if (bio) {
+                                       PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, NULL, NULL);
+                                       char *b64key = malloc(4096);
+                                       if (b64key) {
+                                               size_t readbytes;
+                                               BIO_read_ex(bio, b64key, 4096, &readbytes);
+                                               b64key[readbytes] = 0;
+                                               char *nl = NULL;
+                                               while (nl=strchr(b64key, '\n'), nl) {           // convert newlines to underscores
+                                                       *nl = '_';
+                                               }
+                                               CtdlSetConfigStr("dkim_private_key", b64key);
+                                               free(b64key);
+                                       }
+                                       free(bio);
+                               }
+                       }
+                       EVP_PKEY_CTX_free(ctx);
+               }
+       }
+
+       char *dkim_selector = CtdlGetConfigStr("dkim_selector");
+       if (dkim_selector) {
+               syslog(LOG_DEBUG, "dkim: selector exists: %s", dkim_selector);
+       }
+       else {
+               // Quick and dirty algorithm to make up a five letter nonsense word as a selector
+               char new_selector[6];
+               int i;
+               for (i=0; i<5; ++i) {
+                       new_selector[i] = (rand() % 26) + 'a';
+               }
+               new_selector[5] = 0;
+               syslog(LOG_DEBUG, "dkim: selector created: %s", new_selector);
+               CtdlSetConfigStr("dkim_selector", new_selector);
+       }
+}
+
+
+// If the DKIM key, DKIM selector, or set of signing domains has changed, we need to tell the administrator about it.
+void dkim_check_advisory(char *inetcfg_in) {
+
+       // If there is no DKIM ... there is nothing to discuss
+       if (IsEmptyStr(CtdlGetConfigStr("dkim_private_key"))) return;
+       if (IsEmptyStr(CtdlGetConfigStr("dkim_selector"))) return;
+
+       // We're going to build a hash of the private key, the selector, and all signing domains.
+       // The way we build it doesn't matter, and it doesn't even have to be secure.
+       // This is just to let us know that we have to post an update to the administrator if the hash changes.
+
+       StrBuf *hashsrc = NewStrBuf();
+       if (!hashsrc) {
+               return;
+       }
+
+       StrBufAppendBufPlain(hashsrc, CtdlGetConfigStr("dkim_private_key"), strlen(CtdlGetConfigStr("dkim_private_key")), 0);
+       StrBufAppendBufPlain(hashsrc, CtdlGetConfigStr("dkim_selector"), strlen(CtdlGetConfigStr("dkim_selector")), 0);
+
+       char *ptr = inetcfg_in;
+       while (ptr && *ptr) {
+               char *sep = strchr(ptr, '|');
+               if (sep && !strncasecmp(sep+1, HKEY("localhost"))) {
+                       StrBufAppendBufPlain(hashsrc, ptr, sep-ptr, 0);
+               }
+               ptr = strchr(ptr, '\n');
+               if (ptr) ++ptr;
+       }
+
+       // make a hash from the string...
+       unsigned char *config_hash = malloc(SHA256_DIGEST_LENGTH);
+       SHA256((unsigned char *)ChrPtr(hashsrc), StrLength(hashsrc), config_hash);
+       FreeStrBuf(&hashsrc);
+
+       // base64 encode it...
+       char *encoded_config_hash = malloc(SHA256_DIGEST_LENGTH * 2);
+       CtdlEncodeBase64(encoded_config_hash, config_hash, SHA256_DIGEST_LENGTH, BASE64_NO_LINEBREAKS);
+       free(config_hash);                                                      // all we need now is the encoded hash
+
+       // Does it match the saved hash?
+       if (    (IsEmptyStr(CtdlGetConfigStr("dkim_config_hash")))
+               || (strcmp(encoded_config_hash, CtdlGetConfigStr("dkim_config_hash")))
+       ) {
+               // No?  Post an Aide notification.
+               StrBuf *message = NewStrBuf();
+               StrBufAppendBufPlain(message, HKEY(
+                       "Content-type: text/plain\r\n"
+                       "\r\n\r\n"
+                       "Your domain configuration may have changed.\r\n\r\n"
+                       "To allow the DKIM signatures of outbound mail to be verified,\r\n"
+                       "please ensure that the following DNS records are created:\r\n"
+                       "\r\n"
+               ),0);
+
+               char *pubkey = NULL;
+               EVP_PKEY *pkey = dkim_import_key(CtdlGetConfigStr("dkim_private_key"));
+               if (pkey) {
+                       pubkey = dkim_get_public_key(pkey);
+                       EVP_PKEY_free(pkey);
+               }
+
+               if (pubkey) {
+                       ptr = inetcfg_in;
+                       while (ptr && *ptr) {
+                               char *sep = strchr(ptr, '|');
+                               if (sep && !strncasecmp(sep+1, HKEY("localhost"))) {
+                                       StrBufAppendPrintf(message, "Host name  : %s._domainkey.", CtdlGetConfigStr("dkim_selector"));
+                                       StrBufAppendBufPlain(message, ptr, sep-ptr, 0);
+                                       StrBufAppendBufPlain(message, HKEY("\r\n"), 0);
+                                       StrBufAppendPrintf(message, "Record type: TXT\r\n");
+                                       StrBufAppendPrintf(message, "Value      : v=DKIM1;k=rsa;p=%s\r\n", pubkey);
+                                       StrBufAppendPrintf(message, "\r\n");
+                               }
+                               ptr = strchr(ptr, '\n');
+                               if (ptr) {
+                                       ++ptr;
+                               }
+                       }
+                       free(pubkey);
+               }
+               else {
+                       StrBufAppendBufPlain(message, HKEY("YOW!  Something went wrong.\r\n\r\n"), 0);
+               }
+
+               quickie_message("Citadel",
+                       NULL,                           // from
+                       NULL,                           // to
+                       AIDEROOM,                       // room
+                       ChrPtr(message),                // text
+                       FMT_RFC822,                     // format
+                       "Confirm your DKIM records"     // subject
+               );
+               FreeStrBuf(&message);
+       }
+
+       // Save it to the config database so we don't do this except when it changes.
+       CtdlSetConfigStr("dkim_config_hash", encoded_config_hash);
+       free(encoded_config_hash);
+}
index b153207567cbf0aebb36357624d57e7cb2fe5b0d..9ecf144b1a6601a802fa1502a0b631f30ca387f0 100644 (file)
@@ -134,9 +134,9 @@ void smtp_greeting(int is_msa) {
 // SMTPS is just like SMTP, except it goes crypto right away.
 void smtps_greeting(void) {
        CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);
-#ifdef HAVE_OPENSSL
-       if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO;          // kill session if no crypto
-#endif
+       if (!CC->redirect_ssl) {
+               CC->kill_me = KILLME_NO_CRYPTO;         // kill session if no crypto
+       }
        smtp_greeting(0);
 }
 
@@ -214,7 +214,6 @@ void smtp_hello(int which_command) {
                cprintf("250-HELP\r\n");
                cprintf("250-SIZE %ld\r\n", CtdlGetConfigLong("c_maxmsglen"));
 
-#ifdef HAVE_OPENSSL
                // Offer the STARTTLS option...
                if (    (!CC->redirect_ssl)                                                     // not if we're already TLS
                        && (    (SMTP->is_msa)                                                  // Always on port 587
@@ -223,7 +222,6 @@ void smtp_hello(int which_command) {
                ) {
                        cprintf("250-STARTTLS\r\n");
                }
-#endif
 
                cprintf("250-AUTH LOGIN PLAIN\r\n"
                        "250-AUTH=LOGIN PLAIN\r\n"
@@ -964,12 +962,10 @@ void smtp_command_loop(void) {
                smtp_rcpt();
                return;
        }
-#ifdef HAVE_OPENSSL
        if (!strncasecmp(ChrPtr(SMTP->Cmd), "STARTTLS", 8)) {
                smtp_starttls();
                return;
        }
-#endif
 
        cprintf("502 I'm afraid I can't do that.\r\n");
 }
@@ -1015,14 +1011,12 @@ char *ctdl_module_init_smtp(void) {
                                        NULL, 
                                        CitadelServiceSMTP_MTA);
 
-#ifdef HAVE_OPENSSL
                CtdlRegisterServiceHook(CtdlGetConfigInt("c_smtps_port"),       // SMTPS MTA
                                        NULL,
                                        smtps_greeting,
                                        smtp_command_loop,
                                        NULL,
                                        CitadelServiceSMTPS_MTA);
-#endif
 
                CtdlRegisterServiceHook(CtdlGetConfigInt("c_msa_port"),         // SMTP MSA
                                        NULL,
index ea7289e38be659b27a88882865d86b6a0ed5b2c4..6eedc56d02bb37d3523a6cd1b282c71e077650d0 100644 (file)
@@ -224,49 +224,31 @@ int smtp_attempt_delivery(long msgid, char *recp, char *envelope_from, char *sou
                char unsubscribe_url[SIZ];
                snprintf(base_url, sizeof base_url, "https://%s/listsub", CtdlGetConfigStr("c_fqdn"));
                generate_one_click_url(unsubscribe_url, base_url, "unsubscribe", source_room, recp);
-               cprintf("List-Unsubscribe: %s\r\n", unsubscribe_url);
+               cprintf("List-Unsubscribe: <%s>\r\n", unsubscribe_url);                 // RFC 2369
                cprintf("List-Unsubscribe-Post: List-Unsubscribe=One-Click\r\n");       // RFC 8058
-
        }
 
        CtdlOutputMsg(msgid, MT_RFC822, HEADERS_ALL, 0, 1, NULL, 0, NULL, &fromaddr, NULL);
        s.TheMessage = CC->redirect_buffer;
        CC->redirect_buffer = NULL;
 
-#if 0
-       // FIXME genericize this
-       char *pkey_in =
-               "-----BEGIN PRIVATE KEY-----\n"
-               "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDfuefcepokRrnp\n"
-               "SSDsxu+QDqeD8GL9QnZz/N6IxTdBv6Wc10ExBe2IjS5dKI7AvhSSEK0zGE8Hkpmw\n"
-               "eccbiepQqeueteWzAMZ1uT43bD3k7eye7vWobiOP9QtoYGR6sG25h2W5Tbc91W4f\n"
-               "dvYnxYVJjx8wIVF0f3o25v+rQueoo0HlvGyA9/xi9GAaJL05OmK1xnMJgSvW/Q8Q\n"
-               "zq7apf1D6XPXHuhv5tevElkZ5jlvM2w0cTVyAzMrUh6Rkcn9xM4/NPWYghBc3jO4\n"
-               "TrPnSrobQGrX0fcizE/FN6I0in0Ke8Z+gMM8NeFcsjvLZe9MpY9i0pw/ygLIh5t3\n"
-               "O4qpwC1JAgMBAAECggEAIwiTCMEAGzciDKhhagJ66BWLYMtHTP5X2zDZThSH4xlW\n"
-               "HznL4RfbCtuEy5y6we7h/L90x8ACPB7WRz7CkYrmsMvy9A7q0b2I1k10MyyVgqBJ\n"
-               "QdgMitv4YKYQK7+QbG/tNrS/lqVXUOz3iiDQSgkRpqOtUBWfkj0WD7vbhF99NDhV\n"
-               "dxaehFkKv3yNy0bXJlHJBJ6KtOUnDwub8TExh8dyj3kB8Qzj4I98shaXPNUSSaOw\n"
-               "zG6QG72yrxlMs495jkIPbF2JDidmLrX+oVISwKyaBWx+BkFV/KFAEKgaB5/nCw7+\n"
-               "qq/jxsmXim3HuQ3MIAjq1yw9aGRH1HMi8Gn7tYlNGwKBgQDy6EEKpuEiW9wwlI2+\n"
-               "GVuSkhSTTX1h6qK/ay8Jtyb8yJM/BxogAQlfjdgFixiZHy5MaomTbfeT2GDji553\n"
-               "+RsnZ60+g7FI9nHwabSxtuCQ+vjbFqCsdMPAiSeG0bEzo0zf5TjASdUtuZL0vXjl\n"
-               "yMZWDEuESoVNlYlvCOVkw2nvIwKBgQDryPuSq6PNVHRWsKRRs5ju4wKs/1ucBOg5\n"
-               "gCcN8lE03mFCWAlZhypE4/fAhTQ/a5KQoAzc0QZcXRueDyNsnc+QWw3/QWf8/fkV\n"
-               "HPfTWS3Dcuj+4RnWUucaZ/mKFlTC3+eNSlpyaPIMlCjXGsJ9GlPrsaAi9KPbD2v/\n"
-               "XcMq/PMOowKBgHVf7S3sfZVQthFzdxqIvksQ84hKRW/vJT1B2bTkH56+fQhTsjgM\n"
-               "yC64J85l7DjxbDnYsSngVWXHhOnvKV/nq0tbOcefcydCjsQREBNfvxvPajjTskgj\n"
-               "FAQRQlxPL0U4f4khBk9EXhJ+PZithaHjZpNl1YfTSp62x3Yz4kTSeHnpAoGAGn5m\n"
-               "5kArE7NdrzACBrwrfww7DL1Uyd8zSOLBgKutvEcQnqfNxSWO9la3TAarrESmH2Ic\n"
-               "j+Nc15wOsl/5FwdUf1/73qa2zJKtHlY28qSeo8uRqrIYeSCvnyP3wjBoLc2C8zlb\n"
-               "mGd6azdqr2DuYahHrcAzwjnC/6Zn+DXM7FOn7AkCgYBp1xxY88cCoF24yffkD3MC\n"
-               "ACUury4qRSDTGx6/qCCkIyWxg1vuiDrlPWhSwQznxHvovcfpdjdbWcFY87IK6mpG\n"
-               "aJHwMJ7Kw+baoxGPZWHwdg6BgvUCihe3xlcaq6rOBoLviD6FOzbogg++Tvi0LemG\n"
-               "y/wEs/mZkaRzW4n41ir0Xw==\n"
-               "-----END PRIVATE KEY-----\n"
-       ;
-       dkim_sign(s.TheMessage, pkey_in, "dev.citadel.org", "foo");
-#endif
+       // If we have a DKIM key, try to sign the message.
+       char *dkim_private_key = CtdlGetConfigStr("dkim_private_key");
+       char *dkim_selector = CtdlGetConfigStr("dkim_selector");
+       char *dkim_from_domain = (strchr(fromaddr, '@') ? strchr(fromaddr, '@')+1 : NULL);
+       if (
+               !IsEmptyStr(dkim_from_domain)                   // Is the sending domain non-empty?
+               && IsDirectory(fromaddr, 0)                     // and is it one of "our" domains?
+               && !IsEmptyStr(dkim_private_key)                // Do we have a private signing key?
+               && !IsEmptyStr(dkim_selector)                   // and a selector to go with it?
+       ) {
+               // If you answered "yes" to all of the above questions, congratulations!  We get to sign the message!
+               syslog(LOG_DEBUG, "smtpclient: dkim-signing for selector <%s> in domain <%s>", dkim_selector, dkim_from_domain);
+
+               // Remember, the dkim_sign() function is capable of handling a PEM-encoded PKCS#7 private key that
+               // has had all of its newlines replaced by underscores -- which is exactly how we store it.
+               dkim_sign(s.TheMessage,dkim_private_key, dkim_from_domain, dkim_selector);
+       }
 
        // Prepare the buffer for transmittal
        s.bytes_total = StrLength(s.TheMessage);
@@ -616,6 +598,7 @@ char *ctdl_module_init_smtpclient(void) {
                CtdlRegisterSessionHook(smtp_do_queue_quick, EVT_HOUSE, PRIO_AGGR + 51);
                CtdlRegisterSessionHook(smtp_do_queue_full, EVT_TIMER, PRIO_AGGR + 51);
                smtp_init_spoolout();
+               dkim_init();
        }
 
        // return our module id for the log
index 1a4e17162076fbade021b5567b0be6f4836db72d..cdaea243aa45acc671308bf9a98cd3e24adda5ca 100644 (file)
@@ -30,3 +30,7 @@ enum {
 void smtp_do_bounce(const char *instr, int is_final);
 char *smtpstatus(int code);
 void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector);
+void dkim_init(void);
+void dkim_check_advisory(char *inetcfg_in);
+EVP_PKEY *dkim_import_key(char *pkey_in);
+char *dkim_get_public_key(EVP_PKEY *pkey);
index 9dacbffad865639f8172a470fb4f24ba723d9d74..81b239c90ab4eebf71d8f0f5fd9483eae971b8eb 100644 (file)
@@ -192,11 +192,9 @@ void xmpp_stream_start(void *data, const char *supplied_el, const char **attr)
        /*
         * TLS encryption (but only if it isn't already active)
         */ 
-#ifdef HAVE_OPENSSL
        if (!CC->redirect_ssl) {
                cprintf("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'></starttls>");
        }
-#endif
 
        if (!CC->logged_in) {
                /* If we're not logged in yet, offer SASL as our feature set */
@@ -487,14 +485,9 @@ void xmpp_xml_end(void *data, const char *supplied_el) {
        }
 
        else if (!strcasecmp(el, "starttls")) {
-#ifdef HAVE_OPENSSL
                cprintf("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
                CtdlModuleStartCryptoMsgs(NULL, NULL, NULL);
                if (!CC->redirect_ssl) CC->kill_me = KILLME_NO_CRYPTO;
-#else
-               cprintf("<failure xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
-               CC->kill_me = KILLME_NO_CRYPTO;
-#endif
        }
 
        else if (!strcasecmp(el, "ping")) {
index d1929a22689810954e42930329098c8d28cc3c9d..f52a6e26f3fb48c3f530a4c0e476bace18d9db11 100644 (file)
@@ -1,16 +1,6 @@
-/*
- * XMPP event queue
- *
- * Copyright (c) 2007-2021 by Art Cancro
- *
- * This program is open source software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
+// XMPP event queue
+// Copyright (c) 2007-2024 by Art Cancro
+// This program is open source software.  Use, duplication, or disclosure is subject to the GNU General Public License v3.
 
 #include "../../sysdep.h"
 #include <stdlib.h>
@@ -49,7 +39,7 @@ void xmpp_queue_event(int event_type, char *email_addr) {
 
        syslog(LOG_DEBUG, "xmpp: xmpp_queue_event(%d, %s)", event_type, email_addr);
 
-       /* Purge events more than a minute old */
+       // Purge events more than a minute old
        begin_critical_section(S_XMPP_QUEUE);
        do {
                purged_something = 0;
@@ -64,7 +54,7 @@ void xmpp_queue_event(int event_type, char *email_addr) {
        } while(purged_something);
        end_critical_section(S_XMPP_QUEUE);
 
-       /* Create a new event */
+       // Create a new event
        new_event = (struct xmpp_event *) malloc(sizeof(struct xmpp_event));
        new_event->next = NULL;
        new_event->event_time = time(NULL);
@@ -73,7 +63,7 @@ void xmpp_queue_event(int event_type, char *email_addr) {
        new_event->session_which_generated_this_event = CC->cs_pid;
        safestrncpy(new_event->event_jid, email_addr, sizeof new_event->event_jid);
 
-       /* Add it to the list */
+       // Add it to the list
        begin_critical_section(S_XMPP_QUEUE);
        if (xmpp_queue == NULL) {
                xmpp_queue = new_event;
@@ -88,7 +78,7 @@ void xmpp_queue_event(int event_type, char *email_addr) {
        }
        end_critical_section(S_XMPP_QUEUE);
 
-       /* Tell the sessions that something is happening */
+       // Tell the sessions that something is happening
        begin_critical_section(S_SESSION_TABLE);
        for (cptr = ContextList; cptr != NULL; cptr = cptr->next) {
                if ((cptr->logged_in) && (cptr->h_async_function == xmpp_async_loop)) {
@@ -99,15 +89,13 @@ void xmpp_queue_event(int event_type, char *email_addr) {
 }
 
 
-/* 
- * Are we interested in anything from the queue?  (Called in async loop)
- */
+// Are we interested in anything from the queue?  (Called in async loop)
 void xmpp_process_events(void) {
        struct xmpp_event *xptr = NULL;
        int highest_event = 0;
 
        for (xptr=xmpp_queue; xptr!=NULL; xptr=xptr->next) {
-               if (xptr->event_seq > XMPP->last_event_processed) {             // we are getting crashes on this line?
+               if (xptr->event_seq > XMPP->last_event_processed) {
 
                        switch(xptr->event_type) {
 
index 8582fba301bed1b1f50209c45b5384ec34a04187..aaf4446c604f07f6b434bffa7dc905fd26e84109 100644 (file)
@@ -1488,16 +1488,13 @@ int CtdlOutputMsg(long msg_num,         // message number (local) to fetch
                        );
 
                if ((Author != NULL) && (*Author == NULL)) {
-                       long len;
-                       CM_GetAsField(TheMessage, eAuthor, Author, &len);
+                       *Author = strdup(TheMessage->cm_fields[eAuthor]);
                }
                if ((Address != NULL) && (*Address == NULL)) {  
-                       long len;
-                       CM_GetAsField(TheMessage, erFc822Addr, Address, &len);
+                       *Address = strdup(TheMessage->cm_fields[erFc822Addr]);
                }
                if ((MessageID != NULL) && (*MessageID == NULL)) {      
-                       long len;
-                       CM_GetAsField(TheMessage, emessageId, MessageID, &len);
+                       *MessageID = strdup(TheMessage->cm_fields[emessageId]);
                }
                CM_Free(TheMessage);
                TheMessage = NULL;
index 8787beae805027c94b5d7336cea1e755473ea8dc..260bd8dc23a6bb994fd04b9348bf4d16e0f8dd25 100644 (file)
@@ -526,9 +526,7 @@ int PerformXmsgHooks(char *sender, char *sender_email, char *recp, char *msg) {
 
 // "Start TLS" function that is (hopefully) adaptable for any protocol
 void CtdlModuleStartCryptoMsgs(char *ok_response, char *nosup_response, char *error_response) {
-#ifdef HAVE_OPENSSL
        CtdlStartTLS (ok_response, nosup_response, error_response);
-#endif
 }
 
 
index 8d1f7d0ff3bbf99c93e9bfa5895d407dc53e286b..24833b737cd9bd881e8e68245c8025211f932f58 100644 (file)
 #endif
 
 #include "citadel_defs.h"
-#ifdef HAVE_OPENSSL
 #define OPENSSL_NO_KRB5                        // work around redhat b0rken ssl headers
 #include <openssl/ssl.h>
-#endif
 
 
 // New format for a message in memory
index 58f94624dfd5b07cf01c60465c48b6a7dcc4f281..6f3209468c2298bd91fe03fedd9cad74d7713166 100644 (file)
@@ -69,9 +69,7 @@ void init_sysdep(void) {
 #endif
 
        // If we've got OpenSSL, we're going to use it.
-#ifdef HAVE_OPENSSL
        init_ssl();
-#endif
 
        if (pthread_key_create(&MyConKey, NULL) != 0) {                         // TSD for sessions
                syslog(LOG_CRIT, "sysdep: can't create TSD key: %m");
@@ -252,19 +250,17 @@ static unsigned on = 1, off = 0;
 
 void buffer_output(void) {
 #ifdef HAVE_TCP_BUFFERING
-#ifdef HAVE_OPENSSL
-       if (!CC->redirect_ssl)
-#endif
+       if (!CC->redirect_ssl) {
                setsockopt(CC->client_socket, IPPROTO_TCP, TCP_CORK, &on, 4);
+       }
 #endif
 }
 
 void unbuffer_output(void) {
 #ifdef HAVE_TCP_BUFFERING
-#ifdef HAVE_OPENSSL
-       if (!CC->redirect_ssl)
-#endif
+       if (!CC->redirect_ssl) {
                setsockopt(CC->client_socket, IPPROTO_TCP, TCP_CORK, &off, 4);
+       }
 #endif
 }
 
@@ -305,12 +301,10 @@ int client_write(const char *buf, int nbytes) {
                return 0;
        }
 
-#ifdef HAVE_OPENSSL
        if (Ctx->redirect_ssl) {
                client_write_ssl(buf, nbytes);
                return 0;
        }
-#endif
        if (Ctx->client_socket == -1) return -1;
 
        fdflags = fcntl(Ctx->client_socket, F_GETFL);
@@ -397,16 +391,13 @@ int client_read_blob(StrBuf *Target, int bytes, int timeout) {
        const char *Error;
        int retval = 0;
 
-#ifdef HAVE_OPENSSL
        if (CC->redirect_ssl) {
                retval = client_read_sslblob(Target, bytes, timeout);
                if (retval < 0) {
                        syslog(LOG_ERR, "sysdep: client_read_blob() failed");
                }
        }
-       else 
-#endif
-       {
+       else {
                retval = StrBufReadBLOBBuffered(Target, 
                                                CC->RecvBuf.Buf,
                                                &CC->RecvBuf.ReadWritePointer,
@@ -505,14 +496,11 @@ int CtdlClientGetLine(StrBuf *Target) {
        int rc;
 
        FlushStrBuf(Target);
-#ifdef HAVE_OPENSSL
        if (CC->redirect_ssl) {
                rc = client_readline_sslbuffer(Target, CC->RecvBuf.Buf, &CC->RecvBuf.ReadWritePointer, 1);
                return rc;
        }
-       else 
-#endif
-       {
+       else {
                rc = StrBufTCP_read_buffered_line_fast(Target, 
                                                       CC->RecvBuf.Buf,
                                                       &CC->RecvBuf.ReadWritePointer,
index 4d46b69605d6dbde93be0001df17a74e5ac79aca..5a9d9e8912c33315bab25b24b546cdcf0e7b6ef6 100644 (file)
@@ -1,13 +1,20 @@
 # dkimtester
 
-This was originally where we developed the DKIM code for Citadel
-but it is properly merged into Citadel now.  What's left is just
-a test harness.
+This is a test harness for Citadel's DKIM signing code.  It is not likely
+that you will use this program unless you're hacking on the DKIM signer
+itself.  The private key embedded in the test program matches the DKIM record
+for `dev.citadel.org` at the time this is being written.  That record looks
+like this:
 
-You must have the `Mail::DKIM::Verifier` perl module installed,
-which can be found on CPAN.
+```
+foo._domainkey.dev.citadel.org IN TXT "v=DKIM1;k=rsa;p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA37nn3HqaJEa56Ukg7MbvkA6ng/Bi/UJ2c/zeiMU3Qb+lnNdBMQXtiI0uXSiOwL4UkhCtMxhPB5KZsHnHG4nqUKnrnrXlswDGdbk+N2w95O3snu71qG4jj/ULaGBkerBtuYdluU23PdVuH3b2J8WFSY8fMCFRdH96Nub/q0LnqKNB5bxsgPf8YvRgGiS9OTpitcZzCYEr1v0PEM6u2qX9Q+lz1x7ob+bXrxJZGeY5bzNsNHE1cgMzK1IekZHJ/cTOPzT1mIIQXN4zuE6z50q6G0Bq19H3IsxPxTeiNIp9CnvGfoDDPDXhXLI7y2XvTKWPYtKcP8oCyIebdzuKqcAtSQIDAQAB"
+```
+If you intend to work with this program, that key will be long gone by the
+time you read this, and *you* don't control `dev.citadel.org` anyway, so you
+will have to create your own host name and set your own DKIM record.  You can
+use this private key if you want to, though.
 
-Also it depends on a DKIM record for `dev.citadel.org` which is
-correct at the time I am writing this.  Good luck keeping that in
-place.
+To run this test, you also must have the `Mail::DKIM::Verifier` perl module
+installed, which can be found on CPAN.
 
+Again -- this is not intended to be part of a regression test suite.
index c923bd5d3e5519d05f7259ffbef623eabb19584e..4a4bf33912ee74b290824085a54825ef8a903ea8 100644 (file)
@@ -2,55 +2,32 @@
 // This contains a private key that, at the time of writing, matches the DKIM public key for dev.citadel.org
 // We can use the attached test message to validate a signature against that.
 
-#include <stdlib.h>
-#include <unistd.h>
 #include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <time.h>
-#include <assert.h>
 #include <syslog.h>
 #include <libcitadel.h>
 
-// oof, a prototype where one does not belong hehe
+// This was easier than trying to figure out the header situation
 void dkim_sign(StrBuf *email, char *pkey_in, char *domain, char *selector);
 
 int main(int argc, char *argv[]) {
 
+       // display the greeting
+       fprintf(stderr,
+               "\033[44m\033[1m╔════════════════════════════════════════════════════════════════════════╗\033[0m\n"
+               "\033[44m\033[1m║ DKIM signature test program for Citadel                                ║\033[0m\n"
+               "\033[44m\033[1m║ Copyright (c) 2024 by citadel.org (Art Cancro et al.)                  ║\033[0m\n"
+               "\033[44m\033[1m║ This program is open source software.  Use, duplication, or disclosure ║\033[0m\n"
+               "\033[44m\033[1m║ is subject to the terms of the GNU General Public license v3.          ║\033[0m\n"
+               "\033[44m\033[1m╚════════════════════════════════════════════════════════════════════════╝\033[0m\n"
+       );
+
        openlog("dkim", LOG_PERROR, LOG_USER);
 
-       char *private_key =
-               "-----BEGIN PRIVATE KEY-----\n"
-               "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDfuefcepokRrnp\n"
-               "SSDsxu+QDqeD8GL9QnZz/N6IxTdBv6Wc10ExBe2IjS5dKI7AvhSSEK0zGE8Hkpmw\n"
-               "eccbiepQqeueteWzAMZ1uT43bD3k7eye7vWobiOP9QtoYGR6sG25h2W5Tbc91W4f\n"
-               "dvYnxYVJjx8wIVF0f3o25v+rQueoo0HlvGyA9/xi9GAaJL05OmK1xnMJgSvW/Q8Q\n"
-               "zq7apf1D6XPXHuhv5tevElkZ5jlvM2w0cTVyAzMrUh6Rkcn9xM4/NPWYghBc3jO4\n"
-               "TrPnSrobQGrX0fcizE/FN6I0in0Ke8Z+gMM8NeFcsjvLZe9MpY9i0pw/ygLIh5t3\n"
-               "O4qpwC1JAgMBAAECggEAIwiTCMEAGzciDKhhagJ66BWLYMtHTP5X2zDZThSH4xlW\n"
-               "HznL4RfbCtuEy5y6we7h/L90x8ACPB7WRz7CkYrmsMvy9A7q0b2I1k10MyyVgqBJ\n"
-               "QdgMitv4YKYQK7+QbG/tNrS/lqVXUOz3iiDQSgkRpqOtUBWfkj0WD7vbhF99NDhV\n"
-               "dxaehFkKv3yNy0bXJlHJBJ6KtOUnDwub8TExh8dyj3kB8Qzj4I98shaXPNUSSaOw\n"
-               "zG6QG72yrxlMs495jkIPbF2JDidmLrX+oVISwKyaBWx+BkFV/KFAEKgaB5/nCw7+\n"
-               "qq/jxsmXim3HuQ3MIAjq1yw9aGRH1HMi8Gn7tYlNGwKBgQDy6EEKpuEiW9wwlI2+\n"
-               "GVuSkhSTTX1h6qK/ay8Jtyb8yJM/BxogAQlfjdgFixiZHy5MaomTbfeT2GDji553\n"
-               "+RsnZ60+g7FI9nHwabSxtuCQ+vjbFqCsdMPAiSeG0bEzo0zf5TjASdUtuZL0vXjl\n"
-               "yMZWDEuESoVNlYlvCOVkw2nvIwKBgQDryPuSq6PNVHRWsKRRs5ju4wKs/1ucBOg5\n"
-               "gCcN8lE03mFCWAlZhypE4/fAhTQ/a5KQoAzc0QZcXRueDyNsnc+QWw3/QWf8/fkV\n"
-               "HPfTWS3Dcuj+4RnWUucaZ/mKFlTC3+eNSlpyaPIMlCjXGsJ9GlPrsaAi9KPbD2v/\n"
-               "XcMq/PMOowKBgHVf7S3sfZVQthFzdxqIvksQ84hKRW/vJT1B2bTkH56+fQhTsjgM\n"
-               "yC64J85l7DjxbDnYsSngVWXHhOnvKV/nq0tbOcefcydCjsQREBNfvxvPajjTskgj\n"
-               "FAQRQlxPL0U4f4khBk9EXhJ+PZithaHjZpNl1YfTSp62x3Yz4kTSeHnpAoGAGn5m\n"
-               "5kArE7NdrzACBrwrfww7DL1Uyd8zSOLBgKutvEcQnqfNxSWO9la3TAarrESmH2Ic\n"
-               "j+Nc15wOsl/5FwdUf1/73qa2zJKtHlY28qSeo8uRqrIYeSCvnyP3wjBoLc2C8zlb\n"
-               "mGd6azdqr2DuYahHrcAzwjnC/6Zn+DXM7FOn7AkCgYBp1xxY88cCoF24yffkD3MC\n"
-               "ACUury4qRSDTGx6/qCCkIyWxg1vuiDrlPWhSwQznxHvovcfpdjdbWcFY87IK6mpG\n"
-               "aJHwMJ7Kw+baoxGPZWHwdg6BgvUCihe3xlcaq6rOBoLviD6FOzbogg++Tvi0LemG\n"
-               "y/wEs/mZkaRzW4n41ir0Xw==\n"
-               "-----END PRIVATE KEY-----\n"
-       ;
+       // dkim.c can handle a PEM-encoded PKCS#7 private key that has had all of the newlines replaced by underscores.
+       // It will convert them back to newlines before importing the key.
+       // This is the format that Citadel Server uses to store the key in its configuration database.
+       char *private_key = "-----BEGIN PRIVATE KEY-----_MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDfuefcepokRrnp_SSDsxu+QDqeD8GL9QnZz/N6IxTdBv6Wc10ExBe2IjS5dKI7AvhSSEK0zGE8Hkpmw_eccbiepQqeueteWzAMZ1uT43bD3k7eye7vWobiOP9QtoYGR6sG25h2W5Tbc91W4f_dvYnxYVJjx8wIVF0f3o25v+rQueoo0HlvGyA9/xi9GAaJL05OmK1xnMJgSvW/Q8Q_zq7apf1D6XPXHuhv5tevElkZ5jlvM2w0cTVyAzMrUh6Rkcn9xM4/NPWYghBc3jO4_TrPnSrobQGrX0fcizE/FN6I0in0Ke8Z+gMM8NeFcsjvLZe9MpY9i0pw/ygLIh5t3_O4qpwC1JAgMBAAECggEAIwiTCMEAGzciDKhhagJ66BWLYMtHTP5X2zDZThSH4xlW_HznL4RfbCtuEy5y6we7h/L90x8ACPB7WRz7CkYrmsMvy9A7q0b2I1k10MyyVgqBJ_QdgMitv4YKYQK7+QbG/tNrS/lqVXUOz3iiDQSgkRpqOtUBWfkj0WD7vbhF99NDhV_dxaehFkKv3yNy0bXJlHJBJ6KtOUnDwub8TExh8dyj3kB8Qzj4I98shaXPNUSSaOw_zG6QG72yrxlMs495jkIPbF2JDidmLrX+oVISwKyaBWx+BkFV/KFAEKgaB5/nCw7+_qq/jxsmXim3HuQ3MIAjq1yw9aGRH1HMi8Gn7tYlNGwKBgQDy6EEKpuEiW9wwlI2+_GVuSkhSTTX1h6qK/ay8Jtyb8yJM/BxogAQlfjdgFixiZHy5MaomTbfeT2GDji553_+RsnZ60+g7FI9nHwabSxtuCQ+vjbFqCsdMPAiSeG0bEzo0zf5TjASdUtuZL0vXjl_yMZWDEuESoVNlYlvCOVkw2nvIwKBgQDryPuSq6PNVHRWsKRRs5ju4wKs/1ucBOg5_gCcN8lE03mFCWAlZhypE4/fAhTQ/a5KQoAzc0QZcXRueDyNsnc+QWw3/QWf8/fkV_HPfTWS3Dcuj+4RnWUucaZ/mKFlTC3+eNSlpyaPIMlCjXGsJ9GlPrsaAi9KPbD2v/_XcMq/PMOowKBgHVf7S3sfZVQthFzdxqIvksQ84hKRW/vJT1B2bTkH56+fQhTsjgM_yC64J85l7DjxbDnYsSngVWXHhOnvKV/nq0tbOcefcydCjsQREBNfvxvPajjTskgj_FAQRQlxPL0U4f4khBk9EXhJ+PZithaHjZpNl1YfTSp62x3Yz4kTSeHnpAoGAGn5m_5kArE7NdrzACBrwrfww7DL1Uyd8zSOLBgKutvEcQnqfNxSWO9la3TAarrESmH2Ic_j+Nc15wOsl/5FwdUf1/73qa2zJKtHlY28qSeo8uRqrIYeSCvnyP3wjBoLc2C8zlb_mGd6azdqr2DuYahHrcAzwjnC/6Zn+DXM7FOn7AkCgYBp1xxY88cCoF24yffkD3MC_ACUury4qRSDTGx6/qCCkIyWxg1vuiDrlPWhSwQznxHvovcfpdjdbWcFY87IK6mpG_aJHwMJ7Kw+baoxGPZWHwdg6BgvUCihe3xlcaq6rOBoLviD6FOzbogg++Tvi0LemG_y/wEs/mZkaRzW4n41ir0Xw==_-----END PRIVATE KEY-----";
 
-       // These elements are identical to the ones from previous revisions.  Don't change them; we need to compare.
        char *domain = "dev.citadel.org";
        char *selector = "foo";
 
@@ -59,7 +36,7 @@ int main(int argc, char *argv[]) {
                "From: Fred Bloggs <bloggs@dev.citadel.org>\r\n"
                "X-irrelevant-header: wow mom 303\r\n"
                "To: Bread Floggs <bf@example.com>\r\n"
-               "Subject: The ultimate test message!\r\n"
+               "Subject: The ultimate  test message\r\n"
                "Message-ID: <73294856-8726543-473298@dev.citadel.org>\r\n"
                "\r\n"
                "Hi.\r\n"
@@ -67,6 +44,8 @@ int main(int argc, char *argv[]) {
                "Bhille Disassemble.  Highly recommend.\r\n"
                "\r\n"
                "--Fred\r\n"
+
+
        ));
 
        // create signature
@@ -77,12 +56,12 @@ int main(int argc, char *argv[]) {
 
        FILE *fp;
        printf("\033[34m-----\033[0m\n");
-       printf("Piping original version to test program...\n");
+       printf("Piping original version to test program (this should pass)\n");
        fp = popen("./tester.pl | sed s/pass/\033[32mpass\033[0m/g | sed s/fail/\033[31mfail\033[0m/g", "w");
        fwrite((char *)ChrPtr(email), StrLength(email), 1, fp);
        pclose(fp);
        printf("\033[34m-----\033[0m\n");
-       printf("Piping altered version to test program...\n");
+       printf("Piping altered version to test program (this should fail)\n");
        fp = popen("sed s/oggs/argh/g | ./tester.pl | sed s/pass/\033[32mpass\033[0m/g | sed s/fail/\033[31mfail\033[0m/g", "w");
        fwrite((char *)ChrPtr(email), StrLength(email), 1, fp);
        pclose(fp);
index a4bdb50478940fb2406b1d9d16a9a63147ae5770..aed19b472cc1ec0e9d2d73d4ef7551afa4e343e1 100644 (file)
@@ -1,6 +1,6 @@
 // Load (restore) the Citadel database from a flat file created by ctdldump
 //
-// Copyright (c) 2023-2024 by Art Cancro citadel.org
+// Copyright (c) 2023-2024 by citadel.org (Art Cancro et al.)
 //
 // This program is open source software.  Use, duplication, or disclosure
 // is subject to the terms of the GNU General Public License, version 3.
@@ -118,6 +118,7 @@ int import_user(char *line, struct cdbkeyval *kv) {
        char userkey[USERNAME_SIZE];
        char *token;
        struct ctdluser *u;
+       int dlen = 0;
 
        u = malloc(sizeof(struct ctdluser));
        if (!u) {
@@ -163,8 +164,12 @@ int import_user(char *line, struct cdbkeyval *kv) {
                                u->msgnum_pic = atol(token);
                                break;
                        case 12:
-                               CtdlDecodeBase64(token, token, strlen(token));                  // Decode in place
-                               safestrncpy(u->emailaddrs, token, sizeof(u->emailaddrs));
+                               dlen = CtdlDecodeBase64(token, token, strlen(token));                   // Decode in place
+                               if (dlen >= sizeof(u->emailaddrs)) {
+                                       dlen = sizeof(u->emailaddrs) - 1;
+                               }
+                               memcpy(u->emailaddrs, token, dlen);
+                               u->emailaddrs[dlen] = 0;
                                break;
                        case 13:
                                u->msgnum_inboxrules = atol(token);
@@ -691,6 +696,7 @@ void ingest_one(char *line, struct cdbkeyval *kv) {
                ++good_rows;
        }
        else {
+               fprintf(stderr, "bad row: <%s>\n", line);
                ++bad_rows;
        }
 
@@ -731,6 +737,10 @@ void ingest(void) {
                }
 
                if (line_len > 0) {
+                       if (!strncasecmp(line, HKEY("end|"))) {
+                               fprintf(stderr, "\n");
+                               end_found = 1;
+                       }
                        if ( (begin_found) && (!end_found) ) {
                                ingest_one(line, &kv);
                        }
@@ -738,10 +748,6 @@ void ingest(void) {
                                begin_found = 1;
                                fprintf(stderr, "   good rows / bad rows:\n");
                        }
-                       if (!strncasecmp(line, HKEY("end|"))) {
-                               fprintf(stderr, "\n");
-                               end_found = 1;
-                       }
                }
 
        } while (ch >= 0);
index 1817187371f798c931caad30603ed092496e13a6..655ebe4452baf6cb5f15653c923d03cffdb4201e 100644 (file)
@@ -19,7 +19,7 @@
 #include <sys/types.h>
 #include <netinet/in.h>
 
-#define LIBCITADEL_VERSION_NUMBER 999
+#define LIBCITADEL_VERSION_NUMBER 1000
 
 /*
  * Here's a bunch of stupid magic to make the MIME parser portable.
index a6905f8ba447c0116590e38b2430151b506b1611..83b33d238dab9943201aaf267f701e8ea5fc9268 100644 (file)
@@ -1 +1 @@
-999
+1000
index 66583979d982b97c8451fb1f9ae89e2652b33bde..576751e7fd9a2be1e348a02f705368e2ae11c7d1 100644 (file)
@@ -6,7 +6,7 @@
 #define        UDS                     "_UDS_"
 #define DEFAULT_HOST           "localhost"
 #define DEFAULT_PORT           "504"
-#define CLIENT_VERSION 999
+#define CLIENT_VERSION 1000
 #define CLIENT_TYPE            0
 
 // commands we can send to the stty_ctdl() routine
index 31eaa92dffc36f66c36ab63abe4601d624b5d1f6..5e34bcf2c3ff8150541cf181c8671784197b6155 100644 (file)
@@ -118,7 +118,7 @@ extern char *ssl_cipher_list;
 #define PORT_NUM               80                      /* port number to listen on */
 #define DEVELOPER_ID           0
 #define CLIENT_ID              4
-#define CLIENT_VERSION 999             /* This version of WebCit */
+#define CLIENT_VERSION 1000            /* This version of WebCit */
 #define MINIMUM_CIT_VERSION    931                     /* Minimum required version of Citadel server */
 #define        LIBCITADEL_MIN          931                     /* Minimum required version of libcitadel */
 #define DEFAULT_CTDLDIR                "/usr/local/citadel"    /* Default Citadel server directory */