############################## OpenAFS Rights and Permissions ############################## This is meant to be an *informative* document of the current behavior of OpenAFS file servers' permission management logic. It is being written in hopes of its ultimate utility towards a *normative* specification document. .. note:: We will often need to refer to line numbers of the code; for the sake of consistency, we will always tag these with the git revision control hash (abbreviated, thankfully) so that there is no risk of ambiguity even as this document and the code undergo parallel revisions. References are given by [git revision:]file name[:command], where "command" is either a line number or a / followed by a POSIX regex. Due to AFS source conventions, function names will often appear as "f.c:/^Func". Descriptive Vocabulary ---------------------- The OpenAFS file server logic checks several bits of data within the system when it makes a permission decision. Below, we will use certain *shorthands* for these fields. * Client membership an "administrative" group, which defaults to ``system:administrators`` (PTS ID well-known as ``-204``). (*ADMIN*) (See ``6e167d4:src/viced/viced.c:/SystemId`` for details of group selection.) * Client rights as specified in the ACL of the directory containing the target. (*ACL*) * The UNIX owner UID field (holding a PTS ID) of the target of the operation. (*UID*) * The UNIX user permission flags of the target of the operation. (*UMODE*, part of the UNIX *MODE* bits: ``OWNERREAD``, ``OWNERWRITE``, ``OWNEREXEC``) * The UNIX owner UID field of the root directory of the volume containing the target. This field holds a PTS ID which is said to be the volume owner. (*VOLUID*) * The UNIX mode special bits (*SPEC*), notably ``S_ISUID`` (``04000``) and ``S_ISGID`` (``02000``). Optionally, the server may be compiled with ``-DUSE_GROUP_PERMS`` (it is not by default) which brings in additional checks of the UNIX group owner (*GID*) and permission flags (*GMODE*, part of the UNIX *MODE* bits: ``GROUPREAD``, ``GROUPWRITE``, ``GROUPREXEC``) of the target of the operation. Note that all other UNIX mode bits (``S_IRWXO``, ``S_ISVTX``, and ``010000`` and above) are ignored. (If ``USE_GROUP_PERMS`` is disabled, which is the default, the ``S_IRWXG`` bits are also ignored.) Permission Flags ---------------- OpenAFS defines several ACL flags. Much of this information is available in the manual pages for ``fs setacl`` and ``fs listacl`` but is reproduced here for completeness. Each directory object has its associated ACL, which is a collection of Positive and Negative Access List Entries, which are in turn a pair of a PTS identity and a set of permission flags. The permission flags defined are as follows; in all cases, the direct object of the definition is restricted to those objects in the current directory. +-------------------+-------------------------------------------+ | Administrate | Adjust this ACL | +-------------------+-------------------------------------------+ | Lookup | Enumerate the objects. | +-------------------+-------------------------------------------+ | Delete | Remove objects. | +-------------------+-------------------------------------------+ | Read | Fetch the contents of file objects. | +-------------------+-------------------------------------------+ | Write | Mutate the contents of file objects. | +-------------------+-------------------------------------------+ | Insert | Create new objects. | +-------------------+-------------------------------------------+ | locK | Acquire locks on files. | +-------------------+-------------------------------------------+ | A - H | Eight flag bits defined solely for user | | | applications' use. These are (intended | | | to be) uninterpreted by AFS itself. | +-------------------+-------------------------------------------+ These flags are stored by the AFS file server in a 32-bit word thus (see ``libacl/prs_fs.h`` and ``6e167d4:venus/fs.c:/^PRights`` [there is a patch pending that would make this ``libacl/aclprint.c``]): +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |H|G|F|E|D|C|B|A| | | | | | | | | | | | | | | | | |a|k|d|l|i|w|r| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Unallocated bits are communicated during ACL operations but ignored during server processing (indeed, ``libacl/aclprocs.c:/^acl_Externalize_pr`` simply prints out the field with the ``sprintf`` format code ``%d``; ``libacl/aclprocs.c:/^acl_Internalize_pr`` dually uses ``sscanf`` ``%d``). Interpreting an ACL ------------------- The AFS User Guide, in section "The AFS ACL Permissions", details the process of computing the rights conferred by a given ACL a given PTS ID. A slight formalization is attempted here. 1. The permissions of each entry which names either * the given ID explicitly or * a group to which that ID belongs are ORed together to compute positive permissions. That is, if any entry asserts a flag, that flag is asserted at the end of this scan. 2. The same process is repeated on the negative ACL entries, computing a set of negative permissions. 3. The final result is the postive permissions bitwise-anded with the negation of the negative permissions. This is implemented in ``src/viced/afsfileprocs.c:/^GetRights``. .. todo:: Which has not yet been audited to verify its conformance. Implicit Permissions -------------------- * The insert flag is intended to allow users to also establish the contents of file objects; as such it confers the rights to write to file objects whose *UID* matches the client's PTS ID. (Specified in the manual for ``fs setacl`` section ``DROPBOXES``; CODE: ``6e167d4:src/viced/afsfileprocs.c:1080``) There are some caveats relevant here: * The manual pages describe "dropbox" permissions (list & insert) as conferring the ability to write a file's contents *once and never again*. This is at best viewed as a suggestion of client cache manager behavior; it is not possible to implement this in OpenAFS as the server has no notion of opened or closed files, so the description given in this document above is more accurate from a server and protocol perspective. * It appears to be permitted, from the documentation of ``fs setacl`` that a server may, but is not obligated to, refuse read requests by anonymous clients of files whose containing directory confers "dropbox" permissions to any PTS ID. This does not appear to be implemented in the present OpenAFS source code, as of ``6e167d4``. * The same paragraph as above suggests that the server is permitted to fail creation or write requests from anonymous clients *even if* the permissions calculated would (otherwise) permit it. This does not appear to be implemented in the present OpenAFS source code, as of ``6e167d4``. * The *VOLUID* PTS ID implicitly has Administrate permission on all directories contained in that volume. This cannot be removed, even with negative access list entries. See the call to ``VolumeOwner`` at ``6e167d4:src/viced/afsfileprocs.c:1108`` in the store (and ``CHK_STOREACL``) branch of ``src/viced/afsfileprocs.c:/^Check_PermissionRights``. .. _implicit_admin_on_dir: .. note:: In prior releases, the *UID* PTS ID of each directory also had implicit Administrate permission within that directory, but this is no longer true. * Members of the administrative group (*ADMIN*) implicitly have all permissions specified by the server's ``-implicit`` argument, which defaults to Lookup. See ``6e167d4:src/viced/afsfileprocs.c:778`` (in ``/^GetRights``) and ``6e167d4:src/viced/viced.c:133``. Note that this impacts every condition that tests *ACL* in this document. * Members of the administrative group (*ADMIN*) may additionally implicitly have Lookup permission for certain tests if the server is compiled with ``-DADMIN_IMPLICIT_LOOKUP`` (not default). (This is **not** implemented in ``/^GetRights`` and so does not affect the use of *ACL*) * Members of the administrative group (*ADMIN*) additionally implicitly have Administrate permission (``6e167d4:src/viced/afsfileprocs.c:1107`` in ``/^Check_PermissionRights``) and others. Membership testing is performed by ``src/viced/viced.c:/^VanillaUser`` and this is called in several places. (This, too, is **not** implemented in ``/^GetRights`` and so does not affect the use of *ACL*) .. todo:: Which should be enumerated here! Default Permissions and Ownership --------------------------------- The act of creating an object is complicated and is orchestrated by ``src/viced/afsfileprocs.c:/^SRXAFSS_CreateFile`` or ``src/viced/afsfileprocs.c:/^SRXAFS_MakeDir`` as appropriate. See below for details, but an attempt at a short story is: * Whenever a directory is created, it inherits the *ACL* from its parent directory. (``src/viced/afsfileprocs.c:/^SAFSS_MakeDir``, specifically ``6e167d4:src/viced/afsfileprocs.c:4484``.) * Whenever an object of any type is created * The *GID* is inherited from the parent object: (overseen by ``src/viced/afsfileprocs.c:/^Alloc_NewVnode``; see in particular ``6e167d4:src/viced/afsfileprocs.c:1921``). * The *MODE* is set to ``0777``. That is, the *UMODE* and *GMODE* bits are made all-permissive; the ``S_IRWXO`` bits are also all-permissive, but recall that these bits are ignored. (``src/viced/afsfileprocs.c:/^Update_TargetVnodeStatus``, in particular ``6e167d4:src/viced/afsfileprocs.c:1680``) * The client PTS ID is used to set the *UID*. (``src/viced/afsfileprocs.c:/^Update_TargetVnodeStatus``, in particular ``6e167d4:src/viced/afsfileprocs.c:1681``) * All creation operations allow the client to additionally specify metadata about the object to be created, notably including *UID*, *GID*, and *MODE*. If requested *at creation*, these operations will be performed, with some caveats: *UID* and *GID* may be changed arbitrarily, but *MODE* will always be restricted to a subset of ``0777`` unless the requesting client is an *ADMIN*. For details, see :ref:`the internals of vnode update `. .. warning:: This should perhaps be moderately alarming! Because the create operations ``MakeDir``, ``Symlink``, and ``CreateFile`` all simply call ``CheckWriteMode`` and then pass their given ``struct AFSStoreStatus`` parameters to ``Update_TargetVnodeStatus``, it is possible to create objects with arbitrary *UID* and *GID*; the checks that would be done on a ``StoreStatus`` call (in ``Check_PermissionRights``) are bypassed. It is worth pointing out, perhaps, that the only reason that existing AFS deployments end up with *UID* being equal to the creating client's PTS ID is because the existing CMs do not request ``SETOWNER`` on ``CreateFile``. They do, however, request ``SETGROUP``, which is permitted, making a likely laughingstock of most *GID* values. The author of this document is deeply confused as to why ``Check_PermissionRights`` then refuses to change *GID* fields (and possibly *UID* fields as well!); see below. Client Operations ----------------- The current AFS file server RPC interface is defined in ``src/fsint/afsint.xg`` and enumerates the following 41 RPCs: * Data fetch calls: ``FetchData`` (130) and ``FetchData64`` (65537) * Metadata fetch calls: ``FetchACL`` (131) and ``FetchStatus`` (132) * Data store calls: ``StoreData`` (133) and ``StoreData64`` (65538) * Metadata store calls: ``StoreACL`` (134), ``StoreStatus`` (135), ``BulkStatus`` (155), and ``InlineBulkStatus`` (65536). * Deletion calls: ``RemoveFile`` (136) and ``RemoveDir`` (142) * Creation calls: ``CreateFile`` (137) and ``MakeDir`` (141) * ``Rename`` (138) * Link calls: ``Symlink`` (139), ``Link`` (140), and ``DFSSymlink`` (163) * "Old" locking calls: ``OldSetLock`` (143), ``OldExtendLock`` (144), ``OldReleaseLock`` (145) * "New" locking calls: ``SetLock`` (156), ``ExtendLock`` (157), ``ReleaseLock`` (158) * Callback manipulation calls: ``GiveUpCallBacks`` (147) ``GiveUpAllCallBacks`` (65539) ``CallBackRxConnAddr`` (65541) * Other: ``GetStatistics`` (146) ``GetVolumeInfo`` (148) ``GetVolumeStatus`` (149) ``SetVolumeStatus`` (150) ``GetRootVolume`` (151) ``CheckToken`` (152) ``GetTime`` (153) ``NGetVolumeInfo`` (154) ``XStatsVersion`` (159) ``GetXStats`` (160) ``Lookup`` (161) ``FlushCPS`` (162) ``FsCmd`` (220) ``GetCapabilities`` (65540) Many mutation calls (``StoreStatus``, ``CreateFile``, ``Symlink``, and ``MakeDir``) take a ``struct AFSStoreStatus`` which specifies a bitmask of features to be changed, which is drawn from a set defined at ``6e167d4:src/fsint/afsint.xg:116``. Three flags concern us: * ``SETOWNER`` to adjust the *UID* * ``SETGROUP`` to adjust the *GID* * ``SETMODE`` to adjust the *MODE* While the remainder (``MODTIME``, ``SETSEGSIZE``, and ``FSYNC``) do not. Client Operations Vs Required Permissions ----------------------------------------- .. _vnode_update: Update Internals ```````````````` Before we discuss pre-flight permissions checks, we focus on ``src/viced/afsfileprocs.c:/^Update_TargetVnodeStatus``, which serves to actually carry out writes to vnode status fields but also contains some permission logic. This function is called by most mutation functions: * ``common_StoreData64`` at ``6e167d4:src/viced/afsfileprocs.c:2989`` * ``SAFSS_StoreStatus`` at ``6e167d4:src/viced/afsfileprocs.c:3200`` * ``SAFSS_CreateFile`` at ``6e167d4:src/viced/afsfileprocs.c:3464`` * ``SAFSS_Symlink`` at ``6e167d4:src/viced/afsfileprocs.c:4131`` * ``SAFSS_MakeDir`` at ``6e167d4:src/viced/afsfileprocs.c:4489`` This function modifies the request in several ways as a result of permissions: * If the originating call is ``StoreData64`` (see ``6e167d4:src/viced/afsfileprocs.c:1729`` and following): * The setuid *SPEC* bit is *cleared* unless the requestor is an *ADMIN*. * If the server has been compiled ``-DCREATE_SGUID_ADMIN_ONLY`` (which it is, by default, at ``6e167d4:src/viced/afsfileprocs.c:152``), the setgid *SPEC* bit is cleared unless the requestor is an *ADMIN*. * If the originating call requests a set of ownership (*UID*) (by asserting ``AFS_SETOWNER`` in the incoming status mask; see ``6e167d4:src/viced/afsfileprocs.c:1749`` and following), the same tests and clearings as the previous point are applied. Note that changes of *GID* are always performed if requested, and will *not* cause any bits (most notably ``S_ISGID``) to be cleared. * If the originating call requests a set of all *MODE* bits (by asserting ``AFS_SETMODE`` in the incoming status mask) AND the server is built with ``CREATE_SGUID_ADMIN_ONLY`` defined (which it is by default) AND the caller is not *ADMIN*, the *MODE* bits are restricted to the three RWX triples (i.e., all *SPEC* bits are cleared). This has the effect of prohibiting all users other than *ADMIN* from setting the masked bits. (See ``6e167d4:src/viced/afsfileprocs.c:1767`` and following.) The contained permissions checks would all be overridden if the ``remote`` flag is set (which it isn't in any existing call) as part of the effort towards RW replication. Simpler Client Operations ````````````````````````` A separate pre-flight permissions check exists for many operations, a relatively simple ``src/viced/afsfileprocs.c:/^CheckWriteMode``, which succeeds so long as the operation is targeted at a read-write volume, the caller has the required rights (as indicated in call) in the containing directory *ACL*, and either the target is a directory or the ``OWNERWRITE`` *MODE* bit is set. In particular, * ``RemoveFile`` requires delete rights (at ``6e167d4:src/viced/afsfileprocs.c:3307``), * ``CreateFile`` requires insert rights (at ``6e167d4:src/viced/afsfileprocs.c:3488``); * ``Rename`` performs two such calls, requiring delete rights in the old directory (at ``6e167d4:src/viced/afsfileprocs.c:3644``) and insert rights in the new (at ``6e167d4:src/viced/afsfileprocs.c:3647``) (Note that these may be the same!), * ``Symlink`` requires insert rights in the directory where the link will be created (at ``6e167d4:src/viced/afsfileprocs.c:4094``), * ``Link`` requires insert rights in the directory where the link will be created (at ``6e167d4:src/viced/afsfileprocs.c:4276``), * ``RemoveDir`` requires delete rights of the containing directory (at ``6e167d4:src/viced/afsfileprocs.c:4613``), * ``MakeDir`` can be built with one of two permissions models (see ``6e167d4:src/viced/afsfileprocs.c:4455``): * Require both insert and write rights in the containing directory, if built with ``-DDIRCREATE_NEED_WRITE`` (not default), or * Require just insert rights, otherwise. By default, the latter strategy is used. The justification for the former strategy hinged on the old implicit Administrate permission given to the owner of a directory, which is no longer the case (see :ref:`Implicit Admin on Dir `). Complex Client Operations ````````````````````````` A single function, ``src/viced/afsfileprocs.c:/^Check_PermissionRights``, contains the permission logic for the ten calls comprising fetch and set of data, ACL, and status: * ``FetchData64`` (and ``FetchData``) at ``6e167d4:src/viced/afsfileprocs.c:2325`` * ``FetchACL`` at ``6e167d4:src/viced/afsfileprocs.c:2466`` * ``FetchStatus`` at ``6e167d4:src/viced/afsfileprocs.c:2544`` * ``BulkStatus`` at ``6e167d4:src/viced/afsfileprocs.c:2644`` * ``InlineBulkStatus`` at ``6e167d4:src/viced/afsfileprocs.c:2788`` * ``StoreData64`` (and ``StoreData``) at ``6e167d4:src/viced/afsfileprocs.c:2956`` * ``StoreACL`` at ``6e167d4:src/viced/afsfileprocs.c:3100`` * ``StoreStatus`` at ``6e167d4:src/viced/afsfileprocs.c:3186`` The operation of this pre-flight test is somewhat opaque. Here is our current best attempt at its description: * Read operations are a mess; see ``6e167d4:src/viced/afsfileprocs.c:1030`` and following. The code is a series of checks for reasons for the operation to fail. * Reading the contents of directories or symlinks fails if the *ACL* does not grant ``r``, ``-DADMIN_IMPLICIT_LOOKUP`` is defined and the client is not an *ADMIN*, **and** the client is not the *VOLUID*. Phrased positively, this succeeds if the *ACL* grants ``r``, ``-DADMIN_IMPLICIT_LOOKUP`` is defined and the client is an *ADMIN*, **or** the client is the *VOLUID*. * Reading the contents of files fails under the same conditions as for directories, *as well as* the following conditions: * ``-DUSE_GROUP_PERMS`` is not in effect **and** the client does not match *UID* and the client is not an *ADMIN* **and** the *MODE* bits **do** have ``OWNERREAD`` or ``OWNEREXEC`` asserted. (``6e167d4:src/viced/afsfileprocs.c:1067``) This is documented as a "kludge" to handle the case when *MODE* is ``0`` (possibly from creation) **and** the *UID* is set incorrectly. .. note:: That is, in net, AFS allows, in addition to administrator and owner, any user's read request if there are no read *UMODE* bits asserted. This is, shall we say, a litte different from the usual semantics of *UMODE*. * ``-DUSE_GROUP_PERMS`` being in effect generalizes this test... .. todo:: working here * Reading an ACL or status information while not being an *ADMIN* requires the same conditions as reading the contents of the object, as if it were a directory. (Note that this fact is confusingly encoded in the implementation as ``|| VanillaUser(client)``.) * Reading an ACL or status information while being an *ADMIN* will never fail. * Write operations are no better; see ``6e167d4:src/viced/afsfileprocs.c:1079`` and following. * A store of data to a file, when client matches *UID* and the *ACL* grants the client ``i``, is permitted (unless the server is readonly). * A store of stat metadata to a file, when client matches *UID* and the *ACL* grants the client ``i``, is permitted on a non-readonly server if either: * the *UID* and *GID* are not being modified. * the client is an *ADMIN*. * All other non-data stores are explicitly permitted if the client is an *ADMIN* (``6e167d4:src/viced/afsfileprocs.c:1098``) **even if** the server is readonly. * All other stores fail if the server is readonly. (All subsequent tests of this are superfluous and elided from this description.) * A store of an ACL is permitted only if the *ACL* grants ``a`` or the client matches the *VOLUID*. (``6e167d4:src/viced/afsfileprocs.c:1107``) * A store of status which changes *UID* or *GID* will fail unless the client is an *ADMIN* (``6e167d4:src/viced/afsfileprocs.c:1111``) * A store which mutates the *SPEC* bits ``S_ISUID`` or ``S_ISGID`` will fail unless the client is an *ADMIN* (``6e167d4:src/viced/afsfileprocs.c:1123``) * A store of data will fail unless the *ACL* grants the client ``w`` (``6e167d4:src/viced/afsfileprocs.c:1142``) * ``-DUSE_GROUP_PERMS`` induces some complexity at this point... .. todo:: oh yeah, that * A store of data to a non-directory (i.e. file or symlink) without the *UMODE* including write will fail unless the client is an *ADMIN* (``6e167d4:src/viced/afsfileprocs.c:1167``) * A store of status to a directory will fail without the *ACL* granting both ``di`` (``6e167d4:src/viced/afsfileprocs.c:1182``) * A store of status to a file will fail without the *ACL* granting ``w`` (``6e167d4:src/viced/afsfileprocs.c:1186``) * A store that has not yet failed will succeed. .. todo:: Working here.