aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/auth.rs133
1 files changed, 125 insertions, 8 deletions
diff --git a/src/auth.rs b/src/auth.rs
index 697eff3..31b8206 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -24,10 +24,18 @@ use crate::login::ArcLoginProvider;
/// S: DONE
/// C: VERSION 1 2
/// C: CPID 1
+///
/// C: AUTH 2 PLAIN service=smtp
/// S: CONT 2
/// C: CONT 2 base64stringFollowingRFC4616==
/// S: OK 2 user=alice@example.tld
+///
+/// C: AUTH 42 LOGIN service=smtp
+/// S: CONT 42 VXNlcm5hbWU6
+/// C: CONT 42 b64User
+/// S: CONT 42 UGFzc3dvcmQ6
+/// C: CONT 42 b64Pass
+/// S: FAIL 42 user=alice
/// ```
///
/// ## RFC References
@@ -698,6 +706,44 @@ fn lf_enc(out: &mut BytesMut) {
out.put(&[0x0A][..])
}
+impl Encode for Mechanism {
+ fn encode(&self, out: &mut BytesMut) -> Result<()> {
+ match self {
+ Self::Plain => out.put(&b"PLAIN"[..]),
+ Self::Login => out.put(&b"LOGIN"[..]),
+ }
+ Ok(())
+ }
+}
+
+impl Encode for MechanismParameters {
+ fn encode(&self, out: &mut BytesMut) -> Result<()> {
+ match self {
+ Self::Anonymous => out.put(&b"anonymous"[..]),
+ Self::PlainText => out.put(&b"plaintext"[..]),
+ Self::Dictionary => out.put(&b"dictionary"[..]),
+ Self::Active => out.put(&b"active"[..]),
+ Self::ForwardSecrecy => out.put(&b"forward-secrecy"[..]),
+ Self::MutualAuth => out.put(&b"mutual-auth"[..]),
+ Self::Private => out.put(&b"private"[..]),
+ }
+ Ok(())
+ }
+}
+
+
+impl Encode for FailCode {
+ fn encode(&self, out: &mut BytesMut) -> Result<()> {
+ match self {
+ Self::TempFail => out.put(&b"temp_fail"[..]),
+ Self::AuthzFail => out.put(&b"authz_fail"[..]),
+ Self::UserDisabled => out.put(&b"user_disabled"[..]),
+ Self::PassExpired => out.put(&b"pass_expired"[..]),
+ };
+ Ok(())
+ }
+}
+
impl Encode for ServerCommand {
fn encode(&self, out: &mut BytesMut) -> Result<()> {
match self {
@@ -709,14 +755,85 @@ impl Encode for ServerCommand {
out.put(minor.to_string().as_bytes());
lf_enc(out);
},
- Self::Spid(v) => unimplemented!(),
- Self::Cuid(v) => unimplemented!(),
- Self::Mech { kind, parameters } => unimplemented!(),
- Self::Cookie(v) => unimplemented!(),
- Self::Done => unimplemented!(),
- Self::Cont { id, data } => unimplemented!(),
- Self::Ok { id, user_id, extra_parameters } => unimplemented!(),
- Self::Fail {id, user_id, code, extra_parameters } => unimplemented!(),
+ Self::Spid(pid) => {
+ out.put(&b"SPID"[..]);
+ tab_enc(out);
+ out.put(pid.to_string().as_bytes());
+ lf_enc(out);
+ },
+ Self::Cuid(pid) => {
+ out.put(&b"CUID"[..]);
+ tab_enc(out);
+ out.put(pid.to_string().as_bytes());
+ lf_enc(out);
+ },
+ Self::Cookie(cval) => {
+ out.put(&b"COOKIE"[..]);
+ tab_enc(out);
+ out.put(hex::encode(cval).as_bytes());
+ lf_enc(out);
+
+ },
+ Self::Mech { kind, parameters } => {
+ out.put(&b"MECH"[..]);
+ tab_enc(out);
+ kind.encode(out)?;
+ for p in parameters.iter() {
+ tab_enc(out);
+ p.encode(out)?;
+ }
+ lf_enc(out);
+ },
+ Self::Done => {
+ out.put(&b"DONE"[..]);
+ lf_enc(out);
+ },
+ Self::Cont { id, data } => {
+ out.put(&b"CONT"[..]);
+ tab_enc(out);
+ out.put(id.to_string().as_bytes());
+ if let Some(rdata) = data {
+ tab_enc(out);
+ let b64 = base64::engine::general_purpose::STANDARD.encode(rdata);
+ out.put(b64.as_bytes());
+ }
+ lf_enc(out);
+ },
+ Self::Ok { id, user_id, extra_parameters } => {
+ out.put(&b"OK"[..]);
+ tab_enc(out);
+ out.put(id.to_string().as_bytes());
+ if let Some(user) = user_id {
+ tab_enc(out);
+ out.put(&b"user="[..]);
+ out.put(user.as_bytes());
+ }
+ for p in extra_parameters.iter() {
+ tab_enc(out);
+ out.put(&p[..]);
+ }
+ lf_enc(out);
+ },
+ Self::Fail {id, user_id, code, extra_parameters } => {
+ out.put(&b"FAIL"[..]);
+ tab_enc(out);
+ out.put(id.to_string().as_bytes());
+ if let Some(user) = user_id {
+ tab_enc(out);
+ out.put(&b"user="[..]);
+ out.put(user.as_bytes());
+ }
+ if let Some(code_val) = code {
+ tab_enc(out);
+ out.put(&b"code="[..]);
+ code_val.encode(out)?;
+ }
+ for p in extra_parameters.iter() {
+ tab_enc(out);
+ out.put(&p[..]);
+ }
+ lf_enc(out);
+ },
}
Ok(())
}