1use bytes::{Buf, Bytes};
7
8use super::attrnum;
9use super::attrs::{decode_getattr_envelope, decode_utf8str};
10use crate::error::{NfsError, Result};
11use crate::mount::{AceFlags, AceMask, AceType, Acl, Acl41Flags, AclSupport, NfsAce, NfsAcl41};
12
13pub(crate) fn attrnotsupp_as_unsupported<T>(operation: &str, result: Result<T>) -> Result<T> {
17 match result {
18 Err(NfsError::Nfs4(crate::nfs4::Nfs4ErrorCode::NFS4ERR_ATTRNOTSUPP)) => {
19 Err(NfsError::Unsupported(format!(
20 "{operation} is unavailable for this request: server returned NFS4ERR_ATTRNOTSUPP"
21 )))
22 }
23 other => other,
24 }
25}
26
27const MAX_ACES: usize = 8192;
30
31impl TryFrom<u32> for AceType {
34 type Error = NfsError;
35
36 fn try_from(v: u32) -> Result<Self> {
37 match v {
38 0 => Ok(AceType::AccessAllowed),
39 1 => Ok(AceType::AccessDenied),
40 2 => Ok(AceType::SystemAudit),
41 3 => Ok(AceType::SystemAlarm),
42 _ => Err(NfsError::Xdr(format!("unknown ACE type {}", v))),
43 }
44 }
45}
46
47pub(crate) fn decode_nfsace4(buf: &mut Bytes) -> Result<NfsAce> {
52 if buf.remaining() < 12 {
53 return Err(NfsError::Xdr("nfsace4 truncated".to_string()));
54 }
55 let ace_type = AceType::try_from(buf.get_u32())?;
56 let flags = AceFlags(buf.get_u32());
57 let access_mask = AceMask(buf.get_u32());
58 let who = decode_utf8str(buf)?;
59 Ok(NfsAce {
60 ace_type,
61 flags,
62 access_mask,
63 who,
64 })
65}
66
67pub(crate) fn decode_acl(buf: &mut Bytes) -> Result<Acl> {
70 if buf.remaining() < 4 {
71 return Err(NfsError::Xdr("ACL count truncated".to_string()));
72 }
73 let count = buf.get_u32() as usize;
74 if count > MAX_ACES {
75 return Err(NfsError::Xdr(format!(
76 "ACL has {} entries, max {}",
77 count, MAX_ACES
78 )));
79 }
80 let mut aces = Vec::with_capacity(count);
81 for _ in 0..count {
82 aces.push(decode_nfsace4(buf)?);
83 }
84 Ok(Acl { aces })
85}
86
87pub(super) fn skip_acl(buf: &mut Bytes) -> Result<()> {
91 if buf.remaining() < 4 {
92 return Err(NfsError::Xdr("ACL count truncated".to_string()));
93 }
94 let count = buf.get_u32() as usize;
95 if count > MAX_ACES {
96 return Err(NfsError::Xdr(format!(
97 "ACL has {} entries, max {}",
98 count, MAX_ACES
99 )));
100 }
101 for _ in 0..count {
102 if buf.remaining() < 12 {
104 return Err(NfsError::Xdr("nfsace4 truncated".to_string()));
105 }
106 buf.advance(12);
107 if buf.remaining() < 4 {
109 return Err(NfsError::Xdr("nfsace4 who length truncated".to_string()));
110 }
111 let len = buf.get_u32() as usize;
112 let padded = (len + 3) & !3;
113 if buf.remaining() < padded {
114 return Err(NfsError::Xdr("nfsace4 who data truncated".to_string()));
115 }
116 buf.advance(padded);
117 }
118 Ok(())
119}
120
121pub(super) fn skip_acl41(buf: &mut Bytes) -> Result<()> {
123 if buf.remaining() < 4 {
124 return Err(NfsError::Xdr("NFSv4.1 ACL flags truncated".to_string()));
125 }
126 buf.advance(4);
127 skip_acl(buf)
128}
129
130fn encode_nfsace4(ace: &NfsAce, buf: &mut Vec<u8>) {
134 buf.extend_from_slice(&(ace.ace_type as u32).to_be_bytes());
135 buf.extend_from_slice(&ace.flags.0.to_be_bytes());
136 buf.extend_from_slice(&ace.access_mask.0.to_be_bytes());
137 let who_bytes = ace.who.as_bytes();
139 buf.extend_from_slice(&(who_bytes.len() as u32).to_be_bytes());
140 buf.extend_from_slice(who_bytes);
141 let pad = (4 - who_bytes.len() % 4) % 4;
142 for _ in 0..pad {
143 buf.push(0);
144 }
145}
146
147fn encode_acl(acl: &Acl, buf: &mut Vec<u8>) {
149 buf.extend_from_slice(&(acl.aces.len() as u32).to_be_bytes());
150 for ace in &acl.aces {
151 encode_nfsace4(ace, buf);
152 }
153}
154
155pub(crate) fn encode_setattr_acl(acl: &Acl) -> (Vec<u32>, Vec<u8>) {
158 let word0: u32 = 1 << attrnum::ACL;
159 let mut vals = Vec::new();
160 encode_acl(acl, &mut vals);
161 (vec![word0], vals)
162}
163
164pub(crate) fn encode_setattr_acl41(acl: &NfsAcl41, attribute: u32) -> (Vec<u32>, Vec<u8>) {
165 debug_assert!(matches!(attribute, attrnum::DACL | attrnum::SACL));
166 let mut values = Vec::new();
167 values.extend_from_slice(&acl.flags.0.to_be_bytes());
168 encode_acl(
169 &Acl {
170 aces: acl.aces.clone(),
171 },
172 &mut values,
173 );
174 (vec![0, 1 << (attribute - 32)], values)
175}
176
177pub(crate) fn decode_getattr_acl(data: &mut Bytes) -> Result<Acl> {
181 let (bitmap, mut vals) = decode_getattr_envelope(data)?;
182 let word0 = bitmap.first().copied().unwrap_or(0);
183 if word0 & (1 << attrnum::ACL) == 0 {
184 return Err(NfsError::Xdr(
185 "server did not return FATTR4_ACL".to_string(),
186 ));
187 }
188 if word0 & ((1 << attrnum::ACL) - 1) != 0 {
191 return Err(NfsError::Xdr(
192 "server returned unexpected attributes before FATTR4_ACL".to_string(),
193 ));
194 }
195 decode_acl(&mut vals)
196}
197
198pub(crate) fn decode_getattr_aclsupport(data: &mut Bytes) -> Result<AclSupport> {
200 let (bitmap, mut vals) = decode_getattr_envelope(data)?;
201 let word0 = bitmap.first().copied().unwrap_or(0);
202 if word0 & (1 << attrnum::ACLSUPPORT) == 0 {
203 return Err(NfsError::Xdr(
204 "server did not return FATTR4_ACLSUPPORT".to_string(),
205 ));
206 }
207 if word0 & ((1 << attrnum::ACLSUPPORT) - 1) != 0 {
209 return Err(NfsError::Xdr(
210 "server returned unexpected attributes before FATTR4_ACLSUPPORT".to_string(),
211 ));
212 }
213 if vals.remaining() < 4 {
214 return Err(NfsError::Xdr("ACLSUPPORT value truncated".to_string()));
215 }
216 Ok(AclSupport(vals.get_u32()))
217}
218
219pub(crate) fn decode_getattr_acl41(data: &mut Bytes, attribute: u32) -> Result<NfsAcl41> {
220 debug_assert!(matches!(attribute, attrnum::DACL | attrnum::SACL));
221 let (bitmap, mut vals) = decode_getattr_envelope(data)?;
222 let word1 = bitmap.get(1).copied().unwrap_or(0);
223 let bit = 1 << (attribute - 32);
224 if word1 & bit == 0 {
225 return Err(NfsError::Unsupported(format!(
226 "server does not support NFSv4.1 ACL attribute {attribute}"
227 )));
228 }
229 if vals.remaining() < 4 {
230 return Err(NfsError::Xdr("NFSv4.1 ACL flags truncated".to_string()));
231 }
232 let flags = Acl41Flags(vals.get_u32());
233 let aces = decode_acl(&mut vals)?.aces;
234 Ok(NfsAcl41 { flags, aces })
235}
236
237#[cfg(test)]
238mod tests {
239 use super::*;
240
241 fn make_ace(ace_type: AceType, flags: u32, mask: u32, who: &str) -> NfsAce {
242 NfsAce {
243 ace_type,
244 flags: AceFlags(flags),
245 access_mask: AceMask(mask),
246 who: who.to_string(),
247 }
248 }
249
250 fn encode_one_ace(ace: &NfsAce) -> Vec<u8> {
251 let mut buf = Vec::new();
252 encode_nfsace4(ace, &mut buf);
253 buf
254 }
255
256 #[test]
257 fn ace_type_try_from_valid() {
258 assert_eq!(AceType::try_from(0).unwrap(), AceType::AccessAllowed);
259 assert_eq!(AceType::try_from(1).unwrap(), AceType::AccessDenied);
260 assert_eq!(AceType::try_from(2).unwrap(), AceType::SystemAudit);
261 assert_eq!(AceType::try_from(3).unwrap(), AceType::SystemAlarm);
262 }
263
264 #[test]
265 fn ace_type_try_from_invalid() {
266 assert!(AceType::try_from(4).is_err());
267 assert!(AceType::try_from(999).is_err());
268 }
269
270 #[test]
271 fn roundtrip_single_ace() {
272 let ace = make_ace(AceType::AccessAllowed, 0x01, 0x1F01FF, "OWNER@");
273 let encoded = encode_one_ace(&ace);
274 let mut bytes = Bytes::from(encoded);
275 let decoded = decode_nfsace4(&mut bytes).unwrap();
276 assert_eq!(decoded, ace);
277 assert_eq!(bytes.remaining(), 0);
278 }
279
280 #[test]
281 fn rfc7530_nfsace4_literal_decodes_and_reencodes_exactly() {
282 let wire: &[u8] = &[
283 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 6, b'O', b'W', b'N', b'E', b'R', b'@', 0, 0,
287 ];
288 let mut input = Bytes::from_static(wire);
289 let ace = decode_nfsace4(&mut input).expect("RFC 7530 nfsace4 literal must decode");
290 assert_eq!(ace.ace_type, AceType::AccessAllowed);
291 assert_eq!(ace.flags, AceFlags(0));
292 assert_eq!(ace.access_mask, AceMask(AceMask::READ_DATA));
293 assert_eq!(ace.who, "OWNER@");
294 assert!(input.is_empty());
295 assert_eq!(encode_one_ace(&ace), wire);
296 }
297
298 #[test]
299 fn roundtrip_ace_with_padding() {
300 let ace = make_ace(AceType::AccessDenied, 0x40, 0x20000, "AB");
302 let encoded = encode_one_ace(&ace);
303 assert_eq!(encoded.len(), 20);
305 let mut bytes = Bytes::from(encoded);
306 let decoded = decode_nfsace4(&mut bytes).unwrap();
307 assert_eq!(decoded, ace);
308 }
309
310 #[test]
311 fn roundtrip_acl_empty() {
312 let acl = Acl { aces: vec![] };
313 let mut buf = Vec::new();
314 encode_acl(&acl, &mut buf);
315 assert_eq!(buf, 0u32.to_be_bytes());
316 let mut bytes = Bytes::from(buf);
317 let decoded = decode_acl(&mut bytes).unwrap();
318 assert_eq!(decoded, acl);
319 }
320
321 #[test]
322 fn roundtrip_acl_multiple() {
323 let acl = Acl {
324 aces: vec![
325 make_ace(
326 AceType::AccessAllowed,
327 0,
328 AceMask::READ_DATA | AceMask::EXECUTE,
329 "OWNER@",
330 ),
331 make_ace(
332 AceType::AccessAllowed,
333 AceFlags::IDENTIFIER_GROUP,
334 AceMask::READ_DATA,
335 "GROUP@",
336 ),
337 make_ace(AceType::AccessDenied, 0, AceMask::WRITE_DATA, "EVERYONE@"),
338 ],
339 };
340 let mut buf = Vec::new();
341 encode_acl(&acl, &mut buf);
342 let mut bytes = Bytes::from(buf);
343 let decoded = decode_acl(&mut bytes).unwrap();
344 assert_eq!(decoded, acl);
345 assert_eq!(bytes.remaining(), 0);
346 }
347
348 #[test]
349 fn decode_nfsace4_truncated() {
350 let mut bytes = Bytes::from_static(&[0u8; 8]); assert!(decode_nfsace4(&mut bytes).is_err());
352 }
353
354 #[test]
355 fn decode_acl_count_truncated() {
356 let mut bytes = Bytes::from_static(&[0u8; 2]); assert!(decode_acl(&mut bytes).is_err());
358 }
359
360 #[test]
361 fn decode_acl_exceeds_max() {
362 let mut buf = Vec::new();
363 buf.extend_from_slice(&((MAX_ACES as u32 + 1).to_be_bytes()));
364 let mut bytes = Bytes::from(buf);
365 assert!(decode_acl(&mut bytes).is_err());
366 }
367
368 #[test]
369 fn skip_acl_empty() {
370 let mut buf = Vec::new();
371 buf.extend_from_slice(&0u32.to_be_bytes()); let mut bytes = Bytes::from(buf);
373 skip_acl(&mut bytes).unwrap();
374 assert_eq!(bytes.remaining(), 0);
375 }
376
377 #[test]
378 fn skip_acl_with_entries() {
379 let acl = Acl {
380 aces: vec![
381 make_ace(AceType::AccessAllowed, 0, 0x1F, "OWNER@"),
382 make_ace(AceType::AccessDenied, 0, 0x02, "EVERYONE@"),
383 ],
384 };
385 let mut buf = Vec::new();
386 encode_acl(&acl, &mut buf);
387 buf.push(0xFF);
389 let mut bytes = Bytes::from(buf);
390 skip_acl(&mut bytes).unwrap();
391 assert_eq!(bytes.remaining(), 1);
392 assert_eq!(bytes[0], 0xFF);
393 }
394
395 #[test]
396 fn special_who_strings() {
397 for who in &[
398 "OWNER@",
399 "GROUP@",
400 "EVERYONE@",
401 "INTERACTIVE@",
402 "NETWORK@",
403 "BATCH@",
404 "ANONYMOUS@",
405 "AUTHENTICATED@",
406 "SERVICE@",
407 ] {
408 let ace = make_ace(AceType::AccessAllowed, 0, AceMask::READ_DATA, who);
409 let encoded = encode_one_ace(&ace);
410 let mut bytes = Bytes::from(encoded);
411 let decoded = decode_nfsace4(&mut bytes).unwrap();
412 assert_eq!(decoded.who, *who);
413 }
414 }
415
416 #[test]
417 fn encode_setattr_acl_bitmap() {
418 let acl = Acl {
419 aces: vec![make_ace(AceType::AccessAllowed, 0, 0x1F, "OWNER@")],
420 };
421 let (attrmask, vals) = encode_setattr_acl(&acl);
422 assert_eq!(attrmask, vec![1u32 << 12]);
423 assert_eq!(&vals[..4], &1u32.to_be_bytes());
425 }
426
427 #[test]
428 fn nfsv41_acl_round_trips_flags_inherited_ace_and_word_one_bitmap() {
429 let acl = NfsAcl41 {
430 flags: Acl41Flags(Acl41Flags::AUTO_INHERIT | Acl41Flags::PROTECTED),
431 aces: vec![make_ace(
432 AceType::AccessAllowed,
433 AceFlags::FILE_INHERIT | AceFlags::INHERITED,
434 AceMask::READ_DATA | AceMask::READ_ACL,
435 "EVERYONE@",
436 )],
437 };
438 let (bitmap, values) = encode_setattr_acl41(&acl, attrnum::DACL);
439 assert_eq!(bitmap, vec![0, 1 << 26]);
440 assert_eq!(&values[..4], &acl.flags.0.to_be_bytes());
441
442 let mut response = Vec::new();
443 response.extend_from_slice(&2u32.to_be_bytes());
444 response.extend_from_slice(&0u32.to_be_bytes());
445 response.extend_from_slice(&(1u32 << 26).to_be_bytes());
446 response.extend_from_slice(&(values.len() as u32).to_be_bytes());
447 response.extend_from_slice(&values);
448 let mut bytes = Bytes::from(response);
449 assert_eq!(
450 decode_getattr_acl41(&mut bytes, attrnum::DACL).unwrap(),
451 acl
452 );
453 }
454
455 #[test]
456 fn skip_nfsv41_acl_consumes_flags_and_aces_only() {
457 let acl = NfsAcl41 {
458 flags: Acl41Flags(Acl41Flags::DEFAULTED),
459 aces: vec![make_ace(
460 AceType::SystemAudit,
461 AceFlags::SUCCESSFUL_ACCESS,
462 AceMask::WRITE_DATA,
463 "EVERYONE@",
464 )],
465 };
466 let (_, mut values) = encode_setattr_acl41(&acl, attrnum::SACL);
467 values.push(0xff);
468 let mut bytes = Bytes::from(values);
469 skip_acl41(&mut bytes).unwrap();
470 assert_eq!(bytes.as_ref(), &[0xff]);
471 }
472
473 #[test]
474 fn ace_flags_contains() {
475 let flags = AceFlags(AceFlags::FILE_INHERIT | AceFlags::DIRECTORY_INHERIT);
476 assert!(flags.contains(AceFlags::FILE_INHERIT));
477 assert!(flags.contains(AceFlags::DIRECTORY_INHERIT));
478 assert!(!flags.contains(AceFlags::INHERIT_ONLY));
479 }
480
481 #[test]
482 fn ace_mask_contains() {
483 let mask = AceMask(AceMask::READ_DATA | AceMask::WRITE_DATA);
484 assert!(mask.contains(AceMask::READ_DATA));
485 assert!(mask.contains(AceMask::WRITE_DATA));
486 assert!(!mask.contains(AceMask::EXECUTE));
487 }
488
489 #[test]
490 fn acl_support_supports() {
491 let support = AclSupport(AclSupport::ALLOW | AclSupport::DENY);
492 assert!(support.supports(AclSupport::ALLOW));
493 assert!(support.supports(AclSupport::DENY));
494 assert!(!support.supports(AclSupport::AUDIT));
495 }
496
497 #[test]
498 fn decode_getattr_acl_response() {
499 let acl = Acl {
500 aces: vec![make_ace(
501 AceType::AccessAllowed,
502 0,
503 AceMask::READ_DATA,
504 "OWNER@",
505 )],
506 };
507 let mut resp = Vec::new();
509 resp.extend_from_slice(&1u32.to_be_bytes()); resp.extend_from_slice(&(1u32 << 12).to_be_bytes()); let mut acl_data = Vec::new();
514 encode_acl(&acl, &mut acl_data);
515 resp.extend_from_slice(&(acl_data.len() as u32).to_be_bytes());
516 resp.extend_from_slice(&acl_data);
517
518 let mut bytes = Bytes::from(resp);
519 let decoded = decode_getattr_acl(&mut bytes).unwrap();
520 assert_eq!(decoded, acl);
521 }
522
523 #[test]
524 fn decode_getattr_acl_missing_bit() {
525 let mut resp = Vec::new();
526 resp.extend_from_slice(&1u32.to_be_bytes()); resp.extend_from_slice(&0u32.to_be_bytes()); resp.extend_from_slice(&0u32.to_be_bytes()); let mut bytes = Bytes::from(resp);
530 assert!(decode_getattr_acl(&mut bytes).is_err());
531 }
532
533 #[test]
534 fn decode_getattr_aclsupport_response() {
535 let mut resp = Vec::new();
536 resp.extend_from_slice(&1u32.to_be_bytes()); resp.extend_from_slice(&(1u32 << 13).to_be_bytes()); let support_val = AclSupport::ALLOW | AclSupport::DENY;
539 resp.extend_from_slice(&4u32.to_be_bytes()); resp.extend_from_slice(&support_val.to_be_bytes());
541 let mut bytes = Bytes::from(resp);
542 let support = decode_getattr_aclsupport(&mut bytes).unwrap();
543 assert_eq!(support, AclSupport(support_val));
544 }
545}