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