SMTP-Relay: add other ways of filtering
authorWilfried Goesgens <dothebart@citadel.org>
Tue, 24 Jul 2012 19:01:33 +0000 (21:01 +0200)
committerWilfried Goesgens <dothebart@citadel.org>
Tue, 24 Jul 2012 19:01:33 +0000 (21:01 +0200)
  - FROM is changed in all cases (as it was before...)
  - FROM isn't evaluated at all (as it was before)
  - FROM is looked up in the list of available email addresses, and corrected if not found.
  - FROM is looked up in the list of available email addresses, and if not found, relay access is denied.

citadel/modules/smtp/serv_smtp.c
libcitadel/lib/libcitadel.h
webcit/siteconfig.c
webcit/static/t/aide/siteconfig/tab_network.html

index 2ebcc4bc12440a88e14dd1a3927376a1fb25a606..a4e7d75afb00d2a131631eeb304950a881a85071 100644 (file)
@@ -690,43 +690,48 @@ void smtp_data(void) {
         * to something ugly like "0000058008.Sent Items>" when the message
         * is read with a Citadel client.
         */
-       if ( (CC->logged_in) && (config.c_rfc822_strict_from == 0) ) {
-
-#ifdef SMTP_REJECT_INVALID_SENDER
+       if ( (CC->logged_in) && (config.c_rfc822_strict_from != CFG_SMTP_FROM_NOFILTER) ) {
                int validemail = 0;
-
-               if (!IsEmptyStr(CC->cs_inet_email) && 
-                   !IsEmptyStr(msg->cm_fields['F']))
-                       validemail = strcmp(CC->cs_inet_email, msg->cm_fields['F']) == 0;
-               if ((!validemail) && 
-                   (!IsEmptyStr(CC->cs_inet_other_emails)))
+               
+               if (!IsEmptyStr(msg->cm_fields['F'])       &&
+                   ((config.c_rfc822_strict_from == CFG_SMTP_FROM_CORRECT) || 
+                    (config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT)    )  )
                {
-                       int num_secondary_emails = 0;
-                       int i;
-                       num_secondary_emails = num_tokens(CC->cs_inet_other_emails, '|');
-                       for (i=0; i<num_secondary_emails && !validemail; ++i) {
-                               char buf[256];
-                               extract_token(buf, CC->cs_inet_other_emails,i,'|',sizeof CC->cs_inet_other_emails);
-                               validemail = strcmp(buf, msg->cm_fields['F']) == 0;
+                       if (!IsEmptyStr(CC->cs_inet_email))
+                               validemail = strcmp(CC->cs_inet_email, msg->cm_fields['F']) == 0;
+                       if ((!validemail) && 
+                           (!IsEmptyStr(CC->cs_inet_other_emails)))
+                       {
+                               int num_secondary_emails = 0;
+                               int i;
+                               num_secondary_emails = num_tokens(CC->cs_inet_other_emails, '|');
+                               for (i=0; i < num_secondary_emails && !validemail; ++i) {
+                                       char buf[256];
+                                       extract_token(buf, CC->cs_inet_other_emails,i,'|',sizeof CC->cs_inet_other_emails);
+                                       validemail = strcmp(buf, msg->cm_fields['F']) == 0;
+                               }
                        }
                }
-               if (!validemail) {
+
+               if (!validemail && (config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT)) {
                        syslog(LOG_ERR, "invalid sender '%s' - rejecting this message", msg->cm_fields['F']);
                        cprintf("550 Invalid sender '%s' - rejecting this message.\r\n", msg->cm_fields['F']);
                        return;
                }
-#endif /* SMTP_REJECT_INVALID_SENDER */
 
                if (msg->cm_fields['A'] != NULL) free(msg->cm_fields['A']);
                if (msg->cm_fields['N'] != NULL) free(msg->cm_fields['N']);
                if (msg->cm_fields['H'] != NULL) free(msg->cm_fields['H']);
-               if (msg->cm_fields['F'] != NULL) free(msg->cm_fields['F']);
                if (msg->cm_fields['O'] != NULL) free(msg->cm_fields['O']);
                msg->cm_fields['A'] = strdup(CC->user.fullname);
                msg->cm_fields['N'] = strdup(config.c_nodename);
                msg->cm_fields['H'] = strdup(config.c_humannode);
-               msg->cm_fields['F'] = strdup(CC->cs_inet_email);
                msg->cm_fields['O'] = strdup(MAILROOM);
+
+               if (!validemail) {
+                       if (msg->cm_fields['F'] != NULL) free(msg->cm_fields['F']);
+                       msg->cm_fields['F'] = strdup(CC->cs_inet_email);
+               }
        }
 
        /* Set the "envelope from" address */
index 9b58553b10a3650c8a8988a5f4187a597bd5d6e8..03364a0baa1f96ea87543a59e585d2ea0f2fea21 100644 (file)
@@ -659,6 +659,10 @@ extern ConstStr RoomNetCfgStrs[maxRoomNetCfg];
 extern "C" {
 #endif
 
+#define CFG_SMTP_FROM_FILTERALL 0
+#define CFG_SMTP_FROM_NOFILTER 1
+#define CFG_SMTP_FROM_CORRECT 2
+#define CFG_SMTP_FROM_REJECT 3
 /*
  * MIME types used in Citadel for configuration stuff
  */
index 5bd9fffcb23146ee15f0dbdc4d3601b3c68b39bd..dede757680390795fccc3f398ef7994d726ebc5e 100644 (file)
@@ -128,6 +128,9 @@ void LoadZoneFiles(void)
 
 typedef struct _CfgMapping {
        int type;
+       int min;
+       int max;
+       const char *defval;
        const char *Key;
        long len;
 } CfgMapping;
@@ -135,76 +138,77 @@ typedef struct _CfgMapping {
 #define CFG_STR 1
 #define CFG_YES 2
 #define CFG_NO 3
+#define CFG_INT 4
 
 CfgMapping ServerConfig[] = {
-       {CFG_STR, HKEY("c_nodename")},
-       {CFG_STR, HKEY("c_fqdn")},
-       {CFG_STR, HKEY("c_humannode")},
-       {CFG_STR, HKEY("c_phonenum")},
-       {CFG_YES, HKEY("c_creataide")},
-       {CFG_STR, HKEY("c_sleeping")},
-       {CFG_STR, HKEY("c_initax")},
-       {CFG_YES, HKEY("c_regiscall")},
-       {CFG_YES, HKEY("c_twitdetect")},
-       {CFG_STR, HKEY("c_twitroom")},
-       {CFG_STR, HKEY("c_moreprompt")},
-       {CFG_YES, HKEY("c_restrict")},
-       {CFG_STR, HKEY("c_bbs_city")},
-       {CFG_STR, HKEY("c_sysadm")},
-       {CFG_STR, HKEY("c_maxsessions")},
-       {CFG_STR, HKEY("reserved1")},
-       {CFG_STR, HKEY("c_userpurge")},
-       {CFG_STR, HKEY("c_roompurge")},
-       {CFG_STR, HKEY("c_logpages")},
-       {CFG_STR, HKEY("c_createax")},
-       {CFG_STR, HKEY("c_maxmsglen")},
-       {CFG_STR, HKEY("c_min_workers")},
-       {CFG_STR, HKEY("c_max_workers")},
-       {CFG_STR, HKEY("c_pop3_port")},
-       {CFG_STR, HKEY("c_smtp_port")},
-       {CFG_NO , HKEY("c_rfc822_strict_from")},        /* note: reverse bool */
-       {CFG_YES, HKEY("c_aide_zap")},
-       {CFG_STR, HKEY("c_imap_port")},
-       {CFG_STR, HKEY("c_net_freq")},
-       {CFG_YES, HKEY("c_disable_newu")},
-       {CFG_STR, HKEY("reserved2")},
-       {CFG_STR, HKEY("c_purge_hour")},
-       {CFG_STR, HKEY("c_ldap_host")},
-       {CFG_STR, HKEY("c_ldap_port")},
-       {CFG_STR, HKEY("c_ldap_base_dn")},
-       {CFG_STR, HKEY("c_ldap_bind_dn")},
-       {CFG_STR, HKEY("c_ldap_bind_pw")},
-       {CFG_STR, HKEY("c_ip_addr")},
-       {CFG_STR, HKEY("c_msa_port")},
-       {CFG_STR, HKEY("c_imaps_port")},
-       {CFG_STR, HKEY("c_pop3s_port")},
-       {CFG_STR, HKEY("c_smtps_port")},
-       {CFG_YES, HKEY("c_enable_fulltext")},
-       {CFG_YES, HKEY("c_auto_cull")},
-       {CFG_YES, HKEY("c_instant_expunge")},
-       {CFG_YES, HKEY("c_allow_spoofing")},
-       {CFG_YES, HKEY("c_journal_email")},
-       {CFG_YES, HKEY("c_journal_pubmsgs")},
-       {CFG_STR, HKEY("c_journal_dest")},
-       {CFG_STR, HKEY("c_default_cal_zone")},
-       {CFG_STR, HKEY("c_pftcpdict_port")},
-       {CFG_STR, HKEY("c_mgesve_port")},
-       {CFG_STR, HKEY("c_auth_mode")},
-       {CFG_STR, HKEY("c_funambol_host")},
-       {CFG_STR, HKEY("c_funambol_port")},
-       {CFG_STR, HKEY("c_funambol_source")},
-       {CFG_STR, HKEY("c_funambol_auth")},
-       {CFG_YES, HKEY("c_rbl_at_greeting")},
-       {CFG_STR, HKEY("c_master_user")},
-       {CFG_STR, HKEY("c_master_pass")},
-       {CFG_STR, HKEY("c_pager_program")},
-       {CFG_YES, HKEY("c_imap_keep_from")},
-       {CFG_STR, HKEY("c_xmpp_c2s_port")},
-       {CFG_STR, HKEY("c_xmpp_s2s_port")},
-       {CFG_STR, HKEY("c_pop3_fetch")},
-       {CFG_STR, HKEY("c_pop3_fastest")},
-       {CFG_YES, HKEY("c_spam_flag_only")},
-       {CFG_YES, HKEY("c_guest_logins")}
+       {CFG_STR, 0, 0, "", HKEY("c_nodename")},
+       {CFG_STR, 0, 0, "", HKEY("c_fqdn")},
+       {CFG_STR, 0, 0, "", HKEY("c_humannode")},
+       {CFG_STR, 0, 0, "", HKEY("c_phonenum")},
+       {CFG_YES, 0, 0, "", HKEY("c_creataide")},
+       {CFG_STR, 0, 0, "", HKEY("c_sleeping")},
+       {CFG_STR, 0, 0, "", HKEY("c_initax")},
+       {CFG_YES, 0, 0, "", HKEY("c_regiscall")},
+       {CFG_YES, 0, 0, "", HKEY("c_twitdetect")},
+       {CFG_STR, 0, 0, "", HKEY("c_twitroom")},
+       {CFG_STR, 0, 0, "", HKEY("c_moreprompt")},
+       {CFG_YES, 0, 0, "", HKEY("c_restrict")},
+       {CFG_STR, 0, 0, "", HKEY("c_bbs_city")},
+       {CFG_STR, 0, 0, "", HKEY("c_sysadm")},
+       {CFG_STR, 0, 0, "", HKEY("c_maxsessions")},
+       {CFG_STR, 0, 0, "", HKEY("reserved1")},
+       {CFG_STR, 0, 0, "", HKEY("c_userpurge")},
+       {CFG_STR, 0, 0, "", HKEY("c_roompurge")},
+       {CFG_STR, 0, 0, "", HKEY("c_logpages")},
+       {CFG_STR, 0, 0, "", HKEY("c_createax")},
+       {CFG_STR, 0, 0, "", HKEY("c_maxmsglen")},
+       {CFG_STR, 0, 0, "", HKEY("c_min_workers")},
+       {CFG_STR, 0, 0, "", HKEY("c_max_workers")},
+       {CFG_STR, 0, 0, "", HKEY("c_pop3_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_smtp_port")},
+       {CFG_INT, CFG_SMTP_FROM_FILTERALL, CFG_SMTP_FROM_REJECT, "0", HKEY("c_rfc822_strict_from")},    
+       {CFG_YES, 0, 0, "", HKEY("c_aide_zap")},
+       {CFG_STR, 0, 0, "", HKEY("c_imap_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_net_freq")},
+       {CFG_YES, 0, 0, "", HKEY("c_disable_newu")},
+       {CFG_STR, 0, 0, "", HKEY("reserved2")},
+       {CFG_STR, 0, 0, "", HKEY("c_purge_hour")},
+       {CFG_STR, 0, 0, "", HKEY("c_ldap_host")},
+       {CFG_STR, 0, 0, "", HKEY("c_ldap_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_ldap_base_dn")},
+       {CFG_STR, 0, 0, "", HKEY("c_ldap_bind_dn")},
+       {CFG_STR, 0, 0, "", HKEY("c_ldap_bind_pw")},
+       {CFG_STR, 0, 0, "", HKEY("c_ip_addr")},
+       {CFG_STR, 0, 0, "", HKEY("c_msa_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_imaps_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_pop3s_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_smtps_port")},
+       {CFG_YES, 0, 0, "", HKEY("c_enable_fulltext")},
+       {CFG_YES, 0, 0, "", HKEY("c_auto_cull")},
+       {CFG_YES, 0, 0, "", HKEY("c_instant_expunge")},
+       {CFG_YES, 0, 0, "", HKEY("c_allow_spoofing")},
+       {CFG_YES, 0, 0, "", HKEY("c_journal_email")},
+       {CFG_YES, 0, 0, "", HKEY("c_journal_pubmsgs")},
+       {CFG_STR, 0, 0, "", HKEY("c_journal_dest")},
+       {CFG_STR, 0, 0, "", HKEY("c_default_cal_zone")},
+       {CFG_STR, 0, 0, "", HKEY("c_pftcpdict_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_mgesve_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_auth_mode")},
+       {CFG_STR, 0, 0, "", HKEY("c_funambol_host")},
+       {CFG_STR, 0, 0, "", HKEY("c_funambol_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_funambol_source")},
+       {CFG_STR, 0, 0, "", HKEY("c_funambol_auth")},
+       {CFG_YES, 0, 0, "", HKEY("c_rbl_at_greeting")},
+       {CFG_STR, 0, 0, "", HKEY("c_master_user")},
+       {CFG_STR, 0, 0, "", HKEY("c_master_pass")},
+       {CFG_STR, 0, 0, "", HKEY("c_pager_program")},
+       {CFG_YES, 0, 0, "", HKEY("c_imap_keep_from")},
+       {CFG_STR, 0, 0, "", HKEY("c_xmpp_c2s_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_xmpp_s2s_port")},
+       {CFG_STR, 0, 0, "", HKEY("c_pop3_fetch")},
+       {CFG_STR, 0, 0, "", HKEY("c_pop3_fastest")},
+       {CFG_YES, 0, 0, "", HKEY("c_spam_flag_only")},
+       {CFG_YES, 0, 0, "", HKEY("c_guest_logins")}
 };
 
 
@@ -273,7 +277,7 @@ void load_siteconfig(void)
 void siteconfig(void)
 {
        wcsession *WCC = WC;
-       int i;
+       int i, value;
        StrBuf *Line;
 
        if (strlen(bstr("ok_button")) == 0) {
@@ -308,6 +312,14 @@ void siteconfig(void)
                                          ServerConfig[i].len) ?
                                  "0" : "1");
                        break;
+               case CFG_INT:
+                       value = IBstr(ServerConfig[i].Key, 
+                                     ServerConfig[i].len);
+                       if ((value < ServerConfig[i].min) ||
+                           (value > ServerConfig[i].max))
+                               value = atol(ServerConfig[i].defval);
+                       serv_printf("%d", value);
+                       break;
                }
        }
         serv_puts("000");
@@ -477,6 +489,11 @@ InitModule_SITECONFIG
        REGISTERTokenParamDefine(EXPIRE_NUMMSGS);
        REGISTERTokenParamDefine(EXPIRE_AGE);
 
+       REGISTERTokenParamDefine(CFG_SMTP_FROM_FILTERALL);
+       REGISTERTokenParamDefine(CFG_SMTP_FROM_NOFILTER);
+       REGISTERTokenParamDefine(CFG_SMTP_FROM_CORRECT);
+       REGISTERTokenParamDefine(CFG_SMTP_FROM_REJECT);
+
        RegisterConditional(HKEY("COND:EXPIRE:MODE"), 2, ConditionalExpire, CTX_NONE);
        RegisterNamespace("EXPIRE:VALUE", 1, 2, tmplput_ExpireValue, NULL, CTX_NONE);
        RegisterNamespace("EXPIRE:MODE", 1, 2, tmplput_ExpireMode, NULL, CTX_NONE);
index 738cd08837fb6f00ce9514fdd9c02803e862c380..3997292ecebee2f95d13536e292b9e59a4558037 100644 (file)
@@ -7,11 +7,31 @@
 <input type="text" NAME="c_smtp_port" MAXLENGTH="5" VALUE='<?SERV:CFG("c_smtp_port")>'></td></tr>
 
 <tr><td><?_("Correct forged From: lines during authenticated SMTP")></td><td>
-<input type="checkbox" NAME="c_rfc822_strict_from" VALUE="yes" <?%("COND:SERVCFG", 1, "c_rfc822_strict_from", 1, "", "CHECKED")>></td></tr>
+<ul>
+<li>
+ <input type="radio" NAME="c_rfc822_strict_from" value="<?DEF:VAL(#"CFG_SMTP_FROM_FILTERALL")>" <?%("COND:SERVCFG", 1, "c_rfc822_strict_from", #"CFG_SMTP_FROM_FILTERALL", "CHECKED", "")> />
+  <?_("Always replace / insert the users primary email address")>
+</li><li>
+ <input type="radio" NAME="c_rfc822_strict_from" value="<?DEF:VAL(#"CFG_SMTP_FROM_NOFILTER")>"  <?%("COND:SERVCFG", 1, "c_rfc822_strict_from", #"CFG_SMTP_FROM_NOFILTER",  "CHECKED", "")> />
+ <?_("Don't check the From: header at all")>
+</li><li>
+ <input type="radio" NAME="c_rfc822_strict_from" value="<?DEF:VAL(#"CFG_SMTP_FROM_CORRECT")>"   <?%("COND:SERVCFG", 1, "c_rfc822_strict_from", #"CFG_SMTP_FROM_CORRECT",   "CHECKED", "")> />
+ <?_("If the specified email is none of the users email-aliases, replace it with his primary mail address")>
+</li><li>
+ <input type="radio" NAME="c_rfc822_strict_from" value="<?DEF:VAL(#"CFG_SMTP_FROM_REJECT")>"    <?%("COND:SERVCFG", 1, "c_rfc822_strict_from", #"CFG_SMTP_FROM_REJECT",    "CHECKED", "")> />
+ <?_("If the specified email is none of the users email-aliases or missing, refuse to relay the email")>
+</li>
+</ul>
+<!--
+<input type="checkbox" NAME="c_rfc822_strict_from" VALUE="yes" <?%("COND:SERVCFG", 1, "c_rfc822_strict_from", 1, "", "CHECKED")>>
+-->
+</td></tr>
 
 <tr><td><?_("Flag message as spam, instead of rejecting it")></td><td>
 <input type="checkbox" NAME="c_spam_flag_only" VALUE="yes" <?%("COND:SERVCFG", 1, "c_spam_flag_only", 1, "CHECKED", "")>></td></tr>
 
+<tr><td></td></tr>
+
 <tr><td><?_("IMAP listener port (-1 to disable)")></td><td>
 <input type="text" NAME="c_imap_port" MAXLENGTH="5" VALUE='<?SERV:CFG("c_imap_port")>'></td></tr>