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