Subject: Re: [nfsv4] ACL mode bit descriptions in minorversion1-02

From: Lisa Week <[email-masked]>
Date: Wed, 31 May 2006 16:33:41 -0600

Hi,

Sorry for the delay, but I have finished making the next round of 
changes to the ACL text to describe the client's role in enforcing 
access.  I have attached the diffs and the changes to the text in the 
current minor version doc are represented as follows: Lines with "+" in 
front means the lines were added.  Lines with "-" in front means the 
lines were removed.

Comments?

Thanks,
Lisa

Sam Falkner wrote:

>
> On May 16, 2006, at 12:05 PM, J. Bruce Fields wrote:
>
>> On Tue, May 16, 2006 at 11:31:30AM -0600, Lisa Week wrote:
>>
>>> Is this text supposed to be 1.) a specification of the server  behavior
>>> or 2.) documentation of the implementation considerations for the  
>>> client
>>> (i.e. have clients consider the fact that they may need to do access
>>> checking via ACCESS as well)?
>>>
>>> I thought it was the second, we can decide.  I think there is a fine
>>> line here and we just have to clarify the goal.
>>
>>
>> I don't know.  I think this would be useful information to have in the
>> spec, so I suppose it's a question of which organization is clearest.
>> If you think there's a better place for it, I don't suppose I have a
>> strong opinion.
>
>
> How about if the server part of the discussion (1. above) were put in  
> the
> part that discusses each of the access_mask bits?  I think that would be
> easiest.
>
> - Sam

--- acl-minorversion.txt	Wed May 24 12:06:55 2006
+++ modified-acl-minorversion.txt	Wed May 31 15:50:59 2006
@@ -1,1160 +1,1218 @@
 3.16.  Access Control Lists
 
    The NFS version 4 ACL attribute is an array of access control entries
    (ACE).  Although, the client can read and write the ACL attribute,
    the NFSv4 model is the server does all access control based on the
    server's interpretation of the ACL.  If at any point the client wants
    to check access without issuing an operation that modifies or reads
    data or metadata, the client can use the OPEN and ACCESS operations
    to do so.  There are various access control entry types, as defined
    in Section 3.16.1.  The server is able to communicate which ACE types
    are supported by returning the appropriate value within the
    aclsupport attribute.  Each ACE covers one or more operations on a
    file or directory as described in Section 3.16.2.  It may also
    contain one or more flags that modify the semantics of the ACE as
    defined in Section 3.16.3.
 
    The NFS ACE attribute is defined as follows:
 
             typedef uint32_t        acetype4;
             typedef uint32_t        aceflag4;
             typedef uint32_t        acemask4;
 
             struct nfsace4 {
                     acetype4        type;
                     aceflag4        flag;
                     acemask4        access_mask;
                     utf8str_mixed   who;
             };
 
    To determine if a request succeeds, each nfsace4 entry is processed
    in order by the server.  Only ACEs which have a "who" that matches
    the requester are considered.  Each ACE is processed until all of the
    bits of the requester's access have been ALLOWED.  Once a bit (see
    below) has been ALLOWED by an ACCESS_ALLOWED_ACE, it is no longer
    considered in the processing of later ACEs.  If an ACCESS_DENIED_ACE
    is encountered where the requester's access still has unALLOWED bits
    in common with the "access_mask" of the ACE, the request is denied.
    However, unlike the ALLOWED and DENIED ACE types, the ALARM and AUDIT
    ACE types do not affect a requester's access, and instead are for
    triggering events as a result of a requester's access attempt.
 
    Therefore, all AUDIT and ALARM ACEs are processed until end of the
    ACL.  When the ACL is fully processed, if there are bits in
    requester's mask that have not been considered whether the server
    allows or denies, the access is denied.  Even though a request is
    denied, servers may choose to have other restrictions or
    implementation defined security policies in place.  In those cases,
    access may be decided outside of what is in the ACL.  Examples of
    such security policies or restrictions are:
 
    o  The owner of the file will always be able granted ACE4_WRITE_ACL
       and ACE4_READ_ACL permissions.  This would prevent the user from
       getting into the situation where they can't ever modify the ACL.
 
    o  The ACL may say that an entity is to be granted ACE4_WRITE_DATA
       permission, but the file system is mounted read only, therefore
       write access is denied.
 
    As mentioned before, this is one of the reasons that client
-   implementations are not recommended to do their own access checking.
+   implementations are not recommended to do access checks based on
+   their interpretation the ACL, but rather use the OPEN and ACCESS
+   operations to do access checks.  This allows the client to act on
+   the results of having the server determine whether or not access should
+   be granted based on its interpretation of the ACL.
 
+   Clients must be aware of situations in which an object's ACL will
+   define a certain access even though the server will not enforce it.
+   In general, but especially in these situations, the client needs to
+   do its part in the enforcement of access as defined by the ACL.  To
+   do this, the client may issue the appropriate ACCESS operation prior
+   to servicing the request of the user or application in order to
+   determine whether the user or application should be granted the
+   access requested.
+
+   Some situations in which the ACL may define accesses that the
+   server doesn't enforce:
+
+   o All servers will allow a user the ability to read the data of the
+   file when only the execute permission is granted (i.e. If the ACL
+   denies the user the ACE4_READ_DATA access and allows the user
+   ACE4_EXECUTE, the server will allow the user to read the data of the
+   file).
+
+   o Many servers have the notion of owner-override in which the owner
+   of the object is allowed to override accesses that are denied by the
+   ACL.
+
    The NFS version 4 ACL model is quite rich.  Some server platforms may
    provide access control functionality that goes beyond the UNIX-style
    mode attribute, but which is not as rich as the NFS ACL model.  So
    that users can take advantage of this more limited functionality, the
    server may indicate that it supports ACLs as long as it follows the
    guidelines for mapping between its ACL model and the NFS version 4
    ACL model.
 
    The situation is complicated by the fact that a server may have
    multiple modules that enforce ACLs.  For example, the enforcement for
    NFS version 4 access may be different from the enforcement for local
    access, and both may be different from the enforcement for access
    through other protocols such as SMB.  So it may be useful for a
    server to accept an ACL even if not all of its modules are able to
    support it.
 
    The guiding principle in all cases is that the server must not accept
    ACLs that appear to make the file more secure than it really is.
 
 3.16.1.  ACE type

       Type         Description
       _____________________________________________________
       ALLOW        Explicitly grants the access defined in
                    acemask4 to the file or directory.
 
       DENY         Explicitly denies the access defined in
                    acemask4 to the file or directory.
 
       AUDIT        LOG (system dependent) any access
                    attempt to a file or directory which
                    uses any of the access methods specified
                    in acemask4.
 
       ALARM        Generate a system ALARM (system
                    dependent) when any access attempt is
                    made to a file or directory for the
                    access methods specified in acemask4.
 
    A server need not support all of the above ACE types.  The bitmask
    constants used to represent the above definitions within the
    aclsupport attribute are as follows:
 
          const ACL4_SUPPORT_ALLOW_ACL    = 0x00000001;
          const ACL4_SUPPORT_DENY_ACL     = 0x00000002;
          const ACL4_SUPPORT_AUDIT_ACL    = 0x00000004;
          const ACL4_SUPPORT_ALARM_ACL    = 0x00000008;
 
    The semantics of the "type" field follow the descriptions provided
    above.
 
    The constants used for the type field (acetype4) are as follows:
 
          const ACE4_ACCESS_ALLOWED_ACE_TYPE      = 0x00000000;
          const ACE4_ACCESS_DENIED_ACE_TYPE       = 0x00000001;
          const ACE4_SYSTEM_AUDIT_ACE_TYPE        = 0x00000002;
          const ACE4_SYSTEM_ALARM_ACE_TYPE        = 0x00000003;
 
    Clients should not attempt to set an ACE unless the server claims
    support for that ACE type.  If the server receives a request to set
    an ACE that it cannot store, it MUST reject the request with
    NFS4ERR_ATTRNOTSUPP.  If the server receives a request to set an ACE
    that it can store but cannot enforce, the server SHOULD reject the
    request with NFS4ERR_ATTRNOTSUPP.
 
    Example: suppose a server can enforce NFS ACLs for NFS access but
    cannot enforce ACLs for local access.  If arbitrary processes can run
    on the server, then the server SHOULD NOT indicate ACL support.  On
    the other hand, if only trusted administrative programs run locally,
    then the server may indicate ACL support.
 
 3.16.2.  ACE Access Mask
 
    The access_mask field contains values based on the following:
 
       ACE4_READ_DATA
          Operation(s) affected:
               READ
               OPEN
          Discussion:
               Permission to read the data of the file.
 
+	      Servers SHOULD allow a user the ability to read the data
+	      of the file when only the ACE4_EXECUTE access mask bit is
+	      allowed.
+
       ACE4_LIST_DIRECTORY
           Operation(s) affected:
               READDIR
           Discussion:
               Permission to list the contents of a directory.
 
       ACE4_WRITE_DATA
           Operation(s) affected:
               WRITE
               OPEN
           Discussion:
               Permission to modify a file's data anywhere in the file's
               offset range.  This includes the ability to write to any
               arbitrary offset and as a result to grow the file.
 
       ACE4_ADD_FILE
           Operation(s) affected:
               CREATE
               OPEN
           Discussion:
               Permission to add a new file in a directory.  The CREATE
               operation is affected when nfs_ftype4 is NF4LNK, NF4BLK,
               NF4CHR, NF4SOCK, or NF4FIFO. (NF4DIR is not listed because
               it is covered by ACE4_ADD_SUBDIRECTORY.) OPEN is affected
               when used to create a regular file.
 
       ACE4_APPEND_DATA
           Operation(s) affected:
               WRITE
               OPEN
           Discussion:
                The ability to modify a file's data, but only starting at
                EOF.  This allows for the notion of append-only files, by
                allowing ACE4_APPEND_DATA and denying ACE4_WRITE_DATA to
                the same user or group.  If a file has an ACL such as the
                one described above and a WRITE request is made for
                somewhere other than EOF, the server SHOULD return
                NFS4ERR_ACCESS.
 
       ACE4_ADD_SUBDIRECTORY
           Operation(s) affected:
               CREATE
           Discussion:
               Permission to create a subdirectory in a directory.  The
               CREATE operation is affected when nfs_ftype4 is NF4DIR.
 
       ACE4_READ_NAMED_ATTRS
           Operation(s) affected:
               OPENATTR
           Discussion:
               Permission to read the named attributes of a file or to
               lookup the named attributes directory.  OPENATTR is
               affected when it is not used to create a named attribute
               directory.  This is when 1.) createdir is TRUE, but a
               named attribute directory already exists, or 2.) createdir
               is FALSE.
 
       ACE4_WRITE_NAMED_ATTRS
           Operation(s) affected:
               OPENATTR
           Discussion:
               Permission to write the named attributes of a file or
               to create a named attribute directory.  OPENATTR is
               affected when it is used to create a named attribute
               directory.  This is when createdir is TRUE and no named
               attribute directory exists.  The ability to check whether
               or not a named attribute directory exists depends on the
               ability to look it up, therefore, users also need the
               ACE4_READ_NAMED_ATTRS permission in order to create a
               named attribute directory.
 
       ACE4_EXECUTE
           Operation(s) affected:
               LOOKUP
+	      READ
+	      OPEN
           Discussion:
               Permission to execute a file or traverse/search a
               directory.
 
+	      Servers SHOULD allow a user the ability to read the data
+	      of the file when only the ACE4_EXECUTE access mask bit is
+	      allowed.  This is because of the fact that there is no
+	      way to execute a file without ultimately reading the
+	      contents.  Additional clarifications to be noted:
+
+	      o If a client issues a SETATTR of an ACL which contains an
+	      ALLOW ACE with the ACE4_EXECUTE access mask bit set, the
+	      server SHOULD NOT silently set the ACE4_READ_DATA bit
+	      in the same ACE.
+
+		For example, following a SETATTR of the following ACL:
+	      		nfsuser:ACE4_EXECUTE:ALLOW
+
+		A subsequent GETATTR of ACL for that file SHOULD return:
+			nfsuser:ACE4_EXECUTE:ALLOW
+		Rather than:
+			nfsuser:ACE4_EXECUTE/ACE4_READ_DATA:ALLOW
+
+	      o Servers MUST answer any ACCESS operations, with access
+	      values including ACCESS4_READ, based on the disposition
+	      of ACE4_READ_DATA in the ACL.  This is so the client has
+	      the ability to enforce the access as defined by the ACL
+	      by issuing ACCCESS prior to allowing the application or
+	      user to attempt to read the data of the file.
+
       ACE4_DELETE_CHILD
           Operation(s) affected:
               REMOVE
           Discussion:
               Permission to delete a file or directory within a
               directory.  See section "ACE4_DELETE vs.
               ACE4_DELETE_CHILD" for information on how these two access
               mask bits interact.
 
       ACE4_READ_ATTRIBUTES
           Operation(s) affected:
               GETATTR of file system object attributes
           Discussion:
               The ability to read basic attributes (non-ACLs) of a file.
               On a UNIX system, basic attributes can be thought of as
               the stat level attributes.  Allowing this access mask bit
               would mean the entity can execute "ls -l" and stat.
 
       ACE4_WRITE_ATTRIBUTES
           Operation(s) affected:
               SETATTR of time_access_set, time_backup,
               time_create, time_modify_set
           Discussion:
               Permission to change the times associated with a file
               or directory to an arbitrary value.  A user having
               ACE4_WRITE_DATA permission, but lacking
               ACE4_WRITE_ATTRIBUTES must be allowed to implicitly set
               the times associated with a file.
 
       ACE4_DELETE
           Operation(s) affected:
               REMOVE
           Discussion:
               Permission to delete the file or directory.  See section
               "ACE4_DELETE vs. ACE4_DELETE_CHILD" for information on how
               these two access mask bits interact.
 
       ACE4_READ_ACL
           Operation(s) affected:
               GETATTR of acl
           Discussion:
               Permission to read the ACL.
 
       ACE4_WRITE_ACL
           Operation(s) affected:
               SETATTR of acl and mode
           Discussion:
               Permission to write the acl and mode attributes.
 
       ACE4_WRITE_OWNER
           Operation(s) affected:
               SETATTR of owner and owner_group
           Discussions:
               Permission to write the owner and owner_group attributes.
               On UNIX systems, this is the ability to execute chown or
               chgrp.
 
       ACE4_SYNCHRONIZE
           Operation(s) affected:
               NONE
           Discussion:
               Permission to access file locally at the server with
               synchronized reads and writes.
 
    The bitmask constants used for the access mask field are as follows:
 
       const ACE4_READ_DATA            = 0x00000001;
       const ACE4_LIST_DIRECTORY       = 0x00000001;
       const ACE4_WRITE_DATA           = 0x00000002;
       const ACE4_ADD_FILE             = 0x00000002;
       const ACE4_APPEND_DATA          = 0x00000004;
       const ACE4_ADD_SUBDIRECTORY     = 0x00000004;
       const ACE4_READ_NAMED_ATTRS     = 0x00000008;
       const ACE4_WRITE_NAMED_ATTRS    = 0x00000010;
       const ACE4_EXECUTE              = 0x00000020;
       const ACE4_DELETE_CHILD         = 0x00000040;
       const ACE4_READ_ATTRIBUTES      = 0x00000080;
       const ACE4_WRITE_ATTRIBUTES     = 0x00000100;
       const ACE4_DELETE               = 0x00010000;
       const ACE4_READ_ACL             = 0x00020000;
       const ACE4_WRITE_ACL            = 0x00040000;
       const ACE4_WRITE_OWNER          = 0x00080000;
       const ACE4_SYNCHRONIZE          = 0x00100000;
 
    Server implementations need not provide the granularity of control
    that is implied by this list of masks.  For example, POSIX-based
    systems might not distinguish APPEND_DATA (the ability to append to a
    file) from WRITE_DATA (the ability to modify existing contents); both
    masks would be tied to a single "write" permission.  When such a
    server returns attributes to the client, it would show both
    APPEND_DATA and WRITE_DATA if and only if the write permission is
    enabled.
 
    If a server receives a SETATTR request that it cannot accurately
    implement, it should error in the direction of more restricted
    access.  For example, suppose a server cannot distinguish overwriting
    data from appending new data, as described in the previous paragraph.
    If a client submits an ACE where APPEND_DATA is set but WRITE_DATA is
    not (or vice versa), the server should reject the request with
    NFS4ERR_ATTRNOTSUPP.  Nonetheless, if the ACE has type DENY, the
    server may silently turn on the other bit, so that both APPEND_DATA
    and WRITE_DATA are denied.
 
 3.16.2.1.  ACE4_DELETE vs. ACE4_DELETE_CHILD
 
    There are two separate access mask bits that govern the ability to
    delete a file: ACE4_DELETE and ACE4_DELETE_CHILD.  ACE4_DELETE is
    intended to be specified by the ACL for the object to be deleted, and
    ACE4_DELETE_CHILD is intended to be specified by the ACL of the
    parent directory.
 
    In addition to ACE4_DELETE and ACE4_DELETE_CHILD, many systems also
    consider the "sticky bit" (MODE4_SVTX) and the appropriate "write"
    mode bit when determining whether to allow a file to be deleted.  The
    mode bit for write corresponds to ACE4_WRITE_DATA, which is the same
    physical bit as ACE4_ADD_FILE.  Therefore, ACE4_ADD_FILE can come
    into play when determining permission to delete.
 
    In the algorithm below, the strategy is that ACE4_DELETE and
    ACE4_DELETE_CHILD take precedence over the sticky bit, and the sticky
    bit takes precedence over the "write" mode bits (reflected in
    ACE4_ADD_FILE).
 
    Server implementations SHOULD grant or deny permission to delete
    based on the following algorithm.
 
           if ACE4_EXECUTE is denied by the parent directory ACL:
               deny delete
           else if ACE4_EXECUTE is unspecified by the parent
           directory ACL:
               deny delete
           else if ACE4_DELETE is allowed by the target object ACL:
               allow delete
           else if ACE4_DELETE_CHILD is allowed by the parent
           directory ACL:
               allow delete
           else if ACE4_DELETE_CHILD is denied by the
           parent directory ACL:
               deny delete
           else if ACE4_ADD_FILE is allowed by the parent directory ACL:
               if MODE4_SVTX is set for the parent directory:
                   if the principal owns the parent directory OR
                       the principal owns the target object OR
                       ACE4_WRITE_DATA is allowed by the target
                       object ACL:
                           allow delete
                       else:
                           deny delete
               else:
                   allow delete
           else:
               deny delete
 
 3.16.3.  ACE flag
 
    The "flag" field contains values based on the following descriptions.
 
    ACE4_FILE_INHERIT_ACE
       Can be placed on a directory and indicates that this ACE should be
       added to each new non-directory file created.
 
    ACE4_DIRECTORY_INHERIT_ACE
       Can be placed on a directory and indicates that this ACE should be
       added to each new directory created.
 
    ACE4_INHERIT_ONLY_ACE
       Can be placed on a directory but does not apply to the directory,
       only to newly created files/directories as specified by the above
       two flags.
 
    ACE4_NO_PROPAGATE_INHERIT_ACE
       Can be placed on a directory.  Normally when a new directory is
       created and an ACE exists on the parent directory which is marked
       ACE4_DIRECTORY_INHERIT_ACE, two ACEs are placed on the new
       directory.  One for the directory itself and one which is an
       inheritable ACE for newly created directories.  This flag tells
       the server to not place an ACE on the newly created directory
       which is inheritable by subdirectories of the created directory.
 
    ACE4_SUCCESSFUL_ACCESS_ACE_FLAG
 
    ACE4_FAILED_ACCESS_ACE_FLAG
       The ACE4_SUCCESSFUL_ACCESS_ACE_FLAG (SUCCESS) and
       ACE4_FAILED_ACCESS_ACE_FLAG (FAILED) flag bits relate only to
       ACE4_SYSTEM_AUDIT_ACE_TYPE (AUDIT) and ACE4_SYSTEM_ALARM_ACE_TYPE
       (ALARM) ACE types.  If during the processing of the file's ACL,
       the server encounters an AUDIT or ALARM ACE that matches the
       principal attempting the OPEN, the server notes that fact, and the
       presence, if any, of the SUCCESS and FAILED flags encountered in
       the AUDIT or ALARM ACE.  Once the server completes the ACL
       processing, and the share reservation processing, and the OPEN
       call, it then notes if the OPEN succeeded or failed.  If the OPEN
       succeeded, and if the SUCCESS flag was set for a matching AUDIT or
       ALARM, then the appropriate AUDIT or ALARM event occurs.  If the
       OPEN failed, and if the FAILED flag was set for the matching AUDIT
       or ALARM, then the appropriate AUDIT or ALARM event occurs.
       Clearly either or both of the SUCCESS or FAILED can be set, but if
       neither is set, the AUDIT or ALARM ACE is not useful.
 
       The previously described processing applies to that of the ACCESS
       operation as well.  The difference being that "success" or
       "failure" does not mean whether ACCESS returns NFS4_OK or not.
       Success means whether ACCESS returns all requested and supported
       bits.  Failure means whether ACCESS failed to return a bit that
       was requested and supported.
 
    ACE4_IDENTIFIER_GROUP
       Indicates that the "who" refers to a GROUP as defined under UNIX
       or a GROUP ACCOUNT as defined under Windows.  Clients and servers
       may ignore the ACE4_IDENTIFIER_GROUP flag on ACEs with a who value
       equal to one of the special identifiers outlined in section "ACE
       who".
 
    The bitmask constants used for the flag field are as follows:
 
       const ACE4_FILE_INHERIT_ACE             = 0x00000001;
       const ACE4_DIRECTORY_INHERIT_ACE        = 0x00000002;
       const ACE4_NO_PROPAGATE_INHERIT_ACE     = 0x00000004;
       const ACE4_INHERIT_ONLY_ACE             = 0x00000008;
       const ACE4_SUCCESSFUL_ACCESS_ACE_FLAG   = 0x00000010;
       const ACE4_FAILED_ACCESS_ACE_FLAG       = 0x00000020;
       const ACE4_IDENTIFIER_GROUP             = 0x00000040;
 
    A server need not support any of these flags.  If the server supports
    flags that are similar to, but not exactly the same as, these flags,
    the implementation may define a mapping between the protocol-defined
    flags and the implementation-defined flags.  Again, the guiding
    principle is that the file not appear to be more secure than it
    really is.
 
    For example, suppose a client tries to set an ACE with
    ACE4_FILE_INHERIT_ACE set but not ACE4_DIRECTORY_INHERIT_ACE.  If the
    server does not support any form of ACL inheritance, the server
    should reject the request with NFS4ERR_ATTRNOTSUPP.  If the server
    supports a single "inherit ACE" flag that applies to both files and
    directories, the server may reject the request (i.e., requiring the
    client to set both the file and directory inheritance flags).  The
    server may also accept the request and silently turn on the
    ACE4_DIRECTORY_INHERIT_ACE flag.
 
 3.16.4.  ACE who
 
    There are several special identifiers ("who") which need to be
    understood universally, rather than in the context of a particular
    DNS domain.  Some of these identifiers cannot be understood when an
    NFS client accesses the server, but have meaning when a local process
    accesses the file.  The ability to display and modify these
    permissions is permitted over NFS, even if none of the access methods
    on the server understands the identifiers.
 
       Who                    Description
       _______________________________________________________________
       "OWNER"                The owner of the file.
       "GROUP"                The group associated with the file.
       "EVERYONE"             The world, including the owner and
                              owning group.
       "INTERACTIVE"          Accessed from an interactive terminal.
       "NETWORK"              Accessed via the network.
       "DIALUP"               Accessed as a dialup user to the server.
       "BATCH"                Accessed from a batch job.
       "ANONYMOUS"            Accessed without any authentication.
       "AUTHENTICATED"        Any authenticated user (opposite of
                              ANONYMOUS)
       "SERVICE"              Access from a system service.
 
    To avoid conflict, these special identifiers are distinguish by an
    appended "@" and should appear in the form "xxxx@" (note: no domain
    name after the "@").  For example: ANONYMOUS@.
 
 3.16.4.1.  Discussion on EVERYONE@
 
    It is important to note that "EVERYONE@" is not equivalent to the
    UNIX "other" entity.  This is because, by definition, UNIX "other"
    does not include the owner or owning group of a file.  "EVERYONE@"
    means literally everyone, including the owner or owning group.
 
 3.16.4.2.  Discussion on OWNER@ and GROUP@
 
    Due to the use of the special identifiers "OWNER@" and "GROUP@" to
    indicate that an ACE applies to the the owner and owning group,
    respectively, associated with a file, the ACL cannot be used to
    determine the owner and owning group of a file.  This information
    should be indicated by the values of the owner and owner_group file
    attributes returned by the server.
 
 3.16.5.  Mode Attribute
 
    The NFS version 4 mode attribute is based on the UNIX mode bits.  The
    following bits are defined:
 
          const MODE4_SUID = 0x800;  /* set user id on execution */
          const MODE4_SGID = 0x400;  /* set group id on execution */
          const MODE4_SVTX = 0x200;  /* save text even after use */
          const MODE4_RUSR = 0x100;  /* read permission: owner */
          const MODE4_WUSR = 0x080;  /* write permission: owner */
          const MODE4_XUSR = 0x040;  /* execute permission: owner */
          const MODE4_RGRP = 0x020;  /* read permission: group */
          const MODE4_WGRP = 0x010;  /* write permission: group */
          const MODE4_XGRP = 0x008;  /* execute permission: group */
          const MODE4_ROTH = 0x004;  /* read permission: other */
          const MODE4_WOTH = 0x002;  /* write permission: other */
          const MODE4_XOTH = 0x001;  /* execute permission: other */
 
    Bits MODE4_RUSR, MODE4_WUSR, and MODE4_XUSR apply to the principal
    identified in the owner attribute.  Bits MODE4_RGRP, MODE4_WGRP, and
    MODE4_XGRP apply to the principals identified in the owner_group
    attribute.  Bits MODE4_ROTH, MODE4_WOTH, MODE4_XOTH apply to any
    principal that does not match that in the owner group, and does not
    have a group matching that of the owner_group attribute.
 
    The remaining bits are not defined by this protocol and MUST NOT be
    used.  The minor version mechanism must be used to define further bit
    usage.
 
    Note that in UNIX, if a file has the MODE4_SGID bit set and no
    MODE4_XGRP bit set, then READ and WRITE must use mandatory file
    locking.
 
 3.16.6.  Interaction Between Mode and ACL Attributes
 
    As defined, there is a certain amount of overlap between ACL and mode
    file attributes.  Even though there is overlap, ACLs don't contain
    all the information specified by a mode and modes can't possibly
    contain all the information specified by an ACL.
 
    For servers that support both mode and ACL, the mode's MODE4_R*,
    MODE4_W* and MODE4_X* values should be computed from the ACL and
    should be recomputed upon each SETATTR of ACL.  Similarly, upon
    SETATTR of mode, the ACL should be modified in order to allow the
    mode computed from the ACL to be the same as the mode given to
    SETATTR.  The mode computed from any given ACL should be
    deterministic.  This means that given an ACL, the same mode will
    always be computed.
 
    For servers that support ACL and not mode, clients may handle
    applications which set and get the mode by creating the correct ACL
    to send to the server and by computing the mode from the ACL,
    respectively.  In this case, the methods used by the server to keep
    the mode in sync with the ACL can also be used by the client.  These
    methods are explained in sections Section 3.16.6.3 Section 3.16.6.1
    and Section 3.16.6.2.
 
    Since the mode can't possibly represent all of the information that
    is defined by an ACL, there are some descrepencies to be aware of.
    As explained in the section "Deficiencies in a Mode Representation of
    an ACL", the mode bits computed from the ACL could potentially convey
    more restrictive permissions than what would be granted via the ACL.
    Because of this clients are not recommended to do their own access
    checks based on the mode of a file.
 
    Because the mode attribute includes bits (i.e.  MODE4_SUID,
    MODE4_SGID, MODE4_SVTX) that have nothing to do with ACL semantics,
    it is permitted for clients to specify both the ACL attribute and
    mode in the same SETATTR operation.  However, because there is no
    prescribed order for processing the attributes in a SETATTR, clients
    may see differing results.  For recommendations on how to achieve
    consistent behavior, see Section 3.16.6.4 for recommendations.
 
 3.16.6.1.  Recomputing mode upon SETATTR of ACL
 
    Keeping the mode and ACL attributes synchronized is important, but as
    mentioned previously, the mode cannot possibly represent all of the
    information in the ACL.  Still, the mode should be modified to
    represent the access as accurately as possible.
 
    The general algorithm to assign a new mode attribute to an object
    based on a new ACL being set is:
 
    1.  Walk through the ACEs in order, looking for ACEs with a "who"
        value of OWNER@, GROUP@, or EVERYONE@.
 
    2.  It is understood that ACEs with a "who" value of OWNER@ affect
        the *USR bits of the mode, GROUP@ affect *GRP bits, and EVERYONE@
        affect *USR, *GRP, and *OTH bits.
 
    3.  If such an ACE specifies ALLOW or DENY for ACE4_READ_DATA,
        ACE4_WRITE_DATA, or ACE4_EXECUTE, and the mode bits affected have
        not been determined yet, set them to one (if ALLOW) or zero (if
        DENY).
 
    4.  Upon completion, any mode bits as yet undetermined have a value
        of zero.
 
    This pseudocode more precisely describes the algorithm:
 
           /* octal constants for the mode bits */
           RUSR = 0400
           WUSR = 0200
           XUSR = 0100
           RGRP = 0040
           WGRP = 0020
           XGRP = 0010
           ROTH = 0004
           WOTH = 0002
           XOTH = 0001
 
          /*
           * old_mode represents the previous value
           * of the mode of the object.
           */
 
           mode_t mode = 0, seen = 0;
           for each ACE a {
               if a.type is ALLOW or DENY and
               ACE4_INHERIT_ONLY_ACE is not set in a.flags {
                   if a.who is OWNER@ {
                       if ((a.mask & ACE4_READ_DATA) &&
                           (! (seen & RUSR))) {
                               seen |= RUSR;
                               if a.type is ALLOW {
                                   mode |= RUSR;
                               }
                       }
                       if ((a.mask & ACE4_WRITE_DATA) &&
                           (! (seen & WUSR))) {
                               seen |= WUSR;
                               if a.type is ALLOW {
                                   mode |= WUSR;
                               }
                       }
                       if ((a.mask & ACE4_EXECUTE) &&
                           (! (seen & XUSR))) {
                               seen |= XUSR;
                               if a.type is ALLOW {
                                   mode |= XUSR;
                               }
                       }
                   } else if a.who is GROUP@ {
                       if ((a.mask & ACE4_READ_DATA) &&
                           (! (seen & RGRP))) {
                               seen |= RGRP;
                               if a.type is ALLOW {
                                   mode |= RGRP;
                               }
                       }
                       if ((a.mask & ACE4_WRITE_DATA) &&
                           (! (seen & WGRP))) {
                               seen |= WGRP;
                               if a.type is ALLOW {
                                   mode |= WGRP;
                               }
                       }
                       if ((a.mask & ACE4_EXECUTE) &&
                           (! (seen & XGRP))) {
                               seen |= XGRP;
                               if a.type is ALLOW {
                                   mode |= XGRP;
                               }
                       }
                   } else if a.who is EVERYONE@ {
                       if (a.mask & ACE4_READ_DATA) {
                           if ! (seen & RUSR) {
                               seen |= RUSR;
                               if a.type is ALLOW {
                                   mode |= RUSR;
                               }
                           }
                           if ! (seen & RGRP) {
                               seen |= RGRP;
                               if a.type is ALLOW {
                                   mode |= RGRP;
                               }
                           }
                           if ! (seen & ROTH) {
                               seen |= ROTH;
                               if a.type is ALLOW {
                                   mode |= ROTH;
                               }
                           }
                       }
                       if (a.mask & ACE4_WRITE_DATA) {
                           if ! (seen & WUSR) {
                               seen |= WUSR;
                               if a.type is ALLOW {
                                   mode |= WUSR;
                               }
                           }
                           if ! (seen & WGRP) {
                               seen |= WGRP;
                               if a.type is ALLOW {
                                   mode |= WGRP;
                               }
                           }
                           if ! (seen & WOTH) {
                               seen |= WOTH;
                               if a.type is ALLOW {
                                   mode |= WOTH;
                               }
                           }
                       }
                       if (a.mask & ACE4_EXECUTE) {
                           if ! (seen & XUSR) {
                               seen |= XUSR;
                               if a.type is ALLOW {
                                   mode |= XUSR;
                               }
                           }
                           if ! (seen & XGRP) {
                               seen |= XGRP;
                               if a.type is ALLOW {
                                   mode |= XGRP;
                               }
                           }
                           if ! (seen & XOTH) {
                               seen |= XOTH;
                               if a.type is ALLOW {
                                   mode |= XOTH;
                               }
                           }
                       }
                   }
               }
           }
           return mode | (old_mode & (SUID | SGID | SVTX))
 
 3.16.6.2.  Applying the mode given to CREATE or OPEN to an inherited ACL
 
    The goal of implementing ACL inheritance is for newly created objects
    to inherit the ACLs they were intended to inherit, but without
    disregarding the mode that is given with the arguments to the CREATE
    or OPEN operations.  The general algorithm is as follows:
 
    1.  Form an ACL on the newly created object that is the concatenation
        of all inheritable ACEs from its parent directory.  Note that
        there may be zero inheritable ACEs; thus, an object may start
        with an empty ACL.
 
    2.  For each ACE in the new ACL, adjust its flags if necessary, and
        possibly create two ACEs in place of one.  This is necessary to
        honor the intent of the inheritance- related flags and to
        preserve information about the original inheritable ACEs in the
        case that they will be modified by other steps.  The algorithm is
        as follows:
 
        A.  If the ACE4_NO_PROPAGATE_INHERIT_ACE is set, or if the object
            being created is not a directory, then clear the following
            flags:
 
               ACE4_NO_PROPAGATE_INHERIT_ACE
 
               ACE4_FILE_INHERIT_ACE
 
               ACE4_DIRECTORY_INHERIT_ACE
 
               ACE4_INHERIT_ONLY_ACE
 
            Continue on to the next ACE.
 
        B.  If the object being created is a directory and
            ACE4_FILE_INHERIT_ACE is set, but ACE4_DIRECTORY_INHERIT_ACE
            is NOT set, then we ensure that ACE4_INHERIT_ONLY_ACE is set.
            Continue on to the next ACE.  Otherwise:
 
        C.  If the type of the ACE is neither ALLOW nor DENY, then
            continue on to the next ACE.
 
        D.  Copy the original ACE into a second, adjacent ACE.
 
        E.  On the first ACE, ensure that ACE4_INHERIT_ONLY_ACE is set.
 
        F.  On the second ACE, clear the following flags:
 
               ACE4_NO_PROPAGATE_INHERIT_ACE
 
               ACE4_FILE_INHERIT_ACE
 
               ACE4_DIRECTORY_INHERIT_ACE
 
               ACE4_INHERIT_ONLY_ACE
 
        G.  On the second ACE, if the type field is ALLOW, an
            implementation MAY clear the following mask bits:
 
               ACE4_WRITE_ACL
 
               ACE4_WRITE_OWNER

 Shepler                 Expires September 7, 2006              [Page 60]
 
 Internet-Draft           NFSv4 Minior Version 1               March 2006

    3.  To ensure that the mode is honored, apply the algorithm for
        applying a mode to a file/directory with an existing ACL on the
        new object as described in Section 3.16.6.3, using the mode that
        is to be used for file creation.
 
 3.16.6.3.  Applying a Mode to an Existing ACL
 
    An existing ACL can mean two things in this context.  One, that a
    file/directory already exists and it has an ACL.  Two, that a
    directory has inheritable ACEs that will make up the ACL for any new
    files or directories created therein.
 
    The high-level goal of the behavior when a mode is set on a file with
    an existing ACL is to take the new mode into account, without needing
    to delete a pre-existing ACL.
 
    When a mode is applied to an object, e.g. via SETATTR or CREATE/OPEN,
    the ACL must be modified to accommodate the mode.
 
    1.  The ACL is traversed, one ACE at a time.  For each ACE:
 
        1.  If the type of the ACE is neither ALLOW nor DENY, the ACE is
            left unchanged.  Continue to the next ACE.
 
        2.  If the ACE4_INHERIT_ONLY_ACE flag is set on the ACE, it is
            left unchanged.  Continue to the next ACE.
 
        3.  If either or both of ACE4_FILE_INHERIT_ACE or
            ACE4_DIRECTORY_INHERIT_ACE are set:
 
            1.  A copy of the ACE is made, and placed in the ACL
                immediately following the current ACE.
 
            2.  In the first ACE, the flag ACE4_INHERIT_ONLY_ACE is set.
 
            3.  In the second ACE, the following flags are cleared:
 
                   ACE4_FILE_INHERIT_ACE
 
                   ACE4_DIRECTORY_INHERIT_ACE
 
                   ACE4_NO_PROPAGATE_INHERIT_ACE
 
            The algorithm continues on with the second ACE.
 
        4.  If the "who" field is one of the following:
 
               OWNER@
 
               GROUP@
 
               EVERYONE@
 
            then the following mask bits are cleared:
 
               ACE4_READ_DATA / ACE4_LIST_DIRECTORY
 
               ACE4_WRITE_DATA / ACE4_ADD_FILE
 
               ACE4_APPEND_DATA / ACE4_ADD_SUBDIRECTORY
 
               ACE4_EXECUTE
 
            At this point, we proceed to the next ACE.
 
        5.  Otherwise, if the "who" field did not match one of OWNER@,
            GROUP@, or EVERYONE@, the following steps SHOULD be
            performed.
 
            1.  If the type of the ACE is ALLOW, we check the preceding
                ACE (if any).  If it does not meet all of the following
                criteria:
 
                1.  The type field is DENY.
 
                2.  The who field is the same as the current ACE.
 
                3.  The flag bit ACE4_IDENTIFIER_GROUP is the same as it
                    is in the current ACE, and no other flag bits are
                    set.
 
                4.  The mask bits are a subset of the mask bits of the
                    current ACE, and are also a subset of the following:
 
                       ACE4_READ_DATA / ACE4_LIST_DIRECTORY
 
                       ACE4_WRITE_DATA / ACE4_ADD_FILE
 
                       ACE4_APPEND_DATA / ACE4_ADD_SUBDIRECTORY
 
                       ACE4_EXECUTE
 
                then an ACE of type DENY, with a who equal to the current
                ACE, flag bits equal to (<current-ACE-flags> &
                ACE4_IDENTIFIER_GROUP), and no mask bits, is prepended.
 
            2.  The following modifications are made to the prepended
                ACE.  The intent is to mask the following ACE to disallow
                ACE4_READ_DATA, ACE4_WRITE_DATA, ACE4_APPEND_DATA, or
                ACE4_EXECUTE, based upon the group permissions of the new
                mode.  As a special case, if the ACE matches the current
                owner of the file, the owner bits are used, rather than
                the group bits.  This is reflected in the algorithm
                below.
 
           Let there be three bits defined:
 
           #define READ    04
           #define WRITE   02
           #define EXEC    01
 
           Let "amode" be the new mode, right-shifted three
           bits, in order to have the group permission bits
           placed in the three low order bits of amode,
           i.e. amode = mode >> 3
 
           If ACE4_IDENTIFIER_GROUP is not set in the flags,
           and the "who" field of the ACE matches the owner
           of the file, we shift amode three more bits, in
           order to have the owner permission bits placed in
           the three low order bits of amode:
 
           amode = amode >> 3
 
           amode is now used as follows:
 
           If ACE4_READ_DATA is set on the current ACE:
                      If READ is set on amode:
                          ACE4_READ_DATA is cleared on the prepended ACE
                      else:
                          ACE4_READ_DATA is set on the prepended ACE
 
               If ACE4_WRITE_DATA is set on the current ACE:
                      If WRITE is set on amode:
                          ACE4_WRITE_DATA is cleared on the prepended ACE
                      else:
                          ACE4_WRITE_DATA is set on the prepended ACE
               If ACE4_APPEND_DATA is set on the current ACE:
                      If WRITE is set on amode:
                          ACE4_APPEND_DATA is cleared on the
                          prepended ACE
                      else:
                          ACE4_APPEND_DATA is set on the prepended ACE
 
               If ACE4_EXECUTE is set on the current ACE:
                      If EXEC is set on amode:
                          ACE4_EXECUTE is cleared on the prepended ACE
                      else:
                          ACE4_EXECUTE is set on the prepended ACE
 
            3.  To conform with POSIX, and prevent cases where the owner
                of the file is given permissions via an explicit group,
                we implement the following step.
 
                   If ACE4_IDENTIFIER_GROUP is set in the flags field of
                   the ALLOW ACE:
                       Let "mode" be the mode that we are chmoding to:
                           extramode = (mode >> 3) & 07
                           ownermode = mode >> 6
                           extramode &= ~ownermode
                       If extramode is not zero:
                           If extramode & READ:
                               Clear ACE4_READ_DATA in both the
                               prepended DENY ACE and the ALLOW ACE
                           If extramode & WRITE:
                               Clear ACE4_WRITE_DATA and ACE_APPEND_DATA
                               in both the prepended DENY ACE and the
                               ALLOW ACE
                       If extramode & EXEC:
                               Clear ACE4_EXECUTE in both the prepended
                               DENY ACE and the ALLOW ACE
 
    2.  If there are at least six ACEs, the final six ACEs are examined.
        If they are not equal to the following ACEs:
 
           A1) OWNER@:::DENY
           A2) OWNER@:ACE4_WRITE_ACL/ACE4_WRITE_OWNER/
               ACE4_WRITE_ATTRIBUTES/ACE4_WRITE_NAMED_ATTRIBUTES::ALLOW
           A3) GROUP@::ACE4_IDENTIFIER_GROUP:DENY
           A4) GROUP@::ACE4_IDENTIFIER_GROUP:ALLOW
           A5) EVERYONE@:ACE4_WRITE_ACL/ACE4_WRITE_OWNER/
               ACE4_WRITE_ATTRIBUTES/ACE4_WRITE_NAMED_ATTRIBUTES::DENY
           A6) EVERYONE@:ACE4_READ_ACL/ACE4_READ_ATTRIBUTES/
               ACE4_READ_NAMED_ATTRIBUTES/ACE4_SYNCHRONIZE::ALLOW
 
        Then six ACEs matching the above are appended.
 
    3.  The final six ACEs are adjusted according to the incoming mode.
 
           /* octal constants for the mode bits */
 
           RUSR = 0400
           WUSR = 0200
           XUSR = 0100
           RGRP = 0040
           WGRP = 0020
           XGRP = 0010
           ROTH = 0004
           WOTH = 0002
           XOTH = 0001
 
           If RUSR is set: set ACE4_READ_DATA in A2
               else: set ACE4_READ_DATA in A1
           If WUSR is set: set ACE4_WRITE_DATA and ACE4_APPEND_DATA in A2
               else: set ACE4_WRITE_DATA and ACE4_APPEND_DATA in A1
           If XUSR is set: set ACE4_EXECUTE in A2
               else: set ACE4_EXECUTE in A1
           If RGRP is set: set ACE4_READ_DATA in A4
               else: set ACE4_READ_DATA in A3
           If WGRP is set: set ACE4_WRITE_DATA and ACE4_APPEND_DATA in A4
               else: set ACE4_WRITE_DATA and ACE4_APPEND_DATA in A3
           If XGRP is set: set ACE4_EXECUTE in A4
               else: set ACE4_EXECUTE in A3
           If ROTH is set: set ACE4_READ_DATA in A6
               else: set ACE4_READ_DATA in A5
           If WOTH is set: set ACE4_WRITE_DATA and ACE4_APPEND_DATA in A6
               else: set ACE4_WRITE_DATA and ACE4_APPEND_DATA in A5
           If XOTH is set: set ACE4_EXECUTE in A6
               else: set ACE4_EXECUTE in A5
 
 3.16.6.4.  ACL and mode in the same SETATTR
 
    The only reason that a mode and ACL should be set in the same SETATTR
    is if the user wants to set the SUID, SGID and SVTX bits along with
    setting the permissions by means of an ACL.  There is still no way to
    enforce which order the attributes will be set in, and it is likely
    that different orders of operations will produce different results.
 
 3.16.6.4.1.  Client Side Recommendations
 
    If an application needs to enforce a certain behavior, it is
    recommended that the client implementations set mode and ACL in
    separate SETATTR requests.  This will produce consistent and expected
    results.
 
    If an application wants to set SUID, SGID and SVTX bits and an ACL:
 
       In the first SETATTR, set the mode with SUID, SGID and SVTX bits
       as desired and all other bits with a value of 0.
 
       In a following SETATTR (preferably in the same COMPOUND) set the
       ACL.
 
 3.16.6.4.2.  Server Side Recommendations
 
    If both mode and ACL are given to SETATTR, server implementations
    should verify that the mode and ACL don't conflict, i.e. the mode
    computed from the given ACL must be the same as the given mode,
    excluding the SUID, SGID and SVTX bits.  The algorithm for assigning
    a new mode based on the ACL can be used.  This is described in
    section Section 3.16.6.1.  If a server receives a request to set both
    mode and ACL, but the two conflict, the server should return
    NFS4ERR_INVAL.
 
 3.16.6.5.  Inheritance and turning it off
 
    The inheritance of access permissions may be problematic if a user
    cannot prevent their file from inheriting unwanted permissions.  For
    example, a user, "samf", sets up a shared project directory to be
    used by everyone working on Project Foo. "lisagab" is a part of
    Project Foo, but is working on something that should not be seen by
    anyone else.  How can "lisagab" make sure that any new files that she
    creates in this shared project directory do not inherit anything that
    could compromise the security of her work?
 
    More relevant to the implementors of NFS version 4 clients and
    servers is the question of how to communicate the fact that user,
    "lisagab", doesn't want any permissions to be inherited to her newly
    created file or directory.
 
    To do this, implementors should standardize on what the behavior of
    CREATE and OPEN must be if:
 
    1.  just mode is given
 
        In this case, inheritance will take place, but the mode will be
        applied to the inherited ACL as described in Section 3.16.6.1,
        thereby modifying the ACL.
 
    2.  just ACL is given
 
        In this case, inheritance will not take place, and the ACL as
        defined in the CREATE or OPEN will be set without modification.
 
    3.  both mode and ACL are given
 
        In this case, implementors should verify that the mode and ACL
        don't conflict, i.e. the mode computed from the given ACL must be
        the same as the given mode.  The algorithm for assigning a new
        mode based on the ACL can be used.  This is described in
        Section 3.16.6.1) If a server receives a request to set both mode
        and ACL, but the two conflict, the server should return
        NFS4ERR_INVAL.  If the mode and ACL don't conflict, inheritance
        will not take placeand both, the mode and ACL, will be set
        without modification.
 
    4.  neither mode nor ACL are given
 
        In this case, inheritance will take place and no modifications to
        the ACL will happen.  It is worth noting that if no inheritable
        ACEs exist on the parent directory, the file will be created with
        an empty ACL, thus granting no accesses.
 
 3.16.6.6.  Deficiencies in a Mode Representation of an ACL
 
    In the presence of an ACL, there are certain cases when the
    representation of the mode is not guaranteed to be accurate.  An
    example of a situation is detailed below.
 
    As mentioned in Section 3.16.6, the representation of the mode is
    deterministic, but not guaranteed to be accurate.  The mode bits
    potentially convey a more restrictive permission than what will
    actually be granted via the ACL.
 
    Given the following ACL of two ACEs:
 
           GROUP@:ACE4_READ_DATA/ACE4_WRITE_DATA/ACE4_EXECUTE:
               ACE4_IDENTIFIER_GROUP:ALLOW
           EVERYONE@:ACE4_READ_DATA/ACE4_WRITE_DATA/ACE4_EXECUTE::DENY
 
    we would compute a mode of 0070.  However, it is possible, even
    likely, that the owner might be a member of the object's owning
    group, and thus, the owner would be granted read, write, and execute
    access to the object.  This would conflict with the mode of 0070,
    where an owner would be denied this access.
 
    The only way to overcome this deficiency would be to determine
    whether the object's owner is a member of the object's owning group.
    This is difficult, but worse, on a POSIX or any UNIX-like system, it
    is a process' membership in a group that is important, not a user's.
    Thus, any fixed mode intended to represent the above ACL can be
    incorrect.
 
    Example: administrative databases (possibly /etc/passwd and /etc/
    group) indicate that the user "bob" is a member of the group "staff".
    An object has the ACL given above, is owned by "bob", and has an
    owning group of "staff".  User "bob" has logged into the system, and
    thus processes have been created owned by "bob" and having membership
    in group "staff".
 
    A mode representation of the above ACL could thus be 0770, due to
    user "bob" having membership in group "staff".  Now, the
    administrative databases are changed, such that user "bob" is no
    longer in group "staff".  User "bob" logs in to the system again, and
    thus more processes are created, this time owned by "bob" but NOT in
    group "staff".
 
    A mode of 0770 is inaccurate for processes not belonging to group
    "staff".  But even if the mode of the file were proactively changed
    to 0070 at the time the group database was edited, mode 0070 would be
    inaccurate for the pre-existing processes owned by user "bob" and
    having membership in group "staff".
_______________________________________________
nfsv4 mailing list
[email-masked]
https://www1.ietf.org/mailman/listinfo/nfsv4

---

From: Lisa Week <[email-masked]>
Date: Thu, 01 Jun 2006 17:23:30 -0600

Hi,

I just wanted to follow up on this based on the email that I just sent 
out which contains the additional changes to the description of the 
client's role in enforcing access based on comments from you all...

I have not made any additional changes to account for the case which is 
described below.  This is for the reason that I don't think that stating 
that a client should be able to read data when it has write-only access 
is a good thing.  I am not sure how many servers actually allow that.  
For one data point, our server doesn't allow it.

Also, that list is not meant to be an exhaustive list of the different 
server behaviors, just a summary of some of the most well known ones.

Given that anyone have any comments on this?

Thanks,
Lisa

Benny Halevy wrote:

> How about letting the client read data when it has write-only access?  
> This is required for clients that do read-modify-write on partial-page 
> updates.
> In this case the client OS needs to make sure that the data stays in 
> its cache and not returned to users without permission to read it.
>
> Benny
>
> Lisa Week wrote:
>
>> Lisa Week wrote:
>>
>>>
>>>
>>> J. Bruce Fields wrote:
>>>
>>>> On Mon, May 01, 2006 at 08:11:08PM -0600, Lisa Week wrote:
>>>>  
>>>>
>>>>> In both of these cases we potentially have the problem of the ACL 
>>>>> saying one thing and the server enforcing the other.  Right?  In 
>>>>> this situation you are relying on the client to enforce the access.
>>>>>
>>>>> Is this what you had in mind when you recommended adding a 
>>>>> discussion on the client's part in enforcing access?
>>>>>   
>>>>
>>>>
>>>>
>>>>
>>>> Yes.  The current language gives the impression that ACL 
>>>> enforcement is
>>>> performed purely by the server allowing or forbidding certain NFSv4
>>>> operations.  I think that over-simplifies.
>>>>
>>>> But maybe it would be enough just to add a paragraph with a brief
>>>> description of the cases we know about.  Sorry that I don't have
>>>> language to propose....
>>>>
>>>>  
>>>>
>>>
>>> I'll take a stab at it and we can work from there...
>>
>>
>>
>>
>> The client's role in access checking:
>>
>> ------
>> Clients must be aware of situations in which an object's ACL will 
>> define a certain access even though the server will not enforce it.  
>> In general, but especially in these situations, the client needs to 
>> do its part in the enforcement of access as defined by the ACL.  To 
>> do this, the client may issue the appropriate ACCESS operation prior 
>> to servicing the request of the user or application in order to 
>> determine whether the user or application should be granted the 
>> access requested.
>>
>> Known situations in which the ACL may define accesses that the server 
>> doesn't enforce:
>>
>> o Many UNIX-based servers will allow a user the ability to read the 
>> data of the file when only the execute permission is granted (i.e. If 
>> the ACL denies the user the ACE4_READ_DATA access and allows the user 
>> ACE4_EXECUTE, the server will allow the user to read the data of the 
>> file).  XXX should we add the reason?
>>
>> o Many servers have the notion of owner-override in which the owner 
>> of the object is allowed to override accesses that are denied by the 
>> ACL. XXX again, should we add the reason/rationale?
>> ------
>> Comments?
>>
>> Thanks,
>> Lisa
>>
>>

---

From: "J. Bruce Fields" <[email-masked]>
Date: Tue, 6 Jun 2006 18:35:46 -0400

> front means the lines were added.  Lines with "-" in front means the 

Looks OK to me.

> +	      user to attempt to read the data of the file.

A more succinct way of putting it might be something like:

	"... This is because there is no way to execute a file without
	reading the contents.

	"Though a server may treat ACE4_EXECUTE and AEC4_READ_DATA bits
	identically when deciding to permit a READ operation, it must
	still allow the two bits to be set independently in ACLs, and
	must distinguish between them when replying to ACCESS
	operations.  In particular, it must not silently turn on one of
	the two bits when the other is set, as that would make it
	impossible for the client to correctly enforce the distinction
	between read and execute permissions."

--b.

---

From: Lisa Week <[email-masked]>
Date: Fri, 09 Jun 2006 15:42:08 -0600

>>front means the lines were added.  Lines with "-" in front means the 

Cool.  Thanks for taking a look.

<snip>

>	between read and execute permissions."

Thanks.

I'll look into integrating this wording.  I will probably take pieces of 
the existing text (I think it would be good to keep the example) and 
this text to create the final version.

Thanks,
Lisa

---

From: Lisa Week <[email-masked]>
Date: Thu, 22 Jun 2006 00:11:19 -0600

Hi,

This is regarding Issue 56 - ACL: Clients role in enforcing access

Bruce, I have incorporated your feedback and have attached the final 
changes for review. 

Thanks,
Lisa

--- acl-minorversion.txt	Wed May 24 12:06:55 2006
+++ modified-acl-minorversion.txt	Wed Jun 21 23:53:22 2006
@@ -1,1160 +1,1214 @@
 3.16.  Access Control Lists

 
 
             struct nfsace4 {
                     acetype4        type;
                     aceflag4        flag;
                     acemask4        access_mask;
                     utf8str_mixed   who;
             };

 

 

 
 3.16.1.  ACE type

       Type         Description

 

 

 

 3.16.2.  ACE Access Mask

       ACE4_READ_DATA
          Operation(s) affected:
               READ
               OPEN
          Discussion:

       ACE4_WRITE_DATA
           Operation(s) affected:
               WRITE
               OPEN
           Discussion:
 
       ACE4_ADD_FILE
           Operation(s) affected:
               CREATE
               OPEN
           Discussion:
 
       ACE4_APPEND_DATA
           Operation(s) affected:
               WRITE
               OPEN
           Discussion:
 
       ACE4_ADD_SUBDIRECTORY
           Operation(s) affected:
               CREATE
           Discussion:
 
       ACE4_READ_NAMED_ATTRS
           Operation(s) affected:
               OPENATTR
           Discussion:
 
       ACE4_WRITE_NAMED_ATTRS
           Operation(s) affected:
               OPENATTR
           Discussion:
 
       ACE4_EXECUTE
           Operation(s) affected:
               LOOKUP
+	      READ
+	      OPEN
           Discussion:
 
+	      Servers SHOULD allow a user the ability to read the data
+	      of the file when only the ACE4_EXECUTE access mask bit is
+	      allowed.  This is because there is no way to execute a
+	      file without reading the contents.  Though a server may
+	      treat ACE4_EXECUTE and ACE4_READ_DATA bits identically
+	      when deciding to permit a READ operation, it SHOULD still
+	      allow the two bits to be set independently in ACLs, and
+	      MUST distinguish between them when replying to ACCESS
+	      operations.  In particular, servers SHOULD NOT silently
+	      turn on one of the two bits when the other is set, as
+	      that would make it impossible for the client to correctly
+	      enforce the distinction between read and execute
+	      permissions.
+
+		As an example, following a SETATTR of the following ACL:
+	      		nfsuser:ACE4_EXECUTE:ALLOW
+
+		A subsequent GETATTR of ACL for that file SHOULD return:
+			nfsuser:ACE4_EXECUTE:ALLOW
+		Rather than:
+			nfsuser:ACE4_EXECUTE/ACE4_READ_DATA:ALLOW
+
       ACE4_DELETE_CHILD
           Operation(s) affected:
               REMOVE
           Discussion:
               Permission to delete a file or directory within a
               directory.  See section "ACE4_DELETE vs.
               ACE4_DELETE_CHILD" for information on how these two access
               mask bits interact.
 
       ACE4_READ_ATTRIBUTES
           Operation(s) affected:
 
       ACE4_WRITE_ATTRIBUTES
           Operation(s) affected:
 
       ACE4_DELETE
           Operation(s) affected:
               REMOVE
           Discussion:
 
       ACE4_READ_ACL
           Operation(s) affected:
               GETATTR of acl
           Discussion:
 
       ACE4_WRITE_ACL
           Operation(s) affected:
               SETATTR of acl and mode
           Discussion:
 
       ACE4_WRITE_OWNER
           Operation(s) affected:
 
       ACE4_SYNCHRONIZE
           Operation(s) affected:
               NONE
           Discussion:

---

From: "J. Bruce Fields" <[email-masked]>
Date: Thu, 22 Jun 2006 09:25:30 -0400

> Bruce, I have incorporated your feedback and have attached the final 

Thanks!  Looks good to me.--b.