X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fmodules%2Fsmtp%2Fserv_smtp.c;h=2f9ea6532a052dfd586caa3a675b53375dcf3d8c;hb=cf09c5cb779279f9ad24545e68414edc0340d6fa;hp=d6a8fb6142b75472545189ca79da166a712acae7;hpb=adccf08ddebcb920c4244cc62bc48f85575c2d88;p=citadel.git diff --git a/citadel/modules/smtp/serv_smtp.c b/citadel/modules/smtp/serv_smtp.c index d6a8fb614..2f9ea6532 100644 --- a/citadel/modules/smtp/serv_smtp.c +++ b/citadel/modules/smtp/serv_smtp.c @@ -20,15 +20,15 @@ * 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 @@ -315,17 +318,19 @@ void smtp_webcit_preferences_hack_backend(long msgnum, void *userdata) { return; // already got it } - msg = CtdlFetchMessage(msgnum, 1); + msg = CtdlFetchMessage(msgnum, 1, 1); if (msg == NULL) { return; } - if ( (msg->cm_fields['U']) && (!strcasecmp(msg->cm_fields['U'], "__ 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['M']; - msg->cm_fields['M'] = NULL; + *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(); } @@ -374,13 +394,17 @@ void smtp_help(long offset, long Flags) { void smtp_get_user(long offset) { char buf[SIZ]; - char username[SIZ]; citsmtp *sSMTP = SMTP; - CtdlDecodeBase64(username, ChrPtr(sSMTP->Cmd) + offset, SIZ); + StrBufDecodeBase64(sSMTP->Cmd); + /* syslog(LOG_DEBUG, "Trying <%s>\n", username); */ - if (CtdlLoginExistingUser(NULL, username) == login_ok) { - CtdlEncodeBase64(buf, "Password:", 9, 0); + if (CtdlLoginExistingUser(NULL, ChrPtr(sSMTP->Cmd)) == login_ok) { + size_t len = CtdlEncodeBase64(buf, "Password:", 9, 0); + + if (buf[len - 1] == '\n') { + buf[len - 1] = '\0'; + } cprintf("334 %s\r\n", buf); sSMTP->command_state = smtp_password; } @@ -398,12 +422,11 @@ void smtp_get_pass(long offset, long Flags) { citsmtp *sSMTP = SMTP; char password[SIZ]; - long len; - memset(password, 0, sizeof(password)); - len = CtdlDecodeBase64(password, ChrPtr(sSMTP->Cmd), SIZ); + memset(password, 0, sizeof(password)); + StrBufDecodeBase64(sSMTP->Cmd); /* syslog(LOG_DEBUG, "Trying <%s>\n", password); */ - if (CtdlTryPassword(password, len) == pass_ok) { + if (CtdlTryPassword(SKEY(sSMTP->Cmd)) == pass_ok) { smtp_auth_greeting(offset, Flags); } else { @@ -419,19 +442,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 +491,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; } @@ -475,7 +523,10 @@ void smtp_auth(long offset, long Flags) smtp_get_user(6); } else { - CtdlEncodeBase64(username_prompt, "Username:", 9, 0); + size_t len = CtdlEncodeBase64(username_prompt, "Username:", 9, 0); + if (username_prompt[len - 1] == '\n') { + username_prompt[len - 1] = '\0'; + } cprintf("334 %s\r\n", username_prompt); sSMTP->command_state = smtp_user; } @@ -602,7 +653,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")); } @@ -625,9 +676,13 @@ void smtp_mail(long offset, long flags) { */ 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; } } @@ -644,7 +699,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) { @@ -743,7 +798,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; @@ -809,12 +864,12 @@ 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['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))) { @@ -824,43 +879,38 @@ void smtp_data(long offset, long flags) 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( @@ -877,16 +927,16 @@ 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['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. */ @@ -928,7 +978,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 */ } @@ -956,6 +1006,7 @@ void smtp_starttls(long offset, long flags) */ void smtp_command_loop(void) { + static const ConstStr AuthPlainStr = {HKEY("AUTH PLAIN")}; struct CitContext *CCC = CC; citsmtp *sSMTP = SMTP; const char *pch, *pchs; @@ -976,15 +1027,21 @@ void smtp_command_loop(void) syslog(LOG_DEBUG, "SMTP server: %s\n", ChrPtr(sSMTP->Cmd)); if (sSMTP->command_state == smtp_user) { - smtp_get_user(0); + if (!strncmp(ChrPtr(sSMTP->Cmd), AuthPlainStr.Key, AuthPlainStr.len)) + smtp_try_plain(0, 0); + else + 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); @@ -1052,6 +1109,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); }