Skip to content

Commit c8d57f2

Browse files
committed
nfsv4: support anonymous state IDs for read and write
Motivation: rfc7530#section-9.1.4.3 defiles so-called anonymous state IDs (other and seq all ones) that allow file access without OPEN call. Modification: Update OperationREAD and OperationWRITE to accept anonymous state IDs. File permissions are still checked. Enable corresponding pynfs tests. Result: better spec compliance. Fixes: #160 Acked-by: Marina Sahakyan Target: master
1 parent 960bad8 commit c8d57f2

File tree

3 files changed

+54
-34
lines changed

3 files changed

+54
-34
lines changed

core/src/main/java/org/dcache/nfs/v4/OperationREAD.java

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.nio.ByteBuffer;
2424

2525
import org.dcache.nfs.nfsstat;
26+
import org.dcache.nfs.status.AccessException;
2627
import org.dcache.nfs.status.OpenModeException;
2728
import org.dcache.nfs.v4.xdr.READ4res;
2829
import org.dcache.nfs.v4.xdr.READ4resok;
@@ -47,24 +48,32 @@ public void process(CompoundContext context, nfs_resop4 result) throws IOExcepti
4748
final READ4res res = result.opread;
4849

4950
stateid4 stateid = Stateids.getCurrentStateidIfNeeded(context, _args.opread.stateid);
50-
51-
NFS4Client client;
52-
if (context.getMinorversion() == 0) {
53-
/*
54-
* The NFSv4.0 spec requires lease renewal on READ. See: https://tools.ietf.org/html/rfc7530#page-119
55-
*
56-
* With introduction of sessions in v4.1 update of the lease time done through SEQUENCE operations.
57-
*/
58-
context.getStateHandler().updateClientLeaseTime(stateid);
59-
client = context.getStateHandler().getClientIdByStateId(stateid);
51+
var inode = context.currentInode();
52+
if (Stateids.isStateLess(stateid)) {
53+
// Anonymous access as per RFC 7530
54+
// https://datatracker.ietf.org/doc/html/rfc7530#section-9.1.4.3
55+
// we only check file access rights.
56+
if (context.getFs().access(context.getSubject(), inode, nfs4_prot.ACCESS4_READ) == 0) {
57+
throw new AccessException();
58+
}
6059
} else {
61-
client = context.getSession().getClient();
62-
}
60+
NFS4Client client;
61+
if (context.getMinorversion() == 0) {
62+
/*
63+
* The NFSv4.0 spec requires lease renewal on READ. See: https://tools.ietf.org/html/rfc7530#page-119
64+
*
65+
* With introduction of sessions in v4.1 update of the lease time done through SEQUENCE operations.
66+
*/
67+
context.getStateHandler().updateClientLeaseTime(stateid);
68+
client = context.getStateHandler().getClientIdByStateId(stateid);
69+
} else {
70+
client = context.getSession().getClient();
71+
}
6372

64-
var inode = context.currentInode();
65-
int shareAccess = context.getStateHandler().getFileTracker().getShareAccess(client, inode, stateid);
66-
if ((shareAccess & nfs4_prot.OPEN4_SHARE_ACCESS_READ) == 0) {
67-
throw new OpenModeException("Invalid open mode");
73+
int shareAccess = context.getStateHandler().getFileTracker().getShareAccess(client, inode, stateid);
74+
if ((shareAccess & nfs4_prot.OPEN4_SHARE_ACCESS_READ) == 0) {
75+
throw new OpenModeException("Invalid open mode");
76+
}
6877
}
6978

7079
long offset = _args.opread.offset.value;

core/src/main/java/org/dcache/nfs/v4/OperationWRITE.java

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import org.dcache.nfs.ChimeraNFSException;
2525
import org.dcache.nfs.nfsstat;
26+
import org.dcache.nfs.status.AccessException;
2627
import org.dcache.nfs.status.InvalException;
2728
import org.dcache.nfs.status.IsDirException;
2829
import org.dcache.nfs.status.NfsIoException;
@@ -66,24 +67,34 @@ public void process(CompoundContext context, nfs_resop4 result) throws ChimeraNF
6667
throw new InvalException("path is a symlink");
6768
}
6869

69-
NFS4Client client;
70-
if (context.getMinorversion() == 0) {
71-
/*
72-
* The NFSv4.0 spec requires lease renewal on WRITE. See: https://tools.ietf.org/html/rfc7530#page-119
73-
*
74-
* With introduction of sessions in v4.1 update of the lease time done through SEQUENCE operations.
75-
*/
76-
context.getStateHandler().updateClientLeaseTime(stateid);
77-
client = context.getStateHandler().getClientIdByStateId(stateid);
78-
} else {
79-
client = context.getSession().getClient();
80-
}
81-
8270
var inode = context.currentInode();
71+
if (Stateids.isStateLess(stateid)) {
72+
// Anonymous access as per RFC 7530
73+
// https://datatracker.ietf.org/doc/html/rfc7530#section-9.1.4.3
74+
// we only check file access rights.
75+
if (context.getFs().access(context.getSubject(), inode, nfs4_prot.ACCESS4_MODIFY) == 0) {
76+
throw new AccessException();
77+
}
78+
79+
} else {
8380

84-
int shareAccess = context.getStateHandler().getFileTracker().getShareAccess(client, inode, stateid);
85-
if ((shareAccess & nfs4_prot.OPEN4_SHARE_ACCESS_WRITE) == 0) {
86-
throw new OpenModeException("Invalid open mode");
81+
NFS4Client client;
82+
if (context.getMinorversion() == 0) {
83+
/*
84+
* The NFSv4.0 spec requires lease renewal on WRITE. See: https://tools.ietf.org/html/rfc7530#page-119
85+
*
86+
* With introduction of sessions in v4.1 update of the lease time done through SEQUENCE operations.
87+
*/
88+
context.getStateHandler().updateClientLeaseTime(stateid);
89+
client = context.getStateHandler().getClientIdByStateId(stateid);
90+
} else {
91+
client = context.getSession().getClient();
92+
}
93+
94+
int shareAccess = context.getStateHandler().getFileTracker().getShareAccess(client, inode, stateid);
95+
if ((shareAccess & nfs4_prot.OPEN4_SHARE_ACCESS_WRITE) == 0) {
96+
throw new OpenModeException("Invalid open mode");
97+
}
8798
}
8899

89100
long offset = _args.opwrite.offset.value;

full-test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ services:
3232
noLKU9 noLKUNONE noLOCK12a noLOCK12b noLOCK13 noLOCKRNG noLOCKCHGU noLOCKCHGD noRLOWN3 \
3333
noOPCF1 noOPCF6 noOPDG2 noOPDG3 noOPDG6 noOPDG7 noOPEN15 noOPEN18 noOPEN2 noOPEN20 noOPEN22 \
3434
noOPEN23 noOPEN24 noOPEN26 noOPEN27 noOPEN28 noOPEN3 noOPEN30 noOPEN4 noRENEW3 noRD1 noRD10 \
35-
noRD2 noRD3 noRD5 noRD5a noRD6 noRD7a noRD7b noRD7c noRD7d noRD7f noRD7s noRDDR12 noRDDR11 \
35+
noRD3 noRD5 noRD5a noRD6 noRD7a noRD7b noRD7c noRD7d noRD7f noRD7s noRDDR12 noRDDR11 \
3636
noRPLY1 noRPLY10 noRPLY12 \
3737
noRPLY14 noRPLY2 noRPLY3 noRPLY5 noRPLY6 noRPLY7 noRPLY8 noRPLY9 \
38-
noSEC7 noWRT1 noWRT11 noWRT13 noWRT14 noWRT15 noWRT18 noWRT19 noWRT1b noWRT2 \
38+
noSEC7 noWRT1 noWRT11 noWRT13 noWRT14 noWRT15 noWRT18 noWRT19 noWRT1b \
3939
noWRT3 noWRT6a noWRT6b noWRT6c noWRT6d noWRT6f noWRT6s noWRT8 noWRT9
4040
/run-nfs4.1.sh --noinit --minorversion=2 --xml=/report/xunit-report-v41.xml nfs4j:/data all nochar nosocket noblock nofifo deleg \
4141
noCOUR2 noCSESS25 noCSESS26 noCSESS27 noCSESS28 noCSESS29 noCSID9 noDELEG2 noDELEG8 noEID5f \

0 commit comments

Comments
 (0)