* 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;
};
#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 */
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
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);
}
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");
cprintf("214- QUIT\r\n");
cprintf("214- RCPT\r\n");
cprintf("214- RSET\r\n");
- cprintf("214- VRFY\r\n");
cprintf("214 \r\n");
}
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;
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;
}
-/*
- * 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
* 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;
return;
}
- strcpy(recp, &argbuf[3]);
+ safestrncpy(recp, &argbuf[3], sizeof recp);
striplt(recp);
stripallbut(recp, '<', '>');
}
strcat(SMTP->recipients, recp);
SMTP->number_of_recipients += 1;
- if (valid != NULL)
+ if (valid != NULL) {
free_recipients(valid);
+ }
}
smtp_data();
}
- else if (!strncasecmp(cmdbuf, "EXPN", 4)) {
- smtp_expn(&cmdbuf[5]);
- }
-
else if (!strncasecmp(cmdbuf, "HELO", 4)) {
smtp_hello(&cmdbuf[5], 0);
}
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");
}
/* 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) {
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;
}
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;
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;
}
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_mta_greeting,
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$";
}