AUTH PLAIN: password length has to be its own variable, else it may contain invalid...
[citadel.git] / citadel / modules / smtp / serv_smtp.c
index ad9137ff3961073ae65e030a35f12d7af89c5f4a..892d8e7a7885d4aef9e851923284b9e0a9057333 100644 (file)
  * The VRFY and EXPN commands have been removed from this implementation
  * because nobody uses these commands anymore, except for spammers.
  *
- * Copyright (c) 1998-2012 by the citadel.org team
+ * Copyright (c) 1998-2013 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 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.
+ * 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.
  */
 
 #include "sysdep.h"
@@ -69,6 +69,7 @@
 #include "config.h"
 #include "control.h"
 #include "user_ops.h"
+#include "room_ops.h"
 #include "database.h"
 #include "msgbase.h"
 #include "internet_addressing.h"
@@ -147,6 +148,8 @@ void smtp_greeting(int is_msa)
        sSMTP->from = NewStrBufPlain(NULL, SIZ);
        sSMTP->recipients = NewStrBufPlain(NULL, SIZ);
        sSMTP->OneRcpt = NewStrBufPlain(NULL, SIZ);
+       sSMTP->preferred_sender_email = NULL;
+       sSMTP->preferred_sender_name = NULL;
 
        /* If this config option is set, reject connections from problem
         * addresses immediately instead of after they execute a RCPT
@@ -320,12 +323,14 @@ void smtp_webcit_preferences_hack_backend(long msgnum, void *userdata) {
                return;
        }
 
-       if ( (msg->cm_fields[eMsgSubject]) && (!strcasecmp(msg->cm_fields[eMsgSubject], "__ WebCit Preferences __")) ) {
+       if ( !CM_IsEmpty(msg, eMsgSubject) &&
+            (!strcasecmp(msg->cm_fields[eMsgSubject], "__ WebCit Preferences __")))
+       {
                /* This is it!  Change ownership of the message text so it doesn't get freed. */
                *webcit_conf = (char *)msg->cm_fields[eMesageText];
                msg->cm_fields[eMesageText] = NULL;
        }
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
 }
 
 
@@ -336,6 +341,7 @@ void smtp_webcit_preferences_hack_backend(long msgnum, void *userdata) {
 void smtp_webcit_preferences_hack(void) {
        char config_roomname[ROOMNAMELEN];
        char *webcit_conf = NULL;
+       citsmtp *sSMTP = SMTP;
 
        snprintf(config_roomname, sizeof config_roomname, "%010ld.%s", CC->user.usernum, USERCONFIGROOM);
        if (CtdlGetRoom(&CC->room, config_roomname) != 0) {
@@ -352,10 +358,24 @@ void smtp_webcit_preferences_hack(void) {
                return;
        }
 
-       /* FIXME : now do something with this data */
+       /* Parse the webcit configuration and attempt to do something useful with it */
+       char *str = webcit_conf;
+       char *saveptr = str;
+       char *this_line = NULL;
+       while (this_line = strtok_r(str, "\n", &saveptr), this_line != NULL) {
+               str = NULL;
+               if (!strncasecmp(this_line, "defaultfrom|", 12)) {
+                       sSMTP->preferred_sender_email = NewStrBufPlain(&this_line[12], -1);
+               }
+               if (!strncasecmp(this_line, "defaultname|", 12)) {
+                       sSMTP->preferred_sender_name = NewStrBufPlain(&this_line[12], -1);
+               }
+               if ((!strncasecmp(this_line, "defaultname|", 12)) && (sSMTP->preferred_sender_name == NULL)) {
+                       sSMTP->preferred_sender_name = NewStrBufPlain(&this_line[12], -1);
+               }
 
+       }
        free(webcit_conf);
-       abort();
 }
 
 
@@ -419,19 +439,44 @@ void smtp_get_pass(long offset, long Flags)
 void smtp_try_plain(long offset, long Flags)
 {
        citsmtp *sSMTP = SMTP;
-       char decoded_authstring[1024];
-       char ident[256];
-       char user[256];
-       char pass[256];
+       const char*decoded_authstring;
+       char ident[256] = "";
+       char user[256] = "";
+       char pass[256] = "";
        int result;
-       long len;
 
-       CtdlDecodeBase64(decoded_authstring, ChrPtr(sSMTP->Cmd), StrLength(sSMTP->Cmd));
-       safestrncpy(ident, decoded_authstring, sizeof ident);
-       safestrncpy(user, &decoded_authstring[strlen(ident) + 1], sizeof user);
-       len = safestrncpy(pass, &decoded_authstring[strlen(ident) + strlen(user) + 2], sizeof pass);
-       if (len == -1)
-               len = sizeof(pass) - 1;
+       long decoded_len;
+       long len = 0;
+       long plen = 0;
+
+       memset(pass, 0, sizeof(pass));
+       decoded_len = StrBufDecodeBase64(sSMTP->Cmd);
+
+       if (decoded_len > 0)
+       {
+               decoded_authstring = ChrPtr(sSMTP->Cmd);
+
+               len = safestrncpy(ident, decoded_authstring, sizeof ident);
+
+               decoded_len -= len - 1;
+               decoded_authstring += len + 1;
+
+               if (decoded_len > 0)
+               {
+                       len = safestrncpy(user, decoded_authstring, sizeof user);
+
+                       decoded_authstring += len + 1;
+                       decoded_len -= len - 1;
+               }
+
+               if (decoded_len > 0)
+               {
+                       plen = safestrncpy(pass, decoded_authstring, sizeof pass);
+
+                       if (plen < 0)
+                               plen = sizeof(pass) - 1;
+               }
+       }
 
        sSMTP->command_state = smtp_command;
 
@@ -443,8 +488,8 @@ void smtp_try_plain(long offset, long Flags)
        }
 
        if (result == login_ok) {
-               if (CtdlTryPassword(pass, len) == pass_ok) {
-////                   smtp_webcit_preferences_hack();
+               if (CtdlTryPassword(pass, plen) == pass_ok) {
+                       smtp_webcit_preferences_hack();
                        smtp_auth_greeting(offset, Flags);
                        return;
                }
@@ -602,7 +647,7 @@ void smtp_mail(long offset, long flags) {
         * address so we don't have to contend with the empty string causing
         * other code to fail when it's expecting something there.
         */
-       if (StrLength(sSMTP->from)) {
+       if (StrLength(sSMTP->from) == 0) {
                StrBufPlain(sSMTP->from, HKEY("someone@example.com"));
        }
 
@@ -648,7 +693,7 @@ void smtp_rcpt(long offset, long flags)
 {
        struct CitContext *CCC = CC;
        char message_to_spammer[SIZ];
-       struct recptypes *valid = NULL;
+       recptypes *valid = NULL;
        citsmtp *sSMTP = SMTP;
 
        if (StrLength(sSMTP->from) == 0) {
@@ -747,7 +792,7 @@ void smtp_data(long offset, long flags)
        struct CtdlMessage *msg = NULL;
        long msgnum = (-1L);
        char nowstamp[SIZ];
-       struct recptypes *valid;
+       recptypes *valid;
        int scan_errors;
        int i;
        citsmtp *sSMTP = SMTP;
@@ -813,7 +858,7 @@ void smtp_data(long offset, long flags)
        if ( (CCC->logged_in) && (config.c_rfc822_strict_from != CFG_SMTP_FROM_NOFILTER) ) {
                int validemail = 0;
                
-               if (!IsEmptyStr(msg->cm_fields[erFc822Addr])       &&
+               if (!CM_IsEmpty(msg, erFc822Addr)       &&
                    ((config.c_rfc822_strict_from == CFG_SMTP_FROM_CORRECT) || 
                     (config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT)    )  )
                {
@@ -839,32 +884,27 @@ void smtp_data(long offset, long flags)
                        return;
                }
 
-               if (msg->cm_fields[eAuthor] != NULL) free(msg->cm_fields[eAuthor]);
-               if (msg->cm_fields[eNodeName] != NULL) free(msg->cm_fields[eNodeName]);
-               if (msg->cm_fields[eHumanNode] != NULL) free(msg->cm_fields[eHumanNode]);
-               if (msg->cm_fields[eOriginalRoom] != NULL) free(msg->cm_fields[eOriginalRoom]);
-               msg->cm_fields[eAuthor] = strdup(CCC->user.fullname);
-               msg->cm_fields[eNodeName] = strdup(config.c_nodename);
-               msg->cm_fields[eHumanNode] = strdup(config.c_humannode);
-               msg->cm_fields[eOriginalRoom] = strdup(MAILROOM);
+               CM_SetField(msg, eNodeName, CFG_KEY(c_nodename));
+               CM_SetField(msg, eHumanNode, CFG_KEY(c_humannode));
+               CM_SetField(msg, eOriginalRoom, HKEY(MAILROOM));
+               if (sSMTP->preferred_sender_name != NULL)
+                       CM_SetField(msg, eAuthor, SKEY(sSMTP->preferred_sender_name));
+               else 
+                       CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname));
 
                if (!validemail) {
-                       if (msg->cm_fields[erFc822Addr] != NULL) free(msg->cm_fields[erFc822Addr]);
-                       msg->cm_fields[erFc822Addr] = strdup(CCC->cs_inet_email);
+                       if (sSMTP->preferred_sender_email != NULL)
+                               CM_SetField(msg, erFc822Addr, SKEY(sSMTP->preferred_sender_email));
+                       else
+                               CM_SetField(msg, erFc822Addr, CCC->cs_inet_email, strlen(CCC->cs_inet_email));
                }
        }
 
        /* Set the "envelope from" address */
-       if (msg->cm_fields[eMessagePath] != NULL) {
-               free(msg->cm_fields[eMessagePath]);
-       }
-       msg->cm_fields[eMessagePath] = strdup(ChrPtr(sSMTP->from));
+       CM_SetField(msg, eMessagePath, SKEY(sSMTP->from));
 
        /* Set the "envelope to" address */
-       if (msg->cm_fields[eenVelopeTo] != NULL) {
-               free(msg->cm_fields[eenVelopeTo]);
-       }
-       msg->cm_fields[eenVelopeTo] = strdup(ChrPtr(sSMTP->recipients));
+       CM_SetField(msg, eenVelopeTo, SKEY(sSMTP->recipients));
 
        /* Submit the message into the Citadel system. */
        valid = validate_recipients(
@@ -881,13 +921,13 @@ void smtp_data(long offset, long flags)
                scan_errors = 0;
        }
        else {
-               scan_errors = PerformMessageHooks(msg, EVT_SMTPSCAN);
+               scan_errors = PerformMessageHooks(msg, valid, EVT_SMTPSCAN);
        }
 
        if (scan_errors > 0) {  /* We don't want this message! */
 
-               if (msg->cm_fields[eErrorMsg] == NULL) {
-                       msg->cm_fields[eErrorMsg] = strdup("Message rejected by filter");
+               if (CM_IsEmpty(msg, eErrorMsg)) {
+                       CM_SetField(msg, eErrorMsg, HKEY("Message rejected by filter"));
                }
 
                StrBufPrintf(sSMTP->OneRcpt, "550 %s\r\n", msg->cm_fields[eErrorMsg]);
@@ -932,7 +972,7 @@ void smtp_data(long offset, long flags)
        );
 
        /* Clean up */
-       CtdlFreeMessage(msg);
+       CM_Free(msg);
        free_recipients(valid);
        smtp_data_clear(0, 0);  /* clear out the buffers now */
 }
@@ -981,14 +1021,17 @@ void smtp_command_loop(void)
 
        if (sSMTP->command_state == smtp_user) {
                smtp_get_user(0);
+               return;
        }
 
        else if (sSMTP->command_state == smtp_password) {
                smtp_get_pass(0, 0);
+               return;
        }
 
        else if (sSMTP->command_state == smtp_plain) {
                smtp_try_plain(0, 0);
+               return;
        }
 
        pchs = pch = ChrPtr(sSMTP->Cmd);
@@ -1056,6 +1099,8 @@ void smtp_cleanup_function(void)
        FreeStrBuf(&sSMTP->from);
        FreeStrBuf(&sSMTP->recipients);
        FreeStrBuf(&sSMTP->OneRcpt);
+       FreeStrBuf(&sSMTP->preferred_sender_email);
+       FreeStrBuf(&sSMTP->preferred_sender_name);
 
        free(sSMTP);
 }