blob: fb2d32935e56dcf31ae36d249b0157981ebba029 [file] [log] [blame]
// 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.io2;
/// Options for [`Directory.Open`] and [`Node.Reopen`].
table ConnectionOptions {
/// Flags which can affect the behavior when opening and reopening.
/// If absent, assumes a default of zero.
1: ConnectionFlags flags;
/// Specifies the set of representations accepted by the client, to support
/// a form of protocol negotiation on the node being opened.
/// Refer to the definition of [`NodeProtocols`] for more details.
/// It cannot be zero.
///
/// In addition, clients may assert the type of the object by setting
/// the protocol corresponding to the expected type:
///
/// * If the caller expected a directory but the node cannot be accessed
/// as a directory, the error is `ZX_ERR_NOT_DIR`.
/// * If the caller expected a file but the node cannot be accessed as a
/// file, the error is `ZX_ERR_NOT_FILE`.
/// * In other mismatched cases, the error is `ZX_ERR_WRONG_TYPE`.
///
/// During [`Directory.Open`], if a new object is to be created, `protocols`
/// determines the type of object to create; it must be present.
/// If a valid object type cannot be unambiguously inferred e.g.
/// both `DIRECTORY` and `FILE` were set, the request must fail.
///
/// During [`Node.Reopen`], clients may specify a different but compatible
/// `protocols` to do a "protocol upgrade".
///
/// If more than one protocol is present in `protocols`, the resultant
/// protocol may become any one of them. Clients should specify
/// [`ConnectionFlags.GET_CONNECTION_INFO`] to receive a
/// [`Node.OnConnectionInfo`] event, in order to ascertain the protocol.
///
/// If absent, indicates that the caller accepts any type of node, and
/// the resulting protocol is unspecified.
2: NodeProtocols protocols;
/// Requests rights on the new connection according to the specified rules.
/// See [`fuchsia.io2/RightsRequest`].
///
/// ## 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 Inheritance
///
/// If `rights_request` is absent, inherits at most the rights on the source
/// connection:
///
/// * During [`Node.Reopen`], the new connection would have the same rights
/// as the connection where the `Reopen` call is made.
/// * During [`Directory.Open`], the rights on the connection would inherit
/// from the connection where the `Open` call is made. If the path crosses
/// intermediate proxies, a proxy may strip elements from the resulting
/// rights if the intermediate connection does not have the corresponding
/// rights.
///
/// ## 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. For convenience, clients may query the
/// [`ConnectionInfo.available_operations`] field on a new connection,
/// which is the intersection of the rights and abilities and indicates the
/// guaranteed set of available operations.
///
/// See [`fuchsia.io2/Rights`] and [`fuchsia.io2/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.
3: RightsRequest rights_request;
};
/// Options for requesting rights on the new connection. 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,
/// }
/// }
/// ```
struct RightsRequest {
/// 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.
Rights at_most;
/// 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.
Rights at_least;
/// Controls how the rights on the new connection are computed from
/// `at_most` and `at_least`. See [`fuchsia.io2/RightsResolution`].
RightsResolution resolution;
};
/// When an `Open`/`Reopen` request reaches its final remote server, it should
/// assign rights on the new connection based on one of these modes.
enum RightsResolution : 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
/// [`fuchsia.io2/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;
};
/// Flags applicable to both [`Directory.Open`] and [`Node.Reopen`].
bits ConnectionFlags : uint64 {
/// Requests that an [`Node.OnConnectionInfo`] event be sent as the first
/// message on the protocol request. Requests all fields in the
/// [`ConnectionInfo`] table. Doing so is more efficient than calling
/// [`Node.Describe`] later on the connection.
GET_CONNECTION_INFO = 0x01;
/// Connects to the exposed protocol if the node is a Connector.
/// It is an error to use this flag with other types of nodes.
///
/// If both `GET_CONNECTION_INFO` and `CONNECT` are specified, the channel
/// will receive exactly one [`Node.OnConnectionInfo`] event, after which
/// the protocol switches from [`fuchsia.io2/Node`] to the intended protocol.
/// Message sent by the client prior to receiving [`Node.OnConnectionInfo`]
/// are queued and processed after the protocol switch.
///
/// `CONNECT` cannot be supplied together with `APPEND`.
/// `CONNECT` cannot be supplied together with `TRUNCATE`.
///
/// Requires the [`Rights.CONNECT`] right on the connection.
CONNECT = 0x02;
/// Opens the node in append mode, i.e. the connection should seek to the
/// end of the node before every write.
///
/// If the node does not support appending, it should result in a
/// `ZX_ERR_NOT_SUPPORTED` epitaph.
/// Currently, only [`fuchsia.io2/NodeProtocols.FILE`] connections
/// may be configured for appending.
APPEND = 0x04;
/// Truncates the object before usage, by setting its length to 0.
/// Requires the [`Rights.WRITE_BYTES`] right on the connection.
///
/// If the node does not support truncating, it should result in a
/// `ZX_ERR_NOT_SUPPORTED` epitaph.
TRUNCATE = 0x08;
};