Mechanisms as bit sets.

This commit is contained in:
Mauro D 2022-12-09 17:33:10 +00:00
parent e7df79ef68
commit 5765b4b9fe
6 changed files with 164 additions and 176 deletions

6
.gitignore vendored
View file

@ -8,9 +8,3 @@ Cargo.lock
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk
# Added by cargo
/target
/Cargo.lock

View file

@ -3,9 +3,6 @@ name = "smtp-proto"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
[dev-dependencies] [dev-dependencies]
csv = "1.1"

View file

@ -27,7 +27,7 @@ pub enum Request<T> {
is_last: bool, is_last: bool,
}, },
Auth { Auth {
mechanism: Mechanism, mechanism: u64,
initial_response: T, initial_response: T,
}, },
Noop { Noop {
@ -122,60 +122,55 @@ pub const NOTIFY_SUCCESS: u8 = 0x01;
pub const NOTIFY_FAILURE: u8 = 0x02; pub const NOTIFY_FAILURE: u8 = 0x02;
pub const NOTIFY_DELAY: u8 = 0x04; pub const NOTIFY_DELAY: u8 = 0x04;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub const AUTH_SCRAM_SHA_256_PLUS: u64 = 1u64 << 0;
pub enum Mechanism { pub const AUTH_SCRAM_SHA_256: u64 = 1u64 << 1;
_9798MDsaSha1, pub const AUTH_SCRAM_SHA_1_PLUS: u64 = 1u64 << 2;
_9798MEcdsaSha1, pub const AUTH_SCRAM_SHA_1: u64 = 1u64 << 3;
_9798MRsaSha1Enc, pub const AUTH_OAUTHBEARER: u64 = 1u64 << 4;
_9798UDsaSha1, pub const AUTH_XOAUTH: u64 = 1u64 << 5;
_9798UEcdsaSha1, pub const AUTH_XOAUTH2: u64 = 1u64 << 6;
_9798URsaSha1Enc, pub const AUTH_9798_M_DSA_SHA1: u64 = 1u64 << 7;
Anonymous, pub const AUTH_9798_M_ECDSA_SHA1: u64 = 1u64 << 8;
CramMd5, pub const AUTH_9798_M_RSA_SHA1_ENC: u64 = 1u64 << 9;
DigestMd5, pub const AUTH_9798_U_DSA_SHA1: u64 = 1u64 << 10;
EapAes128, pub const AUTH_9798_U_ECDSA_SHA1: u64 = 1u64 << 11;
EapAes128Plus, pub const AUTH_9798_U_RSA_SHA1_ENC: u64 = 1u64 << 12;
EcdhX25519Challenge, pub const AUTH_EAP_AES128: u64 = 1u64 << 13;
EcdsaNist256pChallenge, pub const AUTH_EAP_AES128_PLUS: u64 = 1u64 << 14;
External, pub const AUTH_ECDH_X25519_CHALLENGE: u64 = 1u64 << 15;
Gs2Krb5, pub const AUTH_ECDSA_NIST256P_CHALLENGE: u64 = 1u64 << 16;
Gs2Krb5Plus, pub const AUTH_EXTERNAL: u64 = 1u64 << 17;
GssSpnego, pub const AUTH_GS2_KRB5: u64 = 1u64 << 18;
Gssapi, pub const AUTH_GS2_KRB5_PLUS: u64 = 1u64 << 19;
KerberosV4, pub const AUTH_GSS_SPNEGO: u64 = 1u64 << 20;
KerberosV5, pub const AUTH_GSSAPI: u64 = 1u64 << 21;
Login, pub const AUTH_KERBEROS_V4: u64 = 1u64 << 22;
NmasSambaAuth, pub const AUTH_KERBEROS_V5: u64 = 1u64 << 23;
NmasAuthen, pub const AUTH_NMAS_SAMBA_AUTH: u64 = 1u64 << 24;
NmasLogin, pub const AUTH_NMAS_AUTHEN: u64 = 1u64 << 25;
Ntlm, pub const AUTH_NMAS_LOGIN: u64 = 1u64 << 26;
Oauth10a, pub const AUTH_NTLM: u64 = 1u64 << 27;
Oauthbearer, pub const AUTH_OAUTH10A: u64 = 1u64 << 28;
Openid20, pub const AUTH_OPENID20: u64 = 1u64 << 29;
Otp, pub const AUTH_OTP: u64 = 1u64 << 30;
Plain, pub const AUTH_SAML20: u64 = 1u64 << 31;
Saml20, pub const AUTH_SECURID: u64 = 1u64 << 32;
ScramSha1, pub const AUTH_SKEY: u64 = 1u64 << 33;
ScramSha1Plus, pub const AUTH_SPNEGO: u64 = 1u64 << 34;
ScramSha256, pub const AUTH_SPNEGO_PLUS: u64 = 1u64 << 35;
ScramSha256Plus, pub const AUTH_SXOVER_PLUS: u64 = 1u64 << 36;
Securid, pub const AUTH_CRAM_MD5: u64 = 1u64 << 37;
Skey, pub const AUTH_DIGEST_MD5: u64 = 1u64 << 38;
Spnego, pub const AUTH_LOGIN: u64 = 1u64 << 39;
SpnegoPlus, pub const AUTH_PLAIN: u64 = 1u64 << 40;
SxoverPlus, pub const AUTH_ANONYMOUS: u64 = 1u64 << 41;
Xoauth,
Xoauth2,
// Unknown
Unknown,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Capability { pub enum Capability {
EightBitMime, EightBitMime,
Atrn, Atrn,
Auth { Auth {
mechanisms: Vec<Mechanism>, mechanisms: u64,
}, },
BinaryMime, BinaryMime,
Burl, Burl,
@ -219,6 +214,7 @@ pub enum MtPriority {
Mixer, Mixer,
Stanag4406, Stanag4406,
Nsep, Nsep,
None,
} }
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -279,6 +275,7 @@ impl IntoString for Vec<u8> {
} }
} }
/*
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -316,3 +313,4 @@ mod tests {
} }
} }
} }
*/

View file

@ -1,9 +1,6 @@
use std::slice::Iter; use std::slice::Iter;
use crate::{ use crate::*;
Body, By, Error, IntoString, Mechanism, Mtrk, Orcpt, Parameter, Request, Ret, Rrvs, LF,
NOTIFY_DELAY, NOTIFY_FAILURE, NOTIFY_SUCCESS, SP,
};
use super::{receiver::ReceiverParser, *}; use super::{receiver::ReceiverParser, *};
@ -1046,7 +1043,7 @@ impl<'x, 'y> Rfc5321Parser<'x, 'y> {
Ok(params) Ok(params)
} }
pub(crate) fn mechanism(&mut self) -> Result<Option<Mechanism>, Error> { pub(crate) fn mechanism(&mut self) -> Result<Option<u64>, Error> {
let mut trailing_chars = [0u8; 8]; let mut trailing_chars = [0u8; 8];
let mut pos = 0; let mut pos = 0;
let mechanism = self.hashed_value_long()?; let mechanism = self.hashed_value_long()?;
@ -1069,54 +1066,54 @@ impl<'x, 'y> Rfc5321Parser<'x, 'y> {
bytes_left: self.bytes_left, bytes_left: self.bytes_left,
}); });
} else if pos > 8 { } else if pos > 8 {
return Ok(Mechanism::Unknown.into()); return Ok(0.into());
} }
} }
Ok(match (mechanism, &trailing_chars[..pos]) { Ok(match (mechanism, &trailing_chars[..pos]) {
(_9798_M_DSA_SHA1, b"") => Mechanism::_9798MDsaSha1.into(), (_9798_M_DSA_SHA1, b"") => AUTH_9798_M_DSA_SHA1.into(),
(_9798_M_ECDSA_SHA, b"1") => Mechanism::_9798MEcdsaSha1.into(), (_9798_M_ECDSA_SHA, b"1") => AUTH_9798_M_ECDSA_SHA1.into(),
(_9798_M_RSA_SHA1_, b"ENC") => Mechanism::_9798MRsaSha1Enc.into(), (_9798_M_RSA_SHA1_, b"ENC") => AUTH_9798_M_RSA_SHA1_ENC.into(),
(_9798_U_DSA_SHA1, b"") => Mechanism::_9798UDsaSha1.into(), (_9798_U_DSA_SHA1, b"") => AUTH_9798_U_DSA_SHA1.into(),
(_9798_U_ECDSA_SHA, b"1") => Mechanism::_9798UEcdsaSha1.into(), (_9798_U_ECDSA_SHA, b"1") => AUTH_9798_U_ECDSA_SHA1.into(),
(_9798_U_RSA_SHA1_, b"ENC") => Mechanism::_9798URsaSha1Enc.into(), (_9798_U_RSA_SHA1_, b"ENC") => AUTH_9798_U_RSA_SHA1_ENC.into(),
(ANONYMOUS, b"") => Mechanism::Anonymous.into(), (ANONYMOUS, b"") => AUTH_ANONYMOUS.into(),
(CRAM_MD5, b"") => Mechanism::CramMd5.into(), (CRAM_MD5, b"") => AUTH_CRAM_MD5.into(),
(DIGEST_MD5, b"") => Mechanism::DigestMd5.into(), (DIGEST_MD5, b"") => AUTH_DIGEST_MD5.into(),
(EAP_AES128, b"") => Mechanism::EapAes128.into(), (EAP_AES128, b"") => AUTH_EAP_AES128.into(),
(EAP_AES128_PLUS, b"") => Mechanism::EapAes128Plus.into(), (EAP_AES128_PLUS, b"") => AUTH_EAP_AES128_PLUS.into(),
(ECDH_X25519_CHAL, b"LENGE") => Mechanism::EcdhX25519Challenge.into(), (ECDH_X25519_CHAL, b"LENGE") => AUTH_ECDH_X25519_CHALLENGE.into(),
(ECDSA_NIST256P_C, b"HALLENGE") => Mechanism::EcdsaNist256pChallenge.into(), (ECDSA_NIST256P_C, b"HALLENGE") => AUTH_ECDSA_NIST256P_CHALLENGE.into(),
(EXTERNAL, b"") => Mechanism::External.into(), (EXTERNAL, b"") => AUTH_EXTERNAL.into(),
(GS2_KRB5, b"") => Mechanism::Gs2Krb5.into(), (GS2_KRB5, b"") => AUTH_GS2_KRB5.into(),
(GS2_KRB5_PLUS, b"") => Mechanism::Gs2Krb5Plus.into(), (GS2_KRB5_PLUS, b"") => AUTH_GS2_KRB5_PLUS.into(),
(GSS_SPNEGO, b"") => Mechanism::GssSpnego.into(), (GSS_SPNEGO, b"") => AUTH_GSS_SPNEGO.into(),
(GSSAPI, b"") => Mechanism::Gssapi.into(), (GSSAPI, b"") => AUTH_GSSAPI.into(),
(KERBEROS_V4, b"") => Mechanism::KerberosV4.into(), (KERBEROS_V4, b"") => AUTH_KERBEROS_V4.into(),
(KERBEROS_V5, b"") => Mechanism::KerberosV5.into(), (KERBEROS_V5, b"") => AUTH_KERBEROS_V5.into(),
(LOGIN, b"") => Mechanism::Login.into(), (LOGIN, b"") => AUTH_LOGIN.into(),
(NMAS_SAMBA_AUTH, b"") => Mechanism::NmasSambaAuth.into(), (NMAS_SAMBA_AUTH, b"") => AUTH_NMAS_SAMBA_AUTH.into(),
(NMAS_AUTHEN, b"") => Mechanism::NmasAuthen.into(), (NMAS_AUTHEN, b"") => AUTH_NMAS_AUTHEN.into(),
(NMAS_LOGIN, b"") => Mechanism::NmasLogin.into(), (NMAS_LOGIN, b"") => AUTH_NMAS_LOGIN.into(),
(NTLM, b"") => Mechanism::Ntlm.into(), (NTLM, b"") => AUTH_NTLM.into(),
(OAUTH10A, b"") => Mechanism::Oauth10a.into(), (OAUTH10A, b"") => AUTH_OAUTH10A.into(),
(OAUTHBEARER, b"") => Mechanism::Oauthbearer.into(), (OAUTHBEARER, b"") => AUTH_OAUTHBEARER.into(),
(OPENID20, b"") => Mechanism::Openid20.into(), (OPENID20, b"") => AUTH_OPENID20.into(),
(OTP, b"") => Mechanism::Otp.into(), (OTP, b"") => AUTH_OTP.into(),
(PLAIN, b"") => Mechanism::Plain.into(), (PLAIN, b"") => AUTH_PLAIN.into(),
(SAML20, b"") => Mechanism::Saml20.into(), (SAML20, b"") => AUTH_SAML20.into(),
(SCRAM_SHA_1, b"") => Mechanism::ScramSha1.into(), (SCRAM_SHA_1, b"") => AUTH_SCRAM_SHA_1.into(),
(SCRAM_SHA_1_PLUS, b"") => Mechanism::ScramSha1Plus.into(), (SCRAM_SHA_1_PLUS, b"") => AUTH_SCRAM_SHA_1_PLUS.into(),
(SCRAM_SHA_256, b"") => Mechanism::ScramSha256.into(), (SCRAM_SHA_256, b"") => AUTH_SCRAM_SHA_256.into(),
(SCRAM_SHA_256_PL, b"US") => Mechanism::ScramSha256Plus.into(), (SCRAM_SHA_256_PL, b"US") => AUTH_SCRAM_SHA_256_PLUS.into(),
(SECURID, b"") => Mechanism::Securid.into(), (SECURID, b"") => AUTH_SECURID.into(),
(SKEY, b"") => Mechanism::Skey.into(), (SKEY, b"") => AUTH_SKEY.into(),
(SPNEGO, b"") => Mechanism::Spnego.into(), (SPNEGO, b"") => AUTH_SPNEGO.into(),
(SPNEGO_PLUS, b"") => Mechanism::SpnegoPlus.into(), (SPNEGO_PLUS, b"") => AUTH_SPNEGO_PLUS.into(),
(SXOVER_PLUS, b"") => Mechanism::SxoverPlus.into(), (SXOVER_PLUS, b"") => AUTH_SXOVER_PLUS.into(),
(XOAUTH, b"") => Mechanism::Xoauth.into(), (XOAUTH, b"") => AUTH_XOAUTH.into(),
(XOAUTH2, b"") => Mechanism::Xoauth2.into(), (XOAUTH2, b"") => AUTH_XOAUTH2.into(),
(0, b"") => None, (0, b"") => None,
_ => Mechanism::Unknown.into(), _ => 0.into(),
}) })
} }
} }
@ -1137,8 +1134,9 @@ impl TryFrom<u128> for Body {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
request::receiver::ReceiverParser, Body, By, Error, Mechanism, Mtrk, Orcpt, Parameter, request::receiver::ReceiverParser, Body, By, Error, Mtrk, Orcpt, Parameter, Request, Ret,
Request, Ret, Rrvs, NOTIFY_DELAY, NOTIFY_FAILURE, NOTIFY_SUCCESS, Rrvs, AUTH_ECDSA_NIST256P_CHALLENGE, AUTH_GSSAPI, AUTH_SCRAM_SHA_256_PLUS, NOTIFY_DELAY,
NOTIFY_FAILURE, NOTIFY_SUCCESS,
}; };
#[test] #[test]
@ -1312,28 +1310,28 @@ mod tests {
( (
"AUTH GSSAPI", "AUTH GSSAPI",
Ok(Request::Auth { Ok(Request::Auth {
mechanism: Mechanism::Gssapi, mechanism: AUTH_GSSAPI,
initial_response: "".to_string(), initial_response: "".to_string(),
}), }),
), ),
( (
"AUTH ECDSA-NIST256P-CHALLENGE =", "AUTH ECDSA-NIST256P-CHALLENGE =",
Ok(Request::Auth { Ok(Request::Auth {
mechanism: Mechanism::EcdsaNist256pChallenge, mechanism: AUTH_ECDSA_NIST256P_CHALLENGE,
initial_response: "=".to_string(), initial_response: "=".to_string(),
}), }),
), ),
( (
"AUTH SCRAM-SHA-256-PLUS base64_goes_here", "AUTH SCRAM-SHA-256-PLUS base64_goes_here",
Ok(Request::Auth { Ok(Request::Auth {
mechanism: Mechanism::ScramSha256Plus, mechanism: AUTH_SCRAM_SHA_256_PLUS,
initial_response: "base64_goes_here".to_string(), initial_response: "base64_goes_here".to_string(),
}), }),
), ),
( (
"AUTH ECDSA-NIST256P-CHALLENGE100 abcde", "AUTH ECDSA-NIST256P-CHALLENGE100 abcde",
Ok(Request::Auth { Ok(Request::Auth {
mechanism: Mechanism::Unknown, mechanism: 0,
initial_response: "abcde".to_string(), initial_response: "abcde".to_string(),
}), }),
), ),

View file

@ -3,7 +3,7 @@ use std::{
io::{self, Write}, io::{self, Write},
}; };
use crate::{Capability, Category, EhloResponse, Mechanism, MtPriority, Response, Severity}; use crate::*;
impl<T: Display> EhloResponse<T> { impl<T: Display> EhloResponse<T> {
pub fn write(&self, mut writer: impl Write) -> io::Result<()> { pub fn write(&self, mut writer: impl Write) -> io::Result<()> {
@ -17,8 +17,11 @@ impl<T: Display> EhloResponse<T> {
Capability::Atrn => write!(writer, "ATRN\r\n"), Capability::Atrn => write!(writer, "ATRN\r\n"),
Capability::Auth { mechanisms } => { Capability::Auth { mechanisms } => {
writer.write_all(b"AUTH")?; writer.write_all(b"AUTH")?;
for mechanism in mechanisms { let mut mechanisms = *mechanisms;
write!(writer, " {}", mechanism)?; while mechanisms != 0 {
let item = 63 - mechanisms.leading_zeros();
mechanisms ^= 1 << item;
write!(writer, " {}", (item as u64).as_mechanism())?;
} }
writer.write_all(b"\r\n") writer.write_all(b"\r\n")
} }
@ -55,6 +58,7 @@ impl<T: Display> EhloResponse<T> {
MtPriority::Mixer => "MIXER", MtPriority::Mixer => "MIXER",
MtPriority::Stanag4406 => "STANAG4406", MtPriority::Stanag4406 => "STANAG4406",
MtPriority::Nsep => "NSEP", MtPriority::Nsep => "NSEP",
MtPriority::None => "MIXER",
} }
), ),
Capability::Mtrk => write!(writer, "MTRK\r\n"), Capability::Mtrk => write!(writer, "MTRK\r\n"),
@ -102,53 +106,57 @@ impl<T: Display> Response<T> {
} }
} }
impl Display for Mechanism { trait AsMechanism {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn as_mechanism(&self) -> &'static str;
f.write_str(match self { }
Mechanism::_9798MDsaSha1 => "9798-M-DSA-SHA1",
Mechanism::_9798MEcdsaSha1 => "9798-M-ECDSA-SHA1", impl AsMechanism for u64 {
Mechanism::_9798MRsaSha1Enc => "9798-M-RSA-SHA1-ENC", fn as_mechanism(&self) -> &'static str {
Mechanism::_9798UDsaSha1 => "9798-U-DSA-SHA1", match *self {
Mechanism::_9798UEcdsaSha1 => "9798-U-ECDSA-SHA1", AUTH_SCRAM_SHA_256_PLUS => "SCRAM-SHA-256-PLUS",
Mechanism::_9798URsaSha1Enc => "9798-U-RSA-SHA1-ENC", AUTH_SCRAM_SHA_256 => "SCRAM-SHA-256",
Mechanism::Anonymous => "ANONYMOUS", AUTH_SCRAM_SHA_1_PLUS => "SCRAM-SHA-1-PLUS",
Mechanism::CramMd5 => "CRAM-MD5", AUTH_SCRAM_SHA_1 => "SCRAM-SHA-1",
Mechanism::DigestMd5 => "DIGEST-MD5", AUTH_OAUTHBEARER => "OAUTHBEARER",
Mechanism::EapAes128 => "EAP-AES128", AUTH_XOAUTH => "XOAUTH",
Mechanism::EapAes128Plus => "EAP-AES128-PLUS", AUTH_XOAUTH2 => "XOAUTH2",
Mechanism::EcdhX25519Challenge => "ECDH-X25519-CHALLENGE", AUTH_9798_M_DSA_SHA1 => "9798-M-DSA-SHA1",
Mechanism::EcdsaNist256pChallenge => "ECDSA-NIST256P-CHALLENGE", AUTH_9798_M_ECDSA_SHA1 => "9798-M-ECDSA-SHA1",
Mechanism::External => "EXTERNAL", AUTH_9798_M_RSA_SHA1_ENC => "9798-M-RSA-SHA1-ENC",
Mechanism::Gs2Krb5 => "GS2-KRB5", AUTH_9798_U_DSA_SHA1 => "9798-U-DSA-SHA1",
Mechanism::Gs2Krb5Plus => "GS2-KRB5-PLUS", AUTH_9798_U_ECDSA_SHA1 => "9798-U-ECDSA-SHA1",
Mechanism::GssSpnego => "GSS-SPNEGO", AUTH_9798_U_RSA_SHA1_ENC => "9798-U-RSA-SHA1-ENC",
Mechanism::Gssapi => "GSSAPI", AUTH_EAP_AES128 => "EAP-AES128",
Mechanism::KerberosV4 => "KERBEROS_V4", AUTH_EAP_AES128_PLUS => "EAP-AES128-PLUS",
Mechanism::KerberosV5 => "KERBEROS_V5", AUTH_ECDH_X25519_CHALLENGE => "ECDH-X25519-CHALLENGE",
Mechanism::Login => "LOGIN", AUTH_ECDSA_NIST256P_CHALLENGE => "ECDSA-NIST256P-CHALLENGE",
Mechanism::NmasSambaAuth => "NMAS-SAMBA-AUTH", AUTH_EXTERNAL => "EXTERNAL",
Mechanism::NmasAuthen => "NMAS_AUTHEN", AUTH_GS2_KRB5 => "GS2-KRB5",
Mechanism::NmasLogin => "NMAS_LOGIN", AUTH_GS2_KRB5_PLUS => "GS2-KRB5-PLUS",
Mechanism::Ntlm => "NTLM", AUTH_GSS_SPNEGO => "GSS-SPNEGO",
Mechanism::Oauth10a => "OAUTH10A", AUTH_GSSAPI => "GSSAPI",
Mechanism::Oauthbearer => "OAUTHBEARER", AUTH_KERBEROS_V4 => "KERBEROS_V4",
Mechanism::Openid20 => "OPENID20", AUTH_KERBEROS_V5 => "KERBEROS_V5",
Mechanism::Otp => "OTP", AUTH_NMAS_SAMBA_AUTH => "NMAS-SAMBA-AUTH",
Mechanism::Plain => "PLAIN", AUTH_NMAS_AUTHEN => "NMAS_AUTHEN",
Mechanism::Saml20 => "SAML20", AUTH_NMAS_LOGIN => "NMAS_LOGIN",
Mechanism::ScramSha1 => "SCRAM-SHA-1", AUTH_NTLM => "NTLM",
Mechanism::ScramSha1Plus => "SCRAM-SHA-1-PLUS", AUTH_OAUTH10A => "OAUTH10A",
Mechanism::ScramSha256 => "SCRAM-SHA-256", AUTH_OPENID20 => "OPENID20",
Mechanism::ScramSha256Plus => "SCRAM-SHA-256-PLUS", AUTH_OTP => "OTP",
Mechanism::Securid => "SECURID", AUTH_SAML20 => "SAML20",
Mechanism::Skey => "SKEY", AUTH_SECURID => "SECURID",
Mechanism::Spnego => "SPNEGO", AUTH_SKEY => "SKEY",
Mechanism::SpnegoPlus => "SPNEGO-PLUS", AUTH_SPNEGO => "SPNEGO",
Mechanism::SxoverPlus => "SXOVER-PLUS", AUTH_SPNEGO_PLUS => "SPNEGO-PLUS",
Mechanism::Xoauth => "XOAUTH", AUTH_SXOVER_PLUS => "SXOVER-PLUS",
Mechanism::Xoauth2 => "XOAUTH2", AUTH_CRAM_MD5 => "CRAM-MD5",
Mechanism::Unknown => "", AUTH_DIGEST_MD5 => "DIGEST-MD5",
}) AUTH_LOGIN => "LOGIN",
AUTH_PLAIN => "PLAIN",
AUTH_ANONYMOUS => "ANONYMOUS",
_ => "",
}
} }
} }

View file

@ -57,10 +57,10 @@ impl ReceiverParser for EhloResponse<String> {
_8BITMIME => Capability::EightBitMime, _8BITMIME => Capability::EightBitMime,
ATRN => Capability::Atrn, ATRN => Capability::Atrn,
AUTH => { AUTH => {
let mut mechanisms = Vec::new(); let mut mechanisms = 0;
while parser.stop_char != LF { while parser.stop_char != LF {
if let Some(mechanism) = parser.mechanism()? { if let Some(mechanism) = parser.mechanism()? {
mechanisms.push(mechanism); mechanisms |= mechanism;
} }
} }
@ -306,10 +306,7 @@ impl Capability {
} else if value.eq_ignore_ascii_case(b"ATRN") { } else if value.eq_ignore_ascii_case(b"ATRN") {
Capability::Atrn.into() Capability::Atrn.into()
} else if value.eq_ignore_ascii_case(b"AUTH") { } else if value.eq_ignore_ascii_case(b"AUTH") {
Capability::Auth { Capability::Auth { mechanisms: 0 }.into()
mechanisms: Vec::new(),
}
.into()
} else if value.eq_ignore_ascii_case(b"BINARYMIME") { } else if value.eq_ignore_ascii_case(b"BINARYMIME") {
Capability::BinaryMime.into() Capability::BinaryMime.into()
} else if value.eq_ignore_ascii_case(b"BURL") { } else if value.eq_ignore_ascii_case(b"BURL") {
@ -374,8 +371,8 @@ impl Capability {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
request::receiver::ReceiverParser, Capability, EhloResponse, Error, Mechanism, MtPriority, request::receiver::ReceiverParser, Capability, EhloResponse, Error, MtPriority, Response,
Response, AUTH_DIGEST_MD5, AUTH_GSSAPI, AUTH_PLAIN,
}; };
#[test] #[test]
@ -424,11 +421,7 @@ mod tests {
Capability::EightBitMime, Capability::EightBitMime,
Capability::Atrn, Capability::Atrn,
Capability::Auth { Capability::Auth {
mechanisms: vec![ mechanisms: AUTH_GSSAPI | AUTH_DIGEST_MD5 | AUTH_PLAIN,
Mechanism::Gssapi,
Mechanism::DigestMd5,
Mechanism::Plain,
],
}, },
Capability::BinaryMime, Capability::BinaryMime,
Capability::Burl, Capability::Burl,