draft-ietf-nfsv4-acl-mapping-04.txt | draft-ietf-nfsv4-acl-mapping-05.txt | |||
---|---|---|---|---|
Network Working Group M. Eriksen | Network Working Group M. Eriksen | |||
Internet-Draft J. Fields | Internet-Draft J. Fields | |||
Expires: November 16, 2006 CITI | Expires: February 23, 2007 CITI | |||
May 15, 2006 | August 22, 2006 | |||
Mapping Between NFSv4 and Posix Draft ACLs | Mapping Between NFSv4 and Posix Draft ACLs | |||
draft-ietf-nfsv4-acl-mapping-04 | draft-ietf-nfsv4-acl-mapping-05 | |||
Status of this Memo | Status of this Memo | |||
By submitting this Internet-Draft, each author represents that any | By submitting this Internet-Draft, each author represents that any | |||
applicable patent or other IPR claims of which he or she is aware | applicable patent or other IPR claims of which he or she is aware | |||
have been or will be disclosed, and any of which he or she becomes | have been or will be disclosed, and any of which he or she becomes | |||
aware will be disclosed, in accordance with Section 6 of BCP 79. | aware will be disclosed, in accordance with Section 6 of BCP 79. | |||
Internet-Drafts are working documents of the Internet Engineering | Internet-Drafts are working documents of the Internet Engineering | |||
Task Force (IETF), its areas, and its working groups. Note that | Task Force (IETF), its areas, and its working groups. Note that | |||
skipping to change at page 1, line 34 | skipping to change at page 1, line 34 | |||
and may be updated, replaced, or obsoleted by other documents at any | and may be updated, replaced, or obsoleted by other documents at any | |||
time. It is inappropriate to use Internet-Drafts as reference | time. It is inappropriate to use Internet-Drafts as reference | |||
material or to cite them other than as "work in progress." | material or to cite them other than as "work in progress." | |||
The list of current Internet-Drafts can be accessed at | The list of current Internet-Drafts can be accessed at | |||
http://www.ietf.org/ietf/1id-abstracts.txt. | http://www.ietf.org/ietf/1id-abstracts.txt. | |||
The list of Internet-Draft Shadow Directories can be accessed at | The list of Internet-Draft Shadow Directories can be accessed at | |||
http://www.ietf.org/shadow.html. | http://www.ietf.org/shadow.html. | |||
This Internet-Draft will expire on November 16, 2006. | This Internet-Draft will expire on February 23, 2007. | |||
Copyright Notice | Copyright Notice | |||
Copyright (C) The Internet Society (2006). | Copyright (C) The Internet Society (2006). | |||
Abstract | Abstract | |||
A number of filesystems and applications support ACLs based on a | A number of filesystems and applications support ACLs based on a | |||
withdrawn POSIX draft [2]. Those ACLs differ significantly from NFS | withdrawn POSIX draft [2]. Those ACLs differ significantly from NFS | |||
version 4 (NFSv4) ACLs [1]. We describe how to translate between the | version 4 ACLs [1]. We describe how to translate between the two | |||
two types of ACLs. | types of ACLs. | |||
1. Introduction | 1. Introduction | |||
Access Control Lists (ACLs) are used to specify fine-grained access | Access Control Lists (ACLs) are used to specify access rights to file | |||
rights to file system objects. An ACL is a list of Access Control | system objects. An ACL is a list of Access Control Entries (ACEs), | |||
Entries (ACEs), each specifying an entity (such as a user) and some | each specifying an entity (such as a user) and some level of access | |||
level of access for that entity. | for that entity. | |||
In the following sections we describe two ACL models: NFSv4 ACLs, and | In the following sections describe NFSv4 ACLs and ACLs based on a | |||
ACLs based on a withdrawn POSIX draft. We will refer to the latter | withdrawn POSIX draft. We will refer to the latter as "POSIX ACLs". | |||
as "POSIX ACLs". Since NFSv4 ACLs are more fine-grained than POSIX | Since NFSv4 ACLs are more fine-grained than POSIX ACLs, it is not | |||
ACLs, it is not possible in general to map an arbitrary NFSv4 ACL to | possible in general to map an arbitrary NFSv4 ACL to a POSIX ACL with | |||
a POSIX ACL with the same semantics. However, it is possible to map | the same semantics. However, it is possible to map any POSIX ACL to | |||
any POSIX ACL to a NFSv4 ACL with nearly identical semantics, and it | a NFSv4 ACL with nearly identical semantics, and it is possible to | |||
is possible to map any NFSv4 ACL to a POSIX ACL in a way that | map any NFSv4 ACL to a POSIX ACL in a way that preserves certain | |||
preserves certain guarantees. We will explain how to do this, and | guarantees. We will explain how to do this, and give guidelines for | |||
give guidelines for clients and servers performing such translation. | clients and servers performing such translation. | |||
2. NFSv4 ACLs | 2. NFSv4 ACLs | |||
An NFSv4 ACL is an ordered sequence of ACEs, each having an entity, a | An NFSv4 ACL is an ordered sequence of ACEs, each having an entity, a | |||
type, some flags, and an access mask. | type, some flags, and an access mask. | |||
The entity may be the name of a user or group, or may be one of a | The entity may be the name of a user or group, or may be one of a | |||
small set of special entities. Among the special entities are | small set of special entities. Among the special entities are | |||
"OWNER@" (the current owner of the file), "GROUP@" (the group | "OWNER@" (the current owner of the file), "GROUP@" (the group | |||
associated with the file), and "EVERYONE@". | associated with the file), and "EVERYONE@". | |||
The type may be ALLOW or DENY. (AUDIT or ALARM are also allowed, but | An ACL may have a "type" of ALLOW or DENY. (AUDIT or ALARM are also | |||
they are not relevant to our discussion). | allowed, but they are not relevant to our discussion). | |||
The access mask has 14 separate bits, including bits to control read, | The access mask has 14 separate bits, including bits to control read, | |||
write, execute, append, ACL modification, file owner modification, | write, execute, append, ACL modification, file owner modification, | |||
etc.; consult [1] for the full list. | etc.; consult [1] for the full list. | |||
Of the flags, four are relevant here. The ACE4_IDENTIFIER_GROUP flag | Of the flags, four are relevant here. The ACE4_IDENTIFIER_GROUP flag | |||
is used to indicate that the entity name is the name of a group. The | is used to indicate that the entity name is the name of a group. The | |||
other three concern inheritance: ACE4_DIRECTORY_INHERIT_ACE indicates | other three concern inheritance: ACE4_DIRECTORY_INHERIT_ACE indicates | |||
that the ACE should be added to new subdirectories of the directory; | that the ACE should be added to new subdirectories of the directory; | |||
ACE4_FILE_INHERIT_ACE does the same for new files; and | ACE4_FILE_INHERIT_ACE does the same for new files; and | |||
ACE4_INHERIT_ONLY indicates that the ACE should be ignored when | ACE4_INHERIT_ONLY indicates that the ACE should be ignored when | |||
determining access to the directory itself. | determining access to the directory itself. | |||
The NFSv4 ACL permission-checking algorithm is straightforward. | The NFSv4 ACL permission-checking algorithm is straightforward. | |||
Assume a a requester asks for access, as specified by a single bit in | First, assume a requester asks for access specified by a single bit | |||
the access bitmask. We allow the access if the first ACE in the ACL | in the access bitmask. We allow the access if the first ACE in the | |||
that matches the requester and that has that bit set is an ALLOW ACE, | ACL that matches the requester and that has that bit set is an ALLOW | |||
and we deny the access if the first such ACE is a DENY ACE. If no | ACE, and we deny the access if the first such ACE is a DENY ACE. If | |||
matching ACE has the bit in question set, behaviour is undefined. If | no matching ACE has the bit in question set, access is normally | |||
an access mask consisting of more than one bit is requested, it | denied. | |||
succeeds if and only if each bit in the mask is allowed. | ||||
If a requester asks for access requiring multiple bits from the | ||||
access bitmask simutaneously, then we allow the access if and only if | ||||
each bit in the requested bitmask would be allowed individually. | ||||
We refer the reader to [1] for further details. | We refer the reader to [1] for further details. | |||
3. POSIX ACLs | 3. POSIX ACLs | |||
A number of operating systems implement ACLs based on the withdrawn | A number of operating systems implement ACLs based on the withdrawn | |||
POSIX 1003.1e/1003.2c Draft Standard 17 [2]. We will refer to such | POSIX 1003.1e/1003.2c Draft Standard 17 [2]. We will refer to such | |||
ACLs as "POSIX ACLs". | ACLs as "POSIX ACLs", though they are not part of any published POSIX | |||
standard. | ||||
POSIX ACLs use access masks with only the traditional "read", | POSIX ACLs use access masks with only the traditional "read", | |||
"write", and "execute" bits. Each ACE in a POSIX ACL is one of five | "write", and "execute" bits. Each ACE in a POSIX ACL is one of five | |||
types: ACL_USER_OBJ, ACL_USER, ACL_GROUP_OBJ, ACL_GROUP, ACL_MASK, | types: ACL_USER_OBJ, ACL_USER, ACL_GROUP_OBJ, ACL_GROUP, ACL_MASK, | |||
and ACL_OTHER. Each ACL_USER ACE has a uid associated with it, and | and ACL_OTHER. Each ACL_USER ACE has a uid associated with it, and | |||
each ACL_GROUP ACE has a gid associated with it. Every POSIX ACL | each ACL_GROUP ACE has a gid associated with it. Every POSIX ACL | |||
must have exactly one ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER ACE, | must have exactly one ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER ACE, | |||
and at most one ACL_MASK ACE. The ACL_MASK ACE is required if the | and at most one ACL_MASK ACE. The ACL_MASK ACE is required if the | |||
ACL has any ACL_USER or ACL_GROUP ACEs. There may not be two | ACL has any ACL_USER or ACL_GROUP ACEs. There may not be two | |||
ACL_USER ACEs with the same uid, and there may not be two ACL_GROUP | ACL_USER ACEs with the same uid, and there may not be two ACL_GROUP | |||
ACEs with the same gid. | ACEs with the same gid. | |||
Given a POSIX ACL and a requester asking for access, permission is | Given a POSIX ACL and a requester asking for access, permission is | |||
determined as follows: | determined by consulting the ACEs in the order ACL_USER_OBJ, | |||
ACL_USER, ACL_GROUP_OBJ, ACL_GROUP, ACL_OTHER, and allowing or | ||||
denying access based on the first ACE encountered that the requester | ||||
matches, except that we never allow the ACL_USER, ACL_OWNER_OBJ, or | ||||
ACL_GROUP objects to grant more than the ACL_MASK object does, and in | ||||
the case of ACL_GROUP_OBJ and ACL_GROUP ACEs, we allow access if any | ||||
one of those ACEs allows access. | ||||
In more detail: | ||||
1. If the requester is the file owner, then allow or deny access | 1. If the requester is the file owner, then allow or deny access | |||
depending on whether the ACL_USER_OBJ ACE allows or denies it. | depending on whether the ACL_USER_OBJ ACE allows or denies it. | |||
Otherwise, | Otherwise, | |||
2. if the requester's uid matches the uid of one of the ACL_USER | 2. if the requester matches the file's group, and the ACL mask ACE | |||
would deny the requested access, then skip to step 5. Otherwise, | ||||
3. if the requester's uid matches the uid of one of the ACL_USER | ||||
ACEs, then allow or deny access depending on whether the | ACEs, then allow or deny access depending on whether the | |||
ACL_USER_OBJ ACE allows or denies it. Otherwise, | ACL_USER_OBJ ACE allows or denies it. Otherwise, | |||
3. Consider the set of all ACL_GROUP ACEs whose gid the requester is | 4. Consider the set of all ACL_GROUP ACEs whose gid the requester is | |||
a member of. Add to that set the ACL_GROUP_OBJ ACE, if the | a member of. Add to that set the ACL_GROUP_OBJ ACE, if the | |||
requester is also a member of the file's group. Allow access if | requester is also a member of the file's group. Allow access if | |||
any ACE in the resulting set allows access. If the set of | any ACE in the resulting set allows access. If the set of | |||
matching ACEs is nonempty, and none allow access, then deny | matching ACEs is nonempty, and none allow access, then deny | |||
access. Otherwise, if the set of matching ACEs is empty, | access. Otherwise, if the set of matching ACEs is empty, | |||
5. if the requester's access mask is allowed by the ACL_OTHER ACE, | ||||
4. if the requester's access mask is allowed by the ACL_OTHER ACE, | ||||
then grant access. Otherwise, deny access. | then grant access. Otherwise, deny access. | |||
The above description omits one detail: in steps (2) and (3), the | ||||
requested bits must be granted both by the matching ACE and by the | ||||
ACL_MASK ACE. The ACL_MASK ACE thus limits the maximum permissions | ||||
which may be granted by any ACL_USER or ACL_GROUP ACE, or by the | ||||
ACL_GROUP_OBJ ACE. | ||||
Each file may have a single POSIX ACL associated with it, used to | Each file may have a single POSIX ACL associated with it, used to | |||
determine access to that file. Directories, however, may have two | determine access to that file. Directories, however, may have two | |||
ACLs: one, the "access ACL", used to determine access to the | ACLs: one, the "access ACL", used to determine access to the | |||
directory, and one, the "default ACL", used only as the ACL to be | directory, and one, the "default ACL", used only as the ACL to be | |||
inherited by newly created objects in the directory. | inherited by newly created objects in the directory. | |||
4. Ordering of NFSv4 and POSIX ACLs | 4. Ordering of NFSv4 and POSIX ACLs | |||
POSIX ACLs are unordered--the order in which the POSIX access- | POSIX ACLs are unordered--the order in which the POSIX access- | |||
checking algorithm considers the entries is determined entirely by | checking algorithm considers the entries is determined entirely by | |||
skipping to change at page 8, line 10 | skipping to change at page 8, line 10 | |||
The NFSv4 ACL permission-checking algorithm has the property that it | The NFSv4 ACL permission-checking algorithm has the property that it | |||
permits a group of bits whenever it would permit each bit | permits a group of bits whenever it would permit each bit | |||
individually, so it is impossible to mimic this behaviour with an | individually, so it is impossible to mimic this behaviour with an | |||
NFSv4 ACL. | NFSv4 ACL. | |||
6. Mapping POSIX ACLs to NFSv4 ACLs | 6. Mapping POSIX ACLs to NFSv4 ACLs | |||
6.1. Requirements | 6.1. Requirements | |||
In the next section we give an example of a mapping of POSIX ACLs | In the next section we give an example of a mapping of POSIX ACLs | |||
into NFSv4 ACLs. We permit a server or client to use a different | into NFSv4 ACLs. A server or client may use a different mapping, but | |||
mapping, provided the mapping meets the following requirements: | the mapping should meet the following requirements: | |||
It must map the POSIX ACL to an NFSv4 ACL with identical access | It must map the POSIX ACL to an NFSv4 ACL with identical access | |||
semantics, ignoring the minor exception described in the previous | semantics, ignoring the minor exception described in the previous | |||
section. | section. | |||
It must map the read mode bit to ACE4_READ_DATA, the write bit to | It must map the read mode bit to ACE4_READ_DATA, the write bit to | |||
ACE4_WRITE_DATA and ACE4_APPEND_DATA (and ACE4_DELETE_CHILD for | ACE4_WRITE_DATA and ACE4_APPEND_DATA (and ACE4_DELETE_CHILD for | |||
directories), and the EXECUTE bit to ACE4_EXECUTE. It should also | directories), and the EXECUTE bit to ACE4_EXECUTE. It should also | |||
allow ACE4_READ_ACL, ACE4_READ_ATTRIBUTES, and ACE4_SYNCHRONIZE | allow ACE4_READ_ACL, ACE4_READ_ATTRIBUTES, and ACE4_SYNCHRONIZE | |||
unconditionally, and allow ACE4_WRITE_ACL and ACE4_WRITE_ATTRIBUTES | unconditionally, and allow ACE4_WRITE_ACL and ACE4_WRITE_ATTRIBUTES | |||
to the owner. The handling of other NFSv4 mode bits may depend on | to the owner. The handling of other NFSv4 mode bits may depend on | |||
the implementation, but it is preferable to leave them unused. | the implementation, but it is preferable to leave them unused. | |||
It should avoid using DENY ACEs. If DENY ACEs are required, it | It should avoid using DENY ACEs. If DENY ACEs are required, it | |||
should attempt to place them at the beginning. (This is not always | should attempt to place them at the beginning. (This is not always | |||
possible.) | possible.) | |||
For simplicity's sake, the translator may choose to handle the mask | The resulting NFSv4 ACL must take into account the mask ACE, by | |||
by first applying it to the USER, GROUP, and GROUP_OBJ ACEs, and then | ensuring that it does not give the group file owner or any users or | |||
mapping the resulting ACL. However, that will result in an ACL from | groups named in the ACL more permissions than permitted by the mask. | |||
which it is impossible to determine the original value of the mask or | It would also be possible to specify a mapping that encoded the mask | |||
of the masked USER, GROUP, and GROUP_OBJ bitmasks. If the resulting | in such a way that the original value of the mask could be recovered | |||
ACL is later translated back to a POSIX ACL, the translator will | by someone that knew the ACL was produced by our algorithm. However, | |||
assume that the value of the mask is the union of the bitmasks | the added complexity and fragility of such a mapping is not worth the | |||
permitted to any USER, GROUP, or GROUP_OBJ. If that would be | small benefit of preserving the mask information, so we do not | |||
incorrect, the original translation should not modify the bitmasks of | attempt that here. | |||
the USER, GROUP, and GROUP_OBJ bitmasks, and should instead use | ||||
additional DENY ACEs as necessary to give the effect of the mask. It | ||||
should also arrange for the first GROUP@ ACE to be a DENY ACE whose | ||||
bitmask is determined by the mask, allowing that ACE to be used to | ||||
determine the original mask value. | ||||
6.2. Example POSIX->NFSv4 Mapping | 6.2. Example POSIX->NFSv4 Mapping | |||
We now describe an algorithm which maps any POSIX ACL to an NFSv4 ACL | We now describe an algorithm which maps any POSIX ACL to an NFSv4 ACL | |||
with the same semantics, meeting the above requirements. | with the same semantics, meeting the above requirements. | |||
First, translate the uid's and gid's on the ACL_USER and ACL_GROUP | First, modify all ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ ACEs by | |||
ACEs into NFSv4 names, using directory services, etc., as | removing any permissions not granted by the mask ACE. The mask ACE | |||
appropriate, and translate ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER | may then be ignored for the rest of this process. | |||
to the special NFSv4 names "OWNER@", "GROUP@", and "EVERYONE@", | ||||
respectively. | Translate the uid's and gid's on the ACL_USER and ACL_GROUP ACEs into | |||
NFSv4 names, using directory services, etc., as appropriate, and | ||||
translate ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER to the special | ||||
NFSv4 names "OWNER@", "GROUP@", and "EVERYONE@", respectively. | ||||
Next, map each POSIX ACE (excepting any mask ACE) in the given POSIX | Next, map each POSIX ACE (excepting any mask ACE) in the given POSIX | |||
ACL to an NFSv4 ALLOW ACE with an entity determined as above, and | ACL to an NFSv4 ALLOW ACE with an entity determined as above, and | |||
with a bitmask determined from the permission bits on the POSIX ACE | with a bitmask determined from the permission bits on the POSIX ACE | |||
as follows: | as follows: | |||
1. If the read bit is set in the POSIX ACE, then set ACE4_READ_DATA. | 1. If the read bit is set in the POSIX ACE, then set ACE4_READ_DATA. | |||
2. If the write bit is set in the POSIX ACE, then set | 2. If the write bit is set in the POSIX ACE, then set | |||
ACE4_WRITE_DATA and ACE4_APPEND_DATA. If the object carrying the | ACE4_WRITE_DATA and ACE4_APPEND_DATA. If the object carrying the | |||
skipping to change at page 9, line 28 | skipping to change at page 9, line 27 | |||
ACE4_EXECUTE. | ACE4_EXECUTE. | |||
4. Set ACE4_READ_ACL, ACE4_READ_ATTRIBUTES, and ACE4_SYNCHRONIZE | 4. Set ACE4_READ_ACL, ACE4_READ_ATTRIBUTES, and ACE4_SYNCHRONIZE | |||
unconditionally. | unconditionally. | |||
5. If the ACE is for the special "OWNER@" entity, set ACE4_WRITE_ACL | 5. If the ACE is for the special "OWNER@" entity, set ACE4_WRITE_ACL | |||
and ACE4_WRITE_ATTRIBUTES. | and ACE4_WRITE_ATTRIBUTES. | |||
6. Clear all other bits in the NFSv4 bitmask. | 6. Clear all other bits in the NFSv4 bitmask. | |||
In addition, we set the GROUP flag in each ACE which corresponds to a | In addition, set the GROUP flag in each ACE which corresponds to a | |||
named group (but not in the GROUP@ ACE, or any of the other special | named group (but not in the GROUP@ ACE, or any of the other special | |||
entity ACEs). | entity ACEs). | |||
At this point, we've replaced the POSIX ACL by an NFSv4 ACL with the | At this point, we've replaced the POSIX ACL by an NFSv4 ACL with the | |||
same number of ACEs (ignoring any mask ACE), all of them ALLOW ACEs. | same number of ACEs (ignoring any mask ACE), all of them ALLOW ACEs. | |||
Order this NFSv4 ACL in the canonical order: OWNER@, users, GROUP@, | Order this NFSv4 ACL in the canonical order: OWNER@, users, GROUP@, | |||
groups, then EVERYONE@. | groups, then EVERYONE@. | |||
If the bitmasks in the resulting ACEs are non-increasing (so no ACE | If the bitmasks in the resulting ACEs are non-increasing (so no ACE | |||
allows a bit not allowed by a previous ACE), then we can skip the | allows a bit not allowed by a previous ACE), then we can skip the | |||
next step. | next step. | |||
Otherwise, we need to insert additional DENY ACE's to emulate the | Otherwise, we need to insert additional DENY ACE's to emulate the | |||
first-match semantics of the POSIX ACL permission-checking algorithm: | first-match semantics of the POSIX ACL permission-checking algorithm: | |||
1. If an ACL_USER_OBJ, ACL_OTHER, or ACL_USER ACE fails to grant | 1. If an ACL_USER_OBJ, ACL_OTHER, or ACL_USER ACE fails to grant | |||
some permissions that are granted later in the ACL, then that ACE | some permissions that are granted later in the ACL, then that ACE | |||
must be prepended by a single DENY ACE. The DENY ACE should have | must be preceded by a single DENY ACE. The DENY ACE should have | |||
the same entity and flags as the corresponding ALLOW ACE, but the | the same entity and flags as the corresponding ALLOW ACE, but the | |||
bitmask on the DENY ACE should be the bitwise NOT of the bitmask | bitmask on the DENY ACE should be the bitwise NOT of the bitmask | |||
on the ALLOW ACE, except that the ACE4_WRITE_OWNER, ACE4_DELETE, | on the ALLOW ACE, except that the ACE4_WRITE_OWNER, ACE4_DELETE, | |||
ACE4_READ_NAMED_ATTRIBUTES, ACE4_WRITE_NAMED_ATTRIBUTES bits | ACE4_READ_NAMED_ATTRIBUTES, and ACE4_WRITE_NAMED_ATTRIBUTES bits | |||
should be cleared, and the ACE4_DELETE_CHILD bit should be | should be cleared, and the ACE4_DELETE_CHILD bit should be | |||
cleared on non-directories. (Also, in the xdr-encoded ACL that | cleared on non-directories. (Also, in the xdr-encoded ACL that | |||
is transmitted, all bits not defined in the protocol should be | is transmitted, all bits not defined in the protocol should be | |||
cleared.) | cleared.) | |||
2. All of the ACL_GROUP_OBJ and ACL_GROUP ACEs are consulted by the | 2. All of the ACL_GROUP_OBJ and ACL_GROUP ACEs are consulted by the | |||
POSIX algorithm before determining permissions. To emulate this | POSIX algorithm before determining permissions. To emulate this | |||
behaviour, instead of adding a single DENY before corresponding | behaviour, instead of adding a single DENY before corresponding | |||
GROUP@ or named group ACEs, we insert a list of DENY ACEs after | GROUP@ or named group ACEs, we insert a list of DENY ACEs after | |||
the list of GROUP@ and named group ACEs. Each DENY ACE is | the list of GROUP@ and named group ACEs. Each DENY ACE is | |||
determined from its corresponding ALLOW ACE exactly as in the | determined from its corresponding ALLOW ACE exactly as in the | |||
previous step. As before, these DENY aces should only be added | previous step. As before, these DENY ACEs should only be added | |||
when they are necessitated by an ACE that is less permissive than | when they are necessitated by an ACE that is less permissive than | |||
the final EVERYONE@ ace. | the final EVERYONE@ ACE. | |||
Finally, we enforce the POSIX mask ACE by prepending each ALLOW ACE | ||||
for a named user, GROUP@, or named group, with a single DENY ACE | ||||
whose entity and flags are the same as those for the corresponding | ||||
ALLOW ACE, but whose bitmask is the inverse of the bitmask determined | ||||
from the mask ACE, with the inverse calculated as described above. | ||||
In the case of named users, these DENY aces may be coalesced with any | ||||
existing prepended DENY aces. The DENY aces are omitted entirely if | ||||
they would have no affect, or if the mask ACE has the same bitmask as | ||||
the maximum of the affected ACEs. (With the one exception that if | ||||
the POSIX ACL posesses exactly 4 ACEs, then a mask-derived DENY ace | ||||
should be inserted before the GROUP@ ace, even if it would not | ||||
otherwise be.) | ||||
Regardless of what scheme is used to represent the mask, the receiver | ||||
will use the first GROUP@ DENY ace to determine the value of the mask | ||||
(if it is different from the union of the bitmasks on the affected | ||||
ACEs), and use the relevant ALLOWs to determine the pre-mask values | ||||
of user and group ACEs. | ||||
The implementation may also choose to just mask out the bitmasks on | ||||
the relevant ALLOW ACEs. This will produce a simpler ACL (in | ||||
particular, an ACL that usually requires no DENY ACE's), at the | ||||
expense of losing some ACL information after a chmod. | ||||
On directories with default ACLs, we translate the default ACL as | On directories with default ACLs, we translate the default ACL as | |||
above, but set the ACE4_INHERIT_ONLY_ACE, ACE4_DIRECTORY_INHERIT_ACE, | above, but set the ACE4_INHERIT_ONLY_ACE, ACE4_DIRECTORY_INHERIT_ACE, | |||
and ACE4_FILE_INHERIT_ACE flags on every ACE in the resulting ACL. | and ACE4_FILE_INHERIT_ACE flags on every ACE in the resulting ACL. | |||
On directories with both default and access ACLs, we translate the | On directories with both default and access ACLs, we translate the | |||
two ACLs and then concatenate them. The order of the concatenation | two ACLs and then concatenate them. The order of the concatenation | |||
is unimportant. | is unimportant. | |||
7. Mapping NFSv4 ACLs to POSIX ACLs | 7. Mapping NFSv4 ACLs to POSIX ACLs | |||
7.1. Requirements | 7.1. Requirements | |||
Any mapping of NFSv4 ACLs to POSIX ACLs must map any NFSv4 ACL that | Any mapping of NFSv4 ACLs to POSIX ACLs must map any NFSv4 ACL that | |||
is semantically equivalent to a POSIX ACL (with the exception of the | is semantically equivalent to a POSIX ACL (with the exception of the | |||
"minor inaccuracy" mentioned above) to the equivalent POSIX ACL. It | "minor inaccuracy" mentioned above) to an equivalent POSIX ACL. | |||
should also extract the mask correctly; as the mask doesn't affect | ||||
the semantics of the NFSv4 ACL, and as there is more than one way the | ||||
mask might be encoded, we require a convention for this. | ||||
Specifically: we require that the mask be computed as the bitmask | ||||
used on the first GROUP@ DENY ACE which precedes any GROUP@ allow | ||||
ACE, unless no such DENY ACE exists, in which case the mask must be | ||||
computed as the union of the bitmasks allowed to all named users, | ||||
groups, and GROUP@ (where by the "bitmask allowed to" an entity we | ||||
mean the maximum bitmask that the ACL would permit to any user | ||||
matching the entity). | ||||
Implementations may vary in how they deal with NFSv4 ACLs that are | However, a more difficult problem is presented by NFSv4 ACLs that are | |||
not precisely semantically equivalent to any POSIX ACL. In | not precisely equivalant to any POSIX ACL. | |||
particular they may return errors for such ACLs instead of attempting | ||||
to map them. However, when possible without compromising security, | The only way that the NFSv4 protocol gives servers to indicate that | |||
they should attempt to be forgiving. | they support only a subset of the ACL model is the "aclsupport" | |||
attribute, which allows a server to advertise that it only supports | ||||
certain ACE types. This allows a server to report that it only | ||||
supports ALLOW ACEs, or that it does not support AUDIT or ALARM ACEs | ||||
(which will be the case for most servers with only POSIX ACLs). But | ||||
it does not give a way to claim support for more complex subsets of | ||||
the ACL model. | ||||
While it is possible for a server to reject any ACLs that do not fit | ||||
its ACL model, this places a large burden on clients and users, since | ||||
the server has no way to explain why it rejected a particular ACL. | ||||
Therefore, it is preferable to be more forgiving, whenever that is | ||||
possible without compromising security, and to limit any restrictions | ||||
to those that are easily documented and verified by users. | ||||
The language of [1] allows a server some flexibility in handling ACLs | The language of [1] allows a server some flexibility in handling ACLs | |||
that it cannot enforce completely accurately, as long as it adheres | that it cannot enforce completely accurately, as long as it adheres | |||
to "the guiding principle... that the server must not accept ACLs | to "the guiding principle... that the server must not accept ACLs | |||
that appear to make [a file] more secure than it really is." | that appear to make [a file] more secure than it really is." | |||
Note that an NFSv4 ACL consisting entirely of ALLOW ACLs can always | ACLs with arbitrary sequences of ALLOWs and DENYs may be particularly | |||
be transformed into a POSIX-equivalent ACL by first sorting it into | troublesome; but note that an NFSv4 ACL consisting entirely of ALLOW | |||
the canonical order, and then inserting DENY ACEs as necessary to | ACLs can always be transformed into a POSIX-equivalent ACL by first | |||
ensure POSIX first-match semantics. Since inserting DENY ACEs can | sorting it into the canonical order, then inserting DENY ACEs as | |||
only restrict access, it is safe for a server to do this. | necessary to ensure POSIX first-match semantics. Since inserting | |||
DENY ACEs can only restrict access, it is safe for a server to do | ||||
this. | ||||
We require any server to accept, at least, any NFSv4 ACL that | Therefore servers should accept, at least, any NFSv4 ACL that | |||
consists entirely of ALLOW ACLs. | consists entirely of ALLOW ACLs. | |||
Clients should also be at least as forgiving, to promote | Clients should also be at least as forgiving, to promote | |||
interoperability when heterogeneous clients share files. | interoperability when heterogeneous clients share files. | |||
7.2. Example NFSv4->POSIX Mapping | 7.2. Example NFSv4->POSIX Mapping | |||
We now give an example of an algorithm that meets the above | We now give an example of an algorithm that meets the above | |||
requirements. We assume it is to be used by a server mapping client- | requirements. We assume it is to be used by a server mapping client- | |||
provided NFSv4 ACLs to POSIX ACLs it can store in its filesystem, so | provided NFSv4 ACLs to POSIX ACLs it can store in its filesystem, so | |||
the translation errs on the side of making the ACL less permissive. | the translation errs on the side of making the ACL more restrictive. | |||
Given an NFSv4 ACL, first calculate the mask by taking the bitmask | In fact, if we ignore some loss of information in the mask ACE, this | |||
from the first GROUP@ DENY ACE from the original NFSv4 ACL, if it | mapping takes an NFSv4 ACL to the unique most permissive POSIX ACL | |||
exists. After doing so, remove that DENY ACE, and clear the bits in | that is no more permissive than the given NFSv4 ACL. | |||
its bitmask from any DENY ACE for a named user, group, or GROUP@ | ||||
which precedes an ALLOW ACE for the same entity. | ||||
In the case where there is no such GROUP@ DENY ACE, continue through | Before starting, if the ACL in question is for a directory, we split | |||
the rest of the algorithm and then calculate the mask as the union of | it into two ACLs, one purely effective and one purely inherited, as | |||
the calculated permissions of all named users, group, and the | follows: | |||
GROUP_OBJ ACE. | ||||
Given an NFSv4 ACL, sort it into canonical order (OWNER@ ACEs first, | 1. ACEs with no inheritance flags are put in the purely effective | |||
then user ACEs, then GROUP@ ACEs, then group ACEs, then EVERYONE@ | ACL. | |||
ACEs.) Also, sort the GROUP@ and group ACEs that all ALLOW ACEs | ||||
precede all DENY ACEs. To do so, take advantage of the following | ||||
observations: | ||||
1. If two consecutive ACEs are either both ALLOW ACEs, or both DENY | 2. Aces with FILE_INHERIT and DIRECTORY_INHERIT both set are put in | |||
ACEs, then we can swap their order without changing the effect of | both the effective and the inherited ACL | |||
the ACL. | ||||
2. If it would be impossible for a single user to match both of the | 3. Aces with FILE_INHERIT, DIRECTORY_INHERIT, and INHERIT_ONLY all | |||
entities on two consecutive ACEs, then we can swap their order | set are put only in the inherited ACL. | |||
without changing the effect of the ACL. | ||||
3. If an ALLOW ACE is immediately followed by a DENY ACE, then | Other combinations of ineritance flags may be rejected or silently | |||
swapping the order of the two ACEs will not make the ACL any more | modified to one of the above. | |||
permissive. | ||||
4. If a DENY ACE is immediately followed by an ALLOW ACE, then | The main algorithm that follows is then performed on each ACL, with | |||
swapping the order of the two ACEs will not make the ACL any more | one used to set the effictive ACL, and one the default ACL. | |||
permissive, *if* we modify the bitmask on the ALLOW ACE by | ||||
clearing any bits that are set in the DENY ACE. | ||||
The second observation is the trickiest: it may usually be safe to | First, we calculate the OTHER mode as follows: | |||
assume that two distinct user names cannot match the same user. An | ||||
implementation with knowledge about group memberships or about the | ||||
current value of the file owner might also use that information, but | ||||
if it does so it will produce a translation that is no longer | ||||
accurate after owners or group memberships change. | ||||
Fortunately, observations 1, 3, and 4 are sufficient to sort any ACL | 1. Initialize the bitmasks other_allow and other_deny both to zero. | |||
into canonical order, so a paranoid implementation can simply ignore | ||||
number 2 completely, while an implementation willing to sacrifice | ||||
some accuracy may choose to do something more complex. | ||||
Ensure that the resulting ACL posesses at least one each of OWNER@, | 2. For each ACE in the ACL, starting from the top: | |||
GROUP@, and EVERYONE@ ACEs, by inserting an ALLOW ACE with a zero | ||||
bitmask if necessary in the correct position. | ||||
Next, for each entity, calculate a bitmask for that entity as | 1. If the ACE is not an EVERYONE@ ACE, ignore it and move to the | |||
follows: Starting with the first ACE for that entity (ignoring all | next ACE. | |||
previous ACEs), perform the NFSv4 ACL-checking algorithm for a user | ||||
that is assumed to match the entity on every DENY ACE that a user | ||||
matching the given entity might match, but is assumed to match only | ||||
those entities on ALLOW ACEs that *any* user matching the current | ||||
entity must match. | ||||
Finally, construct the POSIX ACL by translating NFSv4 entity names to | 2. If the ACE is an EVERYONE@ ALLOW ACE, then add to other_allow | |||
uid's and gid's (and handling special entities in the obvious way), | any bits set in this ACE but not set in other_deny. | |||
then assign a POSIX bitmask determined by the NFSv4 bitmask | ||||
calculated in the previous step; the bitmask calculation should use | 3. If the ACE is an EVERYONE@ DENY ACE, then add to other_deny | |||
the inverse of the mapping described previously in the POSIX-to-NFSv4 | any bits set in this ACE but not set in other_allow. | |||
mapping, erring on the side of denying bits if it cannot determine a | ||||
sensible mapping. However, if certain bits simply cannot be mapped | 3. Discard other_deny. Set the USER_OBJ mask from other_allow using | |||
in a reasonable way to mode bits, the server may simply ignore them | the inverse of the mapping described previously in the POSIX-to- | |||
rather than returning an error. (For example, the server should deny | NFSv4 mapping, erring on the side of denying bits if it cannot | |||
write if either ACE4_WRITE_DATA or ACE4_APPEND_DATA are denied. But | determine a sensible mapping. However, if certain bits simply | |||
it may choose to ignore ACE4_READ_ATTRIBUTES entirely.) | cannot be mapped in a reasonable way to mode bits, the server may | |||
simply ignore them rather than returning an error. (For example, | ||||
the server should deny write if either ACE4_WRITE_DATA or | ||||
ACE4_APPEND_DATA are denied. But it may choose to ignore | ||||
ACE4_READ_ATTRIBUTES entirely; though in that case it may at | ||||
least want to treat specially the case where such bits are | ||||
explicitly denied by some DENY ACE.) | ||||
Note that the bits determined above are exactly the maximum bits that | ||||
will always be permitted to a user that doesn't match the file owner | ||||
or group, or any of the named owners or groups. Thus this choice of | ||||
the OTHER mode is exactly the maximum choice we can safely make. | ||||
Next we calculate the GROUP_OBJ and GROUP masks. | ||||
1. Initialize to zero an allow and deny bitmask for each GROUP_OBJ | ||||
and for each GROUP mask. | ||||
2. For each ACE in the ACL, starting from the top: | ||||
1. If the ACE is an OWNER@ or named user ACE, ignore it and move | ||||
to the next ACE. | ||||
2. If the ACE is an EVERYONE@ ALLOW ACE, then, for each GROUP or | ||||
GROUP_OBJ allow mask, set the bits allowed in the EVERYONE | ||||
ACE but not already in this GROUP or GROUP_OBJ's deny mask. | ||||
3. If the ACE is an EVERYONE@ DENY ACE, then, for each GROUP or | ||||
GROUP_OBJ deny mask, set the bits denied in the EVERYONE ACE | ||||
but not already allowed in this GROUP or GROUP_OBJ's deny | ||||
mask. | ||||
4. If the ACE is a GROUP or GROUP@ ALLOW ACE, then set the allow | ||||
bits in the corresponding GROUP or GROUP_OBJ allow mask that | ||||
are allowed by this ACE but not already denied by the | ||||
corresponding GROUP or GROUP_OBJ deny mask. | ||||
5. If the ACE is a GROUP or GROUP@ DENY ACE, then set the deny | ||||
bits in the corresponding GROUP or GROUP_OBJ deny mask that | ||||
are denied by this ACE but not already allowed by the | ||||
corresponding GROUP or GROUP_OBJ allow mask. Call the | ||||
resulting deny mask "m". In each GROUP or GROUP_OBJ deny | ||||
mask, set every bit that is in m and not already in that | ||||
GROUP or GROUP_OBJ allow mask. | ||||
3. Having calculated allow and deny masks for GROUP_OBJ and each | ||||
GROUP, we now set the corresponding modes from the allow masks as | ||||
we did in the last step of the USER_OBJ mask calculation above. | ||||
Note that the bits thus determined for a group are exactly the | ||||
maximum bits that will always be permitted to a user that matches the | ||||
group in question, and that is denied any bits that could be denied | ||||
by matching other groups, without out being allowed bits by matching | ||||
any such groups. This is the most permissive mode we can choose that | ||||
will never permit more permissions than the original NFSv4 ACL, for | ||||
any possible choice of group memberships. | ||||
An implementation with special knowledge about the current gowning | ||||
group or about group memberships may choose to use that knowledge to | ||||
calculate a more permissive mode. However, doing so may render | ||||
resulting POSIX ACL inaccurate after the owning group changes, or | ||||
after any group memberships change. | ||||
Next, we calculate USER modes by first calculating allow and deny | ||||
masks for each USER as above, this time assuming we are a user that | ||||
does not match the file owner, that matches no user except for the | ||||
one user under consideration, and that matches groups only when they | ||||
would deny some permissions that they have not allowed yet. (To | ||||
ensure this last step it will also be necessary to maintain group | ||||
allow and deny ACEs, as we did in the previous calculation.) We omit | ||||
the detailed steps, which are similar. Again, the implementation may | ||||
choose to use special knowledge about group memberships at the risk | ||||
of increased complexity and of loss of some accuracy. | ||||
Next, we calculate the USER_OBJ mode by calculating allow and deny | ||||
masks for a user that matches the file owner and any user or group | ||||
that denies bits that it does not first allow. | ||||
Finally, if the resulting ACL has any named user or group ACEs, add a | ||||
mask ACE with bitmask equal to the union of the calculated | ||||
permissions of all named users, group, and the GROUP_OBJ ACE. | ||||
The resulting mapping errs on the side of creating a more restrictive | The resulting mapping errs on the side of creating a more restrictive | |||
ACE. However it can be modified to produce a mapping that errs on | ACE. However it can be modified to produce a mapping that errs on | |||
the side of permissiveness, for the purposes of translating a server- | the side of permissiveness, for the purposes of translating a server- | |||
provided NFSv4 ACL to a POSIX ACL to present to a user or | provided NFSv4 ACL to a POSIX ACL to present to a user or | |||
application, as follows: | application, as follows: | |||
1. When sorting ACEs, ALLOW ACEs can always be moved towards the | 1. When performing the final mapping from the allow bitmask to a | |||
start of the ACL, but a DENY ACE can be moved towards the start | mode, we instead using a mapping that errs on the side of | |||
of the ACL only as long as we clear any of the DENY ACE's bitmask | permissiveness; for example, we allow write permissions even if | |||
bits that are set in the intervening ALLOW ACEs. | only one of WRITE_DATA, APPEND_DATA, or (in the case of | |||
directories) DELETE_CHILD is allowed. | ||||
2. When calculating the NFSv4 bitmask for each entity, err on the | 2. Wherever in the above we pessimistically assume that a user will | |||
side of assuming that ALLOW ACEs apply and that DENY ACEs don't, | match any entity that has permissions denied to it before they | |||
with the one exception that when calculating the GROUP@ and named | are first allowed, we instead assume that the user will match any | |||
group bitmasks, ALLOW ACEs for groups other than the one under | entity that has permissions allowed to it before they are first | |||
consideration should be ignored. | denied. | |||
3. When mapping the NFSv4 bitmask to POSIX mode bits, err on the | Once again, the resulting mapping may be seen to produce the unique | |||
side of allowing access. | (up to choice of mask) POSIX ACL which is the most restrictive among | |||
all POSIX ACLs no more restrictive than the given NFSv4 ACL. | ||||
8. Security Considerations | Note that the above algorithms may be optimized in a number of ways: | |||
for example, although they are described in terms of multiple passes, | ||||
it will be simpler and more efficient to calculate the entire POSIX | ||||
ACL in a single pass. | ||||
8. Backwards Compatibility | ||||
Previous versions of this document recommended a different | ||||
POSIX->NFSv4 mapping, which enforces POSIX semantics by inserting | ||||
DENYs into the ACL even when those DENY's would have no effect, and | ||||
which represents the POSIX mask ACE using additional DENYs. The | ||||
resulting ACLs are overly complex and create problems for Windows | ||||
clients, because the default Windows ACL editor prefers to order | ||||
DENYs before ALLOWs. | ||||
The NFSv4 to POSIX mapping we describe in this document can accept | ||||
the NFSv4 ACLs produced by the old mapping. | ||||
However, previous versions of this document also recommended | ||||
accepting only NFSv4 ACLs that were precisely those produced by the | ||||
old POSIX->NFSv4 mapping; therefore, existing implementations of that | ||||
recommendation will reject the NFSv4 ACLs produced by the newer | ||||
mapping. | ||||
We strongly recommend fixing implementations to accept a wider range | ||||
of NFSv4 ACLs. However, we briefly document the old mapping here in | ||||
case that is impossible: | ||||
Names, bitmasks, and flags are determined as in the the current | ||||
mapping. | ||||
Whenever the following instructions requiring taking "the complement" | ||||
of an NFSv4 bitmask, do so as follows: first, take the bitwise NOT of | ||||
the bitmask. Then clear the ACE4_WRITE_OWNER, ACE4_DELETE, | ||||
ACE4_READ_NAMED_ATTRIBUTES, and ACE4_WRITE_NAMED_ATTRIBUTES bits. | ||||
Also, clear the ACE4_DELETE_CHILD bit on non-directories, and clear | ||||
any bits not defined in the protocol. | ||||
Create one ALLOW ACE for each entity (OWNER@, GROUP@, and EVERYONE@, | ||||
and each user and group named in the given POSIX ACL). After each | ||||
OWNER@, EVERYONE@, and named user ACE, append a DENY ACE with the | ||||
same entity and flags as the corresponding ALLOW ACE, but with | ||||
bitmask set to the complement (as defined above) of the ALLOW ACE. | ||||
Do the same for each GROUP@ and named group ACE, but instead of | ||||
inserting each new DENY ACE after the corresponding ALLOW ACE, insert | ||||
all of the DENY ACEs at the end of the list of GROUP@ and named group | ||||
ACEs, in the same order that the GROUP@ and named group ALLOW ACEs | ||||
occur in. | ||||
Finally, prepend each GROUP@, named user, and named group ACE by a | ||||
single DENY whose entity and flags are the same as the corresponding | ||||
ALLOW, but whose bitmask is the complement (as defined above) of the | ||||
bitmask determined from the mask ACE in the given POSIX ACL. Skip | ||||
this step if the given POSIX ACL has no mask ACE. | ||||
9. Security Considerations | ||||
Any automatic mapping from one ACL model to another must provide | Any automatic mapping from one ACL model to another must provide | |||
guarantees as to how the mapping affects the meaning of ACLs, or risk | guarantees as to how the mapping affects the meaning of ACLs, or risk | |||
misleading users about the permissions set on filesystem objects. | misleading users about the permissions set on filesystem objects. | |||
For this reason, caution is recommended when implementing this | For this reason, caution is recommended when implementing this | |||
mapping. It is better to return errors than to break any such | mapping. It is better to return errors than to break any such | |||
guarantees. | guarantees. | |||
That said, there may be cases where small losses in accuracy can | That said, there may be cases where small losses in accuracy can | |||
avoid dramatic interoperability and usability problems; as long as | avoid dramatic interoperability and usability problems; as long as | |||
the losses in accuracy are clearly documented, these tradeoffs may be | the losses in accuracy are clearly documented, these tradeoffs may be | |||
found acceptable. | found acceptable. | |||
For example, a server unable to support all of the NFSv4 mode bits | For example, a server unable to support all of the NFSv4 mode bits | |||
does not have a way to communicate its exact limitations to clients, | does not have a way to communicate its exact limitations to clients, | |||
so clients (and users) may be unable to recover from such errors. | so clients (and users) may be unable to recover from such errors. | |||
For this reason we recommend ignoring bitmask bits that the server is | For this reason we recommend ignoring bitmask bits that the server is | |||
completely unable to map to mode bits, and advertising this fact | completely unable to map to mode bits, at least when no ACE | |||
loudly in the server documentation. If this is considered | explicitly contradicts the server's default behavior. If this is | |||
insufficient, we should add to the NFSv4 protocol additional | considered insufficient, we should add to the NFSv4 protocol | |||
attributes necessary to advertise the server's limitations. | additional attributes necessary to advertise the server's | |||
limitations. | ||||
Note also that this ACL mapping requires mapping between NFSv4 | Note also that any ACL mapping also requires mapping between NFSv4 | |||
usernames and local id's. When the mapping of id's depends on remote | usernames and local id's. When the mapping of id's depends on remote | |||
services, the method used for the mapping must be at least as secure | services, the method used for the mapping must be at least as secure | |||
as the method used to set or get ACLs. | as the method used to set or get ACLs. | |||
9. References | 10. References | |||
[1] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame, | [1] Shepler, S., Callaghan, B., Robinson, D., Thurlow, R., Beame, | |||
C., Eisler, M., and D. Noveck, "Network File System (NFS) | C., Eisler, M., and D. Noveck, "Network File System (NFS) | |||
version 4 Protocol", RFC 3530, April 2003. | version 4 Protocol", RFC 3530, April 2003. | |||
[2] Institute of Electrical and Electronics Engineers, Inc., "IEEE | [2] Institute of Electrical and Electronics Engineers, Inc., "IEEE | |||
Draft P1003.1e", October 1997, | Draft P1003.1e", October 1997, | |||
<http://wt.xpilot.org/publications/posix.1e/download.html>. | <http://wt.xpilot.org/publications/posix.1e/download.html>. | |||
Authors' Addresses | Authors' Addresses | |||
Marius Aamodt Eriksen | Marius Aamodt Eriksen | |||
U. of Michigan Center for Information Technology Integration | U. of Michigan Center for Information Technology Integration | |||
Email: marius@citi.umich.edu | Email: marius@citi.umich.edu | |||
J. Bruce Fields | J. Bruce Fields | |||
U. of Michigan Center for Information Technology Integration | U. of Michigan Center for Information Technology Integration | |||
Email: marius@citi.umich.edu | Email: bfields@citi.umich.edu | |||
Intellectual Property Statement | Intellectual Property Statement | |||
The IETF takes no position regarding the validity or scope of any | The IETF takes no position regarding the validity or scope of any | |||
Intellectual Property Rights or other rights that might be claimed to | Intellectual Property Rights or other rights that might be claimed to | |||
pertain to the implementation or use of the technology described in | pertain to the implementation or use of the technology described in | |||
this document or the extent to which any license under such rights | this document or the extent to which any license under such rights | |||
might or might not be available; nor does it represent that it has | might or might not be available; nor does it represent that it has | |||
made any independent effort to identify any such rights. Information | made any independent effort to identify any such rights. Information | |||
on the procedures with respect to rights in RFC documents can be | on the procedures with respect to rights in RFC documents can be | |||
End of changes. 47 change blocks. | ||||
190 lines changed or deleted | 290 lines changed or added | |||
This html diff was produced by rfcdiff 1.32. The latest version is available from http://www.levkowetz.com/ietf/tools/rfcdiff/ |