* 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"
#include "config.h"
#include "control.h"
#include "user_ops.h"
+#include "room_ops.h"
#include "database.h"
#include "msgbase.h"
#include "internet_addressing.h"
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
}
+/*
+ * Backend function for smtp_webcit_preferences_hack().
+ * Look at a message and determine if it's the preferences file.
+ */
+void smtp_webcit_preferences_hack_backend(long msgnum, void *userdata) {
+ struct CtdlMessage *msg;
+ char **webcit_conf = (char **) userdata;
+
+ if (*webcit_conf) {
+ return; // already got it
+ }
+
+ msg = CtdlFetchMessage(msgnum, 1);
+ if (msg == NULL) {
+ return;
+ }
+
+ 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;
+ }
+ CM_Free(msg);
+}
+
+
+/*
+ * The configuration item for the user's preferred display name for outgoing email is, unfortunately,
+ * stored in the account's WebCit configuration. We have to fetch it now.
+ */
+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) {
+ return;
+ }
+
+ /*
+ * Find the WebCit configuration message
+ */
+
+ CtdlForEachMessage(MSGS_ALL, 1, NULL, NULL, NULL, smtp_webcit_preferences_hack_backend, (void *)&webcit_conf);
+
+ if (!webcit_conf) {
+ return;
+ }
+
+ /* 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);
+}
+
+
/*
* Implement HELP command.
if (result == login_ok) {
if (CtdlTryPassword(pass, len) == pass_ok) {
+ smtp_webcit_preferences_hack();
smtp_auth_greeting(offset, Flags);
return;
}
return;
}
- extract_token(method, ChrPtr(sSMTP->Cmd), 0, ' ', sizeof method);
+ extract_token(method, ChrPtr(sSMTP->Cmd) + offset, 0, ' ', sizeof method);
if (!strncasecmp(method, "login", 5) ) {
- if (StrLength(sSMTP->Cmd) >= 7) {
+ if (StrLength(sSMTP->Cmd) - offset >= 7) {
smtp_get_user(6);
}
else {
if (!strncasecmp(method, "plain", 5) ) {
long len;
- if (num_tokens(ChrPtr(sSMTP->Cmd), ' ') < 2) {
+ if (num_tokens(ChrPtr(sSMTP->Cmd) + offset, ' ') < 2) {
cprintf("334 \r\n");
SMTP->command_state = smtp_plain;
return;
}
len = extract_token(encoded_authstring,
- ChrPtr(sSMTP->Cmd),
+ ChrPtr(sSMTP->Cmd) + offset,
1, ' ',
sizeof encoded_authstring);
StrBufPlain(sSMTP->Cmd, encoded_authstring, len);
- smtp_try_plain(offset, Flags);
+ smtp_try_plain(0, Flags);
return;
}
* Set do_response to nonzero to output the SMTP RSET response code.
*/
void smtp_rset(long offset, long do_response) {
- int is_lmtp;
- int is_unfiltered;
citsmtp *sSMTP = SMTP;
/*
* but we need to preserve this one little piece of information, so
* we save it for later.
*/
- is_lmtp = sSMTP->is_lmtp;
- is_unfiltered = sSMTP->is_unfiltered;
- memset(sSMTP, 0, sizeof(citsmtp));
+ FlushStrBuf(sSMTP->Cmd);
+ FlushStrBuf(sSMTP->helo_node);
+ FlushStrBuf(sSMTP->from);
+ FlushStrBuf(sSMTP->recipients);
+ FlushStrBuf(sSMTP->OneRcpt);
+
+ sSMTP->command_state = 0;
+ sSMTP->number_of_recipients = 0;
+ sSMTP->delivery_mode = 0;
+ sSMTP->message_originated_locally = 0;
+ sSMTP->is_msa = 0;
+ /*
+ * we must remember is_lmtp & is_unfiltered.
+ */
/*
* It is somewhat ambiguous whether we want to log out when a RSET
* }
*/
- /*
- * Reinstate this little piece of information we saved (see above).
- */
- sSMTP->is_lmtp = is_lmtp;
- sSMTP->is_unfiltered = is_unfiltered;
-
if (do_response) {
cprintf("250 Zap!\r\n");
}
* 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"));
}
*/
else if (config.c_allow_spoofing == 0) {
process_rfc822_addr(ChrPtr(sSMTP->from), user, node, name);
+ syslog(LOG_DEBUG, "Claimed envelope sender is '%s' == '%s' @ '%s' ('%s')",
+ ChrPtr(sSMTP->from), user, node, name
+ );
if (CtdlHostAlias(node) != hostalias_nomatch) {
cprintf("550 You must log in to send mail from %s\r\n", node);
FlushStrBuf(sSMTP->from);
+ syslog(LOG_DEBUG, "Rejecting unauthenticated mail from %s", node);
return;
}
}
{
struct CitContext *CCC = CC;
char message_to_spammer[SIZ];
- struct recptypes *valid = NULL;
+ recptypes *valid = NULL;
citsmtp *sSMTP = SMTP;
if (StrLength(sSMTP->from) == 0) {
struct CtdlMessage *msg = NULL;
long msgnum = (-1L);
char nowstamp[SIZ];
- struct recptypes *valid;
+ recptypes *valid;
int scan_errors;
int i;
citsmtp *sSMTP = SMTP;
if ( (CCC->logged_in) && (config.c_rfc822_strict_from != CFG_SMTP_FROM_NOFILTER) ) {
int validemail = 0;
- if (!IsEmptyStr(msg->cm_fields['F']) &&
+ if (!CM_IsEmpty(msg, erFc822Addr) &&
((config.c_rfc822_strict_from == CFG_SMTP_FROM_CORRECT) ||
(config.c_rfc822_strict_from == CFG_SMTP_FROM_REJECT) ) )
{
if (!IsEmptyStr(CCC->cs_inet_email))
- validemail = strcmp(CCC->cs_inet_email, msg->cm_fields['F']) == 0;
+ validemail = strcmp(CCC->cs_inet_email, msg->cm_fields[erFc822Addr]) == 0;
if ((!validemail) &&
(!IsEmptyStr(CCC->cs_inet_other_emails)))
{
for (i=0; i < num_secondary_emails && !validemail; ++i) {
char buf[256];
extract_token(buf, CCC->cs_inet_other_emails,i,'|',sizeof CCC->cs_inet_other_emails);
- validemail = strcmp(buf, msg->cm_fields['F']) == 0;
+ validemail = strcmp(buf, msg->cm_fields[erFc822Addr]) == 0;
}
}
}
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']);
+ syslog(LOG_ERR, "invalid sender '%s' - rejecting this message", msg->cm_fields[erFc822Addr]);
+ cprintf("550 Invalid sender '%s' - rejecting this message.\r\n", msg->cm_fields[erFc822Addr]);
return;
}
- 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['O'] != NULL) free(msg->cm_fields['O']);
- msg->cm_fields['A'] = strdup(CCC->user.fullname);
- msg->cm_fields['N'] = strdup(config.c_nodename);
- msg->cm_fields['H'] = strdup(config.c_humannode);
- msg->cm_fields['O'] = 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['F'] != NULL) free(msg->cm_fields['F']);
- msg->cm_fields['F'] = 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['P'] != NULL) {
- free(msg->cm_fields['P']);
- }
- msg->cm_fields['P'] = strdup(ChrPtr(sSMTP->from));
+ CM_SetField(msg, eMessagePath, SKEY(sSMTP->from));
/* Set the "envelope to" address */
- if (msg->cm_fields['V'] != NULL) {
- free(msg->cm_fields['V']);
- }
- msg->cm_fields['V'] = strdup(ChrPtr(sSMTP->recipients));
+ CM_SetField(msg, eenVelopeTo, SKEY(sSMTP->recipients));
/* Submit the message into the Citadel system. */
valid = validate_recipients(
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['0'] == NULL) {
- msg->cm_fields['0'] = 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['0']);
+ StrBufPrintf(sSMTP->OneRcpt, "550 %s\r\n", msg->cm_fields[eErrorMsg]);
}
else { /* Ok, we'll accept this message. */
);
/* Clean up */
- CtdlFreeMessage(msg);
+ CM_Free(msg);
free_recipients(valid);
smtp_data_clear(0, 0); /* clear out the buffers now */
}
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);
FreeStrBuf(&sSMTP->from);
FreeStrBuf(&sSMTP->recipients);
FreeStrBuf(&sSMTP->OneRcpt);
+ FreeStrBuf(&sSMTP->preferred_sender_email);
+ FreeStrBuf(&sSMTP->preferred_sender_name);
free(sSMTP);
}
if (!threading)
{
SMTPCmds = NewHash(1, NULL);
+
RegisterSmtpCMD("AUTH", smtp_auth, 0);
RegisterSmtpCMD("DATA", smtp_data, 0);
RegisterSmtpCMD("HELO", smtp_hello, HELO);
NULL,
CitadelServiceSMTP_LMTP_UNF);
+ CtdlRegisterCleanupHook(smtp_cleanup);
CtdlRegisterSessionHook(smtp_cleanup_function, EVT_STOP, PRIO_STOP + 250);
}