X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=citadel%2Fserv_smtp.c;h=e1a933475207541eec10b63e70c30ae05dcae20c;hb=ea1849b79ff5c285db6c12eb7e410934c2ac2a05;hp=8cc2b9bf5c64ef979908dbac527936d58257c050;hpb=44bdabdda4dc6e9823e0464c37157c960abac9f7;p=citadel.git diff --git a/citadel/serv_smtp.c b/citadel/serv_smtp.c index 8cc2b9bf5..e1a933475 100644 --- a/citadel/serv_smtp.c +++ b/citadel/serv_smtp.c @@ -14,6 +14,7 @@ * RFC 2033 - Local Mail Transfer Protocol * RFC 2034 - SMTP Service Extension for Returning Enhanced Error Codes * RFC 2197 - SMTP Service Extension for Command Pipelining + * RFC 2476 - Message Submission * RFC 2487 - SMTP Service Extension for Secure SMTP over TLS * RFC 2554 - SMTP Service Extension for Authentication * RFC 2821 - Simple Mail Transfer Protocol @@ -70,6 +71,7 @@ #include "domain.h" #include "clientsocket.h" #include "locate_host.h" +#include "citadel_dirs.h" #ifdef HAVE_OPENSSL #include "serv_crypto.h" @@ -100,7 +102,8 @@ struct citsmtp { /* Information about the current session */ enum { /* Command states for login authentication */ smtp_command, smtp_user, - smtp_password + smtp_password, + smtp_plain }; enum { /* Delivery modes */ @@ -320,17 +323,40 @@ void smtp_get_pass(char *argbuf) { /* - * + * 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; @@ -351,21 +377,16 @@ void smtp_auth(char *argbuf) { } 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) ) { @@ -568,7 +589,7 @@ void smtp_mail(char *argbuf) { else if (config.c_allow_spoofing == 0) { process_rfc822_addr(SMTP->from, user, node, name); if (CtdlHostAlias(node) != hostalias_nomatch) { - cprintf("550 5.1.8 " + cprintf("550 5.7.1 " "You must log in to send mail from %s\r\n", node); strcpy(SMTP->from, ""); @@ -850,6 +871,10 @@ void smtp_command_loop(void) { 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]); } @@ -941,6 +966,8 @@ void smtp_try(const char *key, const char *addr, int *status, char user[1024], node[1024], name[1024]; char buf[1024]; char mailfrom[1024]; + char mx_user[256]; + char mx_pass[256]; char mx_host[256]; char mx_port[256]; int lp, rp; @@ -1025,11 +1052,23 @@ void smtp_try(const char *key, const char *addr, int *status, sock = (-1); for (mx=0; (mx 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, ':'); + } + 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]) { 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)); @@ -1064,8 +1103,8 @@ void smtp_try(const char *key, const char *addr, int *status, /* At this point we know we are talking to a real SMTP server */ - /* Do a HELO command */ - snprintf(buf, sizeof buf, "HELO %s\r\n", config.c_fqdn); + /* Do a EHLO command. If it fails, try the HELO command. */ + snprintf(buf, sizeof buf, "EHLO %s\r\n", config.c_fqdn); lprintf(CTDL_DEBUG, ">%s", buf); sock_write(sock, buf, strlen(buf)); if (ml_sock_gets(sock, buf) < 0) { @@ -1074,6 +1113,16 @@ void smtp_try(const char *key, const char *addr, int *status, goto bail; } lprintf(CTDL_DEBUG, "<%s\n", buf); + if (buf[0] != '2') { + snprintf(buf, sizeof buf, "HELO %s\r\n", config.c_fqdn); + lprintf(CTDL_DEBUG, ">%s", buf); + sock_write(sock, buf, strlen(buf)); + if (ml_sock_gets(sock, buf) < 0) { + *status = 4; + strcpy(dsn, "Connection broken during SMTP HELO"); + goto bail; + } + } if (buf[0] != '2') { if (buf[0] == '4') { *status = 4; @@ -1087,7 +1136,34 @@ void smtp_try(const char *key, const char *addr, int *status, } } - /* HELO succeeded, now try the MAIL From: command */ + /* Do an AUTH command if necessary */ + if (strlen(mx_user) > 0) { + sprintf(buf, "%s%c%s%c%s%c", mx_user, 0, mx_user, 0, mx_pass, 0); + CtdlEncodeBase64(mailfrom, buf, strlen(mx_user) + strlen(mx_user) + strlen(mx_pass) + 3); + snprintf(buf, sizeof buf, "AUTH PLAIN %s\r\n", mailfrom); + lprintf(CTDL_DEBUG, ">%s", buf); + sock_write(sock, buf, strlen(buf)); + if (ml_sock_gets(sock, buf) < 0) { + *status = 4; + strcpy(dsn, "Connection broken during SMTP AUTH"); + goto bail; + } + lprintf(CTDL_DEBUG, "<%s\n", buf); + if (buf[0] != '2') { + if (buf[0] == '4') { + *status = 4; + safestrncpy(dsn, &buf[4], 1023); + goto bail; + } + else { + *status = 5; + safestrncpy(dsn, &buf[4], 1023); + goto bail; + } + } + } + + /* previous command succeeded, now try the MAIL From: command */ snprintf(buf, sizeof buf, "MAIL From: <%s>\r\n", mailfrom); lprintf(CTDL_DEBUG, ">%s", buf); sock_write(sock, buf, strlen(buf)); @@ -1565,17 +1641,18 @@ void smtp_do_procmsg(long msgnum, void *userdata) { * 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, "", 0); } - /* * 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, "", 0); msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); msg->cm_magic = CTDLMESSAGE_MAGIC; @@ -1723,6 +1800,7 @@ void smtp_cleanup_function(void) { char *serv_smtp_init(void) { + CtdlRegisterServiceHook(config.c_smtp_port, /* SMTP MTA */ NULL, smtp_greeting, @@ -1744,23 +1822,13 @@ char *serv_smtp_init(void) NULL); CtdlRegisterServiceHook(0, /* local LMTP */ -#ifndef HAVE_RUN_DIR - "." -#else - RUN_DIR -#endif - "/lmtp.socket", + file_lmtp_socket, lmtp_greeting, smtp_command_loop, NULL); CtdlRegisterServiceHook(0, /* local LMTP */ -#ifndef HAVE_RUN_DIR - "." -#else - RUN_DIR -#endif - "/lmtp-unfiltered.socket", + file_lmtp_unfiltered_socket, lmtp_unfiltered_greeting, smtp_command_loop, NULL);