1use crate::cap::Cap;
9use crate::error::CapSecError;
10use crate::permission::Permission;
11
12pub trait CapProvider<P: Permission> {
15 #[must_use = "ignoring a capability check silently discards scope violations"]
18 fn provide_cap(&self, target: &str) -> Result<Cap<P>, CapSecError>;
19}
20
21#[macro_export]
40macro_rules! impl_cap_provider_for_has {
41 ($ty:ty, $perm:ty) => {
42 impl $crate::cap_provider::CapProvider<$perm> for $ty {
43 fn provide_cap(
44 &self,
45 _target: &str,
46 ) -> Result<$crate::cap::Cap<$perm>, $crate::error::CapSecError> {
47 Ok(<Self as $crate::has::Has<$perm>>::cap_ref(self))
48 }
49 }
50 };
51}
52
53impl<P: Permission> CapProvider<P> for Cap<P> {
56 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
57 Ok(Cap::new())
58 }
59}
60
61impl<P: Permission> CapProvider<P> for crate::cap::SendCap<P> {
62 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
63 Ok(Cap::new())
64 }
65}
66
67macro_rules! impl_cap_provider_subsumes {
70 ($super:ty => $($sub:ty),+) => {
71 $(
72 impl CapProvider<$sub> for Cap<$super> {
73 fn provide_cap(&self, _target: &str) -> Result<Cap<$sub>, CapSecError> {
74 Ok(Cap::new())
75 }
76 }
77 )+
78 }
79}
80
81use crate::permission::*;
82
83impl_cap_provider_subsumes!(FsAll => FsRead, FsWrite);
84impl_cap_provider_subsumes!(NetAll => NetConnect, NetBind);
85
86macro_rules! impl_cap_provider_sendcap_subsumes {
89 ($super:ty => $($sub:ty),+) => {
90 $(
91 impl CapProvider<$sub> for crate::cap::SendCap<$super> {
92 fn provide_cap(&self, _target: &str) -> Result<Cap<$sub>, CapSecError> {
93 Ok(Cap::new())
94 }
95 }
96 )+
97 }
98}
99
100impl_cap_provider_sendcap_subsumes!(FsAll => FsRead, FsWrite);
101impl_cap_provider_sendcap_subsumes!(NetAll => NetConnect, NetBind);
102
103macro_rules! impl_cap_provider_ambient {
106 ($($perm:ty),+) => {
107 $(
108 impl CapProvider<$perm> for Cap<Ambient> {
109 fn provide_cap(&self, _target: &str) -> Result<Cap<$perm>, CapSecError> {
110 Ok(Cap::new())
111 }
112 }
113 )+
114 }
115}
116
117impl_cap_provider_ambient!(
118 FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn
119);
120
121macro_rules! impl_cap_provider_sendcap_ambient {
124 ($($perm:ty),+) => {
125 $(
126 impl CapProvider<$perm> for crate::cap::SendCap<Ambient> {
127 fn provide_cap(&self, _target: &str) -> Result<Cap<$perm>, CapSecError> {
128 Ok(Cap::new())
129 }
130 }
131 )+
132 }
133}
134
135impl_cap_provider_sendcap_ambient!(
136 FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn
137);
138
139macro_rules! impl_cap_provider_tuple_first {
142 ([$($a:ident),+]; $all:tt) => {
143 $( impl_cap_provider_tuple_first!(@inner $a; $all); )+
144 };
145 (@inner $a:ident; [$($b:ident),+]) => {
146 $(
147 impl CapProvider<$a> for Cap<($a, $b)> {
148 fn provide_cap(&self, _target: &str) -> Result<Cap<$a>, CapSecError> {
149 Ok(Cap::new())
150 }
151 }
152 )+
153 };
154}
155
156macro_rules! impl_cap_provider_tuple_second {
157 ($first:ident $(, $rest:ident)+) => {
158 $(
159 impl CapProvider<$first> for Cap<($rest, $first)> {
160 fn provide_cap(&self, _target: &str) -> Result<Cap<$first>, CapSecError> {
161 Ok(Cap::new())
162 }
163 }
164 impl CapProvider<$rest> for Cap<($first, $rest)> {
165 fn provide_cap(&self, _target: &str) -> Result<Cap<$rest>, CapSecError> {
166 Ok(Cap::new())
167 }
168 }
169 )+
170 impl_cap_provider_tuple_second!($($rest),+);
171 };
172 ($single:ident) => {};
173}
174
175impl_cap_provider_tuple_first!(
176 [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient];
177 [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient]
178);
179
180impl_cap_provider_tuple_second!(
181 FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient
182);
183
184macro_rules! impl_cap_provider_sendcap_tuple_first {
187 ([$($a:ident),+]; $all:tt) => {
188 $( impl_cap_provider_sendcap_tuple_first!(@inner $a; $all); )+
189 };
190 (@inner $a:ident; [$($b:ident),+]) => {
191 $(
192 impl CapProvider<$a> for crate::cap::SendCap<($a, $b)> {
193 fn provide_cap(&self, _target: &str) -> Result<Cap<$a>, CapSecError> {
194 Ok(Cap::new())
195 }
196 }
197 )+
198 };
199}
200
201macro_rules! impl_cap_provider_sendcap_tuple_second {
202 ($first:ident $(, $rest:ident)+) => {
203 $(
204 impl CapProvider<$first> for crate::cap::SendCap<($rest, $first)> {
205 fn provide_cap(&self, _target: &str) -> Result<Cap<$first>, CapSecError> {
206 Ok(Cap::new())
207 }
208 }
209 impl CapProvider<$rest> for crate::cap::SendCap<($first, $rest)> {
210 fn provide_cap(&self, _target: &str) -> Result<Cap<$rest>, CapSecError> {
211 Ok(Cap::new())
212 }
213 }
214 )+
215 impl_cap_provider_sendcap_tuple_second!($($rest),+);
216 };
217 ($single:ident) => {};
218}
219
220impl_cap_provider_sendcap_tuple_first!(
221 [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient];
222 [FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient]
223);
224
225impl_cap_provider_sendcap_tuple_second!(
226 FsRead, FsWrite, FsAll, NetConnect, NetBind, NetAll, EnvRead, EnvWrite, Spawn, Ambient
227);
228
229impl<P: Permission> CapProvider<P> for crate::runtime::RuntimeCap<P> {
232 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
233 self.try_cap()
234 }
235}
236
237impl<P: Permission> CapProvider<P> for crate::runtime::RuntimeSendCap<P> {
238 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
239 self.try_cap()
240 }
241}
242
243impl<P: Permission> CapProvider<P> for crate::runtime::TimedCap<P> {
244 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
245 self.try_cap()
246 }
247}
248
249impl<P: Permission> CapProvider<P> for crate::runtime::TimedSendCap<P> {
250 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
251 self.try_cap()
252 }
253}
254
255impl<P: Permission> CapProvider<P> for crate::prescript::LoggedCap<P> {
256 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
257 self.try_cap()
258 }
259}
260
261impl<P: Permission> CapProvider<P> for crate::prescript::LoggedSendCap<P> {
262 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
263 self.try_cap()
264 }
265}
266
267impl<P: Permission> CapProvider<P> for crate::prescript::DualKeyCap<P> {
268 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
269 self.try_cap()
270 }
271}
272
273impl<P: Permission> CapProvider<P> for crate::prescript::DualKeySendCap<P> {
274 fn provide_cap(&self, _target: &str) -> Result<Cap<P>, CapSecError> {
275 self.try_cap()
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 #[test]
284 fn cap_provides() {
285 let root = crate::root::test_root();
286 let cap = root.grant::<FsRead>();
287 assert!(cap.provide_cap("/any").is_ok());
288 }
289
290 #[test]
291 fn sendcap_provides() {
292 let root = crate::root::test_root();
293 let cap = root.grant::<FsRead>().make_send();
294 assert!(cap.provide_cap("/any").is_ok());
295 }
296
297 #[test]
298 fn subsumption_provides() {
299 let root = crate::root::test_root();
300 let cap = root.grant::<FsAll>();
301 let result: Result<Cap<FsRead>, _> = cap.provide_cap("/any");
302 assert!(result.is_ok());
303 }
304
305 #[test]
306 fn ambient_provides() {
307 let root = crate::root::test_root();
308 let cap = root.grant::<Ambient>();
309 let result: Result<Cap<FsRead>, _> = cap.provide_cap("/any");
310 assert!(result.is_ok());
311 }
312
313 #[test]
314 fn tuple_provides() {
315 let root = crate::root::test_root();
316 let cap = root.grant::<(FsRead, NetConnect)>();
317 assert!(CapProvider::<FsRead>::provide_cap(&cap, "/any").is_ok());
318 assert!(CapProvider::<NetConnect>::provide_cap(&cap, "host").is_ok());
319 }
320
321 #[test]
322 fn sendcap_subsumption_provides() {
323 let root = crate::root::test_root();
324 let cap = root.grant::<FsAll>().make_send();
325 let result: Result<Cap<FsRead>, _> = cap.provide_cap("/any");
326 assert!(result.is_ok());
327 }
328
329 #[test]
330 fn sendcap_ambient_provides() {
331 let root = crate::root::test_root();
332 let cap = root.grant::<Ambient>().make_send();
333 let result: Result<Cap<FsRead>, _> = cap.provide_cap("/any");
334 assert!(result.is_ok());
335 }
336
337 #[test]
338 fn sendcap_tuple_provides() {
339 let root = crate::root::test_root();
340 let cap = root.grant::<(FsRead, NetConnect)>().make_send();
341 assert!(CapProvider::<FsRead>::provide_cap(&cap, "/any").is_ok());
342 assert!(CapProvider::<NetConnect>::provide_cap(&cap, "host").is_ok());
343 }
344
345 #[test]
346 fn runtime_cap_provides() {
347 let root = crate::root::test_root();
348 let cap = root.grant::<FsRead>();
349 let (rcap, _revoker) = crate::runtime::RuntimeCap::new(cap);
350 assert!(rcap.provide_cap("/any").is_ok());
351 }
352
353 #[test]
354 fn runtime_cap_provides_fails_after_revocation() {
355 let root = crate::root::test_root();
356 let cap = root.grant::<FsRead>();
357 let (rcap, revoker) = crate::runtime::RuntimeCap::new(cap);
358 revoker.revoke();
359 assert!(rcap.provide_cap("/any").is_err());
360 }
361
362 #[test]
363 fn timed_cap_provides() {
364 let root = crate::root::test_root();
365 let cap = root.grant::<FsRead>();
366 let tcap = crate::runtime::TimedCap::new(cap, std::time::Duration::from_secs(60));
367 assert!(tcap.provide_cap("/any").is_ok());
368 }
369
370 #[test]
371 fn logged_cap_provides() {
372 let root = crate::root::test_root();
373 let cap = root.grant::<FsRead>();
374 let lcap = crate::prescript::LoggedCap::new(cap);
375 assert!(lcap.provide_cap("/any").is_ok());
376 }
377
378 #[test]
379 fn dual_key_cap_provides() {
380 let root = crate::root::test_root();
381 let cap = root.grant::<FsRead>();
382 let (dcap, a, b) = crate::prescript::DualKeyCap::new(cap);
383 a.approve();
384 b.approve();
385 assert!(dcap.provide_cap("/any").is_ok());
386 }
387
388 #[test]
389 fn dual_key_cap_provides_fails_without_approvals() {
390 let root = crate::root::test_root();
391 let cap = root.grant::<FsRead>();
392 let (dcap, _a, _b) = crate::prescript::DualKeyCap::new(cap);
393 assert!(dcap.provide_cap("/any").is_err());
394 }
395}