zero_postgres/protocol/backend/
auth.rs1use zerocopy::{FromBytes, Immutable, KnownLayout};
4
5use crate::error::{Error, Result};
6use crate::protocol::codec::{read_cstr, read_i32, read_u32};
7use crate::protocol::types::TransactionStatus;
8
9pub mod auth_type {
11 pub const OK: i32 = 0;
12 pub const KERBEROS_V5: i32 = 2;
13 pub const CLEARTEXT_PASSWORD: i32 = 3;
14 pub const MD5_PASSWORD: i32 = 5;
15 pub const GSS: i32 = 7;
16 pub const GSS_CONTINUE: i32 = 8;
17 pub const SSPI: i32 = 9;
18 pub const SASL: i32 = 10;
19 pub const SASL_CONTINUE: i32 = 11;
20 pub const SASL_FINAL: i32 = 12;
21}
22
23#[derive(Debug)]
25pub enum AuthenticationMessage<'a> {
26 Ok,
28 KerberosV5,
30 CleartextPassword,
32 Md5Password { salt: [u8; 4] },
34 Gss,
36 GssContinue { data: &'a [u8] },
38 Sspi,
40 Sasl { mechanisms: Vec<&'a str> },
42 SaslContinue { data: &'a [u8] },
44 SaslFinal { data: &'a [u8] },
46}
47
48impl<'a> AuthenticationMessage<'a> {
49 pub fn parse(payload: &'a [u8]) -> Result<Self> {
51 let (auth_type, rest) = read_i32(payload)?;
52
53 match auth_type {
54 auth_type::OK => Ok(AuthenticationMessage::Ok),
55 auth_type::KERBEROS_V5 => Ok(AuthenticationMessage::KerberosV5),
56 auth_type::CLEARTEXT_PASSWORD => Ok(AuthenticationMessage::CleartextPassword),
57 auth_type::MD5_PASSWORD => {
58 if rest.len() < 4 {
59 return Err(Error::Protocol("MD5Password: missing salt".into()));
60 }
61 let mut salt = [0u8; 4];
62 salt.copy_from_slice(&rest[..4]);
63 Ok(AuthenticationMessage::Md5Password { salt })
64 }
65 auth_type::GSS => Ok(AuthenticationMessage::Gss),
66 auth_type::GSS_CONTINUE => Ok(AuthenticationMessage::GssContinue { data: rest }),
67 auth_type::SSPI => Ok(AuthenticationMessage::Sspi),
68 auth_type::SASL => {
69 let mut mechanisms = Vec::new();
70 let mut data = rest;
71 while !data.is_empty() && data[0] != 0 {
72 let (mechanism, remaining) = read_cstr(data)?;
73 mechanisms.push(mechanism);
74 data = remaining;
75 }
76 Ok(AuthenticationMessage::Sasl { mechanisms })
77 }
78 auth_type::SASL_CONTINUE => Ok(AuthenticationMessage::SaslContinue { data: rest }),
79 auth_type::SASL_FINAL => Ok(AuthenticationMessage::SaslFinal { data: rest }),
80 _ => Err(Error::Protocol(format!(
81 "Unknown authentication type: {}",
82 auth_type
83 ))),
84 }
85 }
86}
87
88#[derive(Debug, Clone)]
92pub struct BackendKeyData {
93 pid: u32,
95 secret_key: Vec<u8>,
97}
98
99impl BackendKeyData {
100 pub fn parse(payload: &[u8]) -> Result<Self> {
102 if payload.len() < 4 {
103 return Err(Error::Protocol("BackendKeyData: payload too short".into()));
104 }
105 let (pid, rest) = read_u32(payload)?;
106 if rest.len() < 4 || rest.len() > 256 {
107 return Err(Error::Protocol(format!(
108 "BackendKeyData: invalid secret key length {}",
109 rest.len()
110 )));
111 }
112 Ok(Self {
113 pid,
114 secret_key: rest.to_vec(),
115 })
116 }
117
118 pub fn process_id(&self) -> u32 {
120 self.pid
121 }
122
123 pub fn secret_key(&self) -> &[u8] {
125 &self.secret_key
126 }
127}
128
129#[derive(Debug, Clone)]
131pub struct ParameterStatus<'a> {
132 pub name: &'a str,
134 pub value: &'a str,
136}
137
138impl<'a> ParameterStatus<'a> {
139 pub fn parse(payload: &'a [u8]) -> Result<Self> {
141 let (name, rest) = read_cstr(payload)?;
142 let (value, _) = read_cstr(rest)?;
143 Ok(Self { name, value })
144 }
145}
146
147#[derive(Debug, Clone, Copy, FromBytes, KnownLayout, Immutable)]
149#[repr(C, packed)]
150pub struct ReadyForQuery {
151 pub status: u8,
153}
154
155impl ReadyForQuery {
156 pub fn parse(payload: &[u8]) -> Result<&Self> {
158 Self::ref_from_bytes(payload).map_err(|e| Error::Protocol(format!("ReadyForQuery: {e:?}")))
159 }
160
161 pub fn transaction_status(&self) -> Option<TransactionStatus> {
163 TransactionStatus::from_byte(self.status)
164 }
165}
166
167#[derive(Debug, Clone)]
169pub struct NotificationResponse<'a> {
170 pub pid: u32,
172 pub channel: &'a str,
174 pub payload: &'a str,
176}
177
178impl<'a> NotificationResponse<'a> {
179 pub fn parse(payload: &'a [u8]) -> Result<Self> {
181 let (pid, rest) = read_u32(payload)?;
182 let (channel, rest) = read_cstr(rest)?;
183 let (payload_str, _) = read_cstr(rest)?;
184 Ok(Self {
185 pid,
186 channel,
187 payload: payload_str,
188 })
189 }
190}
191
192#[derive(Debug, Clone)]
194pub struct NegotiateProtocolVersion<'a> {
195 pub newest_minor_version: u32,
197 pub unrecognized_options: Vec<&'a str>,
199}
200
201impl<'a> NegotiateProtocolVersion<'a> {
202 pub fn parse(payload: &'a [u8]) -> Result<Self> {
204 let (newest_minor_version, rest) = read_u32(payload)?;
205 let (num_options, mut rest) = read_u32(rest)?;
206
207 let mut unrecognized_options = Vec::with_capacity(num_options as usize);
208 for _ in 0..num_options {
209 let (option, remaining) = read_cstr(rest)?;
210 unrecognized_options.push(option);
211 rest = remaining;
212 }
213
214 Ok(Self {
215 newest_minor_version,
216 unrecognized_options,
217 })
218 }
219}