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