| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| library fuchsia.io; |
| |
| /// Options for requesting rights on the new connection. |
| /// |
| /// ## Rights Hierarchy |
| /// |
| /// Respecting principles of least privileges, rights in general must meet |
| /// the following restrictions: |
| /// |
| /// * A connection must have nonzero rights. |
| /// * From the perspective of a client, rights must never increase in a |
| /// derived connection. |
| /// * From the perspective of a directory proxy, it must ensure that |
| /// new connections opened through it cannot have more rights than |
| /// the connection where the proxy received the `Open`/`Reopen` call. |
| /// |
| /// The proper enforcement of the rights hierarchy is a powerful refinement |
| /// over the existing access control facilities offered by directory |
| /// sandboxing. |
| /// |
| /// ## Rights vs Abilities |
| /// |
| /// The rights on a connection limits the set of operations allowed on that |
| /// connection, but does not guarantee their availability, because the |
| /// object may not support it. |
| /// |
| /// See [`Rights`] and [`Abilities`]. |
| /// |
| /// ## Implementation Notes |
| /// |
| /// When a directory proxy encounters an absent `rights` field, let `r` be |
| /// the rights on the connection where it received this request, the proxy |
| /// should fill in this field with the following: |
| /// |
| /// ``` |
| /// RightsRequest { |
| /// at_most: r, |
| /// at_least: 0, |
| /// resolution: RightsResolution.MAXIMIZE, |
| /// } |
| /// ``` |
| /// |
| /// before forwarding the request to the remote party. |
| /// |
| /// Because opening a new connection may involve multiple hops through |
| /// directory proxies, we require the client to set an upper bound and lower |
| /// bound on the rights request, and intermediate proxies to refine these |
| /// bounds. |
| /// |
| /// The rights manipulation should be implemented mechanically |
| /// without knowledge of any specific rights, and servers should propagate |
| /// unknown bits members, to gracefully handle future rights extensions. |
| /// |
| /// ## Implementation Notes |
| /// |
| /// It could be common for a client to request an exact set of rights. |
| /// We recommend client libraries to define a helper function like follows: |
| /// |
| /// ``` |
| /// fn Exact(exact_rights: Rights) -> RightsRequest { |
| /// RightsRequest { |
| /// at_most: exact_rights, |
| /// at_least: exact_rights, |
| /// resolution: RightsResolution.MAXIMIZE, |
| /// } |
| /// } |
| /// ``` |
| type RightsRequest = struct { |
| /// Sets an upper bound on the resulting rights. The exact rights will |
| /// depend on `resolution`. |
| /// |
| /// ## Implementation Notes |
| /// |
| /// When a directory proxy encounters this variant, it should compute the |
| /// intersection between this and the rights on the connection where it |
| /// received the request, to shrink the rights. |
| /// |
| /// * If the intersection is empty, or not a superset of `at_least`, |
| /// the proxy should close `object_request` with the |
| /// `ZX_ERR_ACCESS_DENIED` epitaph. |
| /// * Otherwise, the proxy should forward the `Open` call as usual, |
| /// but update `at_most` with the shrunk rights. |
| at_most Rights; |
| |
| /// Sets a lower bound on the resulting rights. The exact rights will |
| /// depend on `resolution`. |
| /// |
| /// + During [`Directory.Open`], you may only specify the same rights as |
| /// what the directory connection already has, or a subset of those. |
| /// + During [`Node.Reopen`], similarly, you may only specify the same or |
| /// a subset of rights possessed by the original connection. |
| /// + Exceeding those rights causes `object_request` to be closed with a |
| /// `ZX_ERR_ACCESS_DENIED` epitaph. |
| /// |
| /// Therefore there are these invariants which should be maintained: |
| /// |
| /// ``` |
| /// at_most ⊋ {} |
| /// at_most ⊃ at_least |
| /// rights_on_connection_where_open_is_received ⊋ {} |
| /// rights_on_connection_where_open_is_received ⊃ at_least |
| /// ``` |
| /// |
| /// using the superset (`⊃`), proper superset (`⊋`), |
| /// and empty set (`{}`) notations. |
| at_least Rights; |
| |
| /// When an `Open`/`Reopen` request reaches its final remote server, it should |
| /// assign rights on the new connection based on one of these modes. |
| resolution @generated_name("RightsResolution") strict enum : uint32 { |
| /// The rights will be the intersection between [`RightsRequest.at_most`] |
| /// and the connection where the `Open`/`Reopen` request was received, |
| /// closing `object_request` with `ZX_ERR_ACCESS_DENIED` if it is empty. |
| MAXIMIZE = 1; |
| |
| /// The rights will be determined by the following rules: |
| /// |
| /// * If the negotiated protocol on the new connection is |
| /// [`Directory`], the rules from the `MAXIMIZE` case applies. |
| /// * Otherwise, the rights will be [`RightsRequest.at_least`] if it |
| /// does not exceed rights on the current connection. |
| /// * Otherwise, `object_request` should be closed with |
| /// `ZX_ERR_ACCESS_DENIED`. |
| /// |
| /// The motivation for this enum is to facilitate implementing POSIX |
| /// compatibility layers. The POSIX file permission model relies on ambient |
| /// authority: access control on files are resolved based on the `mode` of |
| /// the file, and the current user. There is no concept of hierarchical |
| /// permissions. Fuchsia, on the other hand, restricts rights on file |
| /// connections to never exceed that of its containing directory connection. |
| POSIX = 2; |
| }; |
| }; |