Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/nfsserver/nfs_nfsdserv.c
39586 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1989, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Rick Macklem at The University of Guelph.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*
34
*/
35
36
#include <sys/cdefs.h>
37
#include "opt_inet.h"
38
#include "opt_inet6.h"
39
/*
40
* nfs version 2, 3 and 4 server calls to vnode ops
41
* - these routines generally have 3 phases
42
* 1 - break down and validate rpc request in mbuf list
43
* 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
44
* function in nfsd_port.c
45
* 3 - build the rpc reply in an mbuf list
46
* For nfsv4, these functions are called for each Op within the Compound RPC.
47
*/
48
49
#include <fs/nfs/nfsport.h>
50
#include <sys/extattr.h>
51
#include <sys/filio.h>
52
53
/* Global vars */
54
extern u_int32_t newnfs_false, newnfs_true;
55
extern __enum_uint8(vtype) nv34tov_type[8];
56
extern struct timeval nfsboottime;
57
extern int nfsrv_enable_crossmntpt;
58
extern int nfsrv_statehashsize;
59
extern int nfsrv_layouthashsize;
60
extern time_t nfsdev_time;
61
extern volatile int nfsrv_devidcnt;
62
extern int nfsd_debuglevel;
63
extern u_long sb_max_adj;
64
extern int nfsrv_pnfsatime;
65
extern int nfsrv_maxpnfsmirror;
66
extern uint32_t nfs_srvmaxio;
67
extern int nfsrv_issuedelegs;
68
69
static int nfs_async = 0;
70
SYSCTL_DECL(_vfs_nfsd);
71
SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
72
"Tell client that writes were synced even though they were not");
73
extern int nfsrv_doflexfile;
74
SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
75
&nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
76
static int nfsrv_linux42server = 1;
77
SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW,
78
&nfsrv_linux42server, 0,
79
"Enable Linux style NFSv4.2 server (non-RFC compliant)");
80
static bool nfsrv_openaccess = true;
81
SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW,
82
&nfsrv_openaccess, 0,
83
"Enable Linux style NFSv4 Open access check");
84
static char nfsrv_scope[NFSV4_OPAQUELIMIT];
85
SYSCTL_STRING(_vfs_nfsd, OID_AUTO, scope, CTLFLAG_RWTUN,
86
&nfsrv_scope, NFSV4_OPAQUELIMIT, "Server scope");
87
static char nfsrv_owner_major[NFSV4_OPAQUELIMIT];
88
SYSCTL_STRING(_vfs_nfsd, OID_AUTO, owner_major, CTLFLAG_RWTUN,
89
&nfsrv_owner_major, NFSV4_OPAQUELIMIT, "Server owner major");
90
static uint64_t nfsrv_owner_minor;
91
SYSCTL_U64(_vfs_nfsd, OID_AUTO, owner_minor, CTLFLAG_RWTUN,
92
&nfsrv_owner_minor, 0, "Server owner minor");
93
/*
94
* Only enable this if all your exported file systems
95
* (or pNFS DSs for the pNFS case) support VOP_ALLOCATE.
96
*/
97
static bool nfsrv_doallocate = false;
98
SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, enable_v42allocate, CTLFLAG_RW,
99
&nfsrv_doallocate, 0,
100
"Enable NFSv4.2 Allocate operation");
101
static uint64_t nfsrv_maxcopyrange = SSIZE_MAX;
102
SYSCTL_U64(_vfs_nfsd, OID_AUTO, maxcopyrange, CTLFLAG_RW,
103
&nfsrv_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable");
104
105
/*
106
* This list defines the GSS mechanisms supported.
107
* (Don't ask me how you get these strings from the RFC stuff like
108
* iso(1), org(3)... but someone did it, so I don't need to know.)
109
*/
110
static struct nfsgss_mechlist nfsgss_mechlist[] = {
111
{ 9, "\052\206\110\206\367\022\001\002\002", 11 },
112
{ 0, "", 0 },
113
};
114
115
/* local functions */
116
static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
117
struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
118
vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
119
int *diraft_retp, nfsattrbit_t *attrbitp,
120
NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
121
int pathlen);
122
static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
123
struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
124
vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
125
int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
126
NFSPROC_T *p, struct nfsexstuff *exp);
127
128
/*
129
* nfs access service (not a part of NFS V2)
130
*/
131
int
132
nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
133
vnode_t vp, struct nfsexstuff *exp)
134
{
135
u_int32_t *tl;
136
int getret, error = 0;
137
struct nfsvattr nva;
138
u_int32_t testmode, nfsmode, supported = 0;
139
accmode_t deletebit;
140
struct thread *p = curthread;
141
142
if (nd->nd_repstat) {
143
nfsrv_postopattr(nd, 1, &nva);
144
goto out;
145
}
146
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
147
nfsmode = fxdr_unsigned(u_int32_t, *tl);
148
if ((nd->nd_flag & ND_NFSV4) &&
149
(nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
150
NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
151
NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE |
152
NFSACCESS_XALIST))) {
153
nd->nd_repstat = NFSERR_INVAL;
154
vput(vp);
155
goto out;
156
}
157
if (nfsmode & NFSACCESS_READ) {
158
supported |= NFSACCESS_READ;
159
if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
160
NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
161
nfsmode &= ~NFSACCESS_READ;
162
}
163
if (nfsmode & NFSACCESS_MODIFY) {
164
supported |= NFSACCESS_MODIFY;
165
if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
166
NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
167
nfsmode &= ~NFSACCESS_MODIFY;
168
}
169
if (nfsmode & NFSACCESS_EXTEND) {
170
supported |= NFSACCESS_EXTEND;
171
if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
172
NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
173
nfsmode &= ~NFSACCESS_EXTEND;
174
}
175
if (nfsmode & NFSACCESS_XAREAD) {
176
supported |= NFSACCESS_XAREAD;
177
if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
178
NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
179
nfsmode &= ~NFSACCESS_XAREAD;
180
}
181
if (nfsmode & NFSACCESS_XAWRITE) {
182
supported |= NFSACCESS_XAWRITE;
183
if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
184
NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
185
nfsmode &= ~NFSACCESS_XAWRITE;
186
}
187
if (nfsmode & NFSACCESS_XALIST) {
188
supported |= NFSACCESS_XALIST;
189
if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
190
NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
191
nfsmode &= ~NFSACCESS_XALIST;
192
}
193
if (nfsmode & NFSACCESS_DELETE) {
194
supported |= NFSACCESS_DELETE;
195
if (vp->v_type == VDIR)
196
deletebit = VDELETE_CHILD;
197
else
198
deletebit = VDELETE;
199
if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
200
NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
201
nfsmode &= ~NFSACCESS_DELETE;
202
}
203
if (vp->v_type == VDIR)
204
testmode = NFSACCESS_LOOKUP;
205
else
206
testmode = NFSACCESS_EXECUTE;
207
if (nfsmode & testmode) {
208
supported |= (nfsmode & testmode);
209
if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
210
NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
211
nfsmode &= ~testmode;
212
}
213
nfsmode &= supported;
214
if (nd->nd_flag & ND_NFSV3) {
215
getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
216
nfsrv_postopattr(nd, getret, &nva);
217
}
218
vput(vp);
219
if (nd->nd_flag & ND_NFSV4) {
220
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
221
*tl++ = txdr_unsigned(supported);
222
} else
223
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
224
*tl = txdr_unsigned(nfsmode);
225
226
out:
227
NFSEXITCODE2(0, nd);
228
return (0);
229
nfsmout:
230
vput(vp);
231
NFSEXITCODE2(error, nd);
232
return (error);
233
}
234
235
/*
236
* nfs getattr service
237
*/
238
int
239
nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
240
vnode_t vp, __unused struct nfsexstuff *exp)
241
{
242
struct nfsvattr nva;
243
fhandle_t fh;
244
int at_root = 0, error = 0, ret, supports_nfsv4acls;
245
struct nfsreferral *refp;
246
nfsattrbit_t attrbits, tmpbits;
247
struct mount *mp;
248
struct vnode *tvp = NULL;
249
struct vattr va;
250
uint64_t mounted_on_fileno = 0;
251
accmode_t accmode;
252
struct thread *p = curthread;
253
size_t atsiz;
254
long pathval;
255
bool has_hiddensystem, has_namedattr, xattrsupp;
256
uint32_t clone_blksize;
257
258
if (nd->nd_repstat)
259
goto out;
260
if (nd->nd_flag & ND_NFSV4) {
261
error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
262
if (error) {
263
vput(vp);
264
goto out;
265
}
266
267
/*
268
* Check for a referral.
269
*/
270
refp = nfsv4root_getreferral(vp, NULL, 0);
271
if (refp != NULL) {
272
(void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
273
&nd->nd_repstat);
274
vput(vp);
275
goto out;
276
}
277
if (nd->nd_repstat == 0) {
278
accmode = 0;
279
NFSSET_ATTRBIT(&tmpbits, &attrbits);
280
281
/*
282
* GETATTR with write-only attr time_access_set and time_modify_set
283
* should return NFS4ERR_INVAL.
284
*/
285
if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
286
NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
287
error = NFSERR_INVAL;
288
vput(vp);
289
goto out;
290
}
291
if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
292
NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
293
accmode |= VREAD_ACL;
294
}
295
if (NFSNONZERO_ATTRBIT(&tmpbits))
296
accmode |= VREAD_ATTRIBUTES;
297
if (accmode != 0)
298
nd->nd_repstat = nfsvno_accchk(vp, accmode,
299
nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
300
NFSACCCHK_VPISLOCKED, NULL);
301
}
302
}
303
if (!nd->nd_repstat)
304
nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
305
if (!nd->nd_repstat) {
306
if (nd->nd_flag & ND_NFSV4) {
307
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
308
nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
309
if (!nd->nd_repstat)
310
nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
311
&nva, &attrbits, p);
312
if (nd->nd_repstat == 0) {
313
supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
314
xattrsupp = false;
315
if (NFSISSET_ATTRBIT(&attrbits,
316
NFSATTRBIT_XATTRSUPPORT)) {
317
ret = VOP_GETEXTATTR(vp,
318
EXTATTR_NAMESPACE_USER,
319
"xxx", NULL, &atsiz, nd->nd_cred,
320
p);
321
xattrsupp = ret != EOPNOTSUPP;
322
}
323
if (VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM,
324
&pathval) != 0)
325
pathval = 0;
326
has_hiddensystem = pathval > 0;
327
pathval = 0;
328
if (NFSISSET_ATTRBIT(&attrbits,
329
NFSATTRBIT_NAMEDATTR) &&
330
VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR,
331
&pathval) != 0)
332
pathval = 0;
333
has_namedattr = pathval > 0;
334
pathval = 0;
335
if (VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE,
336
&pathval) != 0)
337
pathval = 0;
338
clone_blksize = pathval;
339
mp = vp->v_mount;
340
if (nfsrv_enable_crossmntpt != 0 &&
341
vp->v_type == VDIR &&
342
(vp->v_vflag & VV_ROOT) != 0 &&
343
vp != rootvnode) {
344
tvp = mp->mnt_vnodecovered;
345
vref(tvp);
346
at_root = 1;
347
} else
348
at_root = 0;
349
vfs_ref(mp);
350
NFSVOPUNLOCK(vp);
351
if (at_root != 0) {
352
if ((nd->nd_repstat =
353
NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
354
nd->nd_repstat = VOP_GETATTR(
355
tvp, &va, nd->nd_cred);
356
vput(tvp);
357
} else
358
vrele(tvp);
359
if (nd->nd_repstat == 0)
360
mounted_on_fileno = (uint64_t)
361
va.va_fileid;
362
else
363
at_root = 0;
364
}
365
if (nd->nd_repstat == 0)
366
nd->nd_repstat = vfs_busy(mp, 0);
367
vfs_rel(mp);
368
if (nd->nd_repstat == 0) {
369
(void)nfsvno_fillattr(nd, mp, vp, &nva,
370
&fh, 0, &attrbits, nd->nd_cred, p,
371
isdgram, 1, supports_nfsv4acls,
372
at_root, mounted_on_fileno,
373
xattrsupp, has_hiddensystem,
374
has_namedattr, clone_blksize);
375
vfs_unbusy(mp);
376
}
377
vrele(vp);
378
} else
379
vput(vp);
380
} else {
381
nfsrv_fillattr(nd, &nva);
382
vput(vp);
383
}
384
} else {
385
vput(vp);
386
}
387
388
out:
389
NFSEXITCODE2(error, nd);
390
return (error);
391
}
392
393
/*
394
* nfs setattr service
395
*/
396
int
397
nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
398
vnode_t vp, struct nfsexstuff *exp)
399
{
400
struct nfsvattr nva, nva2;
401
u_int32_t *tl;
402
int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
403
int gotproxystateid;
404
struct timespec guard = { 0, 0 };
405
nfsattrbit_t attrbits, retbits;
406
nfsv4stateid_t stateid;
407
NFSACL_T *aclp = NULL;
408
struct thread *p = curthread;
409
410
NFSZERO_ATTRBIT(&retbits);
411
if (nd->nd_repstat) {
412
nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
413
goto out;
414
}
415
#ifdef NFS4_ACL_EXTATTR_NAME
416
aclp = acl_alloc(M_WAITOK);
417
aclp->acl_cnt = 0;
418
#endif
419
gotproxystateid = 0;
420
NFSVNO_ATTRINIT(&nva);
421
if (nd->nd_flag & ND_NFSV4) {
422
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
423
stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
424
stateid.other[0] = *tl++;
425
stateid.other[1] = *tl++;
426
stateid.other[2] = *tl;
427
if (stateid.other[0] == 0x55555555 &&
428
stateid.other[1] == 0x55555555 &&
429
stateid.other[2] == 0x55555555 &&
430
stateid.seqid == 0xffffffff)
431
gotproxystateid = 1;
432
}
433
error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
434
if (error)
435
goto nfsmout;
436
437
/* For NFSv4, only va_uid and va_flags is used from nva2. */
438
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
439
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN);
440
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM);
441
preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
442
if (!nd->nd_repstat)
443
nd->nd_repstat = preat_ret;
444
445
NFSZERO_ATTRBIT(&retbits);
446
if (nd->nd_flag & ND_NFSV3) {
447
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
448
gcheck = fxdr_unsigned(int, *tl);
449
if (gcheck) {
450
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
451
fxdr_nfsv3time(tl, &guard);
452
}
453
if (!nd->nd_repstat && gcheck &&
454
(nva2.na_ctime.tv_sec != guard.tv_sec ||
455
nva2.na_ctime.tv_nsec != guard.tv_nsec))
456
nd->nd_repstat = NFSERR_NOT_SYNC;
457
if (nd->nd_repstat) {
458
vput(vp);
459
#ifdef NFS4_ACL_EXTATTR_NAME
460
acl_free(aclp);
461
#endif
462
nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
463
goto out;
464
}
465
} else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
466
nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
467
468
/*
469
* Now that we have all the fields, lets do it.
470
* If the size is being changed write access is required, otherwise
471
* just check for a read only file system.
472
*/
473
if (!nd->nd_repstat) {
474
if (NFSVNO_NOTSETSIZE(&nva)) {
475
if (NFSVNO_EXRDONLY(exp) ||
476
(vp->v_mount->mnt_flag & MNT_RDONLY))
477
nd->nd_repstat = EROFS;
478
} else {
479
if (vp->v_type != VREG)
480
nd->nd_repstat = EINVAL;
481
else if (nva2.na_uid != nd->nd_cred->cr_uid ||
482
NFSVNO_EXSTRICTACCESS(exp))
483
nd->nd_repstat = nfsvno_accchk(vp,
484
VWRITE, nd->nd_cred, exp, p,
485
NFSACCCHK_NOOVERRIDE,
486
NFSACCCHK_VPISLOCKED, NULL);
487
}
488
}
489
/*
490
* Proxy operations from the MDS are allowed via the all 0s special
491
* stateid.
492
*/
493
if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
494
gotproxystateid == 0)
495
nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
496
&nva, &attrbits, exp, p);
497
498
if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
499
u_long oldflags;
500
501
oldflags = nva2.na_flags;
502
/*
503
* For V4, try setting the attributes in sets, so that the
504
* reply bitmap will be correct for an error case.
505
*/
506
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
507
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
508
NFSVNO_ATTRINIT(&nva2);
509
NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
510
NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
511
nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
512
exp);
513
if (!nd->nd_repstat) {
514
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
515
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
516
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
517
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
518
}
519
}
520
if (!nd->nd_repstat &&
521
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
522
NFSVNO_ATTRINIT(&nva2);
523
NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
524
nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
525
exp);
526
if (!nd->nd_repstat)
527
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
528
}
529
if (!nd->nd_repstat &&
530
(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
531
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
532
NFSVNO_ATTRINIT(&nva2);
533
NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
534
NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
535
if (nva.na_vaflags & VA_UTIMES_NULL) {
536
nva2.na_vaflags |= VA_UTIMES_NULL;
537
NFSVNO_SETACTIVE(&nva2, vaflags);
538
}
539
nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
540
exp);
541
if (!nd->nd_repstat) {
542
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
543
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
544
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
545
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
546
}
547
}
548
if (!nd->nd_repstat &&
549
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE)) {
550
NFSVNO_ATTRINIT(&nva2);
551
NFSVNO_SETATTRVAL(&nva2, btime, nva.na_btime);
552
nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
553
exp);
554
if (!nd->nd_repstat)
555
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMECREATE);
556
}
557
if (!nd->nd_repstat &&
558
(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
559
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
560
NFSVNO_ATTRINIT(&nva2);
561
NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
562
nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
563
exp);
564
if (!nd->nd_repstat) {
565
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
566
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
567
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
568
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
569
}
570
}
571
if (!nd->nd_repstat &&
572
(NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN) ||
573
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))) {
574
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) {
575
if ((nva.na_flags & UF_HIDDEN) != 0)
576
oldflags |= UF_HIDDEN;
577
else
578
oldflags &= ~UF_HIDDEN;
579
}
580
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM)) {
581
if ((nva.na_flags & UF_SYSTEM) != 0)
582
oldflags |= UF_SYSTEM;
583
else
584
oldflags &= ~UF_SYSTEM;
585
}
586
NFSVNO_ATTRINIT(&nva2);
587
NFSVNO_SETATTRVAL(&nva2, flags, oldflags);
588
nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
589
exp);
590
if (!nd->nd_repstat) {
591
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN))
592
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN);
593
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))
594
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM);
595
}
596
}
597
598
#ifdef NFS4_ACL_EXTATTR_NAME
599
if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
600
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
601
nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
602
if (!nd->nd_repstat)
603
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
604
}
605
#endif
606
} else if (!nd->nd_repstat) {
607
nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
608
exp);
609
}
610
if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
611
postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
612
if (!nd->nd_repstat)
613
nd->nd_repstat = postat_ret;
614
}
615
vput(vp);
616
#ifdef NFS4_ACL_EXTATTR_NAME
617
acl_free(aclp);
618
#endif
619
if (nd->nd_flag & ND_NFSV3)
620
nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
621
else if (nd->nd_flag & ND_NFSV4)
622
(void) nfsrv_putattrbit(nd, &retbits);
623
else if (!nd->nd_repstat)
624
nfsrv_fillattr(nd, &nva);
625
626
out:
627
NFSEXITCODE2(0, nd);
628
return (0);
629
nfsmout:
630
vput(vp);
631
#ifdef NFS4_ACL_EXTATTR_NAME
632
acl_free(aclp);
633
#endif
634
if (nd->nd_flag & ND_NFSV4) {
635
/*
636
* For all nd_repstat, the V4 reply includes a bitmap,
637
* even NFSERR_BADXDR, which is what this will end up
638
* returning.
639
*/
640
(void) nfsrv_putattrbit(nd, &retbits);
641
}
642
NFSEXITCODE2(error, nd);
643
return (error);
644
}
645
646
/*
647
* nfs lookup rpc
648
* (Also performs lookup parent for v4)
649
*/
650
int
651
nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
652
vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
653
{
654
struct nameidata named;
655
vnode_t vp, dirp = NULL;
656
int error = 0, dattr_ret = 1;
657
struct nfsvattr nva, dattr;
658
char *bufp;
659
u_long *hashp;
660
struct thread *p = curthread;
661
struct componentname *cnp;
662
short irflag;
663
664
if (nd->nd_repstat) {
665
nfsrv_postopattr(nd, dattr_ret, &dattr);
666
goto out;
667
}
668
669
/*
670
* For some reason, if dp is a symlink, the error
671
* returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
672
*/
673
if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
674
nd->nd_repstat = NFSERR_SYMLINK;
675
vrele(dp);
676
goto out;
677
}
678
679
cnp = &named.ni_cnd;
680
irflag = vn_irflag_read(dp);
681
if ((irflag & VIRF_NAMEDDIR) != 0)
682
NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF | OPENNAMED);
683
else
684
NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF);
685
nfsvno_setpathbuf(&named, &bufp, &hashp);
686
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
687
if (error) {
688
vrele(dp);
689
nfsvno_relpathbuf(&named);
690
goto out;
691
}
692
if (!nd->nd_repstat) {
693
/* Don't set OPENNAMED for Lookupp (".."). */
694
if (cnp->cn_namelen == 2 && *cnp->cn_pnbuf == '.' &&
695
*(cnp->cn_pnbuf + 1) == '.')
696
cnp->cn_flags &= ~OPENNAMED;
697
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
698
} else {
699
vrele(dp);
700
nfsvno_relpathbuf(&named);
701
}
702
if (nd->nd_repstat) {
703
if (dirp) {
704
if (nd->nd_flag & ND_NFSV3)
705
dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
706
0, NULL);
707
vrele(dirp);
708
}
709
if (nd->nd_flag & ND_NFSV3)
710
nfsrv_postopattr(nd, dattr_ret, &dattr);
711
goto out;
712
}
713
nfsvno_relpathbuf(&named);
714
vp = named.ni_vp;
715
if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
716
vp->v_type != VDIR && vp->v_type != VLNK)
717
/*
718
* Only allow lookup of VDIR and VLNK for traversal of
719
* non-exported volumes during NFSv4 mounting.
720
*/
721
nd->nd_repstat = ENOENT;
722
if (nd->nd_repstat == 0) {
723
nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
724
/*
725
* EOPNOTSUPP indicates the file system cannot be exported,
726
* so just pretend the entry does not exist.
727
*/
728
if (nd->nd_repstat == EOPNOTSUPP)
729
nd->nd_repstat = ENOENT;
730
}
731
if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
732
nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
733
if (vpp != NULL && nd->nd_repstat == 0)
734
*vpp = vp;
735
else
736
vput(vp);
737
if (dirp) {
738
if (nd->nd_flag & ND_NFSV3)
739
dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
740
NULL);
741
vrele(dirp);
742
}
743
if (nd->nd_repstat) {
744
if (nd->nd_flag & ND_NFSV3)
745
nfsrv_postopattr(nd, dattr_ret, &dattr);
746
goto out;
747
}
748
if (nd->nd_flag & ND_NFSV2) {
749
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
750
nfsrv_fillattr(nd, &nva);
751
} else if (nd->nd_flag & ND_NFSV3) {
752
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
753
nfsrv_postopattr(nd, 0, &nva);
754
nfsrv_postopattr(nd, dattr_ret, &dattr);
755
}
756
757
out:
758
NFSEXITCODE2(error, nd);
759
return (error);
760
}
761
762
/*
763
* nfs readlink service
764
*/
765
int
766
nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
767
vnode_t vp, __unused struct nfsexstuff *exp)
768
{
769
u_int32_t *tl;
770
struct mbuf *mp = NULL, *mpend = NULL;
771
int getret = 1, len;
772
struct nfsvattr nva;
773
struct thread *p = curthread;
774
uint16_t off;
775
776
if (nd->nd_repstat) {
777
nfsrv_postopattr(nd, getret, &nva);
778
goto out;
779
}
780
if (vp->v_type != VLNK) {
781
if (nd->nd_flag & ND_NFSV2)
782
nd->nd_repstat = ENXIO;
783
else
784
nd->nd_repstat = EINVAL;
785
}
786
if (nd->nd_repstat == 0) {
787
if ((nd->nd_flag & ND_EXTPG) != 0)
788
nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
789
nd->nd_maxextsiz, p, &mp, &mpend, &len);
790
else
791
nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
792
0, p, &mp, &mpend, &len);
793
}
794
if (nd->nd_flag & ND_NFSV3)
795
getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
796
vput(vp);
797
if (nd->nd_flag & ND_NFSV3)
798
nfsrv_postopattr(nd, getret, &nva);
799
if (nd->nd_repstat)
800
goto out;
801
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
802
*tl = txdr_unsigned(len);
803
if (mp != NULL) {
804
nd->nd_mb->m_next = mp;
805
nd->nd_mb = mpend;
806
if ((mpend->m_flags & M_EXTPG) != 0) {
807
nd->nd_bextpg = mpend->m_epg_npgs - 1;
808
nd->nd_bpos = (char *)(void *)
809
PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
810
off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0;
811
nd->nd_bpos += off + mpend->m_epg_last_len;
812
nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len -
813
off;
814
} else
815
nd->nd_bpos = mtod(mpend, char *) + mpend->m_len;
816
}
817
818
out:
819
NFSEXITCODE2(0, nd);
820
return (0);
821
}
822
823
/*
824
* nfs read service
825
*/
826
int
827
nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
828
vnode_t vp, struct nfsexstuff *exp)
829
{
830
u_int32_t *tl;
831
int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
832
struct mbuf *m2, *m3;
833
struct nfsvattr nva;
834
off_t off = 0x0;
835
struct nfsstate st, *stp = &st;
836
struct nfslock lo, *lop = &lo;
837
nfsv4stateid_t stateid;
838
nfsquad_t clientid;
839
struct thread *p = curthread;
840
uint16_t poff;
841
842
if (nd->nd_repstat) {
843
nfsrv_postopattr(nd, getret, &nva);
844
goto out;
845
}
846
if (nd->nd_flag & ND_NFSV2) {
847
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
848
off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
849
reqlen = fxdr_unsigned(int, *tl);
850
} else if (nd->nd_flag & ND_NFSV3) {
851
NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
852
off = fxdr_hyper(tl);
853
tl += 2;
854
reqlen = fxdr_unsigned(int, *tl);
855
} else {
856
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
857
reqlen = fxdr_unsigned(int, *(tl + 6));
858
}
859
if (reqlen > NFS_SRVMAXDATA(nd)) {
860
reqlen = NFS_SRVMAXDATA(nd);
861
} else if (reqlen < 0) {
862
error = EBADRPC;
863
goto nfsmout;
864
}
865
gotproxystateid = 0;
866
if (nd->nd_flag & ND_NFSV4) {
867
stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
868
lop->lo_flags = NFSLCK_READ;
869
stp->ls_ownerlen = 0;
870
stp->ls_op = NULL;
871
stp->ls_uid = nd->nd_cred->cr_uid;
872
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
873
clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
874
clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
875
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
876
if ((nd->nd_flag & ND_NFSV41) != 0)
877
clientid.qval = nd->nd_clientid.qval;
878
else if (nd->nd_clientid.qval != clientid.qval)
879
printf("EEK1 multiple clids\n");
880
} else {
881
if ((nd->nd_flag & ND_NFSV41) != 0)
882
printf("EEK! no clientid from session\n");
883
nd->nd_flag |= ND_IMPLIEDCLID;
884
nd->nd_clientid.qval = clientid.qval;
885
}
886
stp->ls_stateid.other[2] = *tl++;
887
/*
888
* Don't allow the client to use a special stateid for a DS op.
889
*/
890
if ((nd->nd_flag & ND_DSSERVER) != 0 &&
891
((stp->ls_stateid.other[0] == 0x0 &&
892
stp->ls_stateid.other[1] == 0x0 &&
893
stp->ls_stateid.other[2] == 0x0) ||
894
(stp->ls_stateid.other[0] == 0xffffffff &&
895
stp->ls_stateid.other[1] == 0xffffffff &&
896
stp->ls_stateid.other[2] == 0xffffffff) ||
897
stp->ls_stateid.seqid != 0))
898
nd->nd_repstat = NFSERR_BADSTATEID;
899
/* However, allow the proxy stateid. */
900
if (stp->ls_stateid.seqid == 0xffffffff &&
901
stp->ls_stateid.other[0] == 0x55555555 &&
902
stp->ls_stateid.other[1] == 0x55555555 &&
903
stp->ls_stateid.other[2] == 0x55555555)
904
gotproxystateid = 1;
905
off = fxdr_hyper(tl);
906
lop->lo_first = off;
907
tl += 2;
908
lop->lo_end = off + reqlen;
909
/*
910
* Paranoia, just in case it wraps around.
911
*/
912
if (lop->lo_end < off)
913
lop->lo_end = NFS64BITSSET;
914
}
915
if (vp->v_type != VREG) {
916
if (nd->nd_flag & ND_NFSV3)
917
nd->nd_repstat = EINVAL;
918
else
919
nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR :
920
EINVAL;
921
}
922
getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
923
if (!nd->nd_repstat)
924
nd->nd_repstat = getret;
925
if (!nd->nd_repstat &&
926
(nva.na_uid != nd->nd_cred->cr_uid ||
927
NFSVNO_EXSTRICTACCESS(exp))) {
928
nd->nd_repstat = nfsvno_accchk(vp, VREAD,
929
nd->nd_cred, exp, p,
930
NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
931
if (nd->nd_repstat)
932
nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
933
nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
934
NFSACCCHK_VPISLOCKED, NULL);
935
}
936
/*
937
* DS reads are marked by ND_DSSERVER or use the proxy special
938
* stateid.
939
*/
940
if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
941
ND_NFSV4 && gotproxystateid == 0)
942
nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
943
&stateid, exp, nd, p);
944
if (nd->nd_repstat) {
945
vput(vp);
946
if (nd->nd_flag & ND_NFSV3)
947
nfsrv_postopattr(nd, getret, &nva);
948
goto out;
949
}
950
if (off >= nva.na_size) {
951
cnt = 0;
952
eof = 1;
953
} else if (reqlen == 0)
954
cnt = 0;
955
else if ((off + reqlen) >= nva.na_size) {
956
cnt = nva.na_size - off;
957
eof = 1;
958
} else
959
cnt = reqlen;
960
m3 = NULL;
961
if (cnt > 0) {
962
/*
963
* If cnt > MCLBYTES and the reply will not be saved, use
964
* ext_pgs mbufs for TLS.
965
* For NFSv4.0, we do not know for sure if the reply will
966
* be saved, so do not use ext_pgs mbufs for NFSv4.0.
967
* Always use ext_pgs mbufs if ND_EXTPG is set.
968
*/
969
if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES &&
970
(nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS &&
971
(nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4))
972
nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
973
nd->nd_maxextsiz, p, &m3, &m2);
974
else
975
nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
976
0, p, &m3, &m2);
977
if (!(nd->nd_flag & ND_NFSV4)) {
978
getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
979
if (!nd->nd_repstat)
980
nd->nd_repstat = getret;
981
}
982
if (nd->nd_repstat) {
983
vput(vp);
984
if (m3)
985
m_freem(m3);
986
if (nd->nd_flag & ND_NFSV3)
987
nfsrv_postopattr(nd, getret, &nva);
988
goto out;
989
}
990
}
991
vput(vp);
992
if (nd->nd_flag & ND_NFSV2) {
993
nfsrv_fillattr(nd, &nva);
994
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
995
} else {
996
if (nd->nd_flag & ND_NFSV3) {
997
nfsrv_postopattr(nd, getret, &nva);
998
NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
999
*tl++ = txdr_unsigned(cnt);
1000
} else
1001
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1002
if (eof)
1003
*tl++ = newnfs_true;
1004
else
1005
*tl++ = newnfs_false;
1006
}
1007
*tl = txdr_unsigned(cnt);
1008
if (m3) {
1009
nd->nd_mb->m_next = m3;
1010
nd->nd_mb = m2;
1011
if ((m2->m_flags & M_EXTPG) != 0) {
1012
nd->nd_flag |= ND_EXTPG;
1013
nd->nd_bextpg = m2->m_epg_npgs - 1;
1014
nd->nd_bpos = (char *)(void *)
1015
PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]);
1016
poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0;
1017
nd->nd_bpos += poff + m2->m_epg_last_len;
1018
nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len -
1019
poff;
1020
} else
1021
nd->nd_bpos = mtod(m2, char *) + m2->m_len;
1022
}
1023
1024
out:
1025
NFSEXITCODE2(0, nd);
1026
return (0);
1027
nfsmout:
1028
vput(vp);
1029
NFSEXITCODE2(error, nd);
1030
return (error);
1031
}
1032
1033
/*
1034
* nfs write service
1035
*/
1036
int
1037
nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
1038
vnode_t vp, struct nfsexstuff *exp)
1039
{
1040
u_int32_t *tl;
1041
struct nfsvattr nva, forat;
1042
int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
1043
int gotproxystateid, stable = NFSWRITE_FILESYNC;
1044
off_t off;
1045
struct nfsstate st, *stp = &st;
1046
struct nfslock lo, *lop = &lo;
1047
nfsv4stateid_t stateid;
1048
nfsquad_t clientid;
1049
nfsattrbit_t attrbits;
1050
struct thread *p = curthread;
1051
1052
if (nd->nd_repstat) {
1053
nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1054
goto out;
1055
}
1056
gotproxystateid = 0;
1057
if (nd->nd_flag & ND_NFSV2) {
1058
NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1059
off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
1060
tl += 2;
1061
retlen = len = fxdr_unsigned(int32_t, *tl);
1062
} else if (nd->nd_flag & ND_NFSV3) {
1063
NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1064
off = fxdr_hyper(tl);
1065
tl += 3;
1066
stable = fxdr_unsigned(int, *tl++);
1067
retlen = len = fxdr_unsigned(int32_t, *tl);
1068
} else {
1069
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
1070
stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
1071
lop->lo_flags = NFSLCK_WRITE;
1072
stp->ls_ownerlen = 0;
1073
stp->ls_op = NULL;
1074
stp->ls_uid = nd->nd_cred->cr_uid;
1075
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
1076
clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
1077
clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
1078
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
1079
if ((nd->nd_flag & ND_NFSV41) != 0)
1080
clientid.qval = nd->nd_clientid.qval;
1081
else if (nd->nd_clientid.qval != clientid.qval)
1082
printf("EEK2 multiple clids\n");
1083
} else {
1084
if ((nd->nd_flag & ND_NFSV41) != 0)
1085
printf("EEK! no clientid from session\n");
1086
nd->nd_flag |= ND_IMPLIEDCLID;
1087
nd->nd_clientid.qval = clientid.qval;
1088
}
1089
stp->ls_stateid.other[2] = *tl++;
1090
/*
1091
* Don't allow the client to use a special stateid for a DS op.
1092
*/
1093
if ((nd->nd_flag & ND_DSSERVER) != 0 &&
1094
((stp->ls_stateid.other[0] == 0x0 &&
1095
stp->ls_stateid.other[1] == 0x0 &&
1096
stp->ls_stateid.other[2] == 0x0) ||
1097
(stp->ls_stateid.other[0] == 0xffffffff &&
1098
stp->ls_stateid.other[1] == 0xffffffff &&
1099
stp->ls_stateid.other[2] == 0xffffffff) ||
1100
stp->ls_stateid.seqid != 0))
1101
nd->nd_repstat = NFSERR_BADSTATEID;
1102
/* However, allow the proxy stateid. */
1103
if (stp->ls_stateid.seqid == 0xffffffff &&
1104
stp->ls_stateid.other[0] == 0x55555555 &&
1105
stp->ls_stateid.other[1] == 0x55555555 &&
1106
stp->ls_stateid.other[2] == 0x55555555)
1107
gotproxystateid = 1;
1108
off = fxdr_hyper(tl);
1109
lop->lo_first = off;
1110
tl += 2;
1111
stable = fxdr_unsigned(int, *tl++);
1112
retlen = len = fxdr_unsigned(int32_t, *tl);
1113
lop->lo_end = off + len;
1114
/*
1115
* Paranoia, just in case it wraps around, which shouldn't
1116
* ever happen anyhow.
1117
*/
1118
if (lop->lo_end < lop->lo_first)
1119
lop->lo_end = NFS64BITSSET;
1120
}
1121
1122
if (retlen > nfs_srvmaxio || retlen < 0)
1123
nd->nd_repstat = EIO;
1124
if (vp->v_type != VREG && !nd->nd_repstat) {
1125
if (nd->nd_flag & ND_NFSV3)
1126
nd->nd_repstat = EINVAL;
1127
else
1128
nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR :
1129
EINVAL;
1130
}
1131
NFSZERO_ATTRBIT(&attrbits);
1132
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
1133
forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
1134
if (!nd->nd_repstat)
1135
nd->nd_repstat = forat_ret;
1136
if (!nd->nd_repstat &&
1137
(forat.na_uid != nd->nd_cred->cr_uid ||
1138
NFSVNO_EXSTRICTACCESS(exp)))
1139
nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
1140
nd->nd_cred, exp, p,
1141
NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
1142
/*
1143
* DS reads are marked by ND_DSSERVER or use the proxy special
1144
* stateid.
1145
*/
1146
if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
1147
ND_NFSV4 && gotproxystateid == 0)
1148
nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
1149
&stateid, exp, nd, p);
1150
if (nd->nd_repstat) {
1151
vput(vp);
1152
if (nd->nd_flag & ND_NFSV3)
1153
nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1154
goto out;
1155
}
1156
1157
/*
1158
* For NFS Version 2, it is not obvious what a write of zero length
1159
* should do, but I might as well be consistent with Version 3,
1160
* which is to return ok so long as there are no permission problems.
1161
*/
1162
if (retlen > 0) {
1163
nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
1164
nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
1165
error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
1166
if (error)
1167
goto nfsmout;
1168
}
1169
if (nd->nd_flag & ND_NFSV4)
1170
aftat_ret = 0;
1171
else
1172
aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
1173
vput(vp);
1174
if (!nd->nd_repstat)
1175
nd->nd_repstat = aftat_ret;
1176
if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
1177
if (nd->nd_flag & ND_NFSV3)
1178
nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
1179
if (nd->nd_repstat)
1180
goto out;
1181
NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1182
*tl++ = txdr_unsigned(retlen);
1183
/*
1184
* If nfs_async is set, then pretend the write was FILESYNC.
1185
* Warning: Doing this violates RFC1813 and runs a risk
1186
* of data written by a client being lost when the server
1187
* crashes/reboots.
1188
*/
1189
if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
1190
*tl++ = txdr_unsigned(stable);
1191
else
1192
*tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
1193
/*
1194
* Actually, there is no need to txdr these fields,
1195
* but it may make the values more human readable,
1196
* for debugging purposes.
1197
*/
1198
*tl++ = txdr_unsigned(nfsboottime.tv_sec);
1199
*tl = txdr_unsigned(nfsboottime.tv_usec);
1200
} else if (!nd->nd_repstat)
1201
nfsrv_fillattr(nd, &nva);
1202
1203
out:
1204
NFSEXITCODE2(0, nd);
1205
return (0);
1206
nfsmout:
1207
vput(vp);
1208
NFSEXITCODE2(error, nd);
1209
return (error);
1210
}
1211
1212
/*
1213
* nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
1214
* now does a truncate to 0 length via. setattr if it already exists
1215
* The core creation routine has been extracted out into nfsrv_creatsub(),
1216
* so it can also be used by nfsrv_open() for V4.
1217
*/
1218
int
1219
nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
1220
vnode_t dp, struct nfsexstuff *exp)
1221
{
1222
struct nfsvattr nva, dirfor, diraft;
1223
struct nfsv2_sattr *sp;
1224
struct nameidata named;
1225
u_int32_t *tl;
1226
int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
1227
int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
1228
NFSDEV_T rdev = 0;
1229
vnode_t vp = NULL, dirp = NULL;
1230
fhandle_t fh;
1231
char *bufp;
1232
u_long *hashp;
1233
__enum_uint8(vtype) vtyp;
1234
int32_t cverf[2], tverf[2] = { 0, 0 };
1235
struct thread *p = curthread;
1236
1237
if (nd->nd_repstat) {
1238
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1239
goto out;
1240
}
1241
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1242
LOCKPARENT | LOCKLEAF | NOCACHE);
1243
nfsvno_setpathbuf(&named, &bufp, &hashp);
1244
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1245
if (error)
1246
goto nfsmout;
1247
if (!nd->nd_repstat) {
1248
NFSVNO_ATTRINIT(&nva);
1249
if (nd->nd_flag & ND_NFSV2) {
1250
NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1251
vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1252
if (vtyp == VNON)
1253
vtyp = VREG;
1254
NFSVNO_SETATTRVAL(&nva, type, vtyp);
1255
NFSVNO_SETATTRVAL(&nva, mode,
1256
nfstov_mode(sp->sa_mode));
1257
switch (nva.na_type) {
1258
case VREG:
1259
tsize = fxdr_unsigned(int32_t, sp->sa_size);
1260
if (tsize != -1)
1261
NFSVNO_SETATTRVAL(&nva, size,
1262
(u_quad_t)tsize);
1263
break;
1264
case VCHR:
1265
case VBLK:
1266
case VFIFO:
1267
rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
1268
break;
1269
default:
1270
break;
1271
}
1272
} else {
1273
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1274
how = fxdr_unsigned(int, *tl);
1275
switch (how) {
1276
case NFSCREATE_GUARDED:
1277
case NFSCREATE_UNCHECKED:
1278
error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
1279
if (error)
1280
goto nfsmout;
1281
break;
1282
case NFSCREATE_EXCLUSIVE:
1283
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
1284
cverf[0] = *tl++;
1285
cverf[1] = *tl;
1286
exclusive_flag = 1;
1287
break;
1288
}
1289
NFSVNO_SETATTRVAL(&nva, type, VREG);
1290
}
1291
}
1292
if (nd->nd_repstat) {
1293
nfsvno_relpathbuf(&named);
1294
if (nd->nd_flag & ND_NFSV3) {
1295
dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
1296
NULL);
1297
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1298
&diraft);
1299
}
1300
vput(dp);
1301
goto out;
1302
}
1303
1304
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
1305
if (dirp) {
1306
if (nd->nd_flag & ND_NFSV2) {
1307
vrele(dirp);
1308
dirp = NULL;
1309
} else {
1310
dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1311
NULL);
1312
}
1313
}
1314
if (nd->nd_repstat) {
1315
if (nd->nd_flag & ND_NFSV3)
1316
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1317
&diraft);
1318
if (dirp)
1319
vrele(dirp);
1320
goto out;
1321
}
1322
1323
if (!(nd->nd_flag & ND_NFSV2)) {
1324
switch (how) {
1325
case NFSCREATE_GUARDED:
1326
if (named.ni_vp)
1327
nd->nd_repstat = EEXIST;
1328
break;
1329
case NFSCREATE_UNCHECKED:
1330
break;
1331
case NFSCREATE_EXCLUSIVE:
1332
if (named.ni_vp == NULL)
1333
NFSVNO_SETATTRVAL(&nva, mode, 0);
1334
break;
1335
}
1336
}
1337
1338
/*
1339
* Iff doesn't exist, create it
1340
* otherwise just truncate to 0 length
1341
* should I set the mode too ?
1342
*/
1343
nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
1344
&exclusive_flag, cverf, rdev, exp);
1345
1346
if (!nd->nd_repstat) {
1347
nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
1348
if (!nd->nd_repstat)
1349
nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1350
NULL);
1351
vput(vp);
1352
if (!nd->nd_repstat) {
1353
tverf[0] = nva.na_atime.tv_sec;
1354
tverf[1] = nva.na_atime.tv_nsec;
1355
}
1356
}
1357
if (nd->nd_flag & ND_NFSV2) {
1358
if (!nd->nd_repstat) {
1359
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
1360
nfsrv_fillattr(nd, &nva);
1361
}
1362
} else {
1363
if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
1364
|| cverf[1] != tverf[1]))
1365
nd->nd_repstat = EEXIST;
1366
diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1367
vrele(dirp);
1368
if (!nd->nd_repstat) {
1369
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 1);
1370
nfsrv_postopattr(nd, 0, &nva);
1371
}
1372
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1373
}
1374
1375
out:
1376
NFSEXITCODE2(0, nd);
1377
return (0);
1378
nfsmout:
1379
vput(dp);
1380
nfsvno_relpathbuf(&named);
1381
NFSEXITCODE2(error, nd);
1382
return (error);
1383
}
1384
1385
/*
1386
* nfs v3 mknod service (and v4 create)
1387
*/
1388
int
1389
nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
1390
vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1391
{
1392
struct nfsvattr nva, dirfor, diraft;
1393
u_int32_t *tl;
1394
struct nameidata named;
1395
int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1396
u_int32_t major, minor;
1397
__enum_uint8(vtype) vtyp = VNON;
1398
nfstype nfs4type = NFNON;
1399
vnode_t vp, dirp = NULL;
1400
nfsattrbit_t attrbits;
1401
char *bufp = NULL, *pathcp = NULL;
1402
u_long *hashp, cnflags;
1403
NFSACL_T *aclp = NULL;
1404
struct thread *p = curthread;
1405
1406
NFSVNO_ATTRINIT(&nva);
1407
cnflags = LOCKPARENT;
1408
if (nd->nd_repstat) {
1409
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1410
goto out;
1411
}
1412
#ifdef NFS4_ACL_EXTATTR_NAME
1413
aclp = acl_alloc(M_WAITOK);
1414
aclp->acl_cnt = 0;
1415
#endif
1416
1417
/*
1418
* For V4, the creation stuff is here, Yuck!
1419
*/
1420
if (nd->nd_flag & ND_NFSV4) {
1421
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1422
vtyp = nfsv34tov_type(*tl);
1423
nfs4type = fxdr_unsigned(nfstype, *tl);
1424
if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0) {
1425
/*
1426
* Don't allow creation of non-regular file objects
1427
* in a named attribute directory.
1428
*/
1429
nd->nd_repstat = NFSERR_INVAL;
1430
vrele(dp);
1431
#ifdef NFS4_ACL_EXTATTR_NAME
1432
acl_free(aclp);
1433
#endif
1434
goto out;
1435
}
1436
switch (nfs4type) {
1437
case NFLNK:
1438
error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
1439
&pathlen);
1440
if (error)
1441
goto nfsmout;
1442
break;
1443
case NFCHR:
1444
case NFBLK:
1445
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1446
major = fxdr_unsigned(u_int32_t, *tl++);
1447
minor = fxdr_unsigned(u_int32_t, *tl);
1448
nva.na_rdev = NFSMAKEDEV(major, minor);
1449
break;
1450
case NFSOCK:
1451
case NFFIFO:
1452
break;
1453
case NFDIR:
1454
cnflags = LOCKPARENT;
1455
break;
1456
default:
1457
nd->nd_repstat = NFSERR_BADTYPE;
1458
vrele(dp);
1459
#ifdef NFS4_ACL_EXTATTR_NAME
1460
acl_free(aclp);
1461
#endif
1462
goto out;
1463
}
1464
}
1465
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
1466
nfsvno_setpathbuf(&named, &bufp, &hashp);
1467
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1468
if (error)
1469
goto nfsmout;
1470
if (!nd->nd_repstat) {
1471
if (nd->nd_flag & ND_NFSV3) {
1472
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1473
vtyp = nfsv34tov_type(*tl);
1474
}
1475
error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
1476
if (error)
1477
goto nfsmout;
1478
nva.na_type = vtyp;
1479
if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
1480
(vtyp == VCHR || vtyp == VBLK)) {
1481
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
1482
major = fxdr_unsigned(u_int32_t, *tl++);
1483
minor = fxdr_unsigned(u_int32_t, *tl);
1484
nva.na_rdev = NFSMAKEDEV(major, minor);
1485
}
1486
}
1487
1488
dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
1489
if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
1490
if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
1491
dirfor.na_gid == nva.na_gid)
1492
NFSVNO_UNSET(&nva, gid);
1493
nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
1494
}
1495
if (nd->nd_repstat) {
1496
vrele(dp);
1497
#ifdef NFS4_ACL_EXTATTR_NAME
1498
acl_free(aclp);
1499
#endif
1500
nfsvno_relpathbuf(&named);
1501
if (pathcp)
1502
free(pathcp, M_TEMP);
1503
if (nd->nd_flag & ND_NFSV3)
1504
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1505
&diraft);
1506
goto out;
1507
}
1508
1509
/*
1510
* Yuck! For V4, mkdir and link are here and some V4 clients don't fill
1511
* in va_mode, so we'll have to set a default here.
1512
*/
1513
if (NFSVNO_NOTSETMODE(&nva)) {
1514
if (vtyp == VLNK)
1515
nva.na_mode = 0755;
1516
else
1517
nva.na_mode = 0400;
1518
}
1519
1520
if (vtyp == VDIR)
1521
named.ni_cnd.cn_flags |= WILLBEDIR;
1522
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
1523
if (nd->nd_repstat) {
1524
if (dirp) {
1525
if (nd->nd_flag & ND_NFSV3)
1526
dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
1527
p, 0, NULL);
1528
vrele(dirp);
1529
}
1530
#ifdef NFS4_ACL_EXTATTR_NAME
1531
acl_free(aclp);
1532
#endif
1533
if (nd->nd_flag & ND_NFSV3)
1534
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1535
&diraft);
1536
goto out;
1537
}
1538
if (dirp)
1539
dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
1540
1541
if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
1542
if (vtyp == VDIR) {
1543
nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
1544
&dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
1545
exp);
1546
#ifdef NFS4_ACL_EXTATTR_NAME
1547
acl_free(aclp);
1548
#endif
1549
goto out;
1550
} else if (vtyp == VLNK) {
1551
nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1552
&dirfor, &diraft, &diraft_ret, &attrbits,
1553
aclp, p, exp, pathcp, pathlen);
1554
#ifdef NFS4_ACL_EXTATTR_NAME
1555
acl_free(aclp);
1556
#endif
1557
free(pathcp, M_TEMP);
1558
goto out;
1559
}
1560
}
1561
1562
nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
1563
if (!nd->nd_repstat) {
1564
vp = named.ni_vp;
1565
nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
1566
nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1567
if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
1568
nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
1569
NULL);
1570
if (vpp != NULL && nd->nd_repstat == 0) {
1571
NFSVOPUNLOCK(vp);
1572
*vpp = vp;
1573
} else
1574
vput(vp);
1575
}
1576
1577
diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1578
vrele(dirp);
1579
if (!nd->nd_repstat) {
1580
if (nd->nd_flag & ND_NFSV3) {
1581
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
1582
nfsrv_postopattr(nd, 0, &nva);
1583
} else {
1584
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1585
*tl++ = newnfs_false;
1586
txdr_hyper(dirfor.na_filerev, tl);
1587
tl += 2;
1588
txdr_hyper(diraft.na_filerev, tl);
1589
(void) nfsrv_putattrbit(nd, &attrbits);
1590
}
1591
}
1592
if (nd->nd_flag & ND_NFSV3)
1593
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1594
#ifdef NFS4_ACL_EXTATTR_NAME
1595
acl_free(aclp);
1596
#endif
1597
1598
out:
1599
NFSEXITCODE2(0, nd);
1600
return (0);
1601
nfsmout:
1602
vrele(dp);
1603
#ifdef NFS4_ACL_EXTATTR_NAME
1604
acl_free(aclp);
1605
#endif
1606
if (bufp)
1607
nfsvno_relpathbuf(&named);
1608
if (pathcp)
1609
free(pathcp, M_TEMP);
1610
1611
NFSEXITCODE2(error, nd);
1612
return (error);
1613
}
1614
1615
/*
1616
* nfs remove service
1617
*/
1618
int
1619
nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
1620
vnode_t dp, struct nfsexstuff *exp)
1621
{
1622
struct nameidata named;
1623
u_int32_t *tl;
1624
int error = 0, dirfor_ret = 1, diraft_ret = 1;
1625
vnode_t dirp = NULL;
1626
struct nfsvattr dirfor, diraft;
1627
char *bufp;
1628
u_long *hashp;
1629
struct thread *p = curthread;
1630
1631
if (nd->nd_repstat) {
1632
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1633
goto out;
1634
}
1635
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
1636
LOCKPARENT | LOCKLEAF);
1637
nfsvno_setpathbuf(&named, &bufp, &hashp);
1638
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1639
if (error) {
1640
vput(dp);
1641
nfsvno_relpathbuf(&named);
1642
goto out;
1643
}
1644
if (!nd->nd_repstat) {
1645
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
1646
} else {
1647
vput(dp);
1648
nfsvno_relpathbuf(&named);
1649
}
1650
if (dirp) {
1651
if (!(nd->nd_flag & ND_NFSV2)) {
1652
dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1653
NULL);
1654
} else {
1655
vrele(dirp);
1656
dirp = NULL;
1657
}
1658
}
1659
if (!nd->nd_repstat) {
1660
if (nd->nd_flag & ND_NFSV4) {
1661
if (named.ni_vp->v_type == VDIR)
1662
nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
1663
nd->nd_cred, p, exp);
1664
else
1665
nd->nd_repstat = nfsvno_removesub(&named, true,
1666
nd, p, exp);
1667
} else if (nd->nd_procnum == NFSPROC_RMDIR) {
1668
nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
1669
nd->nd_cred, p, exp);
1670
} else {
1671
nd->nd_repstat = nfsvno_removesub(&named, false, nd, p,
1672
exp);
1673
}
1674
}
1675
if (!(nd->nd_flag & ND_NFSV2)) {
1676
if (dirp) {
1677
diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
1678
NULL);
1679
vrele(dirp);
1680
}
1681
if (nd->nd_flag & ND_NFSV3) {
1682
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1683
&diraft);
1684
} else if (!nd->nd_repstat) {
1685
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1686
*tl++ = newnfs_false;
1687
txdr_hyper(dirfor.na_filerev, tl);
1688
tl += 2;
1689
txdr_hyper(diraft.na_filerev, tl);
1690
}
1691
}
1692
1693
out:
1694
NFSEXITCODE2(error, nd);
1695
return (error);
1696
}
1697
1698
/*
1699
* nfs rename service
1700
*/
1701
int
1702
nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
1703
vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1704
{
1705
u_int32_t *tl;
1706
int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
1707
int tdirfor_ret = 1, tdiraft_ret = 1;
1708
struct nameidata fromnd, tond;
1709
vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
1710
struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
1711
struct nfsexstuff tnes;
1712
struct nfsrvfh tfh;
1713
char *bufp, *tbufp = NULL;
1714
u_long *hashp;
1715
fhandle_t fh;
1716
struct thread *p = curthread;
1717
1718
if (nd->nd_repstat) {
1719
nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1720
nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1721
goto out;
1722
}
1723
if (!(nd->nd_flag & ND_NFSV2))
1724
fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
1725
tond.ni_cnd.cn_nameiop = 0;
1726
tond.ni_startdir = NULL;
1727
NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT);
1728
nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
1729
error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
1730
if (error) {
1731
vput(dp);
1732
if (todp)
1733
vrele(todp);
1734
nfsvno_relpathbuf(&fromnd);
1735
goto out;
1736
}
1737
/*
1738
* Unlock dp in this code section, so it is unlocked before
1739
* tdp gets locked. This avoids a potential LOR if tdp is the
1740
* parent directory of dp.
1741
*/
1742
if (nd->nd_flag & ND_NFSV4) {
1743
tdp = todp;
1744
tnes = *toexp;
1745
if (dp != tdp) {
1746
NFSVOPUNLOCK(dp);
1747
/* Might lock tdp. */
1748
tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
1749
NULL);
1750
} else {
1751
tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1752
NULL);
1753
NFSVOPUNLOCK(dp);
1754
}
1755
} else {
1756
tfh.nfsrvfh_len = 0;
1757
error = nfsrv_mtofh(nd, &tfh);
1758
if (error == 0)
1759
error = nfsvno_getfh(dp, &fh, p);
1760
if (error) {
1761
vput(dp);
1762
/* todp is always NULL except NFSv4 */
1763
nfsvno_relpathbuf(&fromnd);
1764
goto out;
1765
}
1766
1767
/* If this is the same file handle, just VREF() the vnode. */
1768
if (!NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1769
vref(dp);
1770
tdp = dp;
1771
tnes = *exp;
1772
tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
1773
NULL);
1774
NFSVOPUNLOCK(dp);
1775
} else {
1776
NFSVOPUNLOCK(dp);
1777
nd->nd_cred->cr_uid = nd->nd_saveduid;
1778
nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1779
0, -1); /* Locks tdp. */
1780
if (tdp) {
1781
tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
1782
p, 1, NULL);
1783
NFSVOPUNLOCK(tdp);
1784
}
1785
}
1786
}
1787
NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE);
1788
nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1789
if (!nd->nd_repstat) {
1790
error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1791
if (error) {
1792
if (tdp)
1793
vrele(tdp);
1794
vrele(dp);
1795
nfsvno_relpathbuf(&fromnd);
1796
nfsvno_relpathbuf(&tond);
1797
goto out;
1798
}
1799
}
1800
if (nd->nd_repstat) {
1801
if (nd->nd_flag & ND_NFSV3) {
1802
nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1803
&fdiraft);
1804
nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1805
&tdiraft);
1806
}
1807
if (tdp)
1808
vrele(tdp);
1809
vrele(dp);
1810
nfsvno_relpathbuf(&fromnd);
1811
nfsvno_relpathbuf(&tond);
1812
goto out;
1813
}
1814
1815
/*
1816
* Done parsing, now down to business.
1817
*/
1818
nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, &fdirp);
1819
if (nd->nd_repstat) {
1820
if (nd->nd_flag & ND_NFSV3) {
1821
nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1822
&fdiraft);
1823
nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1824
&tdiraft);
1825
}
1826
if (fdirp)
1827
vrele(fdirp);
1828
if (tdp)
1829
vrele(tdp);
1830
nfsvno_relpathbuf(&tond);
1831
goto out;
1832
}
1833
if (fromnd.ni_vp->v_type == VDIR)
1834
tond.ni_cnd.cn_flags |= WILLBEDIR;
1835
nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, &tdirp);
1836
nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd, p);
1837
if (fdirp)
1838
fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
1839
if (tdirp)
1840
tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
1841
if (fdirp)
1842
vrele(fdirp);
1843
if (tdirp)
1844
vrele(tdirp);
1845
if (nd->nd_flag & ND_NFSV3) {
1846
nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1847
nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1848
} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1849
NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1850
*tl++ = newnfs_false;
1851
txdr_hyper(fdirfor.na_filerev, tl);
1852
tl += 2;
1853
txdr_hyper(fdiraft.na_filerev, tl);
1854
tl += 2;
1855
*tl++ = newnfs_false;
1856
txdr_hyper(tdirfor.na_filerev, tl);
1857
tl += 2;
1858
txdr_hyper(tdiraft.na_filerev, tl);
1859
}
1860
1861
out:
1862
NFSEXITCODE2(error, nd);
1863
return (error);
1864
}
1865
1866
/*
1867
* nfs link service
1868
*/
1869
int
1870
nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1871
vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
1872
{
1873
struct nameidata named;
1874
u_int32_t *tl;
1875
int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1876
vnode_t dirp = NULL, dp = NULL;
1877
struct nfsvattr dirfor, diraft, at;
1878
struct nfsexstuff tnes;
1879
struct nfsrvfh dfh;
1880
char *bufp;
1881
u_long *hashp;
1882
struct thread *p = curthread;
1883
nfsquad_t clientid;
1884
1885
if (nd->nd_repstat) {
1886
nfsrv_postopattr(nd, getret, &at);
1887
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1888
goto out;
1889
}
1890
if ((vn_irflag_read(vp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0 ||
1891
(tovp != NULL &&
1892
(vn_irflag_read(tovp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0)) {
1893
nd->nd_repstat = NFSERR_INVAL;
1894
if (tovp != NULL)
1895
vrele(tovp);
1896
}
1897
NFSVOPUNLOCK(vp);
1898
if (!nd->nd_repstat && vp->v_type == VDIR) {
1899
if (nd->nd_flag & ND_NFSV4)
1900
nd->nd_repstat = NFSERR_ISDIR;
1901
else
1902
nd->nd_repstat = NFSERR_INVAL;
1903
if (tovp)
1904
vrele(tovp);
1905
}
1906
if (!nd->nd_repstat) {
1907
if (nd->nd_flag & ND_NFSV4) {
1908
dp = tovp;
1909
tnes = *toexp;
1910
} else {
1911
error = nfsrv_mtofh(nd, &dfh);
1912
if (error) {
1913
vrele(vp);
1914
/* tovp is always NULL unless NFSv4 */
1915
goto out;
1916
}
1917
nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL,
1918
0, -1);
1919
if (dp)
1920
NFSVOPUNLOCK(dp);
1921
}
1922
}
1923
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE);
1924
if (!nd->nd_repstat) {
1925
nfsvno_setpathbuf(&named, &bufp, &hashp);
1926
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1927
if (error) {
1928
vrele(vp);
1929
if (dp)
1930
vrele(dp);
1931
nfsvno_relpathbuf(&named);
1932
goto out;
1933
}
1934
if (!nd->nd_repstat) {
1935
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1936
&dirp);
1937
} else {
1938
if (dp)
1939
vrele(dp);
1940
nfsvno_relpathbuf(&named);
1941
}
1942
}
1943
if (dirp) {
1944
if (nd->nd_flag & ND_NFSV2) {
1945
vrele(dirp);
1946
dirp = NULL;
1947
} else {
1948
dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
1949
NULL);
1950
}
1951
}
1952
if (!nd->nd_repstat) {
1953
clientid.qval = 0;
1954
if ((nd->nd_flag & (ND_IMPLIEDCLID | ND_NFSV41)) ==
1955
(ND_IMPLIEDCLID | ND_NFSV41))
1956
clientid.qval = nd->nd_clientid.qval;
1957
nd->nd_repstat = nfsvno_link(&named, vp, clientid, nd->nd_cred,
1958
p, exp);
1959
}
1960
if (nd->nd_flag & ND_NFSV3)
1961
getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
1962
if (dirp) {
1963
diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
1964
vrele(dirp);
1965
}
1966
vrele(vp);
1967
if (nd->nd_flag & ND_NFSV3) {
1968
nfsrv_postopattr(nd, getret, &at);
1969
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1970
} else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1971
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1972
*tl++ = newnfs_false;
1973
txdr_hyper(dirfor.na_filerev, tl);
1974
tl += 2;
1975
txdr_hyper(diraft.na_filerev, tl);
1976
}
1977
1978
out:
1979
NFSEXITCODE2(error, nd);
1980
return (error);
1981
}
1982
1983
/*
1984
* nfs symbolic link service
1985
*/
1986
int
1987
nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1988
vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
1989
{
1990
struct nfsvattr nva, dirfor, diraft;
1991
struct nameidata named;
1992
int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1993
vnode_t dirp = NULL;
1994
char *bufp, *pathcp = NULL;
1995
u_long *hashp;
1996
struct thread *p = curthread;
1997
1998
if (nd->nd_repstat) {
1999
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2000
goto out;
2001
}
2002
if (vpp)
2003
*vpp = NULL;
2004
NFSVNO_ATTRINIT(&nva);
2005
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2006
LOCKPARENT | NOCACHE);
2007
nfsvno_setpathbuf(&named, &bufp, &hashp);
2008
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2009
if (!error && !nd->nd_repstat)
2010
error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
2011
if (error) {
2012
vrele(dp);
2013
nfsvno_relpathbuf(&named);
2014
goto out;
2015
}
2016
if (!nd->nd_repstat) {
2017
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
2018
} else {
2019
vrele(dp);
2020
nfsvno_relpathbuf(&named);
2021
}
2022
if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
2023
vrele(dirp);
2024
dirp = NULL;
2025
}
2026
2027
/*
2028
* And call nfsrvd_symlinksub() to do the common code. It will
2029
* return EBADRPC upon a parsing error, 0 otherwise.
2030
*/
2031
if (!nd->nd_repstat) {
2032
if (dirp != NULL)
2033
dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
2034
NULL);
2035
nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
2036
&dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
2037
pathcp, pathlen);
2038
} else if (dirp != NULL) {
2039
dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
2040
vrele(dirp);
2041
}
2042
if (pathcp)
2043
free(pathcp, M_TEMP);
2044
2045
if (nd->nd_flag & ND_NFSV3) {
2046
if (!nd->nd_repstat) {
2047
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
2048
nfsrv_postopattr(nd, 0, &nva);
2049
}
2050
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2051
}
2052
2053
out:
2054
NFSEXITCODE2(error, nd);
2055
return (error);
2056
}
2057
2058
/*
2059
* Common code for creating a symbolic link.
2060
*/
2061
static void
2062
nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
2063
struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2064
vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2065
int *diraft_retp, nfsattrbit_t *attrbitp,
2066
NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
2067
int pathlen)
2068
{
2069
u_int32_t *tl;
2070
2071
nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
2072
!(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
2073
if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
2074
nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
2075
if (nd->nd_flag & ND_NFSV3) {
2076
nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
2077
if (!nd->nd_repstat)
2078
nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
2079
nvap, nd, p, 1, NULL);
2080
}
2081
if (vpp != NULL && nd->nd_repstat == 0) {
2082
NFSVOPUNLOCK(ndp->ni_vp);
2083
*vpp = ndp->ni_vp;
2084
} else
2085
vput(ndp->ni_vp);
2086
}
2087
if (dirp) {
2088
*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2089
vrele(dirp);
2090
}
2091
if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2092
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2093
*tl++ = newnfs_false;
2094
txdr_hyper(dirforp->na_filerev, tl);
2095
tl += 2;
2096
txdr_hyper(diraftp->na_filerev, tl);
2097
(void) nfsrv_putattrbit(nd, attrbitp);
2098
}
2099
2100
NFSEXITCODE2(0, nd);
2101
}
2102
2103
/*
2104
* nfs mkdir service
2105
*/
2106
int
2107
nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
2108
vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
2109
{
2110
struct nfsvattr nva, dirfor, diraft;
2111
struct nameidata named;
2112
u_int32_t *tl;
2113
int error = 0, dirfor_ret = 1, diraft_ret = 1;
2114
vnode_t dirp = NULL;
2115
char *bufp;
2116
u_long *hashp;
2117
struct thread *p = curthread;
2118
2119
if (nd->nd_repstat) {
2120
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2121
goto out;
2122
}
2123
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE);
2124
nfsvno_setpathbuf(&named, &bufp, &hashp);
2125
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2126
if (error)
2127
goto nfsmout;
2128
if (!nd->nd_repstat) {
2129
NFSVNO_ATTRINIT(&nva);
2130
if (nd->nd_flag & ND_NFSV3) {
2131
error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
2132
if (error)
2133
goto nfsmout;
2134
} else {
2135
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2136
nva.na_mode = nfstov_mode(*tl++);
2137
}
2138
}
2139
if (!nd->nd_repstat) {
2140
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp);
2141
} else {
2142
vrele(dp);
2143
nfsvno_relpathbuf(&named);
2144
}
2145
if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
2146
vrele(dirp);
2147
dirp = NULL;
2148
}
2149
if (nd->nd_repstat) {
2150
if (dirp != NULL) {
2151
dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
2152
NULL);
2153
vrele(dirp);
2154
}
2155
if (nd->nd_flag & ND_NFSV3)
2156
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
2157
&diraft);
2158
goto out;
2159
}
2160
if (dirp != NULL)
2161
dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
2162
2163
/*
2164
* Call nfsrvd_mkdirsub() for the code common to V4 as well.
2165
*/
2166
nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
2167
&diraft_ret, NULL, NULL, p, exp);
2168
2169
if (nd->nd_flag & ND_NFSV3) {
2170
if (!nd->nd_repstat) {
2171
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
2172
nfsrv_postopattr(nd, 0, &nva);
2173
}
2174
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
2175
} else if (!nd->nd_repstat) {
2176
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
2177
nfsrv_fillattr(nd, &nva);
2178
}
2179
2180
out:
2181
NFSEXITCODE2(0, nd);
2182
return (0);
2183
nfsmout:
2184
vrele(dp);
2185
nfsvno_relpathbuf(&named);
2186
NFSEXITCODE2(error, nd);
2187
return (error);
2188
}
2189
2190
/*
2191
* Code common to mkdir for V2,3 and 4.
2192
*/
2193
static void
2194
nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
2195
struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
2196
vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
2197
int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
2198
NFSPROC_T *p, struct nfsexstuff *exp)
2199
{
2200
vnode_t vp;
2201
u_int32_t *tl;
2202
2203
NFSVNO_SETATTRVAL(nvap, type, VDIR);
2204
nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
2205
nd->nd_cred, p, exp);
2206
if (!nd->nd_repstat) {
2207
vp = ndp->ni_vp;
2208
nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
2209
nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
2210
if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
2211
nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
2212
NULL);
2213
if (vpp && !nd->nd_repstat) {
2214
NFSVOPUNLOCK(vp);
2215
*vpp = vp;
2216
} else {
2217
vput(vp);
2218
}
2219
}
2220
if (dirp) {
2221
*diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
2222
vrele(dirp);
2223
}
2224
if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
2225
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
2226
*tl++ = newnfs_false;
2227
txdr_hyper(dirforp->na_filerev, tl);
2228
tl += 2;
2229
txdr_hyper(diraftp->na_filerev, tl);
2230
(void) nfsrv_putattrbit(nd, attrbitp);
2231
}
2232
2233
NFSEXITCODE2(0, nd);
2234
}
2235
2236
/*
2237
* nfs commit service
2238
*/
2239
int
2240
nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
2241
vnode_t vp, __unused struct nfsexstuff *exp)
2242
{
2243
struct nfsvattr bfor, aft;
2244
u_int32_t *tl;
2245
int error = 0, for_ret = 1, aft_ret = 1, cnt;
2246
u_int64_t off;
2247
struct thread *p = curthread;
2248
2249
if (nd->nd_repstat) {
2250
nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2251
goto out;
2252
}
2253
2254
/* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
2255
if (vp->v_type != VREG) {
2256
if (nd->nd_flag & ND_NFSV3)
2257
error = NFSERR_NOTSUPP;
2258
else
2259
error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
2260
goto nfsmout;
2261
}
2262
NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2263
2264
/*
2265
* XXX At this time VOP_FSYNC() does not accept offset and byte
2266
* count parameters, so these arguments are useless (someday maybe).
2267
*/
2268
off = fxdr_hyper(tl);
2269
tl += 2;
2270
cnt = fxdr_unsigned(int, *tl);
2271
if (nd->nd_flag & ND_NFSV3)
2272
for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
2273
nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
2274
if (nd->nd_flag & ND_NFSV3) {
2275
aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
2276
nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
2277
}
2278
vput(vp);
2279
if (!nd->nd_repstat) {
2280
NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
2281
*tl++ = txdr_unsigned(nfsboottime.tv_sec);
2282
*tl = txdr_unsigned(nfsboottime.tv_usec);
2283
}
2284
2285
out:
2286
NFSEXITCODE2(0, nd);
2287
return (0);
2288
nfsmout:
2289
vput(vp);
2290
NFSEXITCODE2(error, nd);
2291
return (error);
2292
}
2293
2294
/*
2295
* nfs statfs service
2296
*/
2297
int
2298
nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
2299
vnode_t vp, __unused struct nfsexstuff *exp)
2300
{
2301
struct statfs *sf;
2302
u_int32_t *tl;
2303
int getret = 1;
2304
struct nfsvattr at;
2305
u_quad_t tval;
2306
struct thread *p = curthread;
2307
2308
sf = NULL;
2309
if (nd->nd_repstat) {
2310
nfsrv_postopattr(nd, getret, &at);
2311
goto out;
2312
}
2313
sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
2314
nd->nd_repstat = nfsvno_statfs(vp, sf);
2315
getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2316
vput(vp);
2317
if (nd->nd_flag & ND_NFSV3)
2318
nfsrv_postopattr(nd, getret, &at);
2319
if (nd->nd_repstat)
2320
goto out;
2321
if (nd->nd_flag & ND_NFSV2) {
2322
NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2323
*tl++ = txdr_unsigned(NFS_V2MAXDATA);
2324
*tl++ = txdr_unsigned(sf->f_bsize);
2325
*tl++ = txdr_unsigned(sf->f_blocks);
2326
*tl++ = txdr_unsigned(sf->f_bfree);
2327
*tl = txdr_unsigned(sf->f_bavail);
2328
} else {
2329
NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2330
tval = (u_quad_t)sf->f_blocks;
2331
tval *= (u_quad_t)sf->f_bsize;
2332
txdr_hyper(tval, tl); tl += 2;
2333
tval = (u_quad_t)sf->f_bfree;
2334
tval *= (u_quad_t)sf->f_bsize;
2335
txdr_hyper(tval, tl); tl += 2;
2336
tval = (u_quad_t)sf->f_bavail;
2337
tval *= (u_quad_t)sf->f_bsize;
2338
txdr_hyper(tval, tl); tl += 2;
2339
tval = (u_quad_t)sf->f_files;
2340
txdr_hyper(tval, tl); tl += 2;
2341
tval = (u_quad_t)sf->f_ffree;
2342
txdr_hyper(tval, tl); tl += 2;
2343
tval = (u_quad_t)sf->f_ffree;
2344
txdr_hyper(tval, tl); tl += 2;
2345
*tl = 0;
2346
}
2347
2348
out:
2349
free(sf, M_STATFS);
2350
NFSEXITCODE2(0, nd);
2351
return (0);
2352
}
2353
2354
/*
2355
* nfs fsinfo service
2356
*/
2357
int
2358
nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2359
vnode_t vp, __unused struct nfsexstuff *exp)
2360
{
2361
u_int32_t *tl;
2362
struct nfsfsinfo fs;
2363
int getret = 1;
2364
struct nfsvattr at;
2365
struct thread *p = curthread;
2366
2367
if (nd->nd_repstat) {
2368
nfsrv_postopattr(nd, getret, &at);
2369
goto out;
2370
}
2371
getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2372
nfsvno_getfs(&fs, isdgram);
2373
vput(vp);
2374
nfsrv_postopattr(nd, getret, &at);
2375
NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2376
*tl++ = txdr_unsigned(fs.fs_rtmax);
2377
*tl++ = txdr_unsigned(fs.fs_rtpref);
2378
*tl++ = txdr_unsigned(fs.fs_rtmult);
2379
*tl++ = txdr_unsigned(fs.fs_wtmax);
2380
*tl++ = txdr_unsigned(fs.fs_wtpref);
2381
*tl++ = txdr_unsigned(fs.fs_wtmult);
2382
*tl++ = txdr_unsigned(fs.fs_dtpref);
2383
txdr_hyper(fs.fs_maxfilesize, tl);
2384
tl += 2;
2385
txdr_nfsv3time(&fs.fs_timedelta, tl);
2386
tl += 2;
2387
*tl = txdr_unsigned(fs.fs_properties);
2388
2389
out:
2390
NFSEXITCODE2(0, nd);
2391
return (0);
2392
}
2393
2394
/*
2395
* nfs pathconf service
2396
*/
2397
int
2398
nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2399
vnode_t vp, __unused struct nfsexstuff *exp)
2400
{
2401
struct nfsv3_pathconf *pc;
2402
int getret = 1;
2403
long linkmax, namemax, chownres, notrunc;
2404
struct nfsvattr at;
2405
struct thread *p = curthread;
2406
2407
if (nd->nd_repstat) {
2408
nfsrv_postopattr(nd, getret, &at);
2409
goto out;
2410
}
2411
nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2412
nd->nd_cred, p);
2413
if (!nd->nd_repstat)
2414
nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2415
nd->nd_cred, p);
2416
if (!nd->nd_repstat)
2417
nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2418
&chownres, nd->nd_cred, p);
2419
if (!nd->nd_repstat)
2420
nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
2421
nd->nd_cred, p);
2422
getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
2423
vput(vp);
2424
nfsrv_postopattr(nd, getret, &at);
2425
if (!nd->nd_repstat) {
2426
NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2427
pc->pc_linkmax = txdr_unsigned(linkmax);
2428
pc->pc_namemax = txdr_unsigned(namemax);
2429
pc->pc_notrunc = txdr_unsigned(notrunc);
2430
pc->pc_chownrestricted = txdr_unsigned(chownres);
2431
2432
/*
2433
* These should probably be supported by VOP_PATHCONF(), but
2434
* until msdosfs is exportable (why would you want to?), the
2435
* Unix defaults should be ok.
2436
*/
2437
pc->pc_caseinsensitive = newnfs_false;
2438
pc->pc_casepreserving = newnfs_true;
2439
}
2440
2441
out:
2442
NFSEXITCODE2(0, nd);
2443
return (0);
2444
}
2445
2446
/*
2447
* nfsv4 lock service
2448
*/
2449
int
2450
nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2451
vnode_t vp, struct nfsexstuff *exp)
2452
{
2453
u_int32_t *tl;
2454
int i;
2455
struct nfsstate *stp = NULL;
2456
struct nfslock *lop;
2457
struct nfslockconflict cf;
2458
int error = 0;
2459
u_short flags = NFSLCK_LOCK, lflags;
2460
u_int64_t offset, len;
2461
nfsv4stateid_t stateid;
2462
nfsquad_t clientid;
2463
struct thread *p = curthread;
2464
2465
NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2466
i = fxdr_unsigned(int, *tl++);
2467
switch (i) {
2468
case NFSV4LOCKT_READW:
2469
flags |= NFSLCK_BLOCKING;
2470
case NFSV4LOCKT_READ:
2471
lflags = NFSLCK_READ;
2472
break;
2473
case NFSV4LOCKT_WRITEW:
2474
flags |= NFSLCK_BLOCKING;
2475
case NFSV4LOCKT_WRITE:
2476
lflags = NFSLCK_WRITE;
2477
break;
2478
default:
2479
nd->nd_repstat = NFSERR_BADXDR;
2480
goto nfsmout;
2481
}
2482
if (*tl++ == newnfs_true)
2483
flags |= NFSLCK_RECLAIM;
2484
offset = fxdr_hyper(tl);
2485
tl += 2;
2486
len = fxdr_hyper(tl);
2487
tl += 2;
2488
if (*tl == newnfs_true)
2489
flags |= NFSLCK_OPENTOLOCK;
2490
if (flags & NFSLCK_OPENTOLOCK) {
2491
NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2492
i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2493
if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2494
nd->nd_repstat = NFSERR_BADXDR;
2495
goto nfsmout;
2496
}
2497
stp = malloc(sizeof (struct nfsstate) + i,
2498
M_NFSDSTATE, M_WAITOK);
2499
stp->ls_ownerlen = i;
2500
stp->ls_op = nd->nd_rp;
2501
stp->ls_seq = fxdr_unsigned(int, *tl++);
2502
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2503
NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2504
NFSX_STATEIDOTHER);
2505
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2506
2507
/*
2508
* For the special stateid of other all 0s and seqid == 1, set
2509
* the stateid to the current stateid, if it is set.
2510
*/
2511
if ((nd->nd_flag & ND_NFSV41) != 0 &&
2512
stp->ls_stateid.seqid == 1 &&
2513
stp->ls_stateid.other[0] == 0 &&
2514
stp->ls_stateid.other[1] == 0 &&
2515
stp->ls_stateid.other[2] == 0) {
2516
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2517
stp->ls_stateid = nd->nd_curstateid;
2518
stp->ls_stateid.seqid = 0;
2519
} else {
2520
nd->nd_repstat = NFSERR_BADSTATEID;
2521
goto nfsmout;
2522
}
2523
}
2524
2525
stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2526
clientid.lval[0] = *tl++;
2527
clientid.lval[1] = *tl++;
2528
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2529
if ((nd->nd_flag & ND_NFSV41) != 0)
2530
clientid.qval = nd->nd_clientid.qval;
2531
else if (nd->nd_clientid.qval != clientid.qval)
2532
printf("EEK3 multiple clids\n");
2533
} else {
2534
if ((nd->nd_flag & ND_NFSV41) != 0)
2535
printf("EEK! no clientid from session\n");
2536
nd->nd_flag |= ND_IMPLIEDCLID;
2537
nd->nd_clientid.qval = clientid.qval;
2538
}
2539
error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2540
if (error)
2541
goto nfsmout;
2542
} else {
2543
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2544
stp = malloc(sizeof (struct nfsstate),
2545
M_NFSDSTATE, M_WAITOK);
2546
stp->ls_ownerlen = 0;
2547
stp->ls_op = nd->nd_rp;
2548
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2549
NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2550
NFSX_STATEIDOTHER);
2551
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2552
2553
/*
2554
* For the special stateid of other all 0s and seqid == 1, set
2555
* the stateid to the current stateid, if it is set.
2556
*/
2557
if ((nd->nd_flag & ND_NFSV41) != 0 &&
2558
stp->ls_stateid.seqid == 1 &&
2559
stp->ls_stateid.other[0] == 0 &&
2560
stp->ls_stateid.other[1] == 0 &&
2561
stp->ls_stateid.other[2] == 0) {
2562
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2563
stp->ls_stateid = nd->nd_curstateid;
2564
stp->ls_stateid.seqid = 0;
2565
} else {
2566
nd->nd_repstat = NFSERR_BADSTATEID;
2567
goto nfsmout;
2568
}
2569
}
2570
2571
stp->ls_seq = fxdr_unsigned(int, *tl);
2572
clientid.lval[0] = stp->ls_stateid.other[0];
2573
clientid.lval[1] = stp->ls_stateid.other[1];
2574
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2575
if ((nd->nd_flag & ND_NFSV41) != 0)
2576
clientid.qval = nd->nd_clientid.qval;
2577
else if (nd->nd_clientid.qval != clientid.qval)
2578
printf("EEK4 multiple clids\n");
2579
} else {
2580
if ((nd->nd_flag & ND_NFSV41) != 0)
2581
printf("EEK! no clientid from session\n");
2582
nd->nd_flag |= ND_IMPLIEDCLID;
2583
nd->nd_clientid.qval = clientid.qval;
2584
}
2585
}
2586
lop = malloc(sizeof (struct nfslock),
2587
M_NFSDLOCK, M_WAITOK);
2588
lop->lo_first = offset;
2589
if (len == NFS64BITSSET) {
2590
lop->lo_end = NFS64BITSSET;
2591
} else {
2592
lop->lo_end = offset + len;
2593
if (lop->lo_end <= lop->lo_first)
2594
nd->nd_repstat = NFSERR_INVAL;
2595
}
2596
lop->lo_flags = lflags;
2597
stp->ls_flags = flags;
2598
stp->ls_uid = nd->nd_cred->cr_uid;
2599
2600
/*
2601
* Do basic access checking.
2602
*/
2603
if (!nd->nd_repstat && vp->v_type != VREG) {
2604
if (vp->v_type == VDIR)
2605
nd->nd_repstat = NFSERR_ISDIR;
2606
else
2607
nd->nd_repstat = NFSERR_INVAL;
2608
}
2609
if (!nd->nd_repstat) {
2610
if (lflags & NFSLCK_WRITE) {
2611
nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2612
nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2613
NFSACCCHK_VPISLOCKED, NULL);
2614
} else {
2615
nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2616
nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2617
NFSACCCHK_VPISLOCKED, NULL);
2618
if (nd->nd_repstat)
2619
nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2620
nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2621
NFSACCCHK_VPISLOCKED, NULL);
2622
}
2623
}
2624
2625
/*
2626
* We call nfsrv_lockctrl() even if nd_repstat set, so that the
2627
* seqid# gets updated. nfsrv_lockctrl() will return the value
2628
* of nd_repstat, if it gets that far.
2629
*/
2630
nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2631
&stateid, exp, nd, p);
2632
if (lop)
2633
free(lop, M_NFSDLOCK);
2634
if (stp)
2635
free(stp, M_NFSDSTATE);
2636
if (!nd->nd_repstat) {
2637
/* For NFSv4.1, set the Current StateID. */
2638
if ((nd->nd_flag & ND_NFSV41) != 0) {
2639
nd->nd_curstateid = stateid;
2640
nd->nd_flag |= ND_CURSTATEID;
2641
}
2642
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2643
*tl++ = txdr_unsigned(stateid.seqid);
2644
NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2645
} else if (nd->nd_repstat == NFSERR_DENIED) {
2646
NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2647
txdr_hyper(cf.cl_first, tl);
2648
tl += 2;
2649
if (cf.cl_end == NFS64BITSSET)
2650
len = NFS64BITSSET;
2651
else
2652
len = cf.cl_end - cf.cl_first;
2653
txdr_hyper(len, tl);
2654
tl += 2;
2655
if (cf.cl_flags == NFSLCK_WRITE)
2656
*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2657
else
2658
*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2659
*tl++ = stateid.other[0];
2660
*tl = stateid.other[1];
2661
(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2662
}
2663
vput(vp);
2664
NFSEXITCODE2(0, nd);
2665
return (0);
2666
nfsmout:
2667
vput(vp);
2668
if (stp)
2669
free(stp, M_NFSDSTATE);
2670
NFSEXITCODE2(error, nd);
2671
return (error);
2672
}
2673
2674
/*
2675
* nfsv4 lock test service
2676
*/
2677
int
2678
nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2679
vnode_t vp, struct nfsexstuff *exp)
2680
{
2681
u_int32_t *tl;
2682
int i;
2683
struct nfsstate *stp = NULL;
2684
struct nfslock lo, *lop = &lo;
2685
struct nfslockconflict cf;
2686
int error = 0;
2687
nfsv4stateid_t stateid;
2688
nfsquad_t clientid;
2689
u_int64_t len;
2690
struct thread *p = curthread;
2691
2692
NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2693
i = fxdr_unsigned(int, *(tl + 7));
2694
if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2695
nd->nd_repstat = NFSERR_BADXDR;
2696
goto nfsmout;
2697
}
2698
stp = malloc(sizeof (struct nfsstate) + i,
2699
M_NFSDSTATE, M_WAITOK);
2700
stp->ls_ownerlen = i;
2701
stp->ls_op = NULL;
2702
stp->ls_flags = NFSLCK_TEST;
2703
stp->ls_uid = nd->nd_cred->cr_uid;
2704
i = fxdr_unsigned(int, *tl++);
2705
switch (i) {
2706
case NFSV4LOCKT_READW:
2707
stp->ls_flags |= NFSLCK_BLOCKING;
2708
case NFSV4LOCKT_READ:
2709
lo.lo_flags = NFSLCK_READ;
2710
break;
2711
case NFSV4LOCKT_WRITEW:
2712
stp->ls_flags |= NFSLCK_BLOCKING;
2713
case NFSV4LOCKT_WRITE:
2714
lo.lo_flags = NFSLCK_WRITE;
2715
break;
2716
default:
2717
nd->nd_repstat = NFSERR_BADXDR;
2718
goto nfsmout;
2719
}
2720
lo.lo_first = fxdr_hyper(tl);
2721
tl += 2;
2722
len = fxdr_hyper(tl);
2723
if (len == NFS64BITSSET) {
2724
lo.lo_end = NFS64BITSSET;
2725
} else {
2726
lo.lo_end = lo.lo_first + len;
2727
if (lo.lo_end <= lo.lo_first)
2728
nd->nd_repstat = NFSERR_INVAL;
2729
}
2730
tl += 2;
2731
clientid.lval[0] = *tl++;
2732
clientid.lval[1] = *tl;
2733
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2734
if ((nd->nd_flag & ND_NFSV41) != 0)
2735
clientid.qval = nd->nd_clientid.qval;
2736
else if (nd->nd_clientid.qval != clientid.qval)
2737
printf("EEK5 multiple clids\n");
2738
} else {
2739
if ((nd->nd_flag & ND_NFSV41) != 0)
2740
printf("EEK! no clientid from session\n");
2741
nd->nd_flag |= ND_IMPLIEDCLID;
2742
nd->nd_clientid.qval = clientid.qval;
2743
}
2744
error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2745
if (error)
2746
goto nfsmout;
2747
if (!nd->nd_repstat && vp->v_type != VREG) {
2748
if (vp->v_type == VDIR)
2749
nd->nd_repstat = NFSERR_ISDIR;
2750
else
2751
nd->nd_repstat = NFSERR_INVAL;
2752
}
2753
if (!nd->nd_repstat)
2754
nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2755
&stateid, exp, nd, p);
2756
if (nd->nd_repstat) {
2757
if (nd->nd_repstat == NFSERR_DENIED) {
2758
NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2759
txdr_hyper(cf.cl_first, tl);
2760
tl += 2;
2761
if (cf.cl_end == NFS64BITSSET)
2762
len = NFS64BITSSET;
2763
else
2764
len = cf.cl_end - cf.cl_first;
2765
txdr_hyper(len, tl);
2766
tl += 2;
2767
if (cf.cl_flags == NFSLCK_WRITE)
2768
*tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2769
else
2770
*tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2771
*tl++ = stp->ls_stateid.other[0];
2772
*tl = stp->ls_stateid.other[1];
2773
(void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2774
}
2775
}
2776
vput(vp);
2777
if (stp)
2778
free(stp, M_NFSDSTATE);
2779
NFSEXITCODE2(0, nd);
2780
return (0);
2781
nfsmout:
2782
vput(vp);
2783
if (stp)
2784
free(stp, M_NFSDSTATE);
2785
NFSEXITCODE2(error, nd);
2786
return (error);
2787
}
2788
2789
/*
2790
* nfsv4 unlock service
2791
*/
2792
int
2793
nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2794
vnode_t vp, struct nfsexstuff *exp)
2795
{
2796
u_int32_t *tl;
2797
int i;
2798
struct nfsstate *stp;
2799
struct nfslock *lop;
2800
int error = 0;
2801
nfsv4stateid_t stateid;
2802
nfsquad_t clientid;
2803
u_int64_t len;
2804
struct thread *p = curthread;
2805
2806
NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2807
stp = malloc(sizeof (struct nfsstate),
2808
M_NFSDSTATE, M_WAITOK);
2809
lop = malloc(sizeof (struct nfslock),
2810
M_NFSDLOCK, M_WAITOK);
2811
stp->ls_flags = NFSLCK_UNLOCK;
2812
lop->lo_flags = NFSLCK_UNLOCK;
2813
stp->ls_op = nd->nd_rp;
2814
i = fxdr_unsigned(int, *tl++);
2815
switch (i) {
2816
case NFSV4LOCKT_READW:
2817
stp->ls_flags |= NFSLCK_BLOCKING;
2818
case NFSV4LOCKT_READ:
2819
break;
2820
case NFSV4LOCKT_WRITEW:
2821
stp->ls_flags |= NFSLCK_BLOCKING;
2822
case NFSV4LOCKT_WRITE:
2823
break;
2824
default:
2825
nd->nd_repstat = NFSERR_BADXDR;
2826
free(stp, M_NFSDSTATE);
2827
free(lop, M_NFSDLOCK);
2828
goto nfsmout;
2829
}
2830
stp->ls_ownerlen = 0;
2831
stp->ls_uid = nd->nd_cred->cr_uid;
2832
stp->ls_seq = fxdr_unsigned(int, *tl++);
2833
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2834
NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2835
NFSX_STATEIDOTHER);
2836
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2837
2838
/*
2839
* For the special stateid of other all 0s and seqid == 1, set the
2840
* stateid to the current stateid, if it is set.
2841
*/
2842
if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
2843
stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
2844
stp->ls_stateid.other[2] == 0) {
2845
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
2846
stp->ls_stateid = nd->nd_curstateid;
2847
stp->ls_stateid.seqid = 0;
2848
} else {
2849
nd->nd_repstat = NFSERR_BADSTATEID;
2850
free(stp, M_NFSDSTATE);
2851
free(lop, M_NFSDLOCK);
2852
goto nfsmout;
2853
}
2854
}
2855
2856
lop->lo_first = fxdr_hyper(tl);
2857
tl += 2;
2858
len = fxdr_hyper(tl);
2859
if (len == NFS64BITSSET) {
2860
lop->lo_end = NFS64BITSSET;
2861
} else {
2862
lop->lo_end = lop->lo_first + len;
2863
if (lop->lo_end <= lop->lo_first)
2864
nd->nd_repstat = NFSERR_INVAL;
2865
}
2866
clientid.lval[0] = stp->ls_stateid.other[0];
2867
clientid.lval[1] = stp->ls_stateid.other[1];
2868
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
2869
if ((nd->nd_flag & ND_NFSV41) != 0)
2870
clientid.qval = nd->nd_clientid.qval;
2871
else if (nd->nd_clientid.qval != clientid.qval)
2872
printf("EEK6 multiple clids\n");
2873
} else {
2874
if ((nd->nd_flag & ND_NFSV41) != 0)
2875
printf("EEK! no clientid from session\n");
2876
nd->nd_flag |= ND_IMPLIEDCLID;
2877
nd->nd_clientid.qval = clientid.qval;
2878
}
2879
if (!nd->nd_repstat && vp->v_type != VREG) {
2880
if (vp->v_type == VDIR)
2881
nd->nd_repstat = NFSERR_ISDIR;
2882
else
2883
nd->nd_repstat = NFSERR_INVAL;
2884
}
2885
/*
2886
* Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2887
* seqid# gets incremented. nfsrv_lockctrl() will return the
2888
* value of nd_repstat, if it gets that far.
2889
*/
2890
nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2891
&stateid, exp, nd, p);
2892
if (stp)
2893
free(stp, M_NFSDSTATE);
2894
if (lop)
2895
free(lop, M_NFSDLOCK);
2896
if (!nd->nd_repstat) {
2897
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2898
*tl++ = txdr_unsigned(stateid.seqid);
2899
NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2900
}
2901
nfsmout:
2902
vput(vp);
2903
NFSEXITCODE2(error, nd);
2904
return (error);
2905
}
2906
2907
/*
2908
* nfsv4 open service
2909
*/
2910
int
2911
nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2912
vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
2913
{
2914
u_int32_t *tl;
2915
int i, retext;
2916
struct nfsstate *stp = NULL;
2917
int error = 0, create, claim, exclusive_flag = 0, override;
2918
u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2919
int how = NFSCREATE_UNCHECKED;
2920
int32_t cverf[2], tverf[2] = { 0, 0 };
2921
vnode_t vp = NULL, dirp = NULL;
2922
struct nfsvattr nva, dirfor, diraft, nva2;
2923
struct nameidata named;
2924
nfsv4stateid_t stateid, delegstateid;
2925
nfsattrbit_t attrbits;
2926
nfsquad_t clientid;
2927
char *bufp = NULL;
2928
u_long *hashp;
2929
NFSACL_T *aclp = NULL;
2930
struct thread *p = curthread;
2931
bool done_namei;
2932
__enum_uint8_decl(wdelegace) { USENONE, USEMODE, USENFSV4ACL }
2933
delegace;
2934
2935
#ifdef NFS4_ACL_EXTATTR_NAME
2936
aclp = acl_alloc(M_WAITOK);
2937
aclp->acl_cnt = 0;
2938
#endif
2939
NFSZERO_ATTRBIT(&attrbits);
2940
done_namei = false;
2941
delegace = USEMODE;
2942
named.ni_cnd.cn_nameiop = 0;
2943
NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2944
i = fxdr_unsigned(int, *(tl + 5));
2945
if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2946
nd->nd_repstat = NFSERR_BADXDR;
2947
goto nfsmout;
2948
}
2949
stp = malloc(sizeof (struct nfsstate) + i,
2950
M_NFSDSTATE, M_WAITOK);
2951
stp->ls_ownerlen = i;
2952
stp->ls_op = nd->nd_rp;
2953
stp->ls_flags = NFSLCK_OPEN;
2954
stp->ls_uid = nd->nd_cred->cr_uid;
2955
stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2956
i = fxdr_unsigned(int, *tl++);
2957
retext = 0;
2958
if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
2959
NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
2960
retext = 1;
2961
/* For now, ignore these. */
2962
i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
2963
switch (i & NFSV4OPEN_WANTDELEGMASK) {
2964
case NFSV4OPEN_WANTANYDELEG:
2965
stp->ls_flags |= (NFSLCK_WANTRDELEG |
2966
NFSLCK_WANTWDELEG);
2967
i &= ~NFSV4OPEN_WANTDELEGMASK;
2968
break;
2969
case NFSV4OPEN_WANTREADDELEG:
2970
stp->ls_flags |= NFSLCK_WANTRDELEG;
2971
i &= ~NFSV4OPEN_WANTDELEGMASK;
2972
break;
2973
case NFSV4OPEN_WANTWRITEDELEG:
2974
stp->ls_flags |= NFSLCK_WANTWDELEG;
2975
i &= ~NFSV4OPEN_WANTDELEGMASK;
2976
break;
2977
case NFSV4OPEN_WANTNODELEG:
2978
stp->ls_flags |= NFSLCK_WANTNODELEG;
2979
i &= ~NFSV4OPEN_WANTDELEGMASK;
2980
break;
2981
case NFSV4OPEN_WANTCANCEL:
2982
printf("NFSv4: ignore Open WantCancel\n");
2983
i &= ~NFSV4OPEN_WANTDELEGMASK;
2984
break;
2985
default:
2986
/* nd_repstat will be set to NFSERR_INVAL below. */
2987
break;
2988
}
2989
}
2990
switch (i) {
2991
case NFSV4OPEN_ACCESSREAD:
2992
stp->ls_flags |= NFSLCK_READACCESS;
2993
break;
2994
case NFSV4OPEN_ACCESSWRITE:
2995
stp->ls_flags |= NFSLCK_WRITEACCESS;
2996
break;
2997
case NFSV4OPEN_ACCESSBOTH:
2998
stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2999
break;
3000
default:
3001
nd->nd_repstat = NFSERR_INVAL;
3002
}
3003
i = fxdr_unsigned(int, *tl++);
3004
switch (i) {
3005
case NFSV4OPEN_DENYNONE:
3006
break;
3007
case NFSV4OPEN_DENYREAD:
3008
stp->ls_flags |= NFSLCK_READDENY;
3009
break;
3010
case NFSV4OPEN_DENYWRITE:
3011
stp->ls_flags |= NFSLCK_WRITEDENY;
3012
break;
3013
case NFSV4OPEN_DENYBOTH:
3014
stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3015
break;
3016
default:
3017
nd->nd_repstat = NFSERR_INVAL;
3018
}
3019
clientid.lval[0] = *tl++;
3020
clientid.lval[1] = *tl;
3021
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3022
if ((nd->nd_flag & ND_NFSV41) != 0)
3023
clientid.qval = nd->nd_clientid.qval;
3024
else if (nd->nd_clientid.qval != clientid.qval)
3025
printf("EEK7 multiple clids\n");
3026
} else {
3027
if ((nd->nd_flag & ND_NFSV41) != 0)
3028
printf("EEK! no clientid from session\n");
3029
nd->nd_flag |= ND_IMPLIEDCLID;
3030
nd->nd_clientid.qval = clientid.qval;
3031
}
3032
error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
3033
if (error)
3034
goto nfsmout;
3035
NFSVNO_ATTRINIT(&nva);
3036
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3037
create = fxdr_unsigned(int, *tl);
3038
if (!nd->nd_repstat)
3039
nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
3040
if (create == NFSV4OPEN_CREATE) {
3041
nva.na_type = VREG;
3042
nva.na_mode = 0;
3043
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3044
how = fxdr_unsigned(int, *tl);
3045
switch (how) {
3046
case NFSCREATE_UNCHECKED:
3047
case NFSCREATE_GUARDED:
3048
error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
3049
if (error)
3050
goto nfsmout;
3051
/*
3052
* If the na_gid being set is the same as that of
3053
* the directory it is going in, clear it, since
3054
* that is what will be set by default. This allows
3055
* a user that isn't in that group to do the create.
3056
*/
3057
if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
3058
nva.na_gid == dirfor.na_gid)
3059
NFSVNO_UNSET(&nva, gid);
3060
if (!nd->nd_repstat)
3061
nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
3062
break;
3063
case NFSCREATE_EXCLUSIVE:
3064
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3065
cverf[0] = *tl++;
3066
cverf[1] = *tl;
3067
if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0)
3068
nd->nd_repstat = NFSERR_INVAL;
3069
break;
3070
case NFSCREATE_EXCLUSIVE41:
3071
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3072
cverf[0] = *tl++;
3073
cverf[1] = *tl;
3074
error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
3075
if (error != 0)
3076
goto nfsmout;
3077
if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0 ||
3078
NFSISSET_ATTRBIT(&attrbits,
3079
NFSATTRBIT_TIMEACCESSSET))
3080
nd->nd_repstat = NFSERR_INVAL;
3081
/*
3082
* If the na_gid being set is the same as that of
3083
* the directory it is going in, clear it, since
3084
* that is what will be set by default. This allows
3085
* a user that isn't in that group to do the create.
3086
*/
3087
if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
3088
nva.na_gid == dirfor.na_gid)
3089
NFSVNO_UNSET(&nva, gid);
3090
if (nd->nd_repstat == 0)
3091
nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
3092
break;
3093
default:
3094
nd->nd_repstat = NFSERR_BADXDR;
3095
goto nfsmout;
3096
}
3097
} else if (create != NFSV4OPEN_NOCREATE) {
3098
nd->nd_repstat = NFSERR_BADXDR;
3099
goto nfsmout;
3100
}
3101
3102
/*
3103
* Now, handle the claim, which usually includes looking up a
3104
* name in the directory referenced by dp. The exception is
3105
* NFSV4OPEN_CLAIMPREVIOUS.
3106
*/
3107
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3108
claim = fxdr_unsigned(int, *tl);
3109
if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim ==
3110
NFSV4OPEN_CLAIMDELEGATECURFH) {
3111
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3112
stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3113
NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
3114
stp->ls_flags |= NFSLCK_DELEGCUR;
3115
} else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim ==
3116
NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3117
stp->ls_flags |= NFSLCK_DELEGPREV;
3118
}
3119
if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
3120
|| claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
3121
if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
3122
claim != NFSV4OPEN_CLAIMNULL)
3123
nd->nd_repstat = NFSERR_INVAL;
3124
if (nd->nd_repstat) {
3125
nd->nd_repstat = nfsrv_opencheck(clientid,
3126
&stateid, stp, NULL, nd, p, nd->nd_repstat);
3127
goto nfsmout;
3128
}
3129
if (create == NFSV4OPEN_CREATE)
3130
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
3131
LOCKPARENT | LOCKLEAF | NOCACHE);
3132
else
3133
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3134
LOCKLEAF);
3135
nfsvno_setpathbuf(&named, &bufp, &hashp);
3136
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3137
if (error) {
3138
vrele(dp);
3139
#ifdef NFS4_ACL_EXTATTR_NAME
3140
acl_free(aclp);
3141
#endif
3142
free(stp, M_NFSDSTATE);
3143
nfsvno_relpathbuf(&named);
3144
NFSEXITCODE2(error, nd);
3145
return (error);
3146
}
3147
if (!nd->nd_repstat) {
3148
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
3149
&dirp);
3150
} else {
3151
vrele(dp);
3152
nfsvno_relpathbuf(&named);
3153
}
3154
if (create == NFSV4OPEN_CREATE) {
3155
switch (how) {
3156
case NFSCREATE_UNCHECKED:
3157
if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3158
/*
3159
* Clear the setable attribute bits, except
3160
* for Size, if it is being truncated.
3161
*/
3162
NFSZERO_ATTRBIT(&attrbits);
3163
if (NFSVNO_ISSETSIZE(&nva))
3164
NFSSETBIT_ATTRBIT(&attrbits,
3165
NFSATTRBIT_SIZE);
3166
}
3167
break;
3168
case NFSCREATE_GUARDED:
3169
if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3170
nd->nd_repstat = EEXIST;
3171
done_namei = true;
3172
}
3173
break;
3174
case NFSCREATE_EXCLUSIVE:
3175
if (nd->nd_repstat == 0 && named.ni_vp == NULL)
3176
nva.na_mode = 0;
3177
/* FALLTHROUGH */
3178
case NFSCREATE_EXCLUSIVE41:
3179
if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3180
nd->nd_repstat = nfsvno_getattr(named.ni_vp,
3181
&nva2, nd, p, 1, NULL);
3182
if (nd->nd_repstat == 0) {
3183
tverf[0] = nva2.na_atime.tv_sec;
3184
tverf[1] = nva2.na_atime.tv_nsec;
3185
if (cverf[0] != tverf[0] ||
3186
cverf[1] != tverf[1])
3187
nd->nd_repstat = EEXIST;
3188
}
3189
if (nd->nd_repstat != 0)
3190
done_namei = true;
3191
}
3192
exclusive_flag = 1;
3193
break;
3194
}
3195
}
3196
nfsvno_open(nd, &named, clientid, &stateid, stp,
3197
&exclusive_flag, &nva, cverf, create, aclp, &attrbits,
3198
nd->nd_cred, done_namei, exp, &vp);
3199
} else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3200
NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH ||
3201
claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3202
if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3203
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3204
i = fxdr_unsigned(int, *tl);
3205
switch (i) {
3206
case NFSV4OPEN_DELEGATEREAD:
3207
stp->ls_flags |= NFSLCK_DELEGREAD;
3208
break;
3209
case NFSV4OPEN_DELEGATEWRITE:
3210
stp->ls_flags |= NFSLCK_DELEGWRITE;
3211
case NFSV4OPEN_DELEGATENONE:
3212
break;
3213
default:
3214
nd->nd_repstat = NFSERR_BADXDR;
3215
goto nfsmout;
3216
}
3217
stp->ls_flags |= NFSLCK_RECLAIM;
3218
} else {
3219
if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3220
nd->nd_repstat = NFSERR_INVAL;
3221
}
3222
vp = dp;
3223
NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3224
if (!VN_IS_DOOMED(vp))
3225
nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3226
stp, vp, nd, p, nd->nd_repstat);
3227
else
3228
nd->nd_repstat = NFSERR_PERM;
3229
} else {
3230
nd->nd_repstat = NFSERR_BADXDR;
3231
goto nfsmout;
3232
}
3233
3234
/*
3235
* Do basic access checking.
3236
*/
3237
if (!nd->nd_repstat && vp->v_type != VREG) {
3238
/*
3239
* The IETF working group decided that this is the correct
3240
* error return for all non-regular files.
3241
*/
3242
nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3243
}
3244
3245
/*
3246
* If the Open is being done for a file that already exists, apply
3247
* normal permission checking including for the file owner, if
3248
* vfs.nfsd.v4openaccess is set.
3249
* Previously, the owner was always allowed to open the file to
3250
* be consistent with the NFS tradition of always allowing the
3251
* owner of the file to write to the file regardless of permissions.
3252
* It now appears that the Linux client expects the owner
3253
* permissions to be checked for opens that are not creating the
3254
* file. I believe the correct approach is to use the Access
3255
* operation's results to be consistent with NFSv3, but that is
3256
* not what the current Linux client appears to be doing.
3257
* Since both the Linux and OpenSolaris NFSv4 servers do this check,
3258
* I have enabled it by default. Since Linux does not apply this
3259
* check for claim_delegate_cur, this code does the same.
3260
* If this semantic change causes a problem, it can be disabled by
3261
* setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the
3262
* previous semantics.
3263
*/
3264
if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE &&
3265
(stp->ls_flags & NFSLCK_DELEGCUR) == 0)
3266
override = NFSACCCHK_NOOVERRIDE;
3267
else
3268
override = NFSACCCHK_ALLOWOWNER;
3269
if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3270
nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3271
exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3272
if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3273
nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3274
exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3275
if (nd->nd_repstat)
3276
nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3277
nd->nd_cred, exp, p, override,
3278
NFSACCCHK_VPISLOCKED, NULL);
3279
}
3280
3281
if (!nd->nd_repstat)
3282
nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3283
3284
if (nd->nd_repstat == 0 && aclp != NULL && nfsrv_issuedelegs != 0 &&
3285
(dp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) {
3286
if (aclp->acl_cnt == 0 && create == NFSV4OPEN_NOCREATE) {
3287
int retacl;
3288
3289
/* We do not yet have an ACL, so try and get one. */
3290
retacl = VOP_GETACL(vp, ACL_TYPE_NFS4, aclp,
3291
nd->nd_cred, p);
3292
if (retacl != 0 && retacl != ENOATTR &&
3293
retacl != EOPNOTSUPP && retacl != EINVAL)
3294
delegace = USENONE;
3295
else if (retacl == 0 && aclp->acl_cnt > 0)
3296
delegace = USENFSV4ACL;
3297
} else if (aclp->acl_cnt > 0 && create == NFSV4OPEN_CREATE) {
3298
delegace = USENFSV4ACL;
3299
}
3300
}
3301
3302
/*
3303
* Do the open locking/delegation stuff.
3304
*/
3305
if (!nd->nd_repstat)
3306
nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3307
&delegstateid, &rflags, exp, p, nva.na_filerev);
3308
3309
/*
3310
* vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3311
* below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3312
* (ie: Leave the NFSVOPUNLOCK() about here.)
3313
*/
3314
if (vp)
3315
NFSVOPUNLOCK(vp);
3316
if (stp)
3317
free(stp, M_NFSDSTATE);
3318
if (!nd->nd_repstat && dirp)
3319
nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3320
if (!nd->nd_repstat) {
3321
/* For NFSv4.1, set the Current StateID. */
3322
if ((nd->nd_flag & ND_NFSV41) != 0) {
3323
nd->nd_curstateid = stateid;
3324
nd->nd_flag |= ND_CURSTATEID;
3325
}
3326
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3327
*tl++ = txdr_unsigned(stateid.seqid);
3328
NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3329
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3330
if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3331
*tl++ = newnfs_true;
3332
*tl++ = 0;
3333
*tl++ = 0;
3334
*tl++ = 0;
3335
*tl++ = 0;
3336
} else {
3337
*tl++ = newnfs_false; /* Since dirp is not locked */
3338
txdr_hyper(dirfor.na_filerev, tl);
3339
tl += 2;
3340
txdr_hyper(diraft.na_filerev, tl);
3341
tl += 2;
3342
}
3343
*tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3344
(void) nfsrv_putattrbit(nd, &attrbits);
3345
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3346
if (rflags & NFSV4OPEN_READDELEGATE)
3347
*tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3348
else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3349
*tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3350
else if (retext != 0) {
3351
*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3352
if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3353
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3354
*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3355
} else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3356
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3357
*tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3358
} else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3359
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3360
*tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3361
*tl = newnfs_false;
3362
} else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3363
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3364
*tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3365
*tl = newnfs_false;
3366
} else if ((rflags &
3367
NFSV4OPEN_WDNOTSUPPDOWNGRADE) != 0) {
3368
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3369
*tl = txdr_unsigned(NFSV4OPEN_NOTSUPPDOWNGRADE);
3370
} else if ((rflags & NFSV4OPEN_WDNOTSUPPUPGRADE) != 0) {
3371
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3372
*tl = txdr_unsigned(NFSV4OPEN_NOTSUPPUPGRADE);
3373
} else {
3374
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3375
*tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3376
}
3377
} else
3378
*tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3379
if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3380
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3381
*tl++ = txdr_unsigned(delegstateid.seqid);
3382
NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3383
NFSX_STATEIDOTHER);
3384
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3385
if (rflags & NFSV4OPEN_RECALL)
3386
*tl = newnfs_true;
3387
else
3388
*tl = newnfs_false;
3389
if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3390
NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3391
*tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3392
txdr_hyper(nva.na_size, tl);
3393
}
3394
3395
/* Set up the write delegation ACE. */
3396
NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3397
if (delegace == USENFSV4ACL) {
3398
int j;
3399
3400
for (j = 0; j < aclp->acl_cnt; j++) {
3401
if (aclp->acl_entry[j].ae_tag ==
3402
ACL_USER_OBJ ||
3403
aclp->acl_entry[j].ae_entry_type !=
3404
ACL_ENTRY_TYPE_ALLOW)
3405
break;
3406
}
3407
if (j < aclp->acl_cnt &&
3408
aclp->acl_entry[j].ae_tag ==
3409
ACL_USER_OBJ &&
3410
aclp->acl_entry[j].ae_entry_type ==
3411
ACL_ENTRY_TYPE_ALLOW) {
3412
/* Use this ACE. */
3413
*tl++ = txdr_unsigned(
3414
NFSV4ACE_ALLOWEDTYPE);
3415
*tl++ = txdr_unsigned(0x0);
3416
*tl = txdr_unsigned(
3417
nfs_aceperm(
3418
aclp->acl_entry[j].ae_perm));
3419
(void)nfsm_strtom(nd, "OWNER@", 6);
3420
} else
3421
delegace = USENONE;
3422
}
3423
if (delegace == USENONE) {
3424
/* Don't allow anything. */
3425
*tl++ = 0x0;
3426
*tl++ = 0x0;
3427
*tl = 0x0;
3428
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3429
*tl = 0;
3430
} else if (delegace == USEMODE) {
3431
/* Build from mode. */
3432
*tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3433
*tl++ = txdr_unsigned(0x0);
3434
acemask = NFSV4ACE_ALLFILESMASK;
3435
if (nva.na_mode & S_IRUSR)
3436
acemask |= NFSV4ACE_READMASK;
3437
if (nva.na_mode & S_IWUSR)
3438
acemask |= NFSV4ACE_WRITEMASK;
3439
if (nva.na_mode & S_IXUSR)
3440
acemask |= NFSV4ACE_EXECUTEMASK;
3441
*tl = txdr_unsigned(acemask);
3442
(void)nfsm_strtom(nd, "OWNER@", 6);
3443
}
3444
}
3445
*vpp = vp;
3446
} else if (vp) {
3447
vrele(vp);
3448
}
3449
if (dirp)
3450
vrele(dirp);
3451
#ifdef NFS4_ACL_EXTATTR_NAME
3452
acl_free(aclp);
3453
#endif
3454
NFSEXITCODE2(0, nd);
3455
return (0);
3456
nfsmout:
3457
vrele(dp);
3458
#ifdef NFS4_ACL_EXTATTR_NAME
3459
acl_free(aclp);
3460
#endif
3461
if (stp)
3462
free(stp, M_NFSDSTATE);
3463
NFSEXITCODE2(error, nd);
3464
return (error);
3465
}
3466
3467
/*
3468
* nfsv4 close service
3469
*/
3470
int
3471
nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3472
vnode_t vp, __unused struct nfsexstuff *exp)
3473
{
3474
u_int32_t *tl;
3475
struct nfsstate st, *stp = &st;
3476
int error = 0, writeacc;
3477
nfsv4stateid_t stateid;
3478
nfsquad_t clientid;
3479
struct nfsvattr na;
3480
struct thread *p = curthread;
3481
3482
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3483
stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3484
stp->ls_ownerlen = 0;
3485
stp->ls_op = nd->nd_rp;
3486
stp->ls_uid = nd->nd_cred->cr_uid;
3487
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3488
NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3489
NFSX_STATEIDOTHER);
3490
3491
/*
3492
* For the special stateid of other all 0s and seqid == 1, set the
3493
* stateid to the current stateid, if it is set.
3494
*/
3495
if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3496
stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3497
stp->ls_stateid.other[2] == 0) {
3498
if ((nd->nd_flag & ND_CURSTATEID) != 0)
3499
stp->ls_stateid = nd->nd_curstateid;
3500
else {
3501
nd->nd_repstat = NFSERR_BADSTATEID;
3502
goto nfsmout;
3503
}
3504
}
3505
3506
stp->ls_flags = NFSLCK_CLOSE;
3507
clientid.lval[0] = stp->ls_stateid.other[0];
3508
clientid.lval[1] = stp->ls_stateid.other[1];
3509
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3510
if ((nd->nd_flag & ND_NFSV41) != 0)
3511
clientid.qval = nd->nd_clientid.qval;
3512
else if (nd->nd_clientid.qval != clientid.qval)
3513
printf("EEK8 multiple clids\n");
3514
} else {
3515
if ((nd->nd_flag & ND_NFSV41) != 0)
3516
printf("EEK! no clientid from session\n");
3517
nd->nd_flag |= ND_IMPLIEDCLID;
3518
nd->nd_clientid.qval = clientid.qval;
3519
}
3520
nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3521
&writeacc);
3522
/* For pNFS, update the attributes. */
3523
if (writeacc != 0 || nfsrv_pnfsatime != 0)
3524
nfsrv_updatemdsattr(vp, &na, p);
3525
vput(vp);
3526
if (!nd->nd_repstat) {
3527
/*
3528
* If the stateid that has been closed is the current stateid,
3529
* unset it.
3530
*/
3531
if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3532
stateid.other[0] == nd->nd_curstateid.other[0] &&
3533
stateid.other[1] == nd->nd_curstateid.other[1] &&
3534
stateid.other[2] == nd->nd_curstateid.other[2])
3535
nd->nd_flag &= ~ND_CURSTATEID;
3536
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3537
*tl++ = txdr_unsigned(stateid.seqid);
3538
NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3539
}
3540
NFSEXITCODE2(0, nd);
3541
return (0);
3542
nfsmout:
3543
vput(vp);
3544
NFSEXITCODE2(error, nd);
3545
return (error);
3546
}
3547
3548
/*
3549
* nfsv4 delegpurge service
3550
*/
3551
int
3552
nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3553
__unused vnode_t vp, __unused struct nfsexstuff *exp)
3554
{
3555
u_int32_t *tl;
3556
int error = 0;
3557
nfsquad_t clientid;
3558
struct thread *p = curthread;
3559
3560
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3561
goto nfsmout;
3562
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3563
clientid.lval[0] = *tl++;
3564
clientid.lval[1] = *tl;
3565
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3566
if ((nd->nd_flag & ND_NFSV41) != 0)
3567
clientid.qval = nd->nd_clientid.qval;
3568
else if (nd->nd_clientid.qval != clientid.qval)
3569
printf("EEK9 multiple clids\n");
3570
} else {
3571
if ((nd->nd_flag & ND_NFSV41) != 0)
3572
printf("EEK! no clientid from session\n");
3573
nd->nd_flag |= ND_IMPLIEDCLID;
3574
nd->nd_clientid.qval = clientid.qval;
3575
}
3576
nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3577
NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3578
nfsmout:
3579
NFSEXITCODE2(error, nd);
3580
return (error);
3581
}
3582
3583
/*
3584
* nfsv4 delegreturn service
3585
*/
3586
int
3587
nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3588
vnode_t vp, __unused struct nfsexstuff *exp)
3589
{
3590
u_int32_t *tl;
3591
int error = 0, writeacc;
3592
nfsv4stateid_t stateid;
3593
nfsquad_t clientid;
3594
struct nfsvattr na;
3595
struct thread *p = curthread;
3596
3597
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3598
stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3599
NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3600
clientid.lval[0] = stateid.other[0];
3601
clientid.lval[1] = stateid.other[1];
3602
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3603
if ((nd->nd_flag & ND_NFSV41) != 0)
3604
clientid.qval = nd->nd_clientid.qval;
3605
else if (nd->nd_clientid.qval != clientid.qval)
3606
printf("EEK10 multiple clids\n");
3607
} else {
3608
if ((nd->nd_flag & ND_NFSV41) != 0)
3609
printf("EEK! no clientid from session\n");
3610
nd->nd_flag |= ND_IMPLIEDCLID;
3611
nd->nd_clientid.qval = clientid.qval;
3612
}
3613
nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3614
NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3615
/* For pNFS, update the attributes. */
3616
if (writeacc != 0 || nfsrv_pnfsatime != 0)
3617
nfsrv_updatemdsattr(vp, &na, p);
3618
nfsmout:
3619
vput(vp);
3620
NFSEXITCODE2(error, nd);
3621
return (error);
3622
}
3623
3624
/*
3625
* nfsv4 get file handle service
3626
*/
3627
int
3628
nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3629
vnode_t vp, __unused struct nfsexstuff *exp)
3630
{
3631
fhandle_t fh;
3632
struct thread *p = curthread;
3633
int siz;
3634
short irflag;
3635
3636
nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3637
irflag = vn_irflag_read(vp);
3638
vput(vp);
3639
if (nd->nd_repstat == 0) {
3640
siz = 0;
3641
if ((irflag & VIRF_NAMEDDIR) != 0)
3642
siz = NFSX_FHMAX + NFSX_V4NAMEDDIRFH;
3643
else if ((irflag & VIRF_NAMEDATTR) != 0)
3644
siz = NFSX_FHMAX + NFSX_V4NAMEDATTRFH;
3645
(void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, siz, 0);
3646
}
3647
NFSEXITCODE2(0, nd);
3648
return (0);
3649
}
3650
3651
/*
3652
* nfsv4 open confirm service
3653
*/
3654
int
3655
nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3656
vnode_t vp, __unused struct nfsexstuff *exp)
3657
{
3658
u_int32_t *tl;
3659
struct nfsstate st, *stp = &st;
3660
int error = 0;
3661
nfsv4stateid_t stateid;
3662
nfsquad_t clientid;
3663
struct thread *p = curthread;
3664
3665
if ((nd->nd_flag & ND_NFSV41) != 0) {
3666
nd->nd_repstat = NFSERR_NOTSUPP;
3667
goto nfsmout;
3668
}
3669
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3670
stp->ls_ownerlen = 0;
3671
stp->ls_op = nd->nd_rp;
3672
stp->ls_uid = nd->nd_cred->cr_uid;
3673
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3674
NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3675
NFSX_STATEIDOTHER);
3676
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3677
stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3678
stp->ls_flags = NFSLCK_CONFIRM;
3679
clientid.lval[0] = stp->ls_stateid.other[0];
3680
clientid.lval[1] = stp->ls_stateid.other[1];
3681
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3682
if ((nd->nd_flag & ND_NFSV41) != 0)
3683
clientid.qval = nd->nd_clientid.qval;
3684
else if (nd->nd_clientid.qval != clientid.qval)
3685
printf("EEK11 multiple clids\n");
3686
} else {
3687
if ((nd->nd_flag & ND_NFSV41) != 0)
3688
printf("EEK! no clientid from session\n");
3689
nd->nd_flag |= ND_IMPLIEDCLID;
3690
nd->nd_clientid.qval = clientid.qval;
3691
}
3692
nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3693
NULL);
3694
if (!nd->nd_repstat) {
3695
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3696
*tl++ = txdr_unsigned(stateid.seqid);
3697
NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3698
}
3699
nfsmout:
3700
vput(vp);
3701
NFSEXITCODE2(error, nd);
3702
return (error);
3703
}
3704
3705
/*
3706
* nfsv4 open downgrade service
3707
*/
3708
int
3709
nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3710
vnode_t vp, __unused struct nfsexstuff *exp)
3711
{
3712
u_int32_t *tl;
3713
int i;
3714
struct nfsstate st, *stp = &st;
3715
int error = 0;
3716
nfsv4stateid_t stateid;
3717
nfsquad_t clientid;
3718
struct thread *p = curthread;
3719
3720
/* opendowngrade can only work on a file object.*/
3721
if (vp->v_type != VREG) {
3722
error = NFSERR_INVAL;
3723
goto nfsmout;
3724
}
3725
NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3726
stp->ls_ownerlen = 0;
3727
stp->ls_op = nd->nd_rp;
3728
stp->ls_uid = nd->nd_cred->cr_uid;
3729
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3730
NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3731
NFSX_STATEIDOTHER);
3732
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3733
3734
/*
3735
* For the special stateid of other all 0s and seqid == 1, set the
3736
* stateid to the current stateid, if it is set.
3737
*/
3738
if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3739
stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3740
stp->ls_stateid.other[2] == 0) {
3741
if ((nd->nd_flag & ND_CURSTATEID) != 0)
3742
stp->ls_stateid = nd->nd_curstateid;
3743
else {
3744
nd->nd_repstat = NFSERR_BADSTATEID;
3745
goto nfsmout;
3746
}
3747
}
3748
3749
stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3750
i = fxdr_unsigned(int, *tl++);
3751
if ((nd->nd_flag & ND_NFSV41) != 0)
3752
i &= ~NFSV4OPEN_WANTDELEGMASK;
3753
switch (i) {
3754
case NFSV4OPEN_ACCESSREAD:
3755
stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3756
break;
3757
case NFSV4OPEN_ACCESSWRITE:
3758
stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3759
break;
3760
case NFSV4OPEN_ACCESSBOTH:
3761
stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3762
NFSLCK_DOWNGRADE);
3763
break;
3764
default:
3765
nd->nd_repstat = NFSERR_INVAL;
3766
}
3767
i = fxdr_unsigned(int, *tl);
3768
switch (i) {
3769
case NFSV4OPEN_DENYNONE:
3770
break;
3771
case NFSV4OPEN_DENYREAD:
3772
stp->ls_flags |= NFSLCK_READDENY;
3773
break;
3774
case NFSV4OPEN_DENYWRITE:
3775
stp->ls_flags |= NFSLCK_WRITEDENY;
3776
break;
3777
case NFSV4OPEN_DENYBOTH:
3778
stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3779
break;
3780
default:
3781
nd->nd_repstat = NFSERR_INVAL;
3782
}
3783
3784
clientid.lval[0] = stp->ls_stateid.other[0];
3785
clientid.lval[1] = stp->ls_stateid.other[1];
3786
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3787
if ((nd->nd_flag & ND_NFSV41) != 0)
3788
clientid.qval = nd->nd_clientid.qval;
3789
else if (nd->nd_clientid.qval != clientid.qval)
3790
printf("EEK12 multiple clids\n");
3791
} else {
3792
if ((nd->nd_flag & ND_NFSV41) != 0)
3793
printf("EEK! no clientid from session\n");
3794
nd->nd_flag |= ND_IMPLIEDCLID;
3795
nd->nd_clientid.qval = clientid.qval;
3796
}
3797
if (!nd->nd_repstat)
3798
nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3799
nd, p, NULL);
3800
if (!nd->nd_repstat) {
3801
/* For NFSv4.1, set the Current StateID. */
3802
if ((nd->nd_flag & ND_NFSV41) != 0) {
3803
nd->nd_curstateid = stateid;
3804
nd->nd_flag |= ND_CURSTATEID;
3805
}
3806
NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3807
*tl++ = txdr_unsigned(stateid.seqid);
3808
NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3809
}
3810
nfsmout:
3811
vput(vp);
3812
NFSEXITCODE2(error, nd);
3813
return (error);
3814
}
3815
3816
/*
3817
* nfsv4 renew lease service
3818
*/
3819
int
3820
nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3821
__unused vnode_t vp, __unused struct nfsexstuff *exp)
3822
{
3823
u_int32_t *tl;
3824
int error = 0;
3825
nfsquad_t clientid;
3826
struct thread *p = curthread;
3827
3828
if ((nd->nd_flag & ND_NFSV41) != 0) {
3829
nd->nd_repstat = NFSERR_NOTSUPP;
3830
goto nfsmout;
3831
}
3832
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3833
goto nfsmout;
3834
NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3835
clientid.lval[0] = *tl++;
3836
clientid.lval[1] = *tl;
3837
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3838
if ((nd->nd_flag & ND_NFSV41) != 0)
3839
clientid.qval = nd->nd_clientid.qval;
3840
else if (nd->nd_clientid.qval != clientid.qval)
3841
printf("EEK13 multiple clids\n");
3842
} else {
3843
if ((nd->nd_flag & ND_NFSV41) != 0)
3844
printf("EEK! no clientid from session\n");
3845
nd->nd_flag |= ND_IMPLIEDCLID;
3846
nd->nd_clientid.qval = clientid.qval;
3847
}
3848
nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3849
NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3850
nfsmout:
3851
NFSEXITCODE2(error, nd);
3852
return (error);
3853
}
3854
3855
/*
3856
* nfsv4 security info service
3857
*/
3858
int
3859
nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3860
vnode_t dp, struct nfsexstuff *exp)
3861
{
3862
u_int32_t *tl;
3863
int len;
3864
struct nameidata named;
3865
vnode_t dirp = NULL, vp;
3866
struct nfsrvfh fh;
3867
struct nfsexstuff retnes;
3868
u_int32_t *sizp;
3869
int error = 0, i;
3870
uint64_t savflag;
3871
char *bufp;
3872
u_long *hashp;
3873
struct thread *p = curthread;
3874
3875
/*
3876
* All this just to get the export flags for the name.
3877
*/
3878
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3879
LOCKLEAF);
3880
nfsvno_setpathbuf(&named, &bufp, &hashp);
3881
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3882
if (error) {
3883
vput(dp);
3884
nfsvno_relpathbuf(&named);
3885
goto out;
3886
}
3887
if (!nd->nd_repstat) {
3888
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
3889
} else {
3890
vput(dp);
3891
nfsvno_relpathbuf(&named);
3892
}
3893
if (dirp)
3894
vrele(dirp);
3895
if (nd->nd_repstat)
3896
goto out;
3897
nfsvno_relpathbuf(&named);
3898
fh.nfsrvfh_len = NFSX_MYFH;
3899
vp = named.ni_vp;
3900
nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3901
vput(vp);
3902
savflag = nd->nd_flag;
3903
if (!nd->nd_repstat) {
3904
/*
3905
* Pretend the next op is Secinfo, so that no wrongsec
3906
* test will be done.
3907
*/
3908
nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
3909
NFSV4OP_SECINFO);
3910
if (vp)
3911
vput(vp);
3912
}
3913
nd->nd_flag = savflag;
3914
if (nd->nd_repstat)
3915
goto out;
3916
3917
/*
3918
* Finally have the export flags for name, so we can create
3919
* the security info.
3920
*/
3921
len = 0;
3922
NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3923
3924
/* If nes_numsecflavor == 0, all are allowed. */
3925
if (retnes.nes_numsecflavor == 0) {
3926
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3927
*tl++ = txdr_unsigned(RPCAUTH_UNIX);
3928
*tl = txdr_unsigned(RPCAUTH_GSS);
3929
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3930
nfsgss_mechlist[KERBV_MECH].len);
3931
NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3932
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3933
*tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3934
*tl = txdr_unsigned(RPCAUTH_GSS);
3935
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3936
nfsgss_mechlist[KERBV_MECH].len);
3937
NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3938
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3939
*tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3940
*tl = txdr_unsigned(RPCAUTH_GSS);
3941
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3942
nfsgss_mechlist[KERBV_MECH].len);
3943
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3944
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3945
*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3946
len = 4;
3947
}
3948
for (i = 0; i < retnes.nes_numsecflavor; i++) {
3949
if (retnes.nes_secflavors[i] == AUTH_SYS) {
3950
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3951
*tl = txdr_unsigned(RPCAUTH_UNIX);
3952
len++;
3953
} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3954
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3955
*tl++ = txdr_unsigned(RPCAUTH_GSS);
3956
(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3957
nfsgss_mechlist[KERBV_MECH].len);
3958
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3959
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3960
*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3961
len++;
3962
} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3963
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3964
*tl++ = txdr_unsigned(RPCAUTH_GSS);
3965
(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3966
nfsgss_mechlist[KERBV_MECH].len);
3967
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3968
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3969
*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3970
len++;
3971
} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3972
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3973
*tl++ = txdr_unsigned(RPCAUTH_GSS);
3974
(void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3975
nfsgss_mechlist[KERBV_MECH].len);
3976
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3977
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
3978
*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3979
len++;
3980
}
3981
}
3982
*sizp = txdr_unsigned(len);
3983
3984
out:
3985
NFSEXITCODE2(error, nd);
3986
return (error);
3987
}
3988
3989
/*
3990
* nfsv4 security info no name service
3991
*/
3992
int
3993
nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram,
3994
vnode_t dp, struct nfsexstuff *exp)
3995
{
3996
uint32_t *tl, *sizp;
3997
struct nameidata named;
3998
vnode_t dirp = NULL, vp;
3999
struct nfsrvfh fh;
4000
struct nfsexstuff retnes;
4001
int error = 0, fhstyle, i, len;
4002
uint64_t savflag;
4003
char *bufp;
4004
u_long *hashp;
4005
struct thread *p = curthread;
4006
4007
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4008
fhstyle = fxdr_unsigned(int, *tl);
4009
switch (fhstyle) {
4010
case NFSSECINFONONAME_PARENT:
4011
if (dp->v_type != VDIR) {
4012
vput(dp);
4013
nd->nd_repstat = NFSERR_NOTDIR;
4014
goto nfsmout;
4015
}
4016
NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
4017
LOCKLEAF);
4018
nfsvno_setpathbuf(&named, &bufp, &hashp);
4019
error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
4020
if (error != 0) {
4021
vput(dp);
4022
nfsvno_relpathbuf(&named);
4023
goto nfsmout;
4024
}
4025
if (nd->nd_repstat == 0)
4026
nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
4027
else
4028
vput(dp);
4029
if (dirp != NULL)
4030
vrele(dirp);
4031
nfsvno_relpathbuf(&named);
4032
vp = named.ni_vp;
4033
break;
4034
case NFSSECINFONONAME_CURFH:
4035
vp = dp;
4036
break;
4037
default:
4038
nd->nd_repstat = NFSERR_INVAL;
4039
vput(dp);
4040
}
4041
if (nd->nd_repstat != 0)
4042
goto nfsmout;
4043
fh.nfsrvfh_len = NFSX_MYFH;
4044
nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
4045
vput(vp);
4046
savflag = nd->nd_flag;
4047
if (nd->nd_repstat == 0) {
4048
/*
4049
* Pretend the next op is Secinfo, so that no wrongsec
4050
* test will be done.
4051
*/
4052
nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
4053
NFSV4OP_SECINFO);
4054
if (vp != NULL)
4055
vput(vp);
4056
}
4057
nd->nd_flag = savflag;
4058
if (nd->nd_repstat != 0)
4059
goto nfsmout;
4060
4061
/*
4062
* Finally have the export flags for fh/parent, so we can create
4063
* the security info.
4064
*/
4065
len = 0;
4066
NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED);
4067
4068
/* If nes_numsecflavor == 0, all are allowed. */
4069
if (retnes.nes_numsecflavor == 0) {
4070
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4071
*tl++ = txdr_unsigned(RPCAUTH_UNIX);
4072
*tl = txdr_unsigned(RPCAUTH_GSS);
4073
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4074
nfsgss_mechlist[KERBV_MECH].len);
4075
NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4076
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4077
*tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
4078
*tl = txdr_unsigned(RPCAUTH_GSS);
4079
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4080
nfsgss_mechlist[KERBV_MECH].len);
4081
NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4082
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4083
*tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
4084
*tl = txdr_unsigned(RPCAUTH_GSS);
4085
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4086
nfsgss_mechlist[KERBV_MECH].len);
4087
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4088
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4089
*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
4090
len = 4;
4091
}
4092
for (i = 0; i < retnes.nes_numsecflavor; i++) {
4093
if (retnes.nes_secflavors[i] == AUTH_SYS) {
4094
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4095
*tl = txdr_unsigned(RPCAUTH_UNIX);
4096
len++;
4097
} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
4098
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4099
*tl = txdr_unsigned(RPCAUTH_GSS);
4100
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4101
nfsgss_mechlist[KERBV_MECH].len);
4102
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4103
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4104
*tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
4105
len++;
4106
} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
4107
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4108
*tl = txdr_unsigned(RPCAUTH_GSS);
4109
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4110
nfsgss_mechlist[KERBV_MECH].len);
4111
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4112
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4113
*tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
4114
len++;
4115
} else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
4116
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4117
*tl = txdr_unsigned(RPCAUTH_GSS);
4118
nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4119
nfsgss_mechlist[KERBV_MECH].len);
4120
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4121
*tl++ = txdr_unsigned(GSS_KERBV_QOP);
4122
*tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
4123
len++;
4124
}
4125
}
4126
*sizp = txdr_unsigned(len);
4127
4128
nfsmout:
4129
NFSEXITCODE2(error, nd);
4130
return (error);
4131
}
4132
4133
/*
4134
* nfsv4 set client id service
4135
*/
4136
int
4137
nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
4138
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4139
{
4140
u_int32_t *tl;
4141
int i;
4142
int error = 0, idlen;
4143
struct nfsclient *clp = NULL;
4144
#ifdef INET
4145
struct sockaddr_in *rin;
4146
#endif
4147
#ifdef INET6
4148
struct sockaddr_in6 *rin6;
4149
#endif
4150
#if defined(INET) || defined(INET6)
4151
u_char *ucp, *ucp2;
4152
#endif
4153
u_char *verf, *addrbuf;
4154
nfsquad_t clientid, confirm;
4155
struct thread *p = curthread;
4156
4157
if ((nd->nd_flag & ND_NFSV41) != 0) {
4158
nd->nd_repstat = NFSERR_NOTSUPP;
4159
goto nfsmout;
4160
}
4161
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4162
goto out;
4163
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4164
verf = (u_char *)tl;
4165
tl += (NFSX_VERF / NFSX_UNSIGNED);
4166
i = fxdr_unsigned(int, *tl);
4167
if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4168
nd->nd_repstat = NFSERR_BADXDR;
4169
goto nfsmout;
4170
}
4171
idlen = i;
4172
if (nd->nd_flag & ND_GSS)
4173
i += nd->nd_princlen;
4174
clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4175
M_ZERO);
4176
clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4177
nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4178
NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4179
/* Allocated large enough for an AF_INET or AF_INET6 socket. */
4180
clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4181
M_WAITOK | M_ZERO);
4182
clp->lc_req.nr_cred = NULL;
4183
NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4184
clp->lc_idlen = idlen;
4185
error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4186
if (error)
4187
goto nfsmout;
4188
if (nd->nd_flag & ND_GSS) {
4189
clp->lc_flags = LCL_GSS;
4190
if (nd->nd_flag & ND_GSSINTEGRITY)
4191
clp->lc_flags |= LCL_GSSINTEGRITY;
4192
else if (nd->nd_flag & ND_GSSPRIVACY)
4193
clp->lc_flags |= LCL_GSSPRIVACY;
4194
} else {
4195
clp->lc_flags = 0;
4196
}
4197
if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
4198
clp->lc_flags |= LCL_NAME;
4199
clp->lc_namelen = nd->nd_princlen;
4200
clp->lc_name = &clp->lc_id[idlen];
4201
NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4202
} else {
4203
clp->lc_uid = nd->nd_cred->cr_uid;
4204
clp->lc_gid = nd->nd_cred->cr_gid;
4205
}
4206
4207
/* If the client is using TLS, do so for the callback connection. */
4208
if (nd->nd_flag & ND_TLS)
4209
clp->lc_flags |= LCL_TLSCB;
4210
4211
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4212
clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
4213
error = nfsrv_getclientipaddr(nd, clp);
4214
if (error)
4215
goto nfsmout;
4216
NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4217
clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
4218
4219
/*
4220
* nfsrv_setclient() does the actual work of adding it to the
4221
* client list. If there is no error, the structure has been
4222
* linked into the client list and clp should no longer be used
4223
* here. When an error is returned, it has not been linked in,
4224
* so it should be free'd.
4225
*/
4226
nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4227
if (nd->nd_repstat == NFSERR_CLIDINUSE) {
4228
/*
4229
* 8 is the maximum length of the port# string.
4230
*/
4231
addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
4232
switch (clp->lc_req.nr_nam->sa_family) {
4233
#ifdef INET
4234
case AF_INET:
4235
if (clp->lc_flags & LCL_TCPCALLBACK)
4236
(void) nfsm_strtom(nd, "tcp", 3);
4237
else
4238
(void) nfsm_strtom(nd, "udp", 3);
4239
rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4240
ucp = (u_char *)&rin->sin_addr.s_addr;
4241
ucp2 = (u_char *)&rin->sin_port;
4242
sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
4243
ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
4244
ucp2[0] & 0xff, ucp2[1] & 0xff);
4245
break;
4246
#endif
4247
#ifdef INET6
4248
case AF_INET6:
4249
if (clp->lc_flags & LCL_TCPCALLBACK)
4250
(void) nfsm_strtom(nd, "tcp6", 4);
4251
else
4252
(void) nfsm_strtom(nd, "udp6", 4);
4253
rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4254
ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
4255
INET6_ADDRSTRLEN);
4256
if (ucp != NULL)
4257
i = strlen(ucp);
4258
else
4259
i = 0;
4260
ucp2 = (u_char *)&rin6->sin6_port;
4261
sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
4262
ucp2[1] & 0xff);
4263
break;
4264
#endif
4265
}
4266
(void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
4267
free(addrbuf, M_TEMP);
4268
}
4269
if (clp) {
4270
free(clp->lc_req.nr_nam, M_SONAME);
4271
NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4272
free(clp->lc_stateid, M_NFSDCLIENT);
4273
free(clp, M_NFSDCLIENT);
4274
}
4275
if (!nd->nd_repstat) {
4276
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
4277
*tl++ = clientid.lval[0];
4278
*tl++ = clientid.lval[1];
4279
*tl++ = confirm.lval[0];
4280
*tl = confirm.lval[1];
4281
}
4282
4283
out:
4284
NFSEXITCODE2(0, nd);
4285
return (0);
4286
nfsmout:
4287
if (clp) {
4288
free(clp->lc_req.nr_nam, M_SONAME);
4289
NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4290
free(clp->lc_stateid, M_NFSDCLIENT);
4291
free(clp, M_NFSDCLIENT);
4292
}
4293
NFSEXITCODE2(error, nd);
4294
return (error);
4295
}
4296
4297
/*
4298
* nfsv4 set client id confirm service
4299
*/
4300
int
4301
nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
4302
__unused int isdgram, __unused vnode_t vp,
4303
__unused struct nfsexstuff *exp)
4304
{
4305
u_int32_t *tl;
4306
int error = 0;
4307
nfsquad_t clientid, confirm;
4308
struct thread *p = curthread;
4309
4310
if ((nd->nd_flag & ND_NFSV41) != 0) {
4311
nd->nd_repstat = NFSERR_NOTSUPP;
4312
goto nfsmout;
4313
}
4314
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4315
goto nfsmout;
4316
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
4317
clientid.lval[0] = *tl++;
4318
clientid.lval[1] = *tl++;
4319
confirm.lval[0] = *tl++;
4320
confirm.lval[1] = *tl;
4321
4322
/*
4323
* nfsrv_getclient() searches the client list for a match and
4324
* returns the appropriate NFSERR status.
4325
*/
4326
nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
4327
NULL, NULL, confirm, 0, nd, p);
4328
nfsmout:
4329
NFSEXITCODE2(error, nd);
4330
return (error);
4331
}
4332
4333
/*
4334
* nfsv4 verify service
4335
*/
4336
int
4337
nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
4338
vnode_t vp, __unused struct nfsexstuff *exp)
4339
{
4340
int error = 0, ret, fhsize = NFSX_MYFH;
4341
struct nfsvattr nva;
4342
struct statfs *sf;
4343
struct nfsfsinfo fs;
4344
fhandle_t fh;
4345
struct thread *p = curthread;
4346
4347
sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4348
nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
4349
if (!nd->nd_repstat)
4350
nd->nd_repstat = nfsvno_statfs(vp, sf);
4351
if (!nd->nd_repstat)
4352
nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
4353
if (!nd->nd_repstat) {
4354
nfsvno_getfs(&fs, isdgram);
4355
error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
4356
sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, NULL, NULL, p,
4357
nd->nd_cred);
4358
if (!error) {
4359
if (nd->nd_procnum == NFSV4OP_NVERIFY) {
4360
if (ret == 0)
4361
nd->nd_repstat = NFSERR_SAME;
4362
else if (ret != NFSERR_NOTSAME)
4363
nd->nd_repstat = ret;
4364
} else if (ret)
4365
nd->nd_repstat = ret;
4366
}
4367
}
4368
vput(vp);
4369
free(sf, M_STATFS);
4370
NFSEXITCODE2(error, nd);
4371
return (error);
4372
}
4373
4374
/*
4375
* nfs openattr rpc
4376
*/
4377
int
4378
nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
4379
struct vnode *dp, struct vnode **vpp, __unused fhandle_t *fhp,
4380
__unused struct nfsexstuff *exp)
4381
{
4382
uint32_t *tl;
4383
struct componentname cn;
4384
int error = 0;
4385
4386
NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN |
4387
NOFOLLOW | LOCKLEAF);
4388
cn.cn_nameptr = ".";
4389
cn.cn_namelen = 1;
4390
cn.cn_lkflags = LK_SHARED;
4391
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4392
if (*tl == newnfs_true)
4393
cn.cn_flags |= CREATENAMED;
4394
4395
nd->nd_repstat = vn_lock(dp, LK_SHARED);
4396
if (nd->nd_repstat != 0)
4397
goto nfsmout;
4398
4399
if ((dp->v_mount->mnt_flag & MNT_NAMEDATTR) == 0)
4400
nd->nd_repstat = NFSERR_NOTSUPP;
4401
if (nd->nd_repstat == 0 && (vn_irflag_read(dp) & (VIRF_NAMEDDIR |
4402
VIRF_NAMEDATTR)) != 0)
4403
nd->nd_repstat = NFSERR_WRONGTYPE;
4404
if (nd->nd_repstat == 0) {
4405
nd->nd_repstat = VOP_LOOKUP(dp, vpp, &cn);
4406
if (nd->nd_repstat == ENOATTR)
4407
nd->nd_repstat = NFSERR_NOENT;
4408
}
4409
if (nd->nd_repstat == 0)
4410
NFSVOPUNLOCK(*vpp);
4411
4412
vput(dp);
4413
NFSEXITCODE2(0, nd);
4414
return (0);
4415
nfsmout:
4416
vrele(dp);
4417
NFSEXITCODE2(error, nd);
4418
return (error);
4419
}
4420
4421
/*
4422
* nfsv4 release lock owner service
4423
*/
4424
int
4425
nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
4426
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4427
{
4428
u_int32_t *tl;
4429
struct nfsstate *stp = NULL;
4430
int error = 0, len;
4431
nfsquad_t clientid;
4432
struct thread *p = curthread;
4433
4434
if ((nd->nd_flag & ND_NFSV41) != 0) {
4435
nd->nd_repstat = NFSERR_NOTSUPP;
4436
goto nfsmout;
4437
}
4438
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4439
goto nfsmout;
4440
NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4441
len = fxdr_unsigned(int, *(tl + 2));
4442
if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
4443
nd->nd_repstat = NFSERR_BADXDR;
4444
goto nfsmout;
4445
}
4446
stp = malloc(sizeof (struct nfsstate) + len,
4447
M_NFSDSTATE, M_WAITOK);
4448
stp->ls_ownerlen = len;
4449
stp->ls_op = NULL;
4450
stp->ls_flags = NFSLCK_RELEASE;
4451
stp->ls_uid = nd->nd_cred->cr_uid;
4452
clientid.lval[0] = *tl++;
4453
clientid.lval[1] = *tl;
4454
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
4455
if ((nd->nd_flag & ND_NFSV41) != 0)
4456
clientid.qval = nd->nd_clientid.qval;
4457
else if (nd->nd_clientid.qval != clientid.qval)
4458
printf("EEK14 multiple clids\n");
4459
} else {
4460
if ((nd->nd_flag & ND_NFSV41) != 0)
4461
printf("EEK! no clientid from session\n");
4462
nd->nd_flag |= ND_IMPLIEDCLID;
4463
nd->nd_clientid.qval = clientid.qval;
4464
}
4465
error = nfsrv_mtostr(nd, stp->ls_owner, len);
4466
if (error)
4467
goto nfsmout;
4468
nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
4469
free(stp, M_NFSDSTATE);
4470
4471
NFSEXITCODE2(0, nd);
4472
return (0);
4473
nfsmout:
4474
if (stp)
4475
free(stp, M_NFSDSTATE);
4476
NFSEXITCODE2(error, nd);
4477
return (error);
4478
}
4479
4480
/*
4481
* nfsv4 exchange_id service
4482
*/
4483
int
4484
nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4485
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4486
{
4487
uint32_t *tl;
4488
int error = 0, i, idlen;
4489
struct nfsclient *clp = NULL;
4490
nfsquad_t clientid, confirm;
4491
uint8_t *verf;
4492
uint32_t sp4type, v41flags;
4493
struct timespec verstime;
4494
nfsopbit_t mustops, allowops;
4495
#ifdef INET
4496
struct sockaddr_in *sin, *rin;
4497
#endif
4498
#ifdef INET6
4499
struct sockaddr_in6 *sin6, *rin6;
4500
#endif
4501
struct thread *p = curthread;
4502
char *s;
4503
4504
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4505
goto nfsmout;
4506
NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4507
verf = (uint8_t *)tl;
4508
tl += (NFSX_VERF / NFSX_UNSIGNED);
4509
i = fxdr_unsigned(int, *tl);
4510
if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4511
nd->nd_repstat = NFSERR_BADXDR;
4512
goto nfsmout;
4513
}
4514
idlen = i;
4515
if (nd->nd_flag & ND_GSS)
4516
i += nd->nd_princlen;
4517
clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4518
M_ZERO);
4519
clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4520
nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4521
NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4522
/* Allocated large enough for an AF_INET or AF_INET6 socket. */
4523
clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4524
M_WAITOK | M_ZERO);
4525
switch (nd->nd_nam->sa_family) {
4526
#ifdef INET
4527
case AF_INET:
4528
rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4529
sin = (struct sockaddr_in *)nd->nd_nam;
4530
rin->sin_family = AF_INET;
4531
rin->sin_len = sizeof(struct sockaddr_in);
4532
rin->sin_port = 0;
4533
rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4534
break;
4535
#endif
4536
#ifdef INET6
4537
case AF_INET6:
4538
rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4539
sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4540
rin6->sin6_family = AF_INET6;
4541
rin6->sin6_len = sizeof(struct sockaddr_in6);
4542
rin6->sin6_port = 0;
4543
rin6->sin6_addr = sin6->sin6_addr;
4544
break;
4545
#endif
4546
}
4547
clp->lc_req.nr_cred = NULL;
4548
NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4549
clp->lc_idlen = idlen;
4550
error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4551
if (error != 0)
4552
goto nfsmout;
4553
if ((nd->nd_flag & ND_GSS) != 0) {
4554
clp->lc_flags = LCL_GSS | LCL_NFSV41;
4555
if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4556
clp->lc_flags |= LCL_GSSINTEGRITY;
4557
else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4558
clp->lc_flags |= LCL_GSSPRIVACY;
4559
} else
4560
clp->lc_flags = LCL_NFSV41;
4561
if ((nd->nd_flag & ND_NFSV42) != 0)
4562
clp->lc_flags |= LCL_NFSV42;
4563
if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4564
clp->lc_flags |= LCL_NAME;
4565
clp->lc_namelen = nd->nd_princlen;
4566
clp->lc_name = &clp->lc_id[idlen];
4567
NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4568
} else {
4569
clp->lc_uid = nd->nd_cred->cr_uid;
4570
clp->lc_gid = nd->nd_cred->cr_gid;
4571
}
4572
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4573
v41flags = fxdr_unsigned(uint32_t, *tl++);
4574
if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4575
NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4576
NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4577
nd->nd_repstat = NFSERR_INVAL;
4578
goto nfsmout;
4579
}
4580
if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4581
confirm.lval[1] = 1;
4582
else
4583
confirm.lval[1] = 0;
4584
if (nfsrv_devidcnt == 0)
4585
v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4586
else
4587
v41flags = NFSV4EXCH_USEPNFSMDS;
4588
sp4type = fxdr_unsigned(uint32_t, *tl);
4589
if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4590
if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 ||
4591
nd->nd_princlen == 0)
4592
nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
4593
if (nd->nd_repstat == 0)
4594
nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL);
4595
if (nd->nd_repstat == 0)
4596
nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL);
4597
if (nd->nd_repstat != 0)
4598
goto nfsmout;
4599
NFSOPBIT_CLRNOTMUST(&mustops);
4600
NFSSET_OPBIT(&clp->lc_mustops, &mustops);
4601
NFSOPBIT_CLRNOTALLOWED(&allowops);
4602
NFSSET_OPBIT(&clp->lc_allowops, &allowops);
4603
clp->lc_flags |= LCL_MACHCRED;
4604
} else if (sp4type != NFSV4EXCH_SP4NONE) {
4605
nd->nd_repstat = NFSERR_NOTSUPP;
4606
goto nfsmout;
4607
}
4608
4609
/*
4610
* nfsrv_setclient() does the actual work of adding it to the
4611
* client list. If there is no error, the structure has been
4612
* linked into the client list and clp should no longer be used
4613
* here. When an error is returned, it has not been linked in,
4614
* so it should be free'd.
4615
*/
4616
nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4617
if (clp != NULL) {
4618
free(clp->lc_req.nr_nam, M_SONAME);
4619
NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4620
free(clp->lc_stateid, M_NFSDCLIENT);
4621
free(clp, M_NFSDCLIENT);
4622
}
4623
if (nd->nd_repstat == 0) {
4624
if (confirm.lval[1] != 0)
4625
v41flags |= NFSV4EXCH_CONFIRMEDR;
4626
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
4627
*tl++ = clientid.lval[0]; /* ClientID */
4628
*tl++ = clientid.lval[1];
4629
*tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4630
*tl++ = txdr_unsigned(v41flags); /* Exch flags */
4631
*tl = txdr_unsigned(sp4type); /* No SSV */
4632
if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4633
nfsrv_putopbit(nd, &mustops);
4634
nfsrv_putopbit(nd, &allowops);
4635
}
4636
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER);
4637
txdr_hyper(nfsrv_owner_minor, tl); /* Owner Minor */
4638
if (nfsrv_owner_major[0] != 0)
4639
s = nfsrv_owner_major;
4640
else
4641
s = nd->nd_cred->cr_prison->pr_hostuuid;
4642
nfsm_strtom(nd, s, strlen(s)); /* Owner Major */
4643
if (nfsrv_scope[0] != 0)
4644
s = nfsrv_scope;
4645
else
4646
s = nd->nd_cred->cr_prison->pr_hostuuid;
4647
nfsm_strtom(nd, s, strlen(s) ); /* Scope */
4648
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4649
*tl = txdr_unsigned(1);
4650
(void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4651
(void)nfsm_strtom(nd, version, strlen(version));
4652
NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4653
verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4654
verstime.tv_nsec = 0;
4655
txdr_nfsv4time(&verstime, tl);
4656
}
4657
NFSEXITCODE2(0, nd);
4658
return (0);
4659
nfsmout:
4660
if (clp != NULL) {
4661
free(clp->lc_req.nr_nam, M_SONAME);
4662
NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4663
free(clp->lc_stateid, M_NFSDCLIENT);
4664
free(clp, M_NFSDCLIENT);
4665
}
4666
NFSEXITCODE2(error, nd);
4667
return (error);
4668
}
4669
4670
/*
4671
* nfsv4 create session service
4672
*/
4673
int
4674
nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4675
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4676
{
4677
uint32_t *tl;
4678
int error = 0;
4679
nfsquad_t clientid, confirm;
4680
struct nfsdsession *sep = NULL;
4681
uint32_t rdmacnt;
4682
struct thread *p = curthread;
4683
static bool do_printf = true;
4684
4685
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4686
goto nfsmout;
4687
sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4688
M_NFSDSESSION, M_WAITOK | M_ZERO);
4689
sep->sess_refcnt = 1;
4690
mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4691
NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4692
clientid.lval[0] = *tl++;
4693
clientid.lval[1] = *tl++;
4694
confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4695
sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4696
/* Persistent sessions and RDMA are not supported. */
4697
sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4698
4699
/* Fore channel attributes. */
4700
NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4701
tl++; /* Header pad always 0. */
4702
sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4703
if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4704
sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4705
if (do_printf)
4706
printf("Consider increasing kern.ipc.maxsockbuf\n");
4707
do_printf = false;
4708
}
4709
sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4710
if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4711
sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4712
if (do_printf)
4713
printf("Consider increasing kern.ipc.maxsockbuf\n");
4714
do_printf = false;
4715
}
4716
sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4717
sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4718
sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4719
if (sep->sess_maxslots > NFSV4_SLOTS)
4720
sep->sess_maxslots = NFSV4_SLOTS;
4721
rdmacnt = fxdr_unsigned(uint32_t, *tl);
4722
if (rdmacnt > 1) {
4723
nd->nd_repstat = NFSERR_BADXDR;
4724
goto nfsmout;
4725
} else if (rdmacnt == 1)
4726
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4727
4728
/* Back channel attributes. */
4729
NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4730
tl++; /* Header pad always 0. */
4731
sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4732
sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4733
sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4734
sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4735
sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4736
rdmacnt = fxdr_unsigned(uint32_t, *tl);
4737
if (rdmacnt > 1) {
4738
nd->nd_repstat = NFSERR_BADXDR;
4739
goto nfsmout;
4740
} else if (rdmacnt == 1)
4741
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4742
4743
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4744
sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4745
4746
/*
4747
* nfsrv_getclient() searches the client list for a match and
4748
* returns the appropriate NFSERR status.
4749
*/
4750
nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4751
NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4752
if (nd->nd_repstat == 0) {
4753
NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4754
NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4755
NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4756
*tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4757
*tl++ = txdr_unsigned(sep->sess_crflags);
4758
4759
/* Fore channel attributes. */
4760
*tl++ = 0;
4761
*tl++ = txdr_unsigned(sep->sess_maxreq);
4762
*tl++ = txdr_unsigned(sep->sess_maxresp);
4763
*tl++ = txdr_unsigned(sep->sess_maxrespcached);
4764
*tl++ = txdr_unsigned(sep->sess_maxops);
4765
*tl++ = txdr_unsigned(sep->sess_maxslots);
4766
*tl++ = txdr_unsigned(1);
4767
*tl++ = txdr_unsigned(0); /* No RDMA. */
4768
4769
/* Back channel attributes. */
4770
*tl++ = 0;
4771
*tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4772
*tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4773
*tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4774
*tl++ = txdr_unsigned(sep->sess_cbmaxops);
4775
*tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4776
*tl++ = txdr_unsigned(1);
4777
*tl = txdr_unsigned(0); /* No RDMA. */
4778
}
4779
nfsmout:
4780
if (nd->nd_repstat != 0 && sep != NULL)
4781
free(sep, M_NFSDSESSION);
4782
NFSEXITCODE2(error, nd);
4783
return (error);
4784
}
4785
4786
/*
4787
* nfsv4 sequence service
4788
*/
4789
int
4790
nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4791
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4792
{
4793
uint32_t *tl;
4794
uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4795
int cache_this, error = 0;
4796
struct thread *p = curthread;
4797
4798
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4799
goto nfsmout;
4800
NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4801
NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4802
NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4803
sequenceid = fxdr_unsigned(uint32_t, *tl++);
4804
nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4805
highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4806
if (*tl == newnfs_true)
4807
cache_this = 1;
4808
else
4809
cache_this = 0;
4810
nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4811
&target_highest_slotid, cache_this, &sflags, p);
4812
if (nd->nd_repstat != NFSERR_BADSLOT)
4813
nd->nd_flag |= ND_HASSEQUENCE;
4814
if (nd->nd_repstat == 0) {
4815
NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4816
NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4817
NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4818
*tl++ = txdr_unsigned(sequenceid);
4819
*tl++ = txdr_unsigned(nd->nd_slotid);
4820
*tl++ = txdr_unsigned(highest_slotid);
4821
*tl++ = txdr_unsigned(target_highest_slotid);
4822
*tl = txdr_unsigned(sflags);
4823
}
4824
nfsmout:
4825
NFSEXITCODE2(error, nd);
4826
return (error);
4827
}
4828
4829
/*
4830
* nfsv4 reclaim complete service
4831
*/
4832
int
4833
nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4834
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4835
{
4836
uint32_t *tl;
4837
int error = 0, onefs;
4838
4839
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4840
/*
4841
* I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4842
* to be used after a file system has been transferred to a different
4843
* file server. However, RFC5661 is somewhat vague w.r.t. this and
4844
* the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4845
* == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4846
* Therefore, just ignore the rca_one_fs == TRUE operation and return
4847
* NFS_OK without doing anything.
4848
*/
4849
onefs = 0;
4850
if (*tl == newnfs_true)
4851
onefs = 1;
4852
nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4853
nfsmout:
4854
NFSEXITCODE2(error, nd);
4855
return (error);
4856
}
4857
4858
/*
4859
* nfsv4 destroy clientid service
4860
*/
4861
int
4862
nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4863
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4864
{
4865
uint32_t *tl;
4866
nfsquad_t clientid;
4867
int error = 0;
4868
struct thread *p = curthread;
4869
4870
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4871
goto nfsmout;
4872
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4873
clientid.lval[0] = *tl++;
4874
clientid.lval[1] = *tl;
4875
nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p);
4876
nfsmout:
4877
NFSEXITCODE2(error, nd);
4878
return (error);
4879
}
4880
4881
/*
4882
* nfsv4 bind connection to session service
4883
*/
4884
int
4885
nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4886
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4887
{
4888
uint32_t *tl;
4889
uint8_t sessid[NFSX_V4SESSIONID];
4890
int error = 0, foreaft;
4891
4892
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4893
goto nfsmout;
4894
NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4895
NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4896
tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4897
foreaft = fxdr_unsigned(int, *tl++);
4898
if (*tl == newnfs_true) {
4899
/* RDMA is not supported. */
4900
nd->nd_repstat = NFSERR_NOTSUPP;
4901
goto nfsmout;
4902
}
4903
4904
nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4905
if (nd->nd_repstat == 0) {
4906
NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4907
NFSX_UNSIGNED);
4908
NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4909
tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4910
*tl++ = txdr_unsigned(foreaft);
4911
*tl = newnfs_false;
4912
}
4913
nfsmout:
4914
NFSEXITCODE2(error, nd);
4915
return (error);
4916
}
4917
4918
/*
4919
* nfsv4 destroy session service
4920
*/
4921
int
4922
nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4923
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4924
{
4925
uint8_t *cp, sessid[NFSX_V4SESSIONID];
4926
int error = 0;
4927
4928
if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4929
goto nfsmout;
4930
NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4931
NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4932
nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4933
nfsmout:
4934
NFSEXITCODE2(error, nd);
4935
return (error);
4936
}
4937
4938
/*
4939
* nfsv4 free stateid service
4940
*/
4941
int
4942
nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4943
__unused vnode_t vp, __unused struct nfsexstuff *exp)
4944
{
4945
uint32_t *tl;
4946
nfsv4stateid_t stateid;
4947
int error = 0;
4948
struct thread *p = curthread;
4949
4950
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4951
stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4952
NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4953
4954
/*
4955
* For the special stateid of other all 0s and seqid == 1, set the
4956
* stateid to the current stateid, if it is set.
4957
*/
4958
if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4959
stateid.other[1] == 0 && stateid.other[2] == 0) {
4960
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4961
stateid = nd->nd_curstateid;
4962
stateid.seqid = 0;
4963
} else {
4964
nd->nd_repstat = NFSERR_BADSTATEID;
4965
goto nfsmout;
4966
}
4967
}
4968
4969
nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4970
4971
/* If the current stateid has been free'd, unset it. */
4972
if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4973
stateid.other[0] == nd->nd_curstateid.other[0] &&
4974
stateid.other[1] == nd->nd_curstateid.other[1] &&
4975
stateid.other[2] == nd->nd_curstateid.other[2])
4976
nd->nd_flag &= ~ND_CURSTATEID;
4977
nfsmout:
4978
NFSEXITCODE2(error, nd);
4979
return (error);
4980
}
4981
4982
/*
4983
* nfsv4 layoutget service
4984
*/
4985
int
4986
nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4987
vnode_t vp, struct nfsexstuff *exp)
4988
{
4989
uint32_t *tl;
4990
nfsv4stateid_t stateid;
4991
int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4992
uint64_t offset, len, minlen;
4993
char *layp;
4994
struct thread *p = curthread;
4995
4996
NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4997
NFSX_STATEID);
4998
tl++; /* Signal layout available. Ignore for now. */
4999
layouttype = fxdr_unsigned(int, *tl++);
5000
iomode = fxdr_unsigned(int, *tl++);
5001
offset = fxdr_hyper(tl); tl += 2;
5002
len = fxdr_hyper(tl); tl += 2;
5003
minlen = fxdr_hyper(tl); tl += 2;
5004
stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5005
NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5006
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5007
maxcnt = fxdr_unsigned(int, *tl);
5008
NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
5009
layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
5010
(uintmax_t)minlen);
5011
if (len < minlen ||
5012
(minlen != UINT64_MAX && offset + minlen < offset) ||
5013
(len != UINT64_MAX && offset + len < offset)) {
5014
nd->nd_repstat = NFSERR_INVAL;
5015
goto nfsmout;
5016
}
5017
5018
/*
5019
* For the special stateid of other all 0s and seqid == 1, set the
5020
* stateid to the current stateid, if it is set.
5021
*/
5022
if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5023
stateid.other[1] == 0 && stateid.other[2] == 0) {
5024
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5025
stateid = nd->nd_curstateid;
5026
stateid.seqid = 0;
5027
} else {
5028
nd->nd_repstat = NFSERR_BADSTATEID;
5029
goto nfsmout;
5030
}
5031
}
5032
5033
layp = NULL;
5034
if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
5035
layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
5036
else if (layouttype == NFSLAYOUT_FLEXFILE)
5037
layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
5038
M_WAITOK);
5039
else
5040
nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
5041
if (layp != NULL)
5042
nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
5043
&iomode, &offset, &len, minlen, &stateid, maxcnt,
5044
&retonclose, &layoutlen, layp, nd->nd_cred, p);
5045
NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
5046
layoutlen);
5047
if (nd->nd_repstat == 0) {
5048
/* For NFSv4.1, set the Current StateID. */
5049
if ((nd->nd_flag & ND_NFSV41) != 0) {
5050
nd->nd_curstateid = stateid;
5051
nd->nd_flag |= ND_CURSTATEID;
5052
}
5053
NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
5054
2 * NFSX_HYPER);
5055
*tl++ = txdr_unsigned(retonclose);
5056
*tl++ = txdr_unsigned(stateid.seqid);
5057
NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5058
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5059
*tl++ = txdr_unsigned(1); /* Only returns one layout. */
5060
txdr_hyper(offset, tl); tl += 2;
5061
txdr_hyper(len, tl); tl += 2;
5062
*tl++ = txdr_unsigned(iomode);
5063
*tl = txdr_unsigned(layouttype);
5064
nfsm_strtom(nd, layp, layoutlen);
5065
} else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
5066
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5067
*tl = newnfs_false;
5068
}
5069
free(layp, M_TEMP);
5070
nfsmout:
5071
vput(vp);
5072
NFSEXITCODE2(error, nd);
5073
return (error);
5074
}
5075
5076
/*
5077
* nfsv4 layoutcommit service
5078
*/
5079
int
5080
nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
5081
vnode_t vp, struct nfsexstuff *exp)
5082
{
5083
uint32_t *tl;
5084
nfsv4stateid_t stateid;
5085
int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
5086
int hasnewsize;
5087
uint64_t offset, len, newoff = 0, newsize;
5088
struct timespec newmtime;
5089
char *layp;
5090
struct thread *p = curthread;
5091
5092
layp = NULL;
5093
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
5094
NFSX_STATEID);
5095
offset = fxdr_hyper(tl); tl += 2;
5096
len = fxdr_hyper(tl); tl += 2;
5097
reclaim = fxdr_unsigned(int, *tl++);
5098
stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5099
NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5100
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5101
/*
5102
* For the special stateid of other all 0s and seqid == 1, set the
5103
* stateid to the current stateid, if it is set.
5104
*/
5105
if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5106
stateid.other[1] == 0 && stateid.other[2] == 0) {
5107
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5108
stateid = nd->nd_curstateid;
5109
stateid.seqid = 0;
5110
} else {
5111
nd->nd_repstat = NFSERR_BADSTATEID;
5112
goto nfsmout;
5113
}
5114
}
5115
5116
hasnewoff = fxdr_unsigned(int, *tl);
5117
if (hasnewoff != 0) {
5118
NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5119
newoff = fxdr_hyper(tl); tl += 2;
5120
} else
5121
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5122
hasnewmtime = fxdr_unsigned(int, *tl);
5123
if (hasnewmtime != 0) {
5124
NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
5125
fxdr_nfsv4time(tl, &newmtime);
5126
tl += (NFSX_V4TIME / NFSX_UNSIGNED);
5127
} else
5128
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5129
layouttype = fxdr_unsigned(int, *tl++);
5130
maxcnt = fxdr_unsigned(int, *tl);
5131
if (maxcnt > 0) {
5132
layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5133
error = nfsrv_mtostr(nd, layp, maxcnt);
5134
if (error != 0)
5135
goto nfsmout;
5136
}
5137
nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
5138
newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
5139
maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
5140
NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
5141
if (nd->nd_repstat == 0) {
5142
if (hasnewsize != 0) {
5143
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5144
*tl++ = newnfs_true;
5145
txdr_hyper(newsize, tl);
5146
} else {
5147
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5148
*tl = newnfs_false;
5149
}
5150
}
5151
nfsmout:
5152
free(layp, M_TEMP);
5153
vput(vp);
5154
NFSEXITCODE2(error, nd);
5155
return (error);
5156
}
5157
5158
/*
5159
* nfsv4 layoutreturn service
5160
*/
5161
int
5162
nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
5163
vnode_t vp, struct nfsexstuff *exp)
5164
{
5165
uint32_t *tl, *layp;
5166
nfsv4stateid_t stateid;
5167
int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
5168
uint64_t offset, len;
5169
struct thread *p = curthread;
5170
5171
layp = NULL;
5172
NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5173
reclaim = *tl++;
5174
layouttype = fxdr_unsigned(int, *tl++);
5175
iomode = fxdr_unsigned(int, *tl++);
5176
kind = fxdr_unsigned(int, *tl);
5177
NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
5178
layouttype, iomode, kind);
5179
if (kind == NFSV4LAYOUTRET_FILE) {
5180
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5181
NFSX_UNSIGNED);
5182
offset = fxdr_hyper(tl); tl += 2;
5183
len = fxdr_hyper(tl); tl += 2;
5184
stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5185
NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5186
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5187
5188
/*
5189
* For the special stateid of other all 0s and seqid == 1, set
5190
* the stateid to the current stateid, if it is set.
5191
*/
5192
if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5193
stateid.other[1] == 0 && stateid.other[2] == 0) {
5194
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5195
stateid = nd->nd_curstateid;
5196
stateid.seqid = 0;
5197
} else {
5198
nd->nd_repstat = NFSERR_BADSTATEID;
5199
goto nfsmout;
5200
}
5201
}
5202
5203
maxcnt = fxdr_unsigned(int, *tl);
5204
/*
5205
* There is no fixed upper bound defined in the RFCs,
5206
* but 128Kbytes should be more than sufficient.
5207
*/
5208
if (maxcnt < 0 || maxcnt > 131072)
5209
maxcnt = 0;
5210
if (maxcnt > 0) {
5211
layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5212
error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
5213
if (error != 0)
5214
goto nfsmout;
5215
}
5216
} else {
5217
if (reclaim == newnfs_true) {
5218
nd->nd_repstat = NFSERR_INVAL;
5219
goto nfsmout;
5220
}
5221
offset = len = 0;
5222
maxcnt = 0;
5223
}
5224
nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
5225
offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
5226
nd->nd_cred, p);
5227
NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
5228
fnd);
5229
if (nd->nd_repstat == 0) {
5230
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5231
if (fnd != 0) {
5232
*tl = newnfs_true;
5233
NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
5234
*tl++ = txdr_unsigned(stateid.seqid);
5235
NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5236
} else
5237
*tl = newnfs_false;
5238
}
5239
nfsmout:
5240
free(layp, M_TEMP);
5241
vput(vp);
5242
NFSEXITCODE2(error, nd);
5243
return (error);
5244
}
5245
5246
/*
5247
* nfsv4 layout error service
5248
*/
5249
int
5250
nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
5251
vnode_t vp, struct nfsexstuff *exp)
5252
{
5253
uint32_t *tl;
5254
nfsv4stateid_t stateid;
5255
int cnt, error = 0, i, stat;
5256
int opnum __unused;
5257
char devid[NFSX_V4DEVICEID];
5258
uint64_t offset, len;
5259
5260
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5261
NFSX_UNSIGNED);
5262
offset = fxdr_hyper(tl); tl += 2;
5263
len = fxdr_hyper(tl); tl += 2;
5264
stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5265
NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5266
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5267
cnt = fxdr_unsigned(int, *tl);
5268
NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
5269
(uintmax_t)len, cnt);
5270
/*
5271
* For the special stateid of other all 0s and seqid == 1, set
5272
* the stateid to the current stateid, if it is set.
5273
*/
5274
if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5275
stateid.other[1] == 0 && stateid.other[2] == 0) {
5276
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5277
stateid = nd->nd_curstateid;
5278
stateid.seqid = 0;
5279
} else {
5280
nd->nd_repstat = NFSERR_BADSTATEID;
5281
goto nfsmout;
5282
}
5283
}
5284
5285
/*
5286
* Ignore offset, len and stateid for now.
5287
*/
5288
for (i = 0; i < cnt; i++) {
5289
NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
5290
NFSX_UNSIGNED);
5291
NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5292
tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5293
stat = fxdr_unsigned(int, *tl++);
5294
opnum = fxdr_unsigned(int, *tl);
5295
NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
5296
/*
5297
* Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC
5298
* errors, disable the mirror.
5299
*/
5300
if (stat != NFSERR_ACCES && stat != NFSERR_STALE &&
5301
stat != NFSERR_NOSPC)
5302
nfsrv_delds(devid, curthread);
5303
5304
/* For NFSERR_NOSPC, mark all deviceids and layouts. */
5305
if (stat == NFSERR_NOSPC)
5306
nfsrv_marknospc(devid, true);
5307
}
5308
nfsmout:
5309
vput(vp);
5310
NFSEXITCODE2(error, nd);
5311
return (error);
5312
}
5313
5314
/*
5315
* nfsv4 layout stats service
5316
*/
5317
int
5318
nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
5319
vnode_t vp, struct nfsexstuff *exp)
5320
{
5321
uint32_t *tl;
5322
nfsv4stateid_t stateid;
5323
int cnt, error = 0;
5324
int layouttype __unused;
5325
char devid[NFSX_V4DEVICEID] __unused;
5326
uint64_t offset __unused, len __unused, readcount __unused;
5327
uint64_t readbytes __unused, writecount __unused, writebytes __unused;
5328
5329
NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
5330
NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
5331
offset = fxdr_hyper(tl); tl += 2;
5332
len = fxdr_hyper(tl); tl += 2;
5333
stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5334
NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5335
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5336
readcount = fxdr_hyper(tl); tl += 2;
5337
readbytes = fxdr_hyper(tl); tl += 2;
5338
writecount = fxdr_hyper(tl); tl += 2;
5339
writebytes = fxdr_hyper(tl); tl += 2;
5340
NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5341
tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5342
layouttype = fxdr_unsigned(int, *tl++);
5343
cnt = fxdr_unsigned(int, *tl);
5344
error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
5345
if (error != 0)
5346
goto nfsmout;
5347
NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
5348
/*
5349
* For the special stateid of other all 0s and seqid == 1, set
5350
* the stateid to the current stateid, if it is set.
5351
*/
5352
if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5353
stateid.other[1] == 0 && stateid.other[2] == 0) {
5354
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5355
stateid = nd->nd_curstateid;
5356
stateid.seqid = 0;
5357
} else {
5358
nd->nd_repstat = NFSERR_BADSTATEID;
5359
goto nfsmout;
5360
}
5361
}
5362
5363
/*
5364
* No use for the stats for now.
5365
*/
5366
nfsmout:
5367
vput(vp);
5368
NFSEXITCODE2(error, nd);
5369
return (error);
5370
}
5371
5372
/*
5373
* nfsv4 io_advise service
5374
*/
5375
int
5376
nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
5377
vnode_t vp, struct nfsexstuff *exp)
5378
{
5379
uint32_t *tl;
5380
nfsv4stateid_t stateid;
5381
nfsattrbit_t hints;
5382
int error = 0, ret;
5383
off_t offset, len;
5384
5385
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5386
stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5387
NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5388
tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5389
offset = fxdr_hyper(tl); tl += 2;
5390
len = fxdr_hyper(tl);
5391
error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
5392
if (error != 0)
5393
goto nfsmout;
5394
/*
5395
* For the special stateid of other all 0s and seqid == 1, set
5396
* the stateid to the current stateid, if it is set.
5397
*/
5398
if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5399
stateid.other[1] == 0 && stateid.other[2] == 0) {
5400
if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5401
stateid = nd->nd_curstateid;
5402
stateid.seqid = 0;
5403
} else {
5404
nd->nd_repstat = NFSERR_BADSTATEID;
5405
goto nfsmout;
5406
}
5407
}
5408
5409
if (offset < 0) {
5410
nd->nd_repstat = NFSERR_INVAL;
5411
goto nfsmout;
5412
}
5413
if (len < 0)
5414
len = 0;
5415
if (vp->v_type != VREG) {
5416
if (vp->v_type == VDIR)
5417
nd->nd_repstat = NFSERR_ISDIR;
5418
else
5419
nd->nd_repstat = NFSERR_WRONGTYPE;
5420
goto nfsmout;
5421
}
5422
5423
/*
5424
* For now, we can only handle WILLNEED and DONTNEED and don't use
5425
* the stateid.
5426
*/
5427
if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
5428
!NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
5429
(NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
5430
!NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
5431
NFSVOPUNLOCK(vp);
5432
if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
5433
ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
5434
NFSZERO_ATTRBIT(&hints);
5435
if (ret == 0)
5436
NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
5437
else
5438
NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5439
} else {
5440
ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
5441
NFSZERO_ATTRBIT(&hints);
5442
if (ret == 0)
5443
NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
5444
else
5445
NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5446
}
5447
vrele(vp);
5448
} else {
5449
NFSZERO_ATTRBIT(&hints);
5450
NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5451
vput(vp);
5452
}
5453
nfsrv_putattrbit(nd, &hints);
5454
NFSEXITCODE2(error, nd);
5455
return (error);
5456
nfsmout:
5457
vput(vp);
5458
NFSEXITCODE2(error, nd);
5459
return (error);
5460
}
5461
5462
/*
5463
* nfsv4 getdeviceinfo service
5464
*/
5465
int
5466
nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5467
__unused vnode_t vp, __unused struct nfsexstuff *exp)
5468
{
5469
uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5470
int cnt, devaddrlen, error = 0, i, layouttype;
5471
char devid[NFSX_V4DEVICEID], *devaddr;
5472
time_t dev_time;
5473
5474
NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5475
NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5476
tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5477
layouttype = fxdr_unsigned(int, *tl++);
5478
maxcnt = fxdr_unsigned(uint32_t, *tl++);
5479
cnt = fxdr_unsigned(int, *tl);
5480
NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5481
maxcnt, cnt);
5482
if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5483
nd->nd_repstat = NFSERR_INVAL;
5484
goto nfsmout;
5485
}
5486
if (cnt > 0) {
5487
NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5488
for (i = 0; i < cnt; i++)
5489
notify[i] = fxdr_unsigned(uint32_t, *tl++);
5490
}
5491
for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5492
notify[i] = 0;
5493
5494
/*
5495
* Check that the device id is not stale. Device ids are recreated
5496
* each time the nfsd threads are restarted.
5497
*/
5498
NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5499
if (dev_time != nfsdev_time) {
5500
nd->nd_repstat = NFSERR_NOENT;
5501
goto nfsmout;
5502
}
5503
5504
/* Look for the device id. */
5505
nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5506
notify, &devaddrlen, &devaddr);
5507
NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5508
if (nd->nd_repstat == 0) {
5509
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5510
*tl = txdr_unsigned(layouttype);
5511
nfsm_strtom(nd, devaddr, devaddrlen);
5512
cnt = 0;
5513
for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5514
if (notify[i] != 0)
5515
cnt = i + 1;
5516
}
5517
NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5518
*tl++ = txdr_unsigned(cnt);
5519
for (i = 0; i < cnt; i++)
5520
*tl++ = txdr_unsigned(notify[i]);
5521
} else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5522
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5523
*tl = txdr_unsigned(maxcnt);
5524
}
5525
nfsmout:
5526
NFSEXITCODE2(error, nd);
5527
return (error);
5528
}
5529
5530
/*
5531
* nfsv4 test stateid service
5532
*/
5533
int
5534
nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5535
__unused vnode_t vp, __unused struct nfsexstuff *exp)
5536
{
5537
uint32_t *tl;
5538
nfsv4stateid_t *stateidp = NULL, *tstateidp;
5539
int cnt, error = 0, i, ret;
5540
struct thread *p = curthread;
5541
5542
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5543
cnt = fxdr_unsigned(int, *tl);
5544
if (cnt <= 0 || cnt > 1024) {
5545
nd->nd_repstat = NFSERR_BADXDR;
5546
goto nfsmout;
5547
}
5548
stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5549
tstateidp = stateidp;
5550
for (i = 0; i < cnt; i++) {
5551
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5552
tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5553
NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5554
tstateidp++;
5555
}
5556
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5557
*tl = txdr_unsigned(cnt);
5558
tstateidp = stateidp;
5559
for (i = 0; i < cnt; i++) {
5560
ret = nfsrv_teststateid(nd, tstateidp, p);
5561
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5562
*tl = txdr_unsigned(ret);
5563
tstateidp++;
5564
}
5565
nfsmout:
5566
free(stateidp, M_TEMP);
5567
NFSEXITCODE2(error, nd);
5568
return (error);
5569
}
5570
5571
/*
5572
* nfs allocate service
5573
*/
5574
int
5575
nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5576
vnode_t vp, struct nfsexstuff *exp)
5577
{
5578
uint32_t *tl;
5579
struct nfsvattr forat;
5580
int error = 0, forat_ret = 1, gotproxystateid;
5581
off_t off, len;
5582
struct nfsstate st, *stp = &st;
5583
struct nfslock lo, *lop = &lo;
5584
nfsv4stateid_t stateid;
5585
nfsquad_t clientid;
5586
nfsattrbit_t attrbits;
5587
5588
if (!nfsrv_doallocate) {
5589
/*
5590
* If any exported file system, such as a ZFS one, cannot
5591
* do VOP_ALLOCATE(), this operation cannot be supported
5592
* for NFSv4.2. This cannot be done 'per filesystem', but
5593
* must be for the entire nfsd NFSv4.2 service.
5594
*/
5595
nd->nd_repstat = NFSERR_NOTSUPP;
5596
goto nfsmout;
5597
}
5598
gotproxystateid = 0;
5599
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5600
stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5601
lop->lo_flags = NFSLCK_WRITE;
5602
stp->ls_ownerlen = 0;
5603
stp->ls_op = NULL;
5604
stp->ls_uid = nd->nd_cred->cr_uid;
5605
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5606
clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5607
clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5608
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5609
if ((nd->nd_flag & ND_NFSV41) != 0)
5610
clientid.qval = nd->nd_clientid.qval;
5611
else if (nd->nd_clientid.qval != clientid.qval)
5612
printf("EEK2 multiple clids\n");
5613
} else {
5614
if ((nd->nd_flag & ND_NFSV41) != 0)
5615
printf("EEK! no clientid from session\n");
5616
nd->nd_flag |= ND_IMPLIEDCLID;
5617
nd->nd_clientid.qval = clientid.qval;
5618
}
5619
stp->ls_stateid.other[2] = *tl++;
5620
/*
5621
* Don't allow this to be done for a DS.
5622
*/
5623
if ((nd->nd_flag & ND_DSSERVER) != 0)
5624
nd->nd_repstat = NFSERR_NOTSUPP;
5625
/* However, allow the proxy stateid. */
5626
if (stp->ls_stateid.seqid == 0xffffffff &&
5627
stp->ls_stateid.other[0] == 0x55555555 &&
5628
stp->ls_stateid.other[1] == 0x55555555 &&
5629
stp->ls_stateid.other[2] == 0x55555555)
5630
gotproxystateid = 1;
5631
off = fxdr_hyper(tl); tl += 2;
5632
lop->lo_first = off;
5633
len = fxdr_hyper(tl);
5634
lop->lo_end = lop->lo_first + len;
5635
/*
5636
* Sanity check the offset and length.
5637
* off and len are off_t (signed int64_t) whereas
5638
* lo_first and lo_end are uint64_t and, as such,
5639
* if off >= 0 && len > 0, lo_end cannot overflow
5640
* unless off_t is changed to something other than
5641
* int64_t. Check lo_end < lo_first in case that
5642
* is someday the case.
5643
*/
5644
if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end >
5645
OFF_MAX || lop->lo_end < lop->lo_first))
5646
nd->nd_repstat = NFSERR_INVAL;
5647
5648
if (nd->nd_repstat == 0 && vp->v_type != VREG)
5649
nd->nd_repstat = NFSERR_WRONGTYPE;
5650
NFSZERO_ATTRBIT(&attrbits);
5651
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5652
forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5653
if (nd->nd_repstat == 0)
5654
nd->nd_repstat = forat_ret;
5655
if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5656
NFSVNO_EXSTRICTACCESS(exp)))
5657
nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5658
curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5659
NULL);
5660
if (nd->nd_repstat == 0 && gotproxystateid == 0)
5661
nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5662
&stateid, exp, nd, curthread);
5663
5664
NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n",
5665
(intmax_t)off, (intmax_t)len, nd->nd_repstat);
5666
if (nd->nd_repstat == 0)
5667
nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5668
curthread);
5669
NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n",
5670
nd->nd_repstat);
5671
vput(vp);
5672
NFSEXITCODE2(0, nd);
5673
return (0);
5674
nfsmout:
5675
vput(vp);
5676
NFSEXITCODE2(error, nd);
5677
return (error);
5678
}
5679
5680
/*
5681
* nfs deallocate service
5682
*/
5683
int
5684
nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram,
5685
vnode_t vp, struct nfsexstuff *exp)
5686
{
5687
uint32_t *tl;
5688
struct nfsvattr forat;
5689
int error = 0, forat_ret = 1, gotproxystateid;
5690
off_t off, len;
5691
struct nfsstate st, *stp = &st;
5692
struct nfslock lo, *lop = &lo;
5693
nfsv4stateid_t stateid;
5694
nfsquad_t clientid;
5695
nfsattrbit_t attrbits;
5696
5697
gotproxystateid = 0;
5698
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5699
stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5700
lop->lo_flags = NFSLCK_WRITE;
5701
stp->ls_ownerlen = 0;
5702
stp->ls_op = NULL;
5703
stp->ls_uid = nd->nd_cred->cr_uid;
5704
stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5705
clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5706
clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5707
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5708
if ((nd->nd_flag & ND_NFSV41) != 0)
5709
clientid.qval = nd->nd_clientid.qval;
5710
else if (nd->nd_clientid.qval != clientid.qval)
5711
printf("EEK2 multiple clids\n");
5712
} else {
5713
if ((nd->nd_flag & ND_NFSV41) != 0)
5714
printf("EEK! no clientid from session\n");
5715
nd->nd_flag |= ND_IMPLIEDCLID;
5716
nd->nd_clientid.qval = clientid.qval;
5717
}
5718
stp->ls_stateid.other[2] = *tl++;
5719
/*
5720
* Don't allow this to be done for a DS.
5721
*/
5722
if ((nd->nd_flag & ND_DSSERVER) != 0)
5723
nd->nd_repstat = NFSERR_NOTSUPP;
5724
/* However, allow the proxy stateid. */
5725
if (stp->ls_stateid.seqid == 0xffffffff &&
5726
stp->ls_stateid.other[0] == 0x55555555 &&
5727
stp->ls_stateid.other[1] == 0x55555555 &&
5728
stp->ls_stateid.other[2] == 0x55555555)
5729
gotproxystateid = 1;
5730
off = fxdr_hyper(tl); tl += 2;
5731
lop->lo_first = off;
5732
len = fxdr_hyper(tl);
5733
if (len < 0)
5734
len = OFF_MAX;
5735
NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off,
5736
(intmax_t)len);
5737
lop->lo_end = lop->lo_first + len;
5738
/*
5739
* Sanity check the offset and length.
5740
* off and len are off_t (signed int64_t) whereas
5741
* lo_first and lo_end are uint64_t and, as such,
5742
* if off >= 0 && len > 0, lo_end cannot overflow
5743
* unless off_t is changed to something other than
5744
* int64_t. Check lo_end < lo_first in case that
5745
* is someday the case.
5746
* The error to return is not specified by RFC 7862 so I
5747
* made this compatible with the Linux knfsd.
5748
*/
5749
if (nd->nd_repstat == 0) {
5750
if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE)
5751
nd->nd_repstat = NFSERR_FBIG;
5752
else if (len == 0 || lop->lo_end < lop->lo_first)
5753
nd->nd_repstat = NFSERR_INVAL;
5754
}
5755
5756
if (nd->nd_repstat == 0 && vp->v_type != VREG)
5757
nd->nd_repstat = NFSERR_WRONGTYPE;
5758
NFSZERO_ATTRBIT(&attrbits);
5759
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5760
forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5761
if (nd->nd_repstat == 0)
5762
nd->nd_repstat = forat_ret;
5763
if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5764
NFSVNO_EXSTRICTACCESS(exp)))
5765
nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5766
curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5767
NULL);
5768
if (nd->nd_repstat == 0 && gotproxystateid == 0)
5769
nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5770
&stateid, exp, nd, curthread);
5771
5772
if (nd->nd_repstat == 0)
5773
nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred,
5774
curthread);
5775
vput(vp);
5776
NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat);
5777
NFSEXITCODE2(0, nd);
5778
return (0);
5779
nfsmout:
5780
vput(vp);
5781
NFSEXITCODE2(error, nd);
5782
return (error);
5783
}
5784
5785
/*
5786
* nfs copy service
5787
*/
5788
int
5789
nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5790
vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5791
{
5792
uint32_t *tl;
5793
struct nfsvattr at;
5794
int cnt, error = 0, ret;
5795
off_t inoff, outoff;
5796
uint64_t len;
5797
size_t xfer;
5798
struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5799
struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5800
nfsquad_t clientid;
5801
nfsv4stateid_t stateid;
5802
nfsattrbit_t attrbits;
5803
void *rl_rcookie, *rl_wcookie;
5804
5805
rl_rcookie = rl_wcookie = NULL;
5806
if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0) {
5807
/*
5808
* For a pNFS server, reply NFSERR_NOTSUPP so that the client
5809
* will do the copy via I/O on the DS(s).
5810
* If vfs.nfsd.maxcopyrange set to 0, disable Copy.
5811
*/
5812
nd->nd_repstat = NFSERR_NOTSUPP;
5813
goto nfsmout;
5814
}
5815
if (vp == tovp) {
5816
/* Copying a byte range within the same file is not allowed. */
5817
nd->nd_repstat = NFSERR_INVAL;
5818
goto nfsmout;
5819
}
5820
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5821
3 * NFSX_UNSIGNED);
5822
instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5823
inlop->lo_flags = NFSLCK_READ;
5824
instp->ls_ownerlen = 0;
5825
instp->ls_op = NULL;
5826
instp->ls_uid = nd->nd_cred->cr_uid;
5827
instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5828
clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5829
clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5830
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5831
clientid.qval = nd->nd_clientid.qval;
5832
instp->ls_stateid.other[2] = *tl++;
5833
outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5834
outlop->lo_flags = NFSLCK_WRITE;
5835
outstp->ls_ownerlen = 0;
5836
outstp->ls_op = NULL;
5837
outstp->ls_uid = nd->nd_cred->cr_uid;
5838
outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5839
outstp->ls_stateid.other[0] = *tl++;
5840
outstp->ls_stateid.other[1] = *tl++;
5841
outstp->ls_stateid.other[2] = *tl++;
5842
inoff = fxdr_hyper(tl); tl += 2;
5843
inlop->lo_first = inoff;
5844
outoff = fxdr_hyper(tl); tl += 2;
5845
outlop->lo_first = outoff;
5846
len = fxdr_hyper(tl); tl += 2;
5847
if (len == 0) {
5848
/* len == 0 means to EOF. */
5849
inlop->lo_end = OFF_MAX;
5850
outlop->lo_end = OFF_MAX;
5851
} else {
5852
inlop->lo_end = inlop->lo_first + len;
5853
outlop->lo_end = outlop->lo_first + len;
5854
}
5855
5856
/*
5857
* At this time only consecutive, synchronous copy is supported,
5858
* so ca_consecutive and ca_synchronous can be ignored.
5859
*/
5860
tl += 2;
5861
5862
cnt = fxdr_unsigned(int, *tl);
5863
if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5864
nd->nd_repstat = NFSERR_NOTSUPP;
5865
if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5866
inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5867
inlop->lo_end < inlop->lo_first || outlop->lo_end <
5868
outlop->lo_first))
5869
nd->nd_repstat = NFSERR_INVAL;
5870
5871
if (nd->nd_repstat == 0 && vp->v_type != VREG)
5872
nd->nd_repstat = NFSERR_WRONGTYPE;
5873
5874
/* Check permissions for the input file. */
5875
NFSZERO_ATTRBIT(&attrbits);
5876
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5877
ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5878
if (nd->nd_repstat == 0)
5879
nd->nd_repstat = ret;
5880
if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5881
NFSVNO_EXSTRICTACCESS(exp)))
5882
nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5883
curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5884
NULL);
5885
if (nd->nd_repstat == 0)
5886
nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5887
clientid, &stateid, exp, nd, curthread);
5888
NFSVOPUNLOCK(vp);
5889
if (nd->nd_repstat != 0)
5890
goto out;
5891
5892
error = NFSVOPLOCK(tovp, LK_SHARED);
5893
if (error != 0)
5894
goto out;
5895
if (tovp->v_type != VREG)
5896
nd->nd_repstat = NFSERR_WRONGTYPE;
5897
5898
/* For the output file, we only need the Owner attribute. */
5899
ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5900
if (nd->nd_repstat == 0)
5901
nd->nd_repstat = ret;
5902
if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5903
NFSVNO_EXSTRICTACCESS(exp)))
5904
nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5905
curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5906
NULL);
5907
if (nd->nd_repstat == 0)
5908
nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5909
clientid, &stateid, toexp, nd, curthread);
5910
NFSVOPUNLOCK(tovp);
5911
5912
/* Range lock the byte ranges for both invp and outvp. */
5913
if (nd->nd_repstat == 0) {
5914
for (;;) {
5915
if (len == 0) {
5916
rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5917
OFF_MAX);
5918
rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5919
OFF_MAX);
5920
} else {
5921
rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5922
outoff + len);
5923
rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5924
inoff + len);
5925
}
5926
if (rl_rcookie != NULL)
5927
break;
5928
vn_rangelock_unlock(tovp, rl_wcookie);
5929
if (len == 0)
5930
rl_rcookie = vn_rangelock_rlock(vp, inoff,
5931
OFF_MAX);
5932
else
5933
rl_rcookie = vn_rangelock_rlock(vp, inoff,
5934
inoff + len);
5935
vn_rangelock_unlock(vp, rl_rcookie);
5936
}
5937
5938
error = NFSVOPLOCK(vp, LK_SHARED);
5939
if (error == 0) {
5940
ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5941
if (ret == 0) {
5942
/*
5943
* Since invp is range locked, na_size should
5944
* not change.
5945
*/
5946
if (len == 0 && at.na_size > inoff) {
5947
/*
5948
* If len == 0, set it based on invp's
5949
* size. If offset is past EOF, just
5950
* leave len == 0.
5951
*/
5952
len = at.na_size - inoff;
5953
} else if (nfsrv_linux42server == 0 &&
5954
inoff + len > at.na_size) {
5955
/*
5956
* RFC-7862 says that NFSERR_INVAL must
5957
* be returned when inoff + len exceeds
5958
* the file size, however the NFSv4.2
5959
* Linux client likes to do this, so
5960
* only check if nfsrv_linux42server
5961
* is not set.
5962
*/
5963
nd->nd_repstat = NFSERR_INVAL;
5964
}
5965
}
5966
NFSVOPUNLOCK(vp);
5967
if (ret != 0 && nd->nd_repstat == 0)
5968
nd->nd_repstat = ret;
5969
} else if (nd->nd_repstat == 0)
5970
nd->nd_repstat = error;
5971
}
5972
5973
/*
5974
* Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
5975
* This size limit can be set to limit the time a copy RPC will
5976
* take.
5977
*/
5978
if (len > nfsrv_maxcopyrange)
5979
xfer = nfsrv_maxcopyrange;
5980
else
5981
xfer = len;
5982
if (nd->nd_repstat == 0) {
5983
nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5984
&xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred,
5985
NULL);
5986
if (nd->nd_repstat == 0)
5987
len = xfer;
5988
}
5989
5990
/* Unlock the ranges. */
5991
if (rl_rcookie != NULL)
5992
vn_rangelock_unlock(vp, rl_rcookie);
5993
if (rl_wcookie != NULL)
5994
vn_rangelock_unlock(tovp, rl_wcookie);
5995
5996
if (nd->nd_repstat == 0) {
5997
NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5998
NFSX_VERF);
5999
*tl++ = txdr_unsigned(0); /* No callback ids. */
6000
txdr_hyper(len, tl); tl += 2;
6001
*tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
6002
*tl++ = txdr_unsigned(nfsboottime.tv_sec);
6003
*tl++ = txdr_unsigned(nfsboottime.tv_usec);
6004
*tl++ = newnfs_true;
6005
*tl = newnfs_true;
6006
}
6007
out:
6008
vrele(vp);
6009
vrele(tovp);
6010
NFSEXITCODE2(error, nd);
6011
return (error);
6012
nfsmout:
6013
vput(vp);
6014
vrele(tovp);
6015
NFSEXITCODE2(error, nd);
6016
return (error);
6017
}
6018
6019
/*
6020
* nfs clone service
6021
*/
6022
int
6023
nfsrvd_clone(struct nfsrv_descript *nd, __unused int isdgram,
6024
vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
6025
{
6026
uint32_t *tl;
6027
struct nfsvattr at;
6028
int error = 0, ret;
6029
off_t inoff, outoff;
6030
uint64_t len;
6031
size_t xfer;
6032
struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
6033
struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
6034
nfsquad_t clientid;
6035
nfsv4stateid_t stateid;
6036
nfsattrbit_t attrbits;
6037
void *rl_rcookie, *rl_wcookie;
6038
long pathval;
6039
6040
rl_rcookie = rl_wcookie = NULL;
6041
pathval = 0;
6042
if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0 ||
6043
VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE, &pathval) != 0 ||
6044
pathval == 0) {
6045
/*
6046
* For a pNFS server, reply NFSERR_NOTSUPP so that the client
6047
* will not do the clone and will do I/O on the DS(s).
6048
* If vfs.nfsd.maxcopyrange set to 0, disable Clone.
6049
*/
6050
nd->nd_repstat = NFSERR_NOTSUPP;
6051
goto nfsmout;
6052
}
6053
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER);
6054
instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
6055
inlop->lo_flags = NFSLCK_READ;
6056
instp->ls_ownerlen = 0;
6057
instp->ls_op = NULL;
6058
instp->ls_uid = nd->nd_cred->cr_uid;
6059
instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
6060
clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
6061
clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
6062
if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
6063
clientid.qval = nd->nd_clientid.qval;
6064
instp->ls_stateid.other[2] = *tl++;
6065
outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
6066
outlop->lo_flags = NFSLCK_WRITE;
6067
outstp->ls_ownerlen = 0;
6068
outstp->ls_op = NULL;
6069
outstp->ls_uid = nd->nd_cred->cr_uid;
6070
outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
6071
outstp->ls_stateid.other[0] = *tl++;
6072
outstp->ls_stateid.other[1] = *tl++;
6073
outstp->ls_stateid.other[2] = *tl++;
6074
inoff = fxdr_hyper(tl); tl += 2;
6075
inlop->lo_first = inoff;
6076
outoff = fxdr_hyper(tl); tl += 2;
6077
outlop->lo_first = outoff;
6078
len = fxdr_hyper(tl);
6079
if (len == 0) {
6080
/* len == 0 means to EOF. */
6081
inlop->lo_end = OFF_MAX;
6082
outlop->lo_end = OFF_MAX;
6083
} else {
6084
inlop->lo_end = inlop->lo_first + len;
6085
outlop->lo_end = outlop->lo_first + len;
6086
}
6087
6088
if ((inoff > OFF_MAX || outoff > OFF_MAX ||
6089
inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
6090
inlop->lo_end < inlop->lo_first || outlop->lo_end <
6091
outlop->lo_first))
6092
nd->nd_repstat = NFSERR_INVAL;
6093
6094
if (nd->nd_repstat == 0 && vp->v_type != VREG)
6095
nd->nd_repstat = NFSERR_WRONGTYPE;
6096
6097
/* Check permissions for the input file. */
6098
NFSZERO_ATTRBIT(&attrbits);
6099
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
6100
ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
6101
if (nd->nd_repstat == 0)
6102
nd->nd_repstat = ret;
6103
if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6104
NFSVNO_EXSTRICTACCESS(exp)))
6105
nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
6106
curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6107
NULL);
6108
if (nd->nd_repstat == 0)
6109
nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
6110
clientid, &stateid, exp, nd, curthread);
6111
if (vp != tovp) {
6112
NFSVOPUNLOCK(vp);
6113
if (nd->nd_repstat != 0)
6114
goto out;
6115
6116
error = NFSVOPLOCK(tovp, LK_SHARED);
6117
if (error != 0)
6118
goto out;
6119
pathval = 0;
6120
if (VOP_PATHCONF(tovp, _PC_CLONE_BLKSIZE, &pathval) != 0 ||
6121
pathval == 0)
6122
nd->nd_repstat = NFSERR_NOTSUPP;
6123
else if (tovp->v_type != VREG)
6124
nd->nd_repstat = NFSERR_WRONGTYPE;
6125
}
6126
6127
/* For the output file, we only need the Owner attribute. */
6128
ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
6129
if (nd->nd_repstat == 0)
6130
nd->nd_repstat = ret;
6131
if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6132
NFSVNO_EXSTRICTACCESS(exp)))
6133
nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
6134
curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6135
NULL);
6136
if (nd->nd_repstat == 0)
6137
nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
6138
clientid, &stateid, toexp, nd, curthread);
6139
NFSVOPUNLOCK(tovp);
6140
6141
/* Range lock the byte ranges for both invp and outvp. */
6142
if (nd->nd_repstat == 0) {
6143
for (;;) {
6144
if (len == 0)
6145
rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6146
OFF_MAX);
6147
else
6148
rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6149
outoff + len);
6150
if (vp != tovp) {
6151
if (len == 0)
6152
rl_rcookie = vn_rangelock_tryrlock(vp,
6153
inoff, OFF_MAX);
6154
else
6155
rl_rcookie = vn_rangelock_tryrlock(vp,
6156
inoff, inoff + len);
6157
if (rl_rcookie != NULL)
6158
break;
6159
} else {
6160
rl_rcookie = NULL;
6161
break;
6162
}
6163
vn_rangelock_unlock(tovp, rl_wcookie);
6164
if (len == 0)
6165
rl_rcookie = vn_rangelock_rlock(vp, inoff,
6166
OFF_MAX);
6167
else
6168
rl_rcookie = vn_rangelock_rlock(vp, inoff,
6169
inoff + len);
6170
vn_rangelock_unlock(vp, rl_rcookie);
6171
}
6172
6173
error = NFSVOPLOCK(vp, LK_SHARED);
6174
if (error == 0) {
6175
ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
6176
if (ret == 0) {
6177
/*
6178
* Since invp is range locked, na_size should
6179
* not change.
6180
*/
6181
if (len == 0 && at.na_size > inoff)
6182
len = SSIZE_MAX; /* To EOF. */
6183
else if (inoff + len > at.na_size)
6184
nd->nd_repstat = NFSERR_INVAL;
6185
}
6186
NFSVOPUNLOCK(vp);
6187
if (ret != 0 && nd->nd_repstat == 0)
6188
nd->nd_repstat = ret;
6189
} else if (nd->nd_repstat == 0)
6190
nd->nd_repstat = error;
6191
}
6192
6193
/*
6194
* Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
6195
* This size limit can be set to limit the time a copy RPC will
6196
* take.
6197
*/
6198
xfer = len;
6199
if (nd->nd_repstat == 0) {
6200
nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
6201
&xfer, COPY_FILE_RANGE_CLONE, nd->nd_cred, nd->nd_cred,
6202
NULL);
6203
if (nd->nd_repstat == ENOSYS)
6204
nd->nd_repstat = NFSERR_INVAL;
6205
}
6206
6207
/* Unlock the ranges. */
6208
if (rl_rcookie != NULL)
6209
vn_rangelock_unlock(vp, rl_rcookie);
6210
if (rl_wcookie != NULL)
6211
vn_rangelock_unlock(tovp, rl_wcookie);
6212
6213
out:
6214
vrele(vp);
6215
vrele(tovp);
6216
NFSEXITCODE2(error, nd);
6217
return (error);
6218
nfsmout:
6219
vput(vp);
6220
vrele(tovp);
6221
NFSEXITCODE2(error, nd);
6222
return (error);
6223
}
6224
6225
/*
6226
* nfs seek service
6227
*/
6228
int
6229
nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
6230
vnode_t vp, struct nfsexstuff *exp)
6231
{
6232
uint32_t *tl;
6233
struct nfsvattr at;
6234
int content, error = 0;
6235
off_t off;
6236
u_long cmd;
6237
nfsattrbit_t attrbits;
6238
bool eof;
6239
6240
NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
6241
/* Ignore the stateid for now. */
6242
tl += (NFSX_STATEID / NFSX_UNSIGNED);
6243
off = fxdr_hyper(tl); tl += 2;
6244
content = fxdr_unsigned(int, *tl);
6245
if (content == NFSV4CONTENT_DATA)
6246
cmd = FIOSEEKDATA;
6247
else if (content == NFSV4CONTENT_HOLE)
6248
cmd = FIOSEEKHOLE;
6249
else
6250
nd->nd_repstat = NFSERR_BADXDR;
6251
if (nd->nd_repstat == 0 && vp->v_type == VDIR)
6252
nd->nd_repstat = NFSERR_ISDIR;
6253
if (nd->nd_repstat == 0 && vp->v_type != VREG)
6254
nd->nd_repstat = NFSERR_WRONGTYPE;
6255
if (nd->nd_repstat == 0 && off < 0)
6256
nd->nd_repstat = NFSERR_NXIO;
6257
if (nd->nd_repstat == 0) {
6258
/* Check permissions for the input file. */
6259
NFSZERO_ATTRBIT(&attrbits);
6260
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
6261
nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
6262
&attrbits);
6263
}
6264
if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6265
NFSVNO_EXSTRICTACCESS(exp)))
6266
nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
6267
curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6268
NULL);
6269
if (nd->nd_repstat != 0)
6270
goto nfsmout;
6271
6272
/* nfsvno_seek() unlocks and vrele()s the vp. */
6273
nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
6274
nd->nd_cred, curthread);
6275
if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
6276
nfsrv_linux42server != 0)
6277
nd->nd_repstat = NFSERR_NXIO;
6278
if (nd->nd_repstat == 0) {
6279
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
6280
if (eof)
6281
*tl++ = newnfs_true;
6282
else
6283
*tl++ = newnfs_false;
6284
txdr_hyper(off, tl);
6285
}
6286
NFSEXITCODE2(error, nd);
6287
return (error);
6288
nfsmout:
6289
vput(vp);
6290
NFSEXITCODE2(error, nd);
6291
return (error);
6292
}
6293
6294
/*
6295
* nfs get extended attribute service
6296
*/
6297
int
6298
nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
6299
vnode_t vp, __unused struct nfsexstuff *exp)
6300
{
6301
uint32_t *tl;
6302
struct mbuf *mp = NULL, *mpend = NULL;
6303
int error, len;
6304
char *name;
6305
struct thread *p = curthread;
6306
uint16_t off;
6307
6308
error = 0;
6309
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6310
len = fxdr_unsigned(int, *tl);
6311
if (len <= 0) {
6312
nd->nd_repstat = NFSERR_BADXDR;
6313
goto nfsmout;
6314
}
6315
if (len > EXTATTR_MAXNAMELEN) {
6316
nd->nd_repstat = NFSERR_NOXATTR;
6317
goto nfsmout;
6318
}
6319
name = malloc(len + 1, M_TEMP, M_WAITOK);
6320
nd->nd_repstat = nfsrv_mtostr(nd, name, len);
6321
if (nd->nd_repstat == 0)
6322
nd->nd_repstat = nfsvno_getxattr(vp, name,
6323
nd->nd_maxresp, nd->nd_cred, nd->nd_flag,
6324
nd->nd_maxextsiz, p, &mp, &mpend, &len);
6325
if (nd->nd_repstat == ENOATTR)
6326
nd->nd_repstat = NFSERR_NOXATTR;
6327
else if (nd->nd_repstat == EOPNOTSUPP)
6328
nd->nd_repstat = NFSERR_NOTSUPP;
6329
if (nd->nd_repstat == 0) {
6330
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6331
*tl = txdr_unsigned(len);
6332
if (len > 0) {
6333
nd->nd_mb->m_next = mp;
6334
nd->nd_mb = mpend;
6335
if ((mpend->m_flags & M_EXTPG) != 0) {
6336
nd->nd_flag |= ND_EXTPG;
6337
nd->nd_bextpg = mpend->m_epg_npgs - 1;
6338
nd->nd_bpos = (char *)(void *)
6339
PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
6340
off = (nd->nd_bextpg == 0) ?
6341
mpend->m_epg_1st_off : 0;
6342
nd->nd_bpos += off + mpend->m_epg_last_len;
6343
nd->nd_bextpgsiz = PAGE_SIZE -
6344
mpend->m_epg_last_len - off;
6345
} else
6346
nd->nd_bpos = mtod(mpend, char *) +
6347
mpend->m_len;
6348
}
6349
}
6350
free(name, M_TEMP);
6351
6352
nfsmout:
6353
if (nd->nd_repstat == 0)
6354
nd->nd_repstat = error;
6355
vput(vp);
6356
NFSEXITCODE2(0, nd);
6357
return (0);
6358
}
6359
6360
/*
6361
* nfs set extended attribute service
6362
*/
6363
int
6364
nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
6365
vnode_t vp, __unused struct nfsexstuff *exp)
6366
{
6367
uint32_t *tl;
6368
struct nfsvattr ova, nva;
6369
nfsattrbit_t attrbits;
6370
int error, len, opt;
6371
char *name;
6372
size_t siz;
6373
struct thread *p = curthread;
6374
6375
error = 0;
6376
name = NULL;
6377
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6378
opt = fxdr_unsigned(int, *tl++);
6379
len = fxdr_unsigned(int, *tl);
6380
if (len <= 0) {
6381
nd->nd_repstat = NFSERR_BADXDR;
6382
goto nfsmout;
6383
}
6384
if (len > EXTATTR_MAXNAMELEN) {
6385
nd->nd_repstat = NFSERR_NOXATTR;
6386
goto nfsmout;
6387
}
6388
name = malloc(len + 1, M_TEMP, M_WAITOK);
6389
error = nfsrv_mtostr(nd, name, len);
6390
if (error != 0)
6391
goto nfsmout;
6392
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6393
len = fxdr_unsigned(int, *tl);
6394
if (len < 0 || len > IOSIZE_MAX) {
6395
nd->nd_repstat = NFSERR_XATTR2BIG;
6396
goto nfsmout;
6397
}
6398
switch (opt) {
6399
case NFSV4SXATTR_CREATE:
6400
error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6401
&siz, nd->nd_cred, p);
6402
if (error != ENOATTR)
6403
nd->nd_repstat = NFSERR_EXIST;
6404
error = 0;
6405
break;
6406
case NFSV4SXATTR_REPLACE:
6407
error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6408
&siz, nd->nd_cred, p);
6409
if (error != 0)
6410
nd->nd_repstat = NFSERR_NOXATTR;
6411
break;
6412
case NFSV4SXATTR_EITHER:
6413
break;
6414
default:
6415
nd->nd_repstat = NFSERR_BADXDR;
6416
}
6417
if (nd->nd_repstat != 0)
6418
goto nfsmout;
6419
6420
/* Now, do the Set Extended attribute, with Change before and after. */
6421
NFSZERO_ATTRBIT(&attrbits);
6422
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6423
nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6424
if (nd->nd_repstat == 0) {
6425
nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
6426
nd->nd_dpos, nd->nd_cred, p);
6427
if (nd->nd_repstat == ENXIO)
6428
nd->nd_repstat = NFSERR_XATTR2BIG;
6429
}
6430
if (nd->nd_repstat == 0 && len > 0)
6431
nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
6432
if (nd->nd_repstat == 0)
6433
nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6434
if (nd->nd_repstat == 0) {
6435
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6436
*tl++ = newnfs_true;
6437
txdr_hyper(ova.na_filerev, tl); tl += 2;
6438
txdr_hyper(nva.na_filerev, tl);
6439
}
6440
6441
nfsmout:
6442
free(name, M_TEMP);
6443
if (nd->nd_repstat == 0)
6444
nd->nd_repstat = error;
6445
vput(vp);
6446
NFSEXITCODE2(0, nd);
6447
return (0);
6448
}
6449
6450
/*
6451
* nfs remove extended attribute service
6452
*/
6453
int
6454
nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
6455
vnode_t vp, __unused struct nfsexstuff *exp)
6456
{
6457
uint32_t *tl;
6458
struct nfsvattr ova, nva;
6459
nfsattrbit_t attrbits;
6460
int error, len;
6461
char *name;
6462
struct thread *p = curthread;
6463
6464
error = 0;
6465
name = NULL;
6466
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6467
len = fxdr_unsigned(int, *tl);
6468
if (len <= 0) {
6469
nd->nd_repstat = NFSERR_BADXDR;
6470
goto nfsmout;
6471
}
6472
if (len > EXTATTR_MAXNAMELEN) {
6473
nd->nd_repstat = NFSERR_NOXATTR;
6474
goto nfsmout;
6475
}
6476
name = malloc(len + 1, M_TEMP, M_WAITOK);
6477
error = nfsrv_mtostr(nd, name, len);
6478
if (error != 0)
6479
goto nfsmout;
6480
6481
if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
6482
printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
6483
error = NFSERR_NOXATTR;
6484
goto nfsmout;
6485
}
6486
/*
6487
* Now, do the Remove Extended attribute, with Change before and
6488
* after.
6489
*/
6490
NFSZERO_ATTRBIT(&attrbits);
6491
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6492
nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6493
if (nd->nd_repstat == 0) {
6494
nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
6495
if (nd->nd_repstat == ENOATTR)
6496
nd->nd_repstat = NFSERR_NOXATTR;
6497
}
6498
if (nd->nd_repstat == 0)
6499
nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6500
if (nd->nd_repstat == 0) {
6501
NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6502
*tl++ = newnfs_true;
6503
txdr_hyper(ova.na_filerev, tl); tl += 2;
6504
txdr_hyper(nva.na_filerev, tl);
6505
}
6506
6507
nfsmout:
6508
free(name, M_TEMP);
6509
if (nd->nd_repstat == 0)
6510
nd->nd_repstat = error;
6511
vput(vp);
6512
NFSEXITCODE2(0, nd);
6513
return (0);
6514
}
6515
6516
/*
6517
* nfs list extended attribute service
6518
*/
6519
int
6520
nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
6521
vnode_t vp, __unused struct nfsexstuff *exp)
6522
{
6523
uint32_t cnt, *tl, len, len2, i, pos, retlen;
6524
int error;
6525
uint64_t cookie, cookie2;
6526
u_char *buf;
6527
bool eof;
6528
struct thread *p = curthread;
6529
6530
error = 0;
6531
buf = NULL;
6532
NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6533
/*
6534
* The cookie doesn't need to be in net byte order, but FreeBSD
6535
* does so to make it more readable in packet traces.
6536
*/
6537
cookie = fxdr_hyper(tl); tl += 2;
6538
len = fxdr_unsigned(uint32_t, *tl);
6539
if (len == 0 || cookie >= IOSIZE_MAX) {
6540
nd->nd_repstat = NFSERR_BADXDR;
6541
goto nfsmout;
6542
}
6543
if (len > nd->nd_maxresp - NFS_MAXXDR)
6544
len = nd->nd_maxresp - NFS_MAXXDR;
6545
len2 = len;
6546
nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
6547
&len, &eof);
6548
if (nd->nd_repstat == EOPNOTSUPP)
6549
nd->nd_repstat = NFSERR_NOTSUPP;
6550
if (nd->nd_repstat == 0) {
6551
cookie2 = cookie + len;
6552
if (cookie2 < cookie)
6553
nd->nd_repstat = NFSERR_BADXDR;
6554
}
6555
retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
6556
if (nd->nd_repstat == 0 && len2 < retlen)
6557
nd->nd_repstat = NFSERR_TOOSMALL;
6558
if (nd->nd_repstat == 0) {
6559
/* Now copy the entries out. */
6560
if (len == 0) {
6561
/* The cookie was at eof. */
6562
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
6563
NFSX_UNSIGNED);
6564
txdr_hyper(cookie2, tl); tl += 2;
6565
*tl++ = txdr_unsigned(0);
6566
*tl = newnfs_true;
6567
goto nfsmout;
6568
}
6569
6570
/* Sanity check the cookie. */
6571
for (pos = 0; pos < len; pos += (i + 1)) {
6572
if (pos == cookie)
6573
break;
6574
i = buf[pos];
6575
}
6576
if (pos != cookie) {
6577
nd->nd_repstat = NFSERR_INVAL;
6578
goto nfsmout;
6579
}
6580
6581
/* Loop around copying the entrie(s) out. */
6582
cnt = 0;
6583
len -= cookie;
6584
i = buf[pos];
6585
while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
6586
NFSX_UNSIGNED) {
6587
if (cnt == 0) {
6588
NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
6589
NFSX_UNSIGNED);
6590
txdr_hyper(cookie2, tl); tl += 2;
6591
}
6592
retlen += nfsm_strtom(nd, &buf[pos + 1], i);
6593
len -= (i + 1);
6594
pos += (i + 1);
6595
i = buf[pos];
6596
cnt++;
6597
}
6598
/*
6599
* eof is set true/false by nfsvno_listxattr(), but if we
6600
* can't copy all entries returned by nfsvno_listxattr(),
6601
* we are not at eof.
6602
*/
6603
if (len > 0)
6604
eof = false;
6605
if (cnt > 0) {
6606
/* *tl is set above. */
6607
*tl = txdr_unsigned(cnt);
6608
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6609
if (eof)
6610
*tl = newnfs_true;
6611
else
6612
*tl = newnfs_false;
6613
} else
6614
nd->nd_repstat = NFSERR_TOOSMALL;
6615
}
6616
6617
nfsmout:
6618
free(buf, M_TEMP);
6619
if (nd->nd_repstat == 0)
6620
nd->nd_repstat = error;
6621
vput(vp);
6622
NFSEXITCODE2(0, nd);
6623
return (0);
6624
}
6625
6626
/*
6627
* nfsv4 service not supported
6628
*/
6629
int
6630
nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
6631
__unused vnode_t vp, __unused struct nfsexstuff *exp)
6632
{
6633
6634
nd->nd_repstat = NFSERR_NOTSUPP;
6635
NFSEXITCODE2(0, nd);
6636
return (0);
6637
}
6638
6639