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