Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ smtp_auth_md5(int fd, char *login, char *password)
" AUTH cram-md5 not available: %s", neterr);
/* if cram-md5 is not available */
free(temp);
return (-1);
return (1);
}

/* skip 3 char status + 1 char space */
Expand All @@ -405,7 +405,7 @@ smtp_auth_md5(int fd, char *login, char *password)
len = base64_encode(buffer, strlen(buffer), &temp);
if (len < 0) {
syslog(LOG_ERR, "can not encode auth reply: %m");
return (-1);
return (1);
}

/* send answer */
Expand All @@ -414,7 +414,7 @@ smtp_auth_md5(int fd, char *login, char *password)
if (read_remote(fd, 0, NULL) != 2) {
syslog(LOG_WARNING, "remote delivery deferred:"
" AUTH cram-md5 failed: %s", neterr);
return (-2);
return (-1);
}

return (0);
Expand Down
1 change: 1 addition & 0 deletions dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ struct mx_hostentry {
struct smtp_auth_mechanisms {
int cram_md5;
int login;
int plain;
};

struct smtp_features {
Expand Down
192 changes: 128 additions & 64 deletions net.c
Original file line number Diff line number Diff line change
Expand Up @@ -258,77 +258,132 @@ read_remote(int fd, int extbufsize, char *extbuf)
return (-1);
}

static int
smtp_auth_login(int fd, char *login, char* password)
{
char *temp;
int len, res = 0;

/* Send AUTH command according to RFC 2554 */
send_remote_command(fd, "AUTH LOGIN");
if (read_remote(fd, 0, NULL) != 3) {
syslog(LOG_NOTICE, "remote delivery deferred:"
" AUTH login not available: %s",
neterr);
return (1);
}

len = base64_encode(login, strlen(login), &temp);
if (len < 0) {
encerr:
syslog(LOG_ERR, "can not encode auth reply: %m");
return (1);
}

send_remote_command(fd, "%s", temp);
free(temp);
res = read_remote(fd, 0, NULL);
if (res != 3) {
syslog(LOG_NOTICE, "remote delivery %s: AUTH login failed: %s",
res == 5 ? "failed" : "deferred", neterr);
return (res == 5 ? -1 : 1);
}

len = base64_encode(password, strlen(password), &temp);
if (len < 0)
goto encerr;

send_remote_command(fd, "%s", temp);
free(temp);
res = read_remote(fd, 0, NULL);
if (res != 2) {
syslog(LOG_NOTICE, "remote delivery %s: Authentication failed: %s",
res == 5 ? "failed" : "deferred", neterr);
return (res == 5 ? -1 : 1);
}

return 0;
}

static int
smtp_auth_plain(int fd, char *login, char* password)
{
char *temp, *authstr;
int len, res = 0;

/* Send AUTH command according to RFC 2554 */
send_remote_command(fd, "AUTH PLAIN");
if (read_remote(fd, 0, NULL) != 3) {
syslog(LOG_NOTICE, "remote delivery deferred:"
" AUTH plain not available: %s",
neterr);
return (1);
}

len = asprintf(&authstr, "%c%s%c%s", '/0', login, '/0', password);
if (len < 0) {
syslog(LOG_ERR, "can not format auth reply: %m");
return (1);
}

len = base64_encode(authstr, len, &temp);
free(authstr);
if (len < 0) {
syslog(LOG_ERR, "can not encode auth reply: %m");
return (1);
}
send_remote_command(fd, "%s", temp);
free(temp);
res = read_remote(fd, 0, NULL);
if (res != 2) {
syslog(LOG_NOTICE, "remote delivery %s: Authentication failed: %s",
res == 5 ? "failed" : "deferred", neterr);
return (res == 5 ? -1 : 1);
}

return 0;
}

/*
* Handle SMTP authentication
*/
static int
smtp_login(int fd, char *login, char* password, const struct smtp_features* features)
smtp_auth(int fd, char *login, char* password, const struct smtp_features* features)
{
char *temp;
int len, res = 0;
int res = 1;

// CRAM-MD5
if (features->auth.cram_md5) {
res = smtp_auth_md5(fd, login, password);
if (res == 0) {
return (0);
} else if (res == -2) {
/*
* If the return code is -2, then then the login attempt failed,
* do not try other login mechanisms
*/
return (1);
if (res != 1) {
return res;
}
}

// LOGIN
if (features->auth.login) {
if ((config.features & INSECURE) != 0 ||
if ((config.features & INSECURE) != 0 ||
(config.features & SECURETRANSFER) != 0) {
/* Send AUTH command according to RFC 2554 */
send_remote_command(fd, "AUTH LOGIN");
if (read_remote(fd, 0, NULL) != 3) {
syslog(LOG_NOTICE, "remote delivery deferred:"
" AUTH login not available: %s",
neterr);
return (1);
}

len = base64_encode(login, strlen(login), &temp);
if (len < 0) {
encerr:
syslog(LOG_ERR, "can not encode auth reply: %m");
return (1);
}

send_remote_command(fd, "%s", temp);
free(temp);
res = read_remote(fd, 0, NULL);
if (res != 3) {
syslog(LOG_NOTICE, "remote delivery %s: AUTH login failed: %s",
res == 5 ? "failed" : "deferred", neterr);
return (res == 5 ? -1 : 1);
// LOGIN
if (features->auth.login) {
res = smtp_auth_login(fd, login, password);
if (res != 1) {
return res;
}
}

len = base64_encode(password, strlen(password), &temp);
if (len < 0)
goto encerr;

send_remote_command(fd, "%s", temp);
free(temp);
res = read_remote(fd, 0, NULL);
if (res != 2) {
syslog(LOG_NOTICE, "remote delivery %s: Authentication failed: %s",
res == 5 ? "failed" : "deferred", neterr);
return (res == 5 ? -1 : 1);
// PLAIN
if (features->auth.plain) {
res = smtp_auth_plain(fd, login, password);
if (res != 1) {
return res;
}
} else {
syslog(LOG_WARNING, "non-encrypted SMTP login is disabled in config, so skipping it. ");
return (1);
}
}
} else if (features->auth.login || features->auth.plain) {
syslog(LOG_WARNING, "non-encrypted SMTP authentication is disabled in config, so skipping it. ");
return (1);
}

return (0);
return res;
}

static int
Expand Down Expand Up @@ -381,6 +436,9 @@ static void parse_auth_line(char* line, struct smtp_auth_mechanisms* auth) {
else if (strcmp(method, "LOGIN") == 0)
auth->login = 1;

else if (strcmp(method, "PLAIN") == 0)
auth->plain = 1;

method = strtok(NULL, " ");
}
}
Expand Down Expand Up @@ -469,6 +527,9 @@ int perform_server_greeting(int fd, struct smtp_features* features) {
if (features->auth.login) {
syslog(LOG_DEBUG, " Server supports LOGIN authentication");
}
if (features->auth.plain) {
syslog(LOG_DEBUG, " Server supports PLAIN authentication");
}

return 0;
}
Expand Down Expand Up @@ -552,18 +613,21 @@ deliver_to_host(struct qitem *it, struct mx_hostentry *host)
* Check if the user wants plain text login without using
* encryption.
*/
syslog(LOG_INFO, "using SMTP authentication for user %s", a->login);
error = smtp_login(fd, a->login, a->password, &features);
if (error < 0) {
syslog(LOG_ERR, "remote delivery failed:"
" SMTP login failed: %m");
snprintf(errmsg, sizeof(errmsg), "SMTP login to %s failed", host->host);
error = -1;
goto out;
}
/* SMTP login is not available, so try without */
else if (error > 0) {
syslog(LOG_WARNING, "SMTP login not available. Trying without.");
if (features.auth.cram_md5 || features.auth.login || features.auth.plain) {
syslog(LOG_INFO, "using SMTP authentication for user %s", a->login);
error = smtp_auth(fd, a->login, a->password, &features);
if (error < 0) {
snprintf(errmsg, sizeof(errmsg), "SMTP auth to %s failed", host->host);
error = -1;
goto out;
}
/* SMTP auth is not available, so try without */
else if (error > 0) {
syslog(LOG_WARNING, "SMTP auth not available. Trying without.");
}
} else {
syslog(LOG_ERR, "No supported AUTH mechanisms in common with server."
" Skipping authentication.");
}
}

Expand Down