Skip to content
Draft
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
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
106 changes: 70 additions & 36 deletions net.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,44 +281,67 @@ smtp_login(int fd, char *login, char* password, const struct smtp_features* feat
}
}

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

len = base64_encode(login, strlen(login), &temp);
if (len < 0) {
if (features->auth.login) {
// LOGIN mechanism
len = base64_encode(login, strlen(login), &temp);
if (len < 0) {
encerr:
syslog(LOG_ERR, "can not encode auth reply: %m");
return (1);
}
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);
}
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);
} else if (features->auth.plain) {
// PLAIN mechanism
size_t buflen = strlen(login) + strlen(password) + 3;
char *plainbuf = malloc(buflen);
if (plainbuf == NULL) {
syslog(LOG_ERR, "remote delivery deferred: unable to allocate memory");
return (1);
}

len = base64_encode(password, strlen(password), &temp);
if (len < 0)
goto encerr;
snprintf(plainbuf, buflen, "%c%s%c%s", '\0', login, '\0', password);

len = base64_encode(plainbuf, buflen, &temp);
free(plainbuf);
if (len < 0)
goto encerr;

send_remote_command(fd, "%s", temp);
free(temp);
}

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",
syslog(LOG_NOTICE, "remote delivery %s: AUTH PLAIN failed: %s",
res == 5 ? "failed" : "deferred", neterr);
return (res == 5 ? -1 : 1);
}
Expand Down Expand Up @@ -381,6 +404,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 +495,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 +581,23 @@ 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_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.");
}
} else {
syslog(LOG_ERR, "No supported AUTH mechanisms in common with server."
" Skipping authentication.");
}
}

Expand Down