enum { /* Command states for login authentication */
smtp_command,
smtp_user,
- smtp_password
+ smtp_password,
+ smtp_plain
};
enum { /* Delivery modes */
/*
* Here's where our SMTP session begins its happy day.
*/
-void smtp_greeting(void) {
+void smtp_greeting(void)
+{
+ char message_to_spammer[1024];
strcpy(CC->cs_clientname, "SMTP session");
CC->internal_pgm = 1;
memset(SMTP_RECPS, 0, SIZ);
memset(SMTP_ROOMS, 0, SIZ);
+ /* If this config option is set, reject connections from problem
+ * addresses immediately instead of after they execute a RCPT
+ */
+ if (config.c_rbl_at_greeting) {
+ if (rbl_check(message_to_spammer)) {
+ cprintf("550 %s\r\n", message_to_spammer);
+ CC->kill_me = 1;
+ /* no need to free(valid), it's not allocated yet */
+ return;
+ }
+ }
+
+ /* Otherwise we're either clean or we check later. */
+
+ if (CC->nologin==1) {
+ cprintf("500 Too many users are already online (maximum is %d)\r\n",
+ config.c_maxsessions
+ );
+ CC->kill_me = 1;
+ /* no need to free(valid), it's not allocated yet */
+ return;
+ }
+
cprintf("220 %s ESMTP Citadel server ready.\r\n", config.c_fqdn);
}
/*
- *
+ * Back end for PLAIN auth method (either inline or multistate)
*/
-void smtp_auth(char *argbuf) {
- char username_prompt[64];
- char method[64];
- char encoded_authstring[1024];
+void smtp_try_plain(char *encoded_authstring) {
char decoded_authstring[1024];
char ident[256];
char user[256];
char pass[256];
+ 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 (CtdlTryPassword(pass) == pass_ok) {
+ smtp_auth_greeting();
+ return;
+ }
+ }
+ cprintf("504 5.7.4 Authentication failed.\r\n");
+}
+
+
+/*
+ * Attempt to perform authenticated SMTP
+ */
+void smtp_auth(char *argbuf) {
+ char username_prompt[64];
+ char method[64];
+ char encoded_authstring[1024];
+
if (CC->logged_in) {
cprintf("504 5.7.4 Already logged in.\r\n");
return;
}
if (!strncasecmp(method, "plain", 5) ) {
- extract_token(encoded_authstring, argbuf, 1, ' ', sizeof 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);
-
- if (CtdlLoginExistingUser(user) == login_ok) {
- if (CtdlTryPassword(pass) == pass_ok) {
- smtp_auth_greeting();
- return;
- }
+ if (num_tokens(argbuf, ' ') < 2) {
+ cprintf("334 \r\n");
+ SMTP->command_state = smtp_plain;
+ return;
}
- cprintf("504 5.7.4 Authentication failed.\r\n");
+
+ extract_token(encoded_authstring, argbuf, 1, ' ', sizeof encoded_authstring);
+
+ smtp_try_plain(encoded_authstring);
+ return;
}
if (strncasecmp(method, "login", 5) ) {
}
/* RBL check */
- if ( (!CC->logged_in)
- && (!SMTP->is_lmtp) ) {
- if (rbl_check(message_to_spammer)) {
- cprintf("550 %s\r\n", message_to_spammer);
- /* no need to free(valid), it's not allocated yet */
- return;
+ if ( (!CC->logged_in) /* Don't RBL authenticated users */
+ && (!SMTP->is_lmtp) ) { /* Don't RBL LMTP clients */
+ if (config.c_rbl_at_greeting == 0) { /* Don't RBL again if we already did it */
+ if (rbl_check(message_to_spammer)) {
+ cprintf("550 %s\r\n", message_to_spammer);
+ /* no need to free(valid), it's not allocated yet */
+ return;
+ }
}
}
}
strcat(SMTP->recipients, recp);
SMTP->number_of_recipients += 1;
+ if (valid != NULL)
+ free(valid);
}
*/
void smtp_data(void) {
char *body;
- struct CtdlMessage *msg;
+ struct CtdlMessage *msg = NULL;
long msgnum = (-1L);
char nowstamp[SIZ];
struct recptypes *valid;
msg->cm_fields['O'] = strdup(MAILROOM);
}
+ /* Set the "envelope from" address */
+ if (msg->cm_fields['P'] != NULL) {
+ free(msg->cm_fields['P']);
+ }
+ msg->cm_fields['P'] = strdup(SMTP->from);
+
+ /* Set the "envelope to" address */
+ if (msg->cm_fields['V'] != NULL) {
+ free(msg->cm_fields['V']);
+ }
+ msg->cm_fields['V'] = strdup(SMTP->recipients);
+
/* Submit the message into the Citadel system. */
valid = validate_recipients(SMTP->recipients);
smtp_get_pass(cmdbuf);
}
+ else if (SMTP->command_state == smtp_plain) {
+ smtp_try_plain(cmdbuf);
+ }
+
else if (!strncasecmp(cmdbuf, "AUTH", 4)) {
smtp_auth(&cmdbuf[5]);
}
sock = (-1);
for (mx=0; (mx<num_mxhosts && sock < 0); ++mx) {
+ char *endpart;
extract_token(buf, mxhosts, mx, '|', sizeof buf);
strcpy(mx_user, "");
strcpy(mx_pass, "");
if (num_tokens(buf, '@') > 1) {
- extract_token(mx_user, buf, 0, '@', sizeof mx_user);
- if (num_tokens(mx_user, ':') > 1) {
- extract_token(mx_pass, mx_user, 1, ':', sizeof mx_pass);
- remove_token(mx_user, 1, ':');
+ strcpy (mx_user, buf);
+ endpart = strrchr(mx_user, '@');
+ *endpart = '\0';
+ strcpy (mx_host, endpart + 1);
+ endpart = strrchr(mx_user, ':');
+ if (endpart != NULL) {
+ strcpy(mx_pass, endpart+1);
+ *endpart = '\0';
}
- remove_token(buf, 0, '@');
}
- extract_token(mx_host, buf, 0, ':', sizeof mx_host);
- extract_token(mx_port, buf, 1, ':', sizeof mx_port);
- if (!mx_port[0]) {
+ else
+ strcpy (mx_host, buf);
+ endpart = strrchr(mx_host, ':');
+ if (endpart != 0){
+ *endpart = '\0';
+ strcpy(mx_port, endpart + 1);
+ }
+ else {
strcpy(mx_port, "25");
}
- lprintf(CTDL_DEBUG, "FIXME user<%s> pass<%s> host<%s> port<%s>\n",
- mx_user, mx_pass, mx_host, mx_port);
lprintf(CTDL_DEBUG, "Trying %s : %s ...\n", mx_host, mx_port);
sock = sock_connect(mx_host, mx_port, "tcp");
snprintf(dsn, SIZ, "Could not connect: %s", strerror(errno));
if (sock >= 0) lprintf(CTDL_DEBUG, "Connected!\n");
- if (sock < 0) snprintf(dsn, SIZ, "%s", strerror(errno));
+ if (sock < 0) {
+ if (errno > 0) {
+ snprintf(dsn, SIZ, "%s", strerror(errno));
+ }
+ else {
+ snprintf(dsn, SIZ, "Unable to connect to %s : %s\n", mx_host, mx_port);
+ }
+ }
}
if (sock < 0) {
give_up = 1;
}
-
-
bmsg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
if (bmsg == NULL) return;
memset(bmsg, 0, sizeof(struct CtdlMessage));
* Called by smtp_do_queue() to handle an individual message.
*/
void smtp_do_procmsg(long msgnum, void *userdata) {
- struct CtdlMessage *msg;
+ struct CtdlMessage *msg = NULL;
char *instr = NULL;
char *results = NULL;
int i;
* message and the message message.
*/
if (incomplete_deliveries_remaining <= 0) {
- CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, msgnum, "", 0);
- CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, text_msgid, "", 0);
+ long delmsgs[2];
+ delmsgs[0] = msgnum;
+ delmsgs[1] = text_msgid;
+ CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, delmsgs, 2, "");
}
-
/*
* Uncompleted delivery instructions remain, so delete the old
* instructions and replace with the updated ones.
*/
if (incomplete_deliveries_remaining > 0) {
- CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, msgnum, "", 0);
+ CtdlDeleteMessages(SMTP_SPOOLOUT_ROOM, &msgnum, 1, "");
msg = malloc(sizeof(struct CtdlMessage));
memset(msg, 0, sizeof(struct CtdlMessage));
msg->cm_magic = CTDLMESSAGE_MAGIC;
lprintf(CTDL_ERR, "Cannot find room <%s>\n", SMTP_SPOOLOUT_ROOM);
return;
}
- CtdlForEachMessage(MSGS_ALL, 0L,
+ CtdlForEachMessage(MSGS_ALL, 0L, NULL,
SPOOLMIME, NULL, smtp_do_procmsg, NULL);
lprintf(CTDL_INFO, "SMTP: queue run completed\n");