1use std::{
2 io::{Cursor, Write},
3 iter::FromIterator,
4 ops::Deref,
5};
6
7use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
8
9use crate::{Error, Opaque};
10
11const MAX_GIDS: usize = 16;
12const MAX_MACHINE_NAME_LEN: u32 = 255;
13
14#[derive(Clone, PartialEq, Default)]
17struct Gids {
18 values: [u32; MAX_GIDS],
20
21 len: u8,
23}
24
25impl Deref for Gids {
26 type Target = [u32];
27
28 fn deref(&self) -> &Self::Target {
29 &self.values[..self.len as usize]
30 }
31}
32
33impl std::fmt::Debug for Gids {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 self.deref().fmt(f)
36 }
37}
38
39impl FromIterator<u32> for Gids {
40 fn from_iter<T: IntoIterator<Item = u32>>(iter: T) -> Self {
41 let mut values = [0; MAX_GIDS];
42 let mut len = 0;
43
44 for v in iter.into_iter() {
46 assert!(len < MAX_GIDS);
48
49 values[len] = v;
50 len += 1;
51 }
52
53 Self {
54 values,
55 len: len as u8,
56 }
57 }
58}
59
60#[derive(Debug, PartialEq, Clone)]
73pub struct AuthUnixParams<T>
74where
75 T: AsRef<[u8]>,
76{
77 stamp: u32,
78 machine_name: Opaque<T>,
79 uid: u32,
80 gid: u32,
81 gids: Gids,
82}
83
84impl<'a> AuthUnixParams<&'a [u8]> {
85 pub(crate) fn from_cursor(r: &mut Cursor<&'a [u8]>, expected_len: u32) -> Result<Self, Error> {
91 let start_pos = r.position();
94
95 let stamp = r.read_u32::<BigEndian>()?;
97
98 let machine_name = Opaque::from_wire(&mut *r, MAX_MACHINE_NAME_LEN as _)?;
100
101 let uid = r.read_u32::<BigEndian>()?;
103 let gid = r.read_u32::<BigEndian>()?;
104
105 let gids_count = r.read_u32::<BigEndian>()? as usize;
107 let gids = match gids_count {
108 0 => Gids::default(),
109 c if c <= 16 => (0..c)
110 .map(|_| r.read_u32::<BigEndian>())
111 .collect::<Result<Gids, _>>()?,
112 _ => return Err(Error::InvalidAuthData),
113 };
114
115 if (r.position() - start_pos) != expected_len as u64 {
118 return Err(Error::InvalidAuthData);
119 }
120
121 Ok(AuthUnixParams {
122 stamp,
123 machine_name,
124 uid,
125 gid,
126 gids,
127 })
128 }
129}
130
131impl<T> AuthUnixParams<T>
132where
133 T: AsRef<[u8]>,
134{
135 pub fn new(
143 stamp: u32,
144 machine_name: T,
145 uid: u32,
146 gid: u32,
147 gids: impl IntoIterator<Item = u32>,
148 ) -> Self {
149 assert!(machine_name.as_ref().len() <= 16);
150
151 Self {
152 stamp,
153 machine_name: Opaque::from_user_payload(machine_name),
154 uid,
155 gid,
156 gids: gids.into_iter().collect::<Gids>(),
157 }
158 }
159
160 pub fn serialise_into<W: Write>(&self, mut buf: W) -> Result<(), std::io::Error> {
163 buf.write_u32::<BigEndian>(self.stamp)?;
164 self.machine_name.serialise_into(&mut buf)?;
165 buf.write_u32::<BigEndian>(self.uid)?;
166 buf.write_u32::<BigEndian>(self.gid)?;
167
168 buf.write_u32::<BigEndian>(self.gids.deref().len() as u32)?;
170
171 for g in &*self.gids {
173 buf.write_u32::<BigEndian>(*g)?;
174 }
175 Ok(())
176 }
177
178 pub fn stamp(&self) -> u32 {
180 self.stamp
181 }
182
183 pub fn machine_name(&self) -> &[u8] {
185 self.machine_name.as_ref()
186 }
187
188 pub fn machine_name_str(&self) -> &str {
195 std::str::from_utf8(self.machine_name.as_ref()).unwrap()
196 }
197
198 pub fn uid(&self) -> u32 {
200 self.uid
201 }
202
203 pub fn gid(&self) -> u32 {
205 self.gid
206 }
207
208 pub fn gids(&self) -> Option<&[u32]> {
211 if self.gids.len == 0 {
212 return None;
213 }
214 Some(&*self.gids)
215 }
216
217 pub fn serialised_len(&self) -> u32 {
220 let mut l = std::mem::size_of::<u32>() * 3;
222
223 l += self.machine_name.serialised_len() as usize;
225
226 l += (self.gids.deref().len() + 1) * std::mem::size_of::<u32>();
228
229 l as u32
230 }
231
232 pub(crate) fn associated_data_len(&self) -> u32 {
235 let mut l = std::mem::size_of::<u32>() * 3;
237
238 l += self.machine_name.len();
240
241 l += std::mem::size_of_val(self.gids.deref());
243
244 l as u32
245 }
246}
247
248#[cfg(feature = "bytes")]
249impl TryFrom<crate::Bytes> for AuthUnixParams<crate::Bytes> {
250 type Error = Error;
251
252 fn try_from(mut v: crate::Bytes) -> Result<Self, Self::Error> {
253 use crate::bytes_ext::BytesReaderExt;
254
255 let stamp = v.try_u32()?;
256
257 let name = v.try_array(MAX_MACHINE_NAME_LEN as _)?;
258 let uid = v.try_u32()?;
259 let gid = v.try_u32()?;
260
261 let gids_count = v.try_u32()? as usize;
262 let gids = match gids_count {
263 0 => Gids::default(),
264 c if c <= 16 => (0..c).map(|_| v.try_u32()).collect::<Result<Gids, _>>()?,
265 _ => return Err(Error::InvalidAuthData),
266 };
267
268 Ok(Self {
269 stamp,
270 machine_name: Opaque::from_user_payload(name),
271 uid,
272 gid,
273 gids,
274 })
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use hex_literal::hex;
281
282 #[cfg(feature = "bytes")]
283 use crate::Bytes;
284
285 use super::*;
286
287 #[test]
288 fn test_serialise_deserialise() {
289 let gids = [
290 501, 12, 20, 61, 79, 80, 81, 98, 701, 33, 100, 204, 250, 395, 398, 399,
291 ];
292 let params = AuthUnixParams::new(0, b"".as_ref(), 501, 20, gids);
293
294 let mut buf = Cursor::new(Vec::new());
295 params
296 .serialise_into(&mut buf)
297 .expect("failed to serialise");
298
299 #[rustfmt::skip]
300 let want = hex!(
330 "0000000000000000000001f50000001400000010000001f50000000c0000001400
331 00003d0000004f000000500000005100000062000002bd000000210000006400000
332 0cc000000fa0000018b0000018e0000018f"
333 );
334
335 let buf = buf.into_inner();
336 assert_eq!(want.len(), buf.len());
337 assert_eq!(want.as_ref(), buf.as_slice());
338
339 let mut c = Cursor::new(want.as_ref());
340 let s = AuthUnixParams::from_cursor(&mut c, 84).expect("deserialise failed");
341
342 assert_eq!(s.serialised_len(), 84);
343 assert_eq!(params, s);
344 }
345
346 #[test]
347 fn test_empty() {
348 let want = hex!("000000000000000000000000000000000000000100000000");
362 let mut c = Cursor::new(want.as_ref());
363
364 let s = AuthUnixParams::from_cursor(&mut c, 24).expect("deserialise failed");
365
366 assert_eq!(s.stamp(), 0);
367 assert_eq!(s.machine_name_str(), "");
368 assert_eq!(s.uid(), 0);
369 assert_eq!(s.gid(), 0);
370 assert_eq!(s.gids(), Some([0].as_slice()));
371 assert_eq!(s.serialised_len(), 24);
372
373 let mut buf = Cursor::new(Vec::new());
374 s.serialise_into(&mut buf).expect("failed to serialise");
375
376 let buf = buf.into_inner();
377 assert_eq!(want.len(), buf.len());
378 assert_eq!(want.as_ref(), buf.as_slice());
379 }
380
381 #[test]
382 #[cfg(feature = "bytes")]
383 fn test_deserialise_bytes() {
384 #[rustfmt::skip]
385 let want = hex!(
415 "0000000000000000000001f50000001400000010000001f50000000c0000001400
416 00003d0000004f000000500000005100000062000002bd000000210000006400000
417 0cc000000fa0000018b0000018e0000018f"
418 );
419 let static_want: &'static [u8] = Box::leak(Box::new(want));
420
421 let got =
422 AuthUnixParams::try_from(Bytes::from(static_want)).expect("failed to deserialise");
423
424 assert_eq!(got.stamp(), 0);
425 assert_eq!(got.machine_name_str(), "");
426 assert_eq!(got.uid(), 501);
427 assert_eq!(got.gid(), 20);
428 assert_eq!(
429 got.gids(),
430 Some(
431 [501, 12, 20, 61, 79, 80, 81, 98, 701, 33, 100, 204, 250, 395, 398, 399].as_slice()
432 )
433 );
434 assert_eq!(got.serialised_len(), 84);
435 }
436
437 #[test]
438 #[cfg(feature = "bytes")]
439 fn test_empty_bytes() {
440 let want = hex!("000000000000000000000000000000000000000100000000");
454 let static_want: &'static [u8] = Box::leak(Box::new(want));
455
456 let s = AuthUnixParams::try_from(Bytes::from(static_want)).expect("deserialise failed");
457
458 assert_eq!(s.stamp(), 0);
459 assert_eq!(s.machine_name_str(), "");
460 assert_eq!(s.uid(), 0);
461 assert_eq!(s.gid(), 0);
462 assert_eq!(s.gids(), Some([0].as_slice()));
463 assert_eq!(s.serialised_len(), 24);
464
465 let mut buf = Cursor::new(Vec::new());
466 s.serialise_into(&mut buf).expect("failed to serialise");
467
468 let buf = buf.into_inner();
469 assert_eq!(want.len(), buf.len());
470 assert_eq!(want.as_ref(), buf.as_slice());
471 }
472
473 #[test]
474 #[should_panic]
475 fn test_long_machine_name_panic() {
476 AuthUnixParams::new(42, [1_u8; 256], 42, 42, None);
477 }
478
479 #[test]
480 #[should_panic]
481 fn test_long_gids_panic() {
482 AuthUnixParams::new(
483 42,
484 Opaque::from_user_payload([].as_slice()),
485 42,
486 42,
487 [
488 1_u32, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
489 ],
490 );
491 }
492}