]> code.citadel.org Git - citadel.git/blobdiff - citadel/serv_smtp.c
mk_module_init.sh now tests to see if echo supports -e and -E
[citadel.git] / citadel / serv_smtp.c
index a6bae93427cd92253bc9841bd23eaac4fa02ef2f..c2329ba9168cf958524ed78e8a568efdd842bc16 100644 (file)
@@ -20,6 +20,9 @@
  * RFC 2821 - Simple Mail Transfer Protocol
  * RFC 2822 - Internet Message Format
  * RFC 2920 - SMTP Service Extension for Command Pipelining
+ *  
+ * The VRFY and EXPN commands have been removed from this implementation
+ * because nobody uses these commands anymore, except for spammers.
  *
  */
 
 #include <arpa/inet.h>
 #include "citadel.h"
 #include "server.h"
-#include "sysdep_decls.h"
 #include "citserver.h"
 #include "support.h"
 #include "config.h"
 #include "control.h"
-#include "serv_extensions.h"
 #include "room_ops.h"
 #include "user_ops.h"
 #include "policy.h"
 #include "snprintf.h"
 #endif
 
+
+#include "ctdl_module.h"
+
+
+
 struct citsmtp {               /* Information about the current session */
        int command_state;
        char helo_node[SIZ];
-       struct ctdluser vrfy_buffer;
-       int vrfy_count;
-       char vrfy_match[SIZ];
        char from[SIZ];
        char recipients[SIZ];
        int number_of_recipients;
@@ -106,14 +109,7 @@ enum {                             /* Command states for login authentication */
        smtp_plain
 };
 
-enum {                         /* Delivery modes */
-       smtp_deliver_local,
-       smtp_deliver_remote
-};
-
 #define SMTP           CC->SMTP
-#define SMTP_RECPS     CC->SMTP_RECPS
-#define SMTP_ROOMS     CC->SMTP_ROOMS
 
 
 int run_queue_now = 0; /* Set to 1 to ignore SMTP send retry times */
@@ -128,7 +124,7 @@ int run_queue_now = 0;      /* Set to 1 to ignore SMTP send retry times */
 /*
  * Here's where our SMTP session begins its happy day.
  */
-void smtp_greeting(void)
+void smtp_greeting(int is_msa)
 {
        char message_to_spammer[1024];
 
@@ -136,20 +132,17 @@ void smtp_greeting(void)
        CC->internal_pgm = 1;
        CC->cs_flags |= CS_STEALTH;
        SMTP = malloc(sizeof(struct citsmtp));
-       SMTP_RECPS = malloc(SIZ);
-       SMTP_ROOMS = malloc(SIZ);
        memset(SMTP, 0, sizeof(struct citsmtp));
-       memset(SMTP_RECPS, 0, SIZ);
-       memset(SMTP_ROOMS, 0, SIZ);
+       SMTP->is_msa = is_msa;
 
        /* If this config option is set, reject connections from problem
         * addresses immediately instead of after they execute a RCPT
         */
-       if (config.c_rbl_at_greeting) {
+       if ( (config.c_rbl_at_greeting) && (SMTP->is_msa == 0) ) {
                if (rbl_check(message_to_spammer)) {
                        cprintf("550 %s\r\n", message_to_spammer);
                        CC->kill_me = 1;
-                       /* no need to free(valid), it's not allocated yet */
+                       /* no need to free_recipients(valid), it's not allocated yet */
                        return;
                }
        }
@@ -161,10 +154,13 @@ void smtp_greeting(void)
                        config.c_maxsessions
                );
                CC->kill_me = 1;
-               /* no need to free(valid), it's not allocated yet */
+               /* no need to free_recipients(valid), it's not allocated yet */
                return;
        }
 
+       /* Note: the FQDN *must* appear as the first thing after the 220 code.
+        * Some clients (including citmail.c) depend on it being there.
+        */
        cprintf("220 %s ESMTP Citadel server ready.\r\n", config.c_fqdn);
 }
 
@@ -175,7 +171,7 @@ void smtp_greeting(void)
 #ifdef HAVE_OPENSSL
 void smtps_greeting(void) {
        CtdlStartTLS(NULL, NULL, NULL);
-       smtp_greeting();
+       smtp_greeting(0);
 }
 #endif
 
@@ -184,8 +180,7 @@ void smtps_greeting(void) {
  * SMTP MSA port requires authentication.
  */
 void smtp_msa_greeting(void) {
-       smtp_greeting();
-       SMTP->is_msa = 1;
+       smtp_greeting(1);
 }
 
 
@@ -193,16 +188,24 @@ void smtp_msa_greeting(void) {
  * LMTP is like SMTP but with some extra bonus footage added.
  */
 void lmtp_greeting(void) {
-       smtp_greeting();
+       smtp_greeting(0);
        SMTP->is_lmtp = 1;
 }
 
 
+/* 
+ * Generic SMTP MTA greeting
+ */
+void smtp_mta_greeting(void) {
+       smtp_greeting(0);
+}
+
+
 /*
  * We also have an unfiltered LMTP socket that bypasses spam filters.
  */
 void lmtp_unfiltered_greeting(void) {
-       smtp_greeting();
+       smtp_greeting(0);
        SMTP->is_lmtp = 1;
        SMTP->is_unfiltered = 1;
 }
@@ -295,7 +298,6 @@ void smtp_help(void) {
        cprintf("214-Commands accepted:\r\n");
        cprintf("214-    DATA\r\n");
        cprintf("214-    EHLO\r\n");
-       cprintf("214-    EXPN\r\n");
        cprintf("214-    HELO\r\n");
        cprintf("214-    HELP\r\n");
        cprintf("214-    MAIL\r\n");
@@ -303,7 +305,6 @@ void smtp_help(void) {
        cprintf("214-    QUIT\r\n");
        cprintf("214-    RCPT\r\n");
        cprintf("214-    RSET\r\n");
-       cprintf("214-    VRFY\r\n");
        cprintf("214     \r\n");
 }
 
@@ -317,7 +318,7 @@ void smtp_get_user(char *argbuf) {
 
        CtdlDecodeBase64(username, argbuf, SIZ);
        /* lprintf(CTDL_DEBUG, "Trying <%s>\n", username); */
-       if (CtdlLoginExistingUser(username) == login_ok) {
+       if (CtdlLoginExistingUser(NULL, username) == login_ok) {
                CtdlEncodeBase64(buf, "Password:", 9);
                cprintf("334 %s\r\n", buf);
                SMTP->command_state = smtp_password;
@@ -355,16 +356,23 @@ void smtp_try_plain(char *encoded_authstring) {
        char ident[256];
        char user[256];
        char pass[256];
+       int result;
 
-       CtdlDecodeBase64(decoded_authstring,
-                       encoded_authstring,
-                       strlen(encoded_authstring) );
+       CtdlDecodeBase64(decoded_authstring, encoded_authstring, strlen(encoded_authstring) );
        safestrncpy(ident, decoded_authstring, sizeof ident);
        safestrncpy(user, &decoded_authstring[strlen(ident) + 1], sizeof user);
        safestrncpy(pass, &decoded_authstring[strlen(ident) + strlen(user) + 2], sizeof pass);
 
        SMTP->command_state = smtp_command;
-       if (CtdlLoginExistingUser(user) == login_ok) {
+
+       if (strlen(ident) > 0) {
+               result = CtdlLoginExistingUser(user, ident);
+       }
+       else {
+               result = CtdlLoginExistingUser(NULL, user);
+       }
+
+       if (result == login_ok) {
                if (CtdlTryPassword(pass) == pass_ok) {
                        smtp_auth_greeting();
                        return;
@@ -422,86 +430,6 @@ void smtp_auth(char *argbuf) {
 }
 
 
-/*
- * Back end for smtp_vrfy() command
- */
-void smtp_vrfy_backend(struct ctdluser *us, void *data) {
-
-       if (!fuzzy_match(us, SMTP->vrfy_match)) {
-               ++SMTP->vrfy_count;
-               memcpy(&SMTP->vrfy_buffer, us, sizeof(struct ctdluser));
-       }
-}
-
-
-/* 
- * Implements the VRFY (verify user name) command.
- * Performs fuzzy match on full user names.
- */
-void smtp_vrfy(char *argbuf) {
-       SMTP->vrfy_count = 0;
-       strcpy(SMTP->vrfy_match, argbuf);
-       ForEachUser(smtp_vrfy_backend, NULL);
-
-       if (SMTP->vrfy_count < 1) {
-               cprintf("550 5.1.1 String does not match anything.\r\n");
-       }
-       else if (SMTP->vrfy_count == 1) {
-               cprintf("250 %s <cit%ld@%s>\r\n",
-                       SMTP->vrfy_buffer.fullname,
-                       SMTP->vrfy_buffer.usernum,
-                       config.c_fqdn);
-       }
-       else if (SMTP->vrfy_count > 1) {
-               cprintf("553 5.1.4 Request ambiguous: %d users matched.\r\n",
-                       SMTP->vrfy_count);
-       }
-
-}
-
-
-
-/*
- * Back end for smtp_expn() command
- */
-void smtp_expn_backend(struct ctdluser *us, void *data) {
-
-       if (!fuzzy_match(us, SMTP->vrfy_match)) {
-
-               if (SMTP->vrfy_count >= 1) {
-                       cprintf("250-%s <cit%ld@%s>\r\n",
-                               SMTP->vrfy_buffer.fullname,
-                               SMTP->vrfy_buffer.usernum,
-                               config.c_fqdn);
-               }
-
-               ++SMTP->vrfy_count;
-               memcpy(&SMTP->vrfy_buffer, us, sizeof(struct ctdluser));
-       }
-}
-
-
-/* 
- * Implements the EXPN (expand user name) command.
- * Performs fuzzy match on full user names.
- */
-void smtp_expn(char *argbuf) {
-       SMTP->vrfy_count = 0;
-       strcpy(SMTP->vrfy_match, argbuf);
-       ForEachUser(smtp_expn_backend, NULL);
-
-       if (SMTP->vrfy_count < 1) {
-               cprintf("550 5.1.1 String does not match anything.\r\n");
-       }
-       else if (SMTP->vrfy_count >= 1) {
-               cprintf("250 %s <cit%ld@%s>\r\n",
-                       SMTP->vrfy_buffer.fullname,
-                       SMTP->vrfy_buffer.usernum,
-                       config.c_fqdn);
-       }
-}
-
-
 /*
  * Implements the RSET (reset state) command.
  * Currently this just zeroes out the state buffer.  If pointers to data
@@ -631,7 +559,7 @@ void smtp_mail(char *argbuf) {
  * Implements the "RCPT To:" command
  */
 void smtp_rcpt(char *argbuf) {
-       char recp[SIZ];
+       char recp[1024];
        char message_to_spammer[SIZ];
        struct recptypes *valid = NULL;
 
@@ -652,7 +580,7 @@ void smtp_rcpt(char *argbuf) {
                return;
        }
 
-       strcpy(recp, &argbuf[3]);
+       safestrncpy(recp, &argbuf[3], sizeof recp);
        striplt(recp);
        stripallbut(recp, '<', '>');
 
@@ -667,7 +595,7 @@ void smtp_rcpt(char *argbuf) {
                if (config.c_rbl_at_greeting == 0) {    /* Don't RBL again if we already did it */
                        if (rbl_check(message_to_spammer)) {
                                cprintf("550 %s\r\n", message_to_spammer);
-                               /* no need to free(valid), it's not allocated yet */
+                               /* no need to free_recipients(valid), it's not allocated yet */
                                return;
                        }
                }
@@ -676,7 +604,7 @@ void smtp_rcpt(char *argbuf) {
        valid = validate_recipients(recp);
        if (valid->num_error != 0) {
                cprintf("599 5.1.1 Error: %s\r\n", valid->errormsg);
-               free(valid);
+               free_recipients(valid);
                return;
        }
 
@@ -684,7 +612,7 @@ void smtp_rcpt(char *argbuf) {
                if (CC->logged_in) {
                         if (CtdlCheckInternetMailPermission(&CC->user)==0) {
                                cprintf("551 5.7.1 <%s> - you do not have permission to send Internet mail\r\n", recp);
-                                free(valid);
+                                free_recipients(valid);
                                 return;
                         }
                 }
@@ -694,7 +622,7 @@ void smtp_rcpt(char *argbuf) {
                if ( (SMTP->message_originated_locally == 0)
                   && (SMTP->is_lmtp == 0) ) {
                        cprintf("551 5.7.1 <%s> - relaying denied\r\n", recp);
-                       free(valid);
+                       free_recipients(valid);
                        return;
                }
        }
@@ -705,8 +633,9 @@ void smtp_rcpt(char *argbuf) {
        }
        strcat(SMTP->recipients, recp);
        SMTP->number_of_recipients += 1;
-       if (valid != NULL) 
-               free(valid);
+       if (valid != NULL)  {
+               free_recipients(valid);
+       }
 }
 
 
@@ -860,7 +789,7 @@ void smtp_data(void) {
 
        /* Clean up */
        CtdlFreeMessage(msg);
-       free(valid);
+       free_recipients(valid);
        smtp_data_clear();      /* clear out the buffers now */
 }
 
@@ -924,10 +853,6 @@ void smtp_command_loop(void) {
                smtp_data();
        }
 
-       else if (!strncasecmp(cmdbuf, "EXPN", 4)) {
-               smtp_expn(&cmdbuf[5]);
-       }
-
        else if (!strncasecmp(cmdbuf, "HELO", 4)) {
                smtp_hello(&cmdbuf[5], 0);
        }
@@ -970,10 +895,6 @@ void smtp_command_loop(void) {
                smtp_starttls();
        }
 #endif
-       else if (!strncasecmp(cmdbuf, "VRFY", 4)) {
-               smtp_vrfy(&cmdbuf[5]);
-       }
-
        else {
                cprintf("502 5.0.0 I'm afraid I can't do that.\r\n");
        }
@@ -1193,9 +1114,10 @@ void smtp_try(const char *key, const char *addr, int *status,
 
        /* Do an AUTH command if necessary */
        if (strlen(mx_user) > 0) {
+               char encoded[1024];
                sprintf(buf, "%s%c%s%c%s", mx_user, '\0', mx_user, '\0', mx_pass);
-               CtdlEncodeBase64(mailfrom, buf, strlen(mx_user) + strlen(mx_user) + strlen(mx_pass) + 2);
-               snprintf(buf, sizeof buf, "AUTH PLAIN %s\r\n", mailfrom);
+               CtdlEncodeBase64(encoded, buf, strlen(mx_user) + strlen(mx_user) + strlen(mx_pass) + 2);
+               snprintf(buf, sizeof buf, "AUTH PLAIN %s\r\n", encoded);
                lprintf(CTDL_DEBUG, ">%s", buf);
                sock_write(sock, buf, strlen(buf));
                if (ml_sock_gets(sock, buf) < 0) {
@@ -1452,12 +1374,7 @@ void smtp_do_bounce(char *instr) {
                        omsgid = atol(addr);
                }
 
-               if (
-                  (!strcasecmp(key, "local"))
-                  || (!strcasecmp(key, "remote"))
-                  || (!strcasecmp(key, "ignet"))
-                  || (!strcasecmp(key, "room"))
-               ) {
+               if (!strcasecmp(key, "remote")) {
                        if (status == 5) bounce_this = 1;
                        if (give_up) bounce_this = 1;
                }
@@ -1475,7 +1392,7 @@ void smtp_do_bounce(char *instr) {
                        strcat(bmsg->cm_fields['M'], addr);
                        strcat(bmsg->cm_fields['M'], ": ");
                        strcat(bmsg->cm_fields['M'], dsn);
-                       strcat(bmsg->cm_fields['M'], "\n");
+                       strcat(bmsg->cm_fields['M'], "\r\n");
 
                        remove_token(instr, i, '\n');
                        --i;
@@ -1540,7 +1457,7 @@ void smtp_do_bounce(char *instr) {
 
                /* Free up the memory we used */
                if (valid != NULL) {
-                       free(valid);
+                       free_recipients(valid);
                }
        }
 
@@ -1576,12 +1493,7 @@ int smtp_purge_completed_deliveries(char *instr) {
 
                completed = 0;
 
-               if (
-                  (!strcasecmp(key, "local"))
-                  || (!strcasecmp(key, "remote"))
-                  || (!strcasecmp(key, "ignet"))
-                  || (!strcasecmp(key, "room"))
-               ) {
+               if (!strcasecmp(key, "remote")) {
                        if (status == 2) completed = 1;
                        else ++incomplete;
                }
@@ -1895,20 +1807,17 @@ void smtp_cleanup_function(void) {
 
        lprintf(CTDL_DEBUG, "Performing SMTP cleanup hook\n");
        free(SMTP);
-       free(SMTP_ROOMS);
-       free(SMTP_RECPS);
 }
 
 
 
 
 
-char *serv_smtp_init(void)
+CTDL_MODULE_INIT(smtp)
 {
-
        CtdlRegisterServiceHook(config.c_smtp_port,     /* SMTP MTA */
                                NULL,
-                               smtp_greeting,
+                               smtp_mta_greeting,
                                smtp_command_loop,
                                NULL);
 
@@ -1927,20 +1836,22 @@ char *serv_smtp_init(void)
                                NULL);
 
        CtdlRegisterServiceHook(0,                      /* local LMTP */
-                                                       file_lmtp_socket,
-                                                       lmtp_greeting,
-                                                       smtp_command_loop,
-                                                       NULL);
+                               file_lmtp_socket,
+                               lmtp_greeting,
+                               smtp_command_loop,
+                               NULL);
 
        CtdlRegisterServiceHook(0,                      /* local LMTP */
-                                                       file_lmtp_unfiltered_socket,
-                                                       lmtp_unfiltered_greeting,
-                                                       smtp_command_loop,
-                                                       NULL);
+                               file_lmtp_unfiltered_socket,
+                               lmtp_unfiltered_greeting,
+                               smtp_command_loop,
+                               NULL);
 
        smtp_init_spoolout();
        CtdlRegisterSessionHook(smtp_do_queue, EVT_TIMER);
        CtdlRegisterSessionHook(smtp_cleanup_function, EVT_STOP);
        CtdlRegisterProtoHook(cmd_smtp, "SMTP", "SMTP utility commands");
+
+       /* return our Subversion id for the Log */
        return "$Id$";
 }