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, exp);
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 exp);
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, exp);
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, exclusive_flag = 0, override;
2968 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2969 int how = NFSCREATE_UNCHECKED;
2970 int32_t cverf[2], tverf[2] = { 0, 0 };
2971 vnode_t vp = NULL, dirp = NULL;
2972 struct nfsvattr nva, dirfor, diraft, nva2;
2973 struct nameidata named;
2974 nfsv4stateid_t stateid, delegstateid;
2975 nfsattrbit_t attrbits;
2976 nfsquad_t clientid;
2977 char *bufp = NULL;
2978 u_long *hashp;
2979 NFSACL_T *aclp = NULL, *daclp = NULL;
2980 struct thread *p = curthread;
2981 bool done_namei;
2982 __enum_uint8_decl(wdelegace) { USENONE, USEMODE, USENFSV4ACL }
2983 delegace;
2984
2985 #ifdef NFS4_ACL_EXTATTR_NAME
2986 aclp = acl_alloc(M_WAITOK);
2987 aclp->acl_cnt = 0;
2988 daclp = acl_alloc(M_WAITOK);
2989 daclp->acl_cnt = 0;
2990 #endif
2991 NFSZERO_ATTRBIT(&attrbits);
2992 done_namei = false;
2993 delegace = USEMODE;
2994 named.ni_cnd.cn_nameiop = 0;
2995 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2996 i = fxdr_unsigned(int, *(tl + 5));
2997 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2998 nd->nd_repstat = NFSERR_BADXDR;
2999 goto nfsmout;
3000 }
3001 stp = malloc(sizeof (struct nfsstate) + i,
3002 M_NFSDSTATE, M_WAITOK);
3003 stp->ls_ownerlen = i;
3004 stp->ls_op = nd->nd_rp;
3005 stp->ls_flags = NFSLCK_OPEN;
3006 stp->ls_uid = nd->nd_cred->cr_uid;
3007 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3008 i = fxdr_unsigned(int, *tl++);
3009 retext = 0;
3010 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
3011 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
3012 retext = 1;
3013 /* For now, ignore these. */
3014 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
3015 switch (i & NFSV4OPEN_WANTDELEGMASK) {
3016 case NFSV4OPEN_WANTANYDELEG:
3017 stp->ls_flags |= (NFSLCK_WANTRDELEG |
3018 NFSLCK_WANTWDELEG);
3019 i &= ~NFSV4OPEN_WANTDELEGMASK;
3020 break;
3021 case NFSV4OPEN_WANTREADDELEG:
3022 stp->ls_flags |= NFSLCK_WANTRDELEG;
3023 i &= ~NFSV4OPEN_WANTDELEGMASK;
3024 break;
3025 case NFSV4OPEN_WANTWRITEDELEG:
3026 stp->ls_flags |= NFSLCK_WANTWDELEG;
3027 i &= ~NFSV4OPEN_WANTDELEGMASK;
3028 break;
3029 case NFSV4OPEN_WANTNODELEG:
3030 stp->ls_flags |= NFSLCK_WANTNODELEG;
3031 i &= ~NFSV4OPEN_WANTDELEGMASK;
3032 break;
3033 case NFSV4OPEN_WANTCANCEL:
3034 printf("NFSv4: ignore Open WantCancel\n");
3035 i &= ~NFSV4OPEN_WANTDELEGMASK;
3036 break;
3037 default:
3038 /* nd_repstat will be set to NFSERR_INVAL below. */
3039 break;
3040 }
3041 }
3042 switch (i) {
3043 case NFSV4OPEN_ACCESSREAD:
3044 stp->ls_flags |= NFSLCK_READACCESS;
3045 break;
3046 case NFSV4OPEN_ACCESSWRITE:
3047 stp->ls_flags |= NFSLCK_WRITEACCESS;
3048 break;
3049 case NFSV4OPEN_ACCESSBOTH:
3050 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
3051 break;
3052 default:
3053 nd->nd_repstat = NFSERR_INVAL;
3054 }
3055 i = fxdr_unsigned(int, *tl++);
3056 switch (i) {
3057 case NFSV4OPEN_DENYNONE:
3058 break;
3059 case NFSV4OPEN_DENYREAD:
3060 stp->ls_flags |= NFSLCK_READDENY;
3061 break;
3062 case NFSV4OPEN_DENYWRITE:
3063 stp->ls_flags |= NFSLCK_WRITEDENY;
3064 break;
3065 case NFSV4OPEN_DENYBOTH:
3066 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3067 break;
3068 default:
3069 nd->nd_repstat = NFSERR_INVAL;
3070 }
3071 clientid.lval[0] = *tl++;
3072 clientid.lval[1] = *tl;
3073 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3074 if ((nd->nd_flag & ND_NFSV41) != 0)
3075 clientid.qval = nd->nd_clientid.qval;
3076 else if (nd->nd_clientid.qval != clientid.qval)
3077 printf("EEK7 multiple clids\n");
3078 } else {
3079 if ((nd->nd_flag & ND_NFSV41) != 0)
3080 printf("EEK! no clientid from session\n");
3081 nd->nd_flag |= ND_IMPLIEDCLID;
3082 nd->nd_clientid.qval = clientid.qval;
3083 }
3084 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
3085 if (error)
3086 goto nfsmout;
3087 NFSVNO_ATTRINIT(&nva);
3088 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3089 create = fxdr_unsigned(int, *tl);
3090 if (!nd->nd_repstat)
3091 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
3092 if (create == NFSV4OPEN_CREATE) {
3093 nva.na_type = VREG;
3094 nva.na_mode = 0;
3095 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3096 how = fxdr_unsigned(int, *tl);
3097 switch (how) {
3098 case NFSCREATE_UNCHECKED:
3099 case NFSCREATE_GUARDED:
3100 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp,
3101 daclp, p);
3102 if (error)
3103 goto nfsmout;
3104 /*
3105 * If the na_gid being set is the same as that of
3106 * the directory it is going in, clear it, since
3107 * that is what will be set by default. This allows
3108 * a user that isn't in that group to do the create.
3109 */
3110 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
3111 nva.na_gid == dirfor.na_gid)
3112 NFSVNO_UNSET(&nva, gid);
3113 if (!nd->nd_repstat)
3114 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
3115 break;
3116 case NFSCREATE_EXCLUSIVE:
3117 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3118 cverf[0] = *tl++;
3119 cverf[1] = *tl;
3120 if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0)
3121 nd->nd_repstat = NFSERR_INVAL;
3122 break;
3123 case NFSCREATE_EXCLUSIVE41:
3124 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
3125 cverf[0] = *tl++;
3126 cverf[1] = *tl;
3127 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp,
3128 daclp, p);
3129 if (error != 0)
3130 goto nfsmout;
3131 if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0 ||
3132 NFSISSET_ATTRBIT(&attrbits,
3133 NFSATTRBIT_TIMEACCESSSET))
3134 nd->nd_repstat = NFSERR_INVAL;
3135 /*
3136 * If the na_gid being set is the same as that of
3137 * the directory it is going in, clear it, since
3138 * that is what will be set by default. This allows
3139 * a user that isn't in that group to do the create.
3140 */
3141 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
3142 nva.na_gid == dirfor.na_gid)
3143 NFSVNO_UNSET(&nva, gid);
3144 if (nd->nd_repstat == 0)
3145 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
3146 break;
3147 default:
3148 nd->nd_repstat = NFSERR_BADXDR;
3149 goto nfsmout;
3150 }
3151 } else if (create != NFSV4OPEN_NOCREATE) {
3152 nd->nd_repstat = NFSERR_BADXDR;
3153 goto nfsmout;
3154 }
3155
3156 /*
3157 * Now, handle the claim, which usually includes looking up a
3158 * name in the directory referenced by dp. The exception is
3159 * NFSV4OPEN_CLAIMPREVIOUS.
3160 */
3161 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3162 claim = fxdr_unsigned(int, *tl);
3163 if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim ==
3164 NFSV4OPEN_CLAIMDELEGATECURFH) {
3165 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3166 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3167 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
3168 stp->ls_flags |= NFSLCK_DELEGCUR;
3169 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim ==
3170 NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3171 stp->ls_flags |= NFSLCK_DELEGPREV;
3172 }
3173 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
3174 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
3175 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
3176 claim != NFSV4OPEN_CLAIMNULL)
3177 nd->nd_repstat = NFSERR_INVAL;
3178 if (nd->nd_repstat) {
3179 nd->nd_repstat = nfsrv_opencheck(clientid,
3180 &stateid, stp, NULL, nd, p, nd->nd_repstat);
3181 goto nfsmout;
3182 }
3183 if (create == NFSV4OPEN_CREATE)
3184 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
3185 LOCKPARENT | LOCKLEAF | NOCACHE);
3186 else
3187 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3188 LOCKLEAF);
3189 nfsvno_setpathbuf(&named, &bufp, &hashp);
3190 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3191 if (error) {
3192 vrele(dp);
3193 #ifdef NFS4_ACL_EXTATTR_NAME
3194 acl_free(aclp);
3195 acl_free(daclp);
3196 #endif
3197 free(stp, M_NFSDSTATE);
3198 nfsvno_relpathbuf(&named);
3199 NFSEXITCODE2(error, nd);
3200 return (error);
3201 }
3202 if (!nd->nd_repstat) {
3203 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
3204 &dirp);
3205 } else {
3206 vrele(dp);
3207 nfsvno_relpathbuf(&named);
3208 }
3209 if (create == NFSV4OPEN_CREATE) {
3210 switch (how) {
3211 case NFSCREATE_UNCHECKED:
3212 if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3213 /*
3214 * Clear the setable attribute bits, except
3215 * for Size, if it is being truncated.
3216 */
3217 NFSZERO_ATTRBIT(&attrbits);
3218 if (NFSVNO_ISSETSIZE(&nva))
3219 NFSSETBIT_ATTRBIT(&attrbits,
3220 NFSATTRBIT_SIZE);
3221 }
3222 break;
3223 case NFSCREATE_GUARDED:
3224 if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3225 nd->nd_repstat = EEXIST;
3226 done_namei = true;
3227 }
3228 break;
3229 case NFSCREATE_EXCLUSIVE:
3230 if (nd->nd_repstat == 0 && named.ni_vp == NULL)
3231 nva.na_mode = 0;
3232 /* FALLTHROUGH */
3233 case NFSCREATE_EXCLUSIVE41:
3234 if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
3235 nd->nd_repstat = nfsvno_getattr(named.ni_vp,
3236 &nva2, nd, p, 1, NULL);
3237 if (nd->nd_repstat == 0) {
3238 tverf[0] = nva2.na_atime.tv_sec;
3239 tverf[1] = nva2.na_atime.tv_nsec;
3240 if (cverf[0] != tverf[0] ||
3241 cverf[1] != tverf[1])
3242 nd->nd_repstat = EEXIST;
3243 }
3244 if (nd->nd_repstat != 0)
3245 done_namei = true;
3246 }
3247 exclusive_flag = 1;
3248 break;
3249 }
3250 }
3251 nfsvno_open(nd, &named, clientid, &stateid, stp,
3252 &exclusive_flag, &nva, cverf, create, aclp, daclp,
3253 &attrbits, nd->nd_cred, done_namei, exp, &vp);
3254 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
3255 NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH ||
3256 claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) {
3257 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3258 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3259 i = fxdr_unsigned(int, *tl);
3260 switch (i) {
3261 case NFSV4OPEN_DELEGATEREAD:
3262 stp->ls_flags |= NFSLCK_DELEGREAD;
3263 break;
3264 case NFSV4OPEN_DELEGATEWRITE:
3265 stp->ls_flags |= NFSLCK_DELEGWRITE;
3266 case NFSV4OPEN_DELEGATENONE:
3267 break;
3268 default:
3269 nd->nd_repstat = NFSERR_BADXDR;
3270 goto nfsmout;
3271 }
3272 stp->ls_flags |= NFSLCK_RECLAIM;
3273 } else {
3274 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
3275 nd->nd_repstat = NFSERR_INVAL;
3276 }
3277 vp = dp;
3278 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3279 if (!VN_IS_DOOMED(vp))
3280 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
3281 stp, vp, nd, p, nd->nd_repstat);
3282 else
3283 nd->nd_repstat = NFSERR_PERM;
3284 } else {
3285 nd->nd_repstat = NFSERR_BADXDR;
3286 goto nfsmout;
3287 }
3288
3289 /*
3290 * Do basic access checking.
3291 */
3292 if (!nd->nd_repstat && vp->v_type != VREG) {
3293 /*
3294 * The IETF working group decided that this is the correct
3295 * error return for all non-regular files.
3296 */
3297 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
3298 }
3299
3300 /*
3301 * If the Open is being done for a file that already exists, apply
3302 * normal permission checking including for the file owner, if
3303 * vfs.nfsd.v4openaccess is set.
3304 * Previously, the owner was always allowed to open the file to
3305 * be consistent with the NFS tradition of always allowing the
3306 * owner of the file to write to the file regardless of permissions.
3307 * It now appears that the Linux client expects the owner
3308 * permissions to be checked for opens that are not creating the
3309 * file. I believe the correct approach is to use the Access
3310 * operation's results to be consistent with NFSv3, but that is
3311 * not what the current Linux client appears to be doing.
3312 * Since both the Linux and OpenSolaris NFSv4 servers do this check,
3313 * I have enabled it by default. Since Linux does not apply this
3314 * check for claim_delegate_cur, this code does the same.
3315 * If this semantic change causes a problem, it can be disabled by
3316 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the
3317 * previous semantics.
3318 */
3319 if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE &&
3320 (stp->ls_flags & NFSLCK_DELEGCUR) == 0)
3321 override = NFSACCCHK_NOOVERRIDE;
3322 else
3323 override = NFSACCCHK_ALLOWOWNER;
3324 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
3325 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
3326 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3327 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
3328 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
3329 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
3330 if (nd->nd_repstat)
3331 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
3332 nd->nd_cred, exp, p, override,
3333 NFSACCCHK_VPISLOCKED, NULL);
3334 }
3335
3336 if (!nd->nd_repstat)
3337 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
3338
3339 if (nd->nd_repstat == 0 && aclp != NULL && nfsrv_issuedelegs != 0 &&
3340 (dp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) {
3341 if (aclp->acl_cnt == 0 && create == NFSV4OPEN_NOCREATE) {
3342 int retacl;
3343
3344 /* We do not yet have an ACL, so try and get one. */
3345 retacl = VOP_GETACL(vp, ACL_TYPE_NFS4, aclp,
3346 nd->nd_cred, p);
3347 if (retacl != 0 && retacl != ENOATTR &&
3348 retacl != EOPNOTSUPP && retacl != EINVAL)
3349 delegace = USENONE;
3350 else if (retacl == 0 && aclp->acl_cnt > 0)
3351 delegace = USENFSV4ACL;
3352 } else if (aclp->acl_cnt > 0 && create == NFSV4OPEN_CREATE) {
3353 delegace = USENFSV4ACL;
3354 }
3355 }
3356
3357 /*
3358 * Do the open locking/delegation stuff.
3359 */
3360 if (!nd->nd_repstat)
3361 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
3362 &delegstateid, &rflags, exp, p, nva.na_filerev);
3363
3364 /*
3365 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
3366 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
3367 * (ie: Leave the NFSVOPUNLOCK() about here.)
3368 */
3369 if (vp)
3370 NFSVOPUNLOCK(vp);
3371 if (stp)
3372 free(stp, M_NFSDSTATE);
3373 if (!nd->nd_repstat && dirp)
3374 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
3375 if (!nd->nd_repstat) {
3376 /* For NFSv4.1, set the Current StateID. */
3377 if ((nd->nd_flag & ND_NFSV41) != 0) {
3378 nd->nd_curstateid = stateid;
3379 nd->nd_flag |= ND_CURSTATEID;
3380 }
3381 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
3382 *tl++ = txdr_unsigned(stateid.seqid);
3383 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3384 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3385 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
3386 *tl++ = newnfs_true;
3387 *tl++ = 0;
3388 *tl++ = 0;
3389 *tl++ = 0;
3390 *tl++ = 0;
3391 } else {
3392 *tl++ = newnfs_false; /* Since dirp is not locked */
3393 txdr_hyper(dirfor.na_filerev, tl);
3394 tl += 2;
3395 txdr_hyper(diraft.na_filerev, tl);
3396 tl += 2;
3397 }
3398 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
3399 (void) nfsrv_putattrbit(nd, &attrbits);
3400 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3401 if (rflags & NFSV4OPEN_READDELEGATE)
3402 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
3403 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
3404 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
3405 else if (retext != 0) {
3406 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
3407 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
3408 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3409 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3410 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
3411 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3412 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
3413 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
3414 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3415 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
3416 *tl = newnfs_false;
3417 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
3418 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3419 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
3420 *tl = newnfs_false;
3421 } else if ((rflags &
3422 NFSV4OPEN_WDNOTSUPPDOWNGRADE) != 0) {
3423 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3424 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPDOWNGRADE);
3425 } else if ((rflags & NFSV4OPEN_WDNOTSUPPUPGRADE) != 0) {
3426 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3427 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPUPGRADE);
3428 } else {
3429 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3430 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3431 }
3432 } else
3433 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3434 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3435 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3436 *tl++ = txdr_unsigned(delegstateid.seqid);
3437 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3438 NFSX_STATEIDOTHER);
3439 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3440 if (rflags & NFSV4OPEN_RECALL)
3441 *tl = newnfs_true;
3442 else
3443 *tl = newnfs_false;
3444 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3445 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3446 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3447 txdr_hyper(nva.na_size, tl);
3448 }
3449
3450 /* Set up the write delegation ACE. */
3451 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3452 if (delegace == USENFSV4ACL) {
3453 int j;
3454
3455 for (j = 0; j < aclp->acl_cnt; j++) {
3456 if (aclp->acl_entry[j].ae_tag ==
3457 ACL_USER_OBJ ||
3458 aclp->acl_entry[j].ae_entry_type !=
3459 ACL_ENTRY_TYPE_ALLOW)
3460 break;
3461 }
3462 if (j < aclp->acl_cnt &&
3463 aclp->acl_entry[j].ae_tag ==
3464 ACL_USER_OBJ &&
3465 aclp->acl_entry[j].ae_entry_type ==
3466 ACL_ENTRY_TYPE_ALLOW) {
3467 /* Use this ACE. */
3468 *tl++ = txdr_unsigned(
3469 NFSV4ACE_ALLOWEDTYPE);
3470 *tl++ = txdr_unsigned(0x0);
3471 *tl = txdr_unsigned(
3472 nfs_aceperm(
3473 aclp->acl_entry[j].ae_perm));
3474 (void)nfsm_strtom(nd, "OWNER@", 6);
3475 } else
3476 delegace = USENONE;
3477 }
3478 if (delegace == USENONE) {
3479 /* Don't allow anything. */
3480 *tl++ = 0x0;
3481 *tl++ = 0x0;
3482 *tl = 0x0;
3483 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3484 *tl = 0;
3485 } else if (delegace == USEMODE) {
3486 /* Build from mode. */
3487 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3488 *tl++ = txdr_unsigned(0x0);
3489 acemask = NFSV4ACE_ALLFILESMASK;
3490 if (nva.na_mode & S_IRUSR)
3491 acemask |= NFSV4ACE_READMASK;
3492 if (nva.na_mode & S_IWUSR)
3493 acemask |= NFSV4ACE_WRITEMASK;
3494 if (nva.na_mode & S_IXUSR)
3495 acemask |= NFSV4ACE_EXECUTEMASK;
3496 *tl = txdr_unsigned(acemask);
3497 (void)nfsm_strtom(nd, "OWNER@", 6);
3498 }
3499 }
3500 *vpp = vp;
3501 } else if (vp) {
3502 vrele(vp);
3503 }
3504 if (dirp)
3505 vrele(dirp);
3506 #ifdef NFS4_ACL_EXTATTR_NAME
3507 acl_free(aclp);
3508 acl_free(daclp);
3509 #endif
3510 NFSEXITCODE2(0, nd);
3511 return (0);
3512 nfsmout:
3513 vrele(dp);
3514 #ifdef NFS4_ACL_EXTATTR_NAME
3515 acl_free(aclp);
3516 acl_free(daclp);
3517 #endif
3518 if (stp)
3519 free(stp, M_NFSDSTATE);
3520 NFSEXITCODE2(error, nd);
3521 return (error);
3522 }
3523
3524 /*
3525 * nfsv4 close service
3526 */
3527 int
nfsrvd_close(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3528 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3529 vnode_t vp, __unused struct nfsexstuff *exp)
3530 {
3531 u_int32_t *tl;
3532 struct nfsstate st, *stp = &st;
3533 int error = 0, writeacc;
3534 nfsv4stateid_t stateid;
3535 nfsquad_t clientid;
3536 struct nfsvattr na;
3537 struct thread *p = curthread;
3538
3539 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3540 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3541 stp->ls_ownerlen = 0;
3542 stp->ls_op = nd->nd_rp;
3543 stp->ls_uid = nd->nd_cred->cr_uid;
3544 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3545 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3546 NFSX_STATEIDOTHER);
3547
3548 /*
3549 * For the special stateid of other all 0s and seqid == 1, set the
3550 * stateid to the current stateid, if it is set.
3551 */
3552 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3553 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3554 stp->ls_stateid.other[2] == 0) {
3555 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3556 stp->ls_stateid = nd->nd_curstateid;
3557 else {
3558 nd->nd_repstat = NFSERR_BADSTATEID;
3559 goto nfsmout;
3560 }
3561 }
3562
3563 stp->ls_flags = NFSLCK_CLOSE;
3564 clientid.lval[0] = stp->ls_stateid.other[0];
3565 clientid.lval[1] = stp->ls_stateid.other[1];
3566 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3567 if ((nd->nd_flag & ND_NFSV41) != 0)
3568 clientid.qval = nd->nd_clientid.qval;
3569 else if (nd->nd_clientid.qval != clientid.qval)
3570 printf("EEK8 multiple clids\n");
3571 } else {
3572 if ((nd->nd_flag & ND_NFSV41) != 0)
3573 printf("EEK! no clientid from session\n");
3574 nd->nd_flag |= ND_IMPLIEDCLID;
3575 nd->nd_clientid.qval = clientid.qval;
3576 }
3577 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3578 &writeacc);
3579 /* For pNFS, update the attributes. */
3580 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3581 nfsrv_updatemdsattr(vp, &na, p);
3582 vput(vp);
3583 if (!nd->nd_repstat) {
3584 /*
3585 * If the stateid that has been closed is the current stateid,
3586 * unset it.
3587 */
3588 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3589 stateid.other[0] == nd->nd_curstateid.other[0] &&
3590 stateid.other[1] == nd->nd_curstateid.other[1] &&
3591 stateid.other[2] == nd->nd_curstateid.other[2])
3592 nd->nd_flag &= ~ND_CURSTATEID;
3593 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3594 *tl++ = txdr_unsigned(stateid.seqid);
3595 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3596 }
3597 NFSEXITCODE2(0, nd);
3598 return (0);
3599 nfsmout:
3600 vput(vp);
3601 NFSEXITCODE2(error, nd);
3602 return (error);
3603 }
3604
3605 /*
3606 * nfsv4 delegpurge service
3607 */
3608 int
nfsrvd_delegpurge(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)3609 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3610 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3611 {
3612 u_int32_t *tl;
3613 int error = 0;
3614 nfsquad_t clientid;
3615 struct thread *p = curthread;
3616
3617 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3618 goto nfsmout;
3619 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3620 clientid.lval[0] = *tl++;
3621 clientid.lval[1] = *tl;
3622 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3623 if ((nd->nd_flag & ND_NFSV41) != 0)
3624 clientid.qval = nd->nd_clientid.qval;
3625 else if (nd->nd_clientid.qval != clientid.qval)
3626 printf("EEK9 multiple clids\n");
3627 } else {
3628 if ((nd->nd_flag & ND_NFSV41) != 0)
3629 printf("EEK! no clientid from session\n");
3630 nd->nd_flag |= ND_IMPLIEDCLID;
3631 nd->nd_clientid.qval = clientid.qval;
3632 }
3633 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3634 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3635 nfsmout:
3636 NFSEXITCODE2(error, nd);
3637 return (error);
3638 }
3639
3640 /*
3641 * nfsv4 delegreturn service
3642 */
3643 int
nfsrvd_delegreturn(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3644 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3645 vnode_t vp, __unused struct nfsexstuff *exp)
3646 {
3647 u_int32_t *tl;
3648 int error = 0, writeacc;
3649 nfsv4stateid_t stateid;
3650 nfsquad_t clientid;
3651 struct nfsvattr na;
3652 struct thread *p = curthread;
3653
3654 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3655 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3656 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3657 clientid.lval[0] = stateid.other[0];
3658 clientid.lval[1] = stateid.other[1];
3659 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3660 if ((nd->nd_flag & ND_NFSV41) != 0)
3661 clientid.qval = nd->nd_clientid.qval;
3662 else if (nd->nd_clientid.qval != clientid.qval)
3663 printf("EEK10 multiple clids\n");
3664 } else {
3665 if ((nd->nd_flag & ND_NFSV41) != 0)
3666 printf("EEK! no clientid from session\n");
3667 nd->nd_flag |= ND_IMPLIEDCLID;
3668 nd->nd_clientid.qval = clientid.qval;
3669 }
3670 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3671 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3672 /* For pNFS, update the attributes. */
3673 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3674 nfsrv_updatemdsattr(vp, &na, p);
3675 nfsmout:
3676 vput(vp);
3677 NFSEXITCODE2(error, nd);
3678 return (error);
3679 }
3680
3681 /*
3682 * nfsv4 get file handle service
3683 */
3684 int
nfsrvd_getfh(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3685 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3686 vnode_t vp, __unused struct nfsexstuff *exp)
3687 {
3688 fhandle_t fh;
3689 struct thread *p = curthread;
3690 int siz;
3691 short irflag;
3692
3693 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3694 irflag = vn_irflag_read(vp);
3695 vput(vp);
3696 if (nd->nd_repstat == 0) {
3697 siz = 0;
3698 if ((irflag & VIRF_NAMEDDIR) != 0)
3699 siz = NFSX_FHMAX + NFSX_V4NAMEDDIRFH;
3700 else if ((irflag & VIRF_NAMEDATTR) != 0)
3701 siz = NFSX_FHMAX + NFSX_V4NAMEDATTRFH;
3702 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, siz, 0);
3703 }
3704 NFSEXITCODE2(0, nd);
3705 return (0);
3706 }
3707
3708 /*
3709 * nfsv4 open confirm service
3710 */
3711 int
nfsrvd_openconfirm(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3712 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3713 vnode_t vp, __unused struct nfsexstuff *exp)
3714 {
3715 u_int32_t *tl;
3716 struct nfsstate st, *stp = &st;
3717 int error = 0;
3718 nfsv4stateid_t stateid;
3719 nfsquad_t clientid;
3720 struct thread *p = curthread;
3721
3722 if ((nd->nd_flag & ND_NFSV41) != 0) {
3723 nd->nd_repstat = NFSERR_NOTSUPP;
3724 goto nfsmout;
3725 }
3726 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3727 stp->ls_ownerlen = 0;
3728 stp->ls_op = nd->nd_rp;
3729 stp->ls_uid = nd->nd_cred->cr_uid;
3730 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3731 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3732 NFSX_STATEIDOTHER);
3733 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3734 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3735 stp->ls_flags = NFSLCK_CONFIRM;
3736 clientid.lval[0] = stp->ls_stateid.other[0];
3737 clientid.lval[1] = stp->ls_stateid.other[1];
3738 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3739 if ((nd->nd_flag & ND_NFSV41) != 0)
3740 clientid.qval = nd->nd_clientid.qval;
3741 else if (nd->nd_clientid.qval != clientid.qval)
3742 printf("EEK11 multiple clids\n");
3743 } else {
3744 if ((nd->nd_flag & ND_NFSV41) != 0)
3745 printf("EEK! no clientid from session\n");
3746 nd->nd_flag |= ND_IMPLIEDCLID;
3747 nd->nd_clientid.qval = clientid.qval;
3748 }
3749 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3750 NULL);
3751 if (!nd->nd_repstat) {
3752 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3753 *tl++ = txdr_unsigned(stateid.seqid);
3754 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3755 }
3756 nfsmout:
3757 vput(vp);
3758 NFSEXITCODE2(error, nd);
3759 return (error);
3760 }
3761
3762 /*
3763 * nfsv4 open downgrade service
3764 */
3765 int
nfsrvd_opendowngrade(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3766 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3767 vnode_t vp, __unused struct nfsexstuff *exp)
3768 {
3769 u_int32_t *tl;
3770 int i;
3771 struct nfsstate st, *stp = &st;
3772 int error = 0;
3773 nfsv4stateid_t stateid;
3774 nfsquad_t clientid;
3775 struct thread *p = curthread;
3776
3777 /* opendowngrade can only work on a file object.*/
3778 if (vp->v_type != VREG) {
3779 error = NFSERR_INVAL;
3780 goto nfsmout;
3781 }
3782 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3783 stp->ls_ownerlen = 0;
3784 stp->ls_op = nd->nd_rp;
3785 stp->ls_uid = nd->nd_cred->cr_uid;
3786 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3787 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3788 NFSX_STATEIDOTHER);
3789 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3790
3791 /*
3792 * For the special stateid of other all 0s and seqid == 1, set the
3793 * stateid to the current stateid, if it is set.
3794 */
3795 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3796 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3797 stp->ls_stateid.other[2] == 0) {
3798 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3799 stp->ls_stateid = nd->nd_curstateid;
3800 else {
3801 nd->nd_repstat = NFSERR_BADSTATEID;
3802 goto nfsmout;
3803 }
3804 }
3805
3806 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3807 i = fxdr_unsigned(int, *tl++);
3808 if ((nd->nd_flag & ND_NFSV41) != 0)
3809 i &= ~NFSV4OPEN_WANTDELEGMASK;
3810 switch (i) {
3811 case NFSV4OPEN_ACCESSREAD:
3812 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3813 break;
3814 case NFSV4OPEN_ACCESSWRITE:
3815 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3816 break;
3817 case NFSV4OPEN_ACCESSBOTH:
3818 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3819 NFSLCK_DOWNGRADE);
3820 break;
3821 default:
3822 nd->nd_repstat = NFSERR_INVAL;
3823 }
3824 i = fxdr_unsigned(int, *tl);
3825 switch (i) {
3826 case NFSV4OPEN_DENYNONE:
3827 break;
3828 case NFSV4OPEN_DENYREAD:
3829 stp->ls_flags |= NFSLCK_READDENY;
3830 break;
3831 case NFSV4OPEN_DENYWRITE:
3832 stp->ls_flags |= NFSLCK_WRITEDENY;
3833 break;
3834 case NFSV4OPEN_DENYBOTH:
3835 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3836 break;
3837 default:
3838 nd->nd_repstat = NFSERR_INVAL;
3839 }
3840
3841 clientid.lval[0] = stp->ls_stateid.other[0];
3842 clientid.lval[1] = stp->ls_stateid.other[1];
3843 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3844 if ((nd->nd_flag & ND_NFSV41) != 0)
3845 clientid.qval = nd->nd_clientid.qval;
3846 else if (nd->nd_clientid.qval != clientid.qval)
3847 printf("EEK12 multiple clids\n");
3848 } else {
3849 if ((nd->nd_flag & ND_NFSV41) != 0)
3850 printf("EEK! no clientid from session\n");
3851 nd->nd_flag |= ND_IMPLIEDCLID;
3852 nd->nd_clientid.qval = clientid.qval;
3853 }
3854 if (!nd->nd_repstat)
3855 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3856 nd, p, NULL);
3857 if (!nd->nd_repstat) {
3858 /* For NFSv4.1, set the Current StateID. */
3859 if ((nd->nd_flag & ND_NFSV41) != 0) {
3860 nd->nd_curstateid = stateid;
3861 nd->nd_flag |= ND_CURSTATEID;
3862 }
3863 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3864 *tl++ = txdr_unsigned(stateid.seqid);
3865 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3866 }
3867 nfsmout:
3868 vput(vp);
3869 NFSEXITCODE2(error, nd);
3870 return (error);
3871 }
3872
3873 /*
3874 * nfsv4 renew lease service
3875 */
3876 int
nfsrvd_renew(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)3877 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3878 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3879 {
3880 u_int32_t *tl;
3881 int error = 0;
3882 nfsquad_t clientid;
3883 struct thread *p = curthread;
3884
3885 if ((nd->nd_flag & ND_NFSV41) != 0) {
3886 nd->nd_repstat = NFSERR_NOTSUPP;
3887 goto nfsmout;
3888 }
3889 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3890 goto nfsmout;
3891 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3892 clientid.lval[0] = *tl++;
3893 clientid.lval[1] = *tl;
3894 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3895 if ((nd->nd_flag & ND_NFSV41) != 0)
3896 clientid.qval = nd->nd_clientid.qval;
3897 else if (nd->nd_clientid.qval != clientid.qval)
3898 printf("EEK13 multiple clids\n");
3899 } else {
3900 if ((nd->nd_flag & ND_NFSV41) != 0)
3901 printf("EEK! no clientid from session\n");
3902 nd->nd_flag |= ND_IMPLIEDCLID;
3903 nd->nd_clientid.qval = clientid.qval;
3904 }
3905 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3906 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3907 nfsmout:
3908 NFSEXITCODE2(error, nd);
3909 return (error);
3910 }
3911
3912 /*
3913 * nfsv4 security info service
3914 */
3915 int
nfsrvd_secinfo(struct nfsrv_descript * nd,int isdgram,vnode_t dp,struct nfsexstuff * exp)3916 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3917 vnode_t dp, struct nfsexstuff *exp)
3918 {
3919 u_int32_t *tl;
3920 int len;
3921 struct nameidata named;
3922 vnode_t dirp = NULL, vp;
3923 struct nfsrvfh fh;
3924 struct nfsexstuff retnes;
3925 u_int32_t *sizp;
3926 int error = 0, i;
3927 uint64_t savflag;
3928 char *bufp;
3929 u_long *hashp;
3930 struct thread *p = curthread;
3931
3932 /*
3933 * All this just to get the export flags for the name.
3934 */
3935 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3936 LOCKLEAF);
3937 nfsvno_setpathbuf(&named, &bufp, &hashp);
3938 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3939 if (error) {
3940 vput(dp);
3941 nfsvno_relpathbuf(&named);
3942 goto out;
3943 }
3944 if (!nd->nd_repstat) {
3945 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
3946 } else {
3947 vput(dp);
3948 nfsvno_relpathbuf(&named);
3949 }
3950 if (dirp)
3951 vrele(dirp);
3952 if (nd->nd_repstat)
3953 goto out;
3954 nfsvno_relpathbuf(&named);
3955 fh.nfsrvfh_len = NFSX_MYFH;
3956 vp = named.ni_vp;
3957 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3958 vput(vp);
3959 savflag = nd->nd_flag;
3960 if (!nd->nd_repstat) {
3961 /*
3962 * Pretend the next op is Secinfo, so that no wrongsec
3963 * test will be done.
3964 */
3965 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
3966 NFSV4OP_SECINFO);
3967 if (vp)
3968 vput(vp);
3969 }
3970 nd->nd_flag = savflag;
3971 if (nd->nd_repstat)
3972 goto out;
3973
3974 /*
3975 * Finally have the export flags for name, so we can create
3976 * the security info.
3977 */
3978 len = 0;
3979 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3980
3981 /* If nes_numsecflavor == 0, all are allowed. */
3982 if (retnes.nes_numsecflavor == 0) {
3983 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3984 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
3985 *tl = txdr_unsigned(RPCAUTH_GSS);
3986 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3987 nfsgss_mechlist[KERBV_MECH].len);
3988 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3989 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3990 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3991 *tl = txdr_unsigned(RPCAUTH_GSS);
3992 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3993 nfsgss_mechlist[KERBV_MECH].len);
3994 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3995 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3996 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3997 *tl = txdr_unsigned(RPCAUTH_GSS);
3998 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3999 nfsgss_mechlist[KERBV_MECH].len);
4000 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4001 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4002 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
4003 len = 4;
4004 }
4005 for (i = 0; i < retnes.nes_numsecflavor; i++) {
4006 if (retnes.nes_secflavors[i] == AUTH_SYS) {
4007 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4008 *tl = txdr_unsigned(RPCAUTH_UNIX);
4009 len++;
4010 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
4011 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4012 *tl++ = txdr_unsigned(RPCAUTH_GSS);
4013 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4014 nfsgss_mechlist[KERBV_MECH].len);
4015 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4016 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4017 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
4018 len++;
4019 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
4020 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4021 *tl++ = txdr_unsigned(RPCAUTH_GSS);
4022 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4023 nfsgss_mechlist[KERBV_MECH].len);
4024 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4025 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4026 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
4027 len++;
4028 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
4029 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4030 *tl++ = txdr_unsigned(RPCAUTH_GSS);
4031 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4032 nfsgss_mechlist[KERBV_MECH].len);
4033 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4034 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4035 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
4036 len++;
4037 }
4038 }
4039 *sizp = txdr_unsigned(len);
4040
4041 out:
4042 NFSEXITCODE2(error, nd);
4043 return (error);
4044 }
4045
4046 /*
4047 * nfsv4 security info no name service
4048 */
4049 int
nfsrvd_secinfononame(struct nfsrv_descript * nd,int isdgram,vnode_t dp,struct nfsexstuff * exp)4050 nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram,
4051 vnode_t dp, struct nfsexstuff *exp)
4052 {
4053 uint32_t *tl, *sizp;
4054 struct nameidata named;
4055 vnode_t dirp = NULL, vp;
4056 struct nfsrvfh fh;
4057 struct nfsexstuff retnes;
4058 int error = 0, fhstyle, i, len;
4059 uint64_t savflag;
4060 char *bufp;
4061 u_long *hashp;
4062 struct thread *p = curthread;
4063
4064 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4065 fhstyle = fxdr_unsigned(int, *tl);
4066 switch (fhstyle) {
4067 case NFSSECINFONONAME_PARENT:
4068 if (dp->v_type != VDIR) {
4069 vput(dp);
4070 nd->nd_repstat = NFSERR_NOTDIR;
4071 goto nfsmout;
4072 }
4073 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
4074 LOCKLEAF);
4075 nfsvno_setpathbuf(&named, &bufp, &hashp);
4076 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
4077 if (error != 0) {
4078 vput(dp);
4079 nfsvno_relpathbuf(&named);
4080 goto nfsmout;
4081 }
4082 if (nd->nd_repstat == 0)
4083 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
4084 else
4085 vput(dp);
4086 if (dirp != NULL)
4087 vrele(dirp);
4088 nfsvno_relpathbuf(&named);
4089 vp = named.ni_vp;
4090 break;
4091 case NFSSECINFONONAME_CURFH:
4092 vp = dp;
4093 break;
4094 default:
4095 nd->nd_repstat = NFSERR_INVAL;
4096 vput(dp);
4097 }
4098 if (nd->nd_repstat != 0)
4099 goto nfsmout;
4100 fh.nfsrvfh_len = NFSX_MYFH;
4101 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
4102 vput(vp);
4103 savflag = nd->nd_flag;
4104 if (nd->nd_repstat == 0) {
4105 /*
4106 * Pretend the next op is Secinfo, so that no wrongsec
4107 * test will be done.
4108 */
4109 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
4110 NFSV4OP_SECINFO);
4111 if (vp != NULL)
4112 vput(vp);
4113 }
4114 nd->nd_flag = savflag;
4115 if (nd->nd_repstat != 0)
4116 goto nfsmout;
4117
4118 /*
4119 * Finally have the export flags for fh/parent, so we can create
4120 * the security info.
4121 */
4122 len = 0;
4123 NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED);
4124
4125 /* If nes_numsecflavor == 0, all are allowed. */
4126 if (retnes.nes_numsecflavor == 0) {
4127 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4128 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
4129 *tl = txdr_unsigned(RPCAUTH_GSS);
4130 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4131 nfsgss_mechlist[KERBV_MECH].len);
4132 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4133 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4134 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
4135 *tl = txdr_unsigned(RPCAUTH_GSS);
4136 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4137 nfsgss_mechlist[KERBV_MECH].len);
4138 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
4139 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4140 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
4141 *tl = txdr_unsigned(RPCAUTH_GSS);
4142 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4143 nfsgss_mechlist[KERBV_MECH].len);
4144 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4145 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4146 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
4147 len = 4;
4148 }
4149 for (i = 0; i < retnes.nes_numsecflavor; i++) {
4150 if (retnes.nes_secflavors[i] == AUTH_SYS) {
4151 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4152 *tl = txdr_unsigned(RPCAUTH_UNIX);
4153 len++;
4154 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
4155 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4156 *tl = txdr_unsigned(RPCAUTH_GSS);
4157 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4158 nfsgss_mechlist[KERBV_MECH].len);
4159 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4160 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4161 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
4162 len++;
4163 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
4164 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4165 *tl = txdr_unsigned(RPCAUTH_GSS);
4166 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4167 nfsgss_mechlist[KERBV_MECH].len);
4168 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4169 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4170 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
4171 len++;
4172 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
4173 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4174 *tl = txdr_unsigned(RPCAUTH_GSS);
4175 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
4176 nfsgss_mechlist[KERBV_MECH].len);
4177 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4178 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
4179 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
4180 len++;
4181 }
4182 }
4183 *sizp = txdr_unsigned(len);
4184
4185 nfsmout:
4186 NFSEXITCODE2(error, nd);
4187 return (error);
4188 }
4189
4190 /*
4191 * nfsv4 set client id service
4192 */
4193 int
nfsrvd_setclientid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4194 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
4195 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4196 {
4197 u_int32_t *tl;
4198 int i;
4199 int error = 0, idlen;
4200 struct nfsclient *clp = NULL;
4201 #ifdef INET
4202 struct sockaddr_in *rin;
4203 #endif
4204 #ifdef INET6
4205 struct sockaddr_in6 *rin6;
4206 #endif
4207 #if defined(INET) || defined(INET6)
4208 u_char *ucp, *ucp2;
4209 #endif
4210 u_char *verf, *addrbuf;
4211 nfsquad_t clientid, confirm;
4212 struct thread *p = curthread;
4213
4214 if ((nd->nd_flag & ND_NFSV41) != 0) {
4215 nd->nd_repstat = NFSERR_NOTSUPP;
4216 goto nfsmout;
4217 }
4218 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4219 goto out;
4220 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4221 verf = (u_char *)tl;
4222 tl += (NFSX_VERF / NFSX_UNSIGNED);
4223 i = fxdr_unsigned(int, *tl);
4224 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4225 nd->nd_repstat = NFSERR_BADXDR;
4226 goto nfsmout;
4227 }
4228 idlen = i;
4229 if (nd->nd_flag & ND_GSS)
4230 i += nd->nd_princlen;
4231 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4232 M_ZERO);
4233 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4234 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4235 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4236 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4237 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4238 M_WAITOK | M_ZERO);
4239 clp->lc_req.nr_cred = NULL;
4240 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4241 clp->lc_idlen = idlen;
4242 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4243 if (error)
4244 goto nfsmout;
4245 if (nd->nd_flag & ND_GSS) {
4246 clp->lc_flags = LCL_GSS;
4247 if (nd->nd_flag & ND_GSSINTEGRITY)
4248 clp->lc_flags |= LCL_GSSINTEGRITY;
4249 else if (nd->nd_flag & ND_GSSPRIVACY)
4250 clp->lc_flags |= LCL_GSSPRIVACY;
4251 } else {
4252 clp->lc_flags = 0;
4253 }
4254 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
4255 clp->lc_flags |= LCL_NAME;
4256 clp->lc_namelen = nd->nd_princlen;
4257 clp->lc_name = &clp->lc_id[idlen];
4258 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4259 } else {
4260 clp->lc_uid = nd->nd_cred->cr_uid;
4261 clp->lc_gid = nd->nd_cred->cr_gid;
4262 }
4263
4264 /* If the client is using TLS, do so for the callback connection. */
4265 if (nd->nd_flag & ND_TLS)
4266 clp->lc_flags |= LCL_TLSCB;
4267
4268 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4269 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
4270 error = nfsrv_getclientipaddr(nd, clp);
4271 if (error)
4272 goto nfsmout;
4273 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4274 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
4275
4276 /*
4277 * nfsrv_setclient() does the actual work of adding it to the
4278 * client list. If there is no error, the structure has been
4279 * linked into the client list and clp should no longer be used
4280 * here. When an error is returned, it has not been linked in,
4281 * so it should be free'd.
4282 */
4283 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4284 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
4285 /*
4286 * 8 is the maximum length of the port# string.
4287 */
4288 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
4289 switch (clp->lc_req.nr_nam->sa_family) {
4290 #ifdef INET
4291 case AF_INET:
4292 if (clp->lc_flags & LCL_TCPCALLBACK)
4293 (void) nfsm_strtom(nd, "tcp", 3);
4294 else
4295 (void) nfsm_strtom(nd, "udp", 3);
4296 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4297 ucp = (u_char *)&rin->sin_addr.s_addr;
4298 ucp2 = (u_char *)&rin->sin_port;
4299 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
4300 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
4301 ucp2[0] & 0xff, ucp2[1] & 0xff);
4302 break;
4303 #endif
4304 #ifdef INET6
4305 case AF_INET6:
4306 if (clp->lc_flags & LCL_TCPCALLBACK)
4307 (void) nfsm_strtom(nd, "tcp6", 4);
4308 else
4309 (void) nfsm_strtom(nd, "udp6", 4);
4310 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4311 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
4312 INET6_ADDRSTRLEN);
4313 if (ucp != NULL)
4314 i = strlen(ucp);
4315 else
4316 i = 0;
4317 ucp2 = (u_char *)&rin6->sin6_port;
4318 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
4319 ucp2[1] & 0xff);
4320 break;
4321 #endif
4322 }
4323 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
4324 free(addrbuf, M_TEMP);
4325 }
4326 if (clp) {
4327 free(clp->lc_req.nr_nam, M_SONAME);
4328 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4329 free(clp->lc_stateid, M_NFSDCLIENT);
4330 free(clp, M_NFSDCLIENT);
4331 }
4332 if (!nd->nd_repstat) {
4333 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
4334 *tl++ = clientid.lval[0];
4335 *tl++ = clientid.lval[1];
4336 *tl++ = confirm.lval[0];
4337 *tl = confirm.lval[1];
4338 }
4339
4340 out:
4341 NFSEXITCODE2(0, nd);
4342 return (0);
4343 nfsmout:
4344 if (clp) {
4345 free(clp->lc_req.nr_nam, M_SONAME);
4346 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4347 free(clp->lc_stateid, M_NFSDCLIENT);
4348 free(clp, M_NFSDCLIENT);
4349 }
4350 NFSEXITCODE2(error, nd);
4351 return (error);
4352 }
4353
4354 /*
4355 * nfsv4 set client id confirm service
4356 */
4357 int
nfsrvd_setclientidcfrm(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4358 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
4359 __unused int isdgram, __unused vnode_t vp,
4360 __unused struct nfsexstuff *exp)
4361 {
4362 u_int32_t *tl;
4363 int error = 0;
4364 nfsquad_t clientid, confirm;
4365 struct thread *p = curthread;
4366
4367 if ((nd->nd_flag & ND_NFSV41) != 0) {
4368 nd->nd_repstat = NFSERR_NOTSUPP;
4369 goto nfsmout;
4370 }
4371 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4372 goto nfsmout;
4373 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
4374 clientid.lval[0] = *tl++;
4375 clientid.lval[1] = *tl++;
4376 confirm.lval[0] = *tl++;
4377 confirm.lval[1] = *tl;
4378
4379 /*
4380 * nfsrv_getclient() searches the client list for a match and
4381 * returns the appropriate NFSERR status.
4382 */
4383 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
4384 NULL, NULL, confirm, 0, nd, p);
4385 nfsmout:
4386 NFSEXITCODE2(error, nd);
4387 return (error);
4388 }
4389
4390 /*
4391 * nfsv4 verify service
4392 */
4393 int
nfsrvd_verify(struct nfsrv_descript * nd,int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)4394 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
4395 vnode_t vp, __unused struct nfsexstuff *exp)
4396 {
4397 int error = 0, ret, fhsize = NFSX_MYFH;
4398 struct nfsvattr nva;
4399 struct statfs *sf;
4400 struct nfsfsinfo fs;
4401 fhandle_t fh;
4402 struct thread *p = curthread;
4403
4404 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4405 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
4406 if (!nd->nd_repstat)
4407 nd->nd_repstat = nfsvno_statfs(vp, sf);
4408 if (!nd->nd_repstat)
4409 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
4410 if (!nd->nd_repstat) {
4411 nfsvno_getfs(&fs, isdgram);
4412 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
4413 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, NULL, NULL, NULL,
4414 p, nd->nd_cred);
4415 if (!error) {
4416 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
4417 if (ret == 0)
4418 nd->nd_repstat = NFSERR_SAME;
4419 else if (ret != NFSERR_NOTSAME)
4420 nd->nd_repstat = ret;
4421 } else if (ret)
4422 nd->nd_repstat = ret;
4423 }
4424 }
4425 vput(vp);
4426 free(sf, M_STATFS);
4427 NFSEXITCODE2(error, nd);
4428 return (error);
4429 }
4430
4431 /*
4432 * nfs openattr rpc
4433 */
4434 int
nfsrvd_openattr(struct nfsrv_descript * nd,__unused int isdgram,struct vnode * dp,struct vnode ** vpp,__unused fhandle_t * fhp,__unused struct nfsexstuff * exp)4435 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
4436 struct vnode *dp, struct vnode **vpp, __unused fhandle_t *fhp,
4437 __unused struct nfsexstuff *exp)
4438 {
4439 uint32_t *tl;
4440 struct componentname cn;
4441 int error = 0;
4442
4443 NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN |
4444 NOFOLLOW | LOCKLEAF);
4445 cn.cn_nameptr = ".";
4446 cn.cn_namelen = 1;
4447 cn.cn_lkflags = LK_SHARED;
4448 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4449 if (*tl == newnfs_true)
4450 cn.cn_flags |= CREATENAMED;
4451
4452 nd->nd_repstat = vn_lock(dp, LK_SHARED);
4453 if (nd->nd_repstat != 0)
4454 goto nfsmout;
4455
4456 if ((dp->v_mount->mnt_flag & MNT_NAMEDATTR) == 0)
4457 nd->nd_repstat = NFSERR_NOTSUPP;
4458 if (nd->nd_repstat == 0 && (vn_irflag_read(dp) & (VIRF_NAMEDDIR |
4459 VIRF_NAMEDATTR)) != 0)
4460 nd->nd_repstat = NFSERR_WRONGTYPE;
4461 if (nd->nd_repstat == 0) {
4462 nd->nd_repstat = VOP_LOOKUP(dp, vpp, &cn);
4463 if (nd->nd_repstat == ENOATTR)
4464 nd->nd_repstat = NFSERR_NOENT;
4465 }
4466 if (nd->nd_repstat == 0)
4467 NFSVOPUNLOCK(*vpp);
4468
4469 vput(dp);
4470 NFSEXITCODE2(0, nd);
4471 return (0);
4472 nfsmout:
4473 vrele(dp);
4474 NFSEXITCODE2(error, nd);
4475 return (error);
4476 }
4477
4478 /*
4479 * nfsv4 release lock owner service
4480 */
4481 int
nfsrvd_releaselckown(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4482 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
4483 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4484 {
4485 u_int32_t *tl;
4486 struct nfsstate *stp = NULL;
4487 int error = 0, len;
4488 nfsquad_t clientid;
4489 struct thread *p = curthread;
4490
4491 if ((nd->nd_flag & ND_NFSV41) != 0) {
4492 nd->nd_repstat = NFSERR_NOTSUPP;
4493 goto nfsmout;
4494 }
4495 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4496 goto nfsmout;
4497 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4498 len = fxdr_unsigned(int, *(tl + 2));
4499 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
4500 nd->nd_repstat = NFSERR_BADXDR;
4501 goto nfsmout;
4502 }
4503 stp = malloc(sizeof (struct nfsstate) + len,
4504 M_NFSDSTATE, M_WAITOK);
4505 stp->ls_ownerlen = len;
4506 stp->ls_op = NULL;
4507 stp->ls_flags = NFSLCK_RELEASE;
4508 stp->ls_uid = nd->nd_cred->cr_uid;
4509 clientid.lval[0] = *tl++;
4510 clientid.lval[1] = *tl;
4511 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
4512 if ((nd->nd_flag & ND_NFSV41) != 0)
4513 clientid.qval = nd->nd_clientid.qval;
4514 else if (nd->nd_clientid.qval != clientid.qval)
4515 printf("EEK14 multiple clids\n");
4516 } else {
4517 if ((nd->nd_flag & ND_NFSV41) != 0)
4518 printf("EEK! no clientid from session\n");
4519 nd->nd_flag |= ND_IMPLIEDCLID;
4520 nd->nd_clientid.qval = clientid.qval;
4521 }
4522 error = nfsrv_mtostr(nd, stp->ls_owner, len);
4523 if (error)
4524 goto nfsmout;
4525 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
4526 free(stp, M_NFSDSTATE);
4527
4528 NFSEXITCODE2(0, nd);
4529 return (0);
4530 nfsmout:
4531 if (stp)
4532 free(stp, M_NFSDSTATE);
4533 NFSEXITCODE2(error, nd);
4534 return (error);
4535 }
4536
4537 /*
4538 * nfsv4 exchange_id service
4539 */
4540 int
nfsrvd_exchangeid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4541 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4542 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4543 {
4544 uint32_t *tl;
4545 int error = 0, i, idlen;
4546 struct nfsclient *clp = NULL;
4547 nfsquad_t clientid, confirm;
4548 uint8_t *verf;
4549 uint32_t sp4type, v41flags;
4550 struct timespec verstime;
4551 nfsopbit_t mustops, allowops;
4552 #ifdef INET
4553 struct sockaddr_in *sin, *rin;
4554 #endif
4555 #ifdef INET6
4556 struct sockaddr_in6 *sin6, *rin6;
4557 #endif
4558 struct thread *p = curthread;
4559 char *s;
4560
4561 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4562 goto nfsmout;
4563 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4564 verf = (uint8_t *)tl;
4565 tl += (NFSX_VERF / NFSX_UNSIGNED);
4566 i = fxdr_unsigned(int, *tl);
4567 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4568 nd->nd_repstat = NFSERR_BADXDR;
4569 goto nfsmout;
4570 }
4571 idlen = i;
4572 if (nd->nd_flag & ND_GSS)
4573 i += nd->nd_princlen;
4574 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4575 M_ZERO);
4576 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4577 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4578 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4579 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4580 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4581 M_WAITOK | M_ZERO);
4582 switch (nd->nd_nam->sa_family) {
4583 #ifdef INET
4584 case AF_INET:
4585 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4586 sin = (struct sockaddr_in *)nd->nd_nam;
4587 rin->sin_family = AF_INET;
4588 rin->sin_len = sizeof(struct sockaddr_in);
4589 rin->sin_port = 0;
4590 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4591 break;
4592 #endif
4593 #ifdef INET6
4594 case AF_INET6:
4595 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4596 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4597 rin6->sin6_family = AF_INET6;
4598 rin6->sin6_len = sizeof(struct sockaddr_in6);
4599 rin6->sin6_port = 0;
4600 rin6->sin6_addr = sin6->sin6_addr;
4601 break;
4602 #endif
4603 }
4604 clp->lc_req.nr_cred = NULL;
4605 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4606 clp->lc_idlen = idlen;
4607 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4608 if (error != 0)
4609 goto nfsmout;
4610 if ((nd->nd_flag & ND_GSS) != 0) {
4611 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4612 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4613 clp->lc_flags |= LCL_GSSINTEGRITY;
4614 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4615 clp->lc_flags |= LCL_GSSPRIVACY;
4616 } else
4617 clp->lc_flags = LCL_NFSV41;
4618 if ((nd->nd_flag & ND_NFSV42) != 0)
4619 clp->lc_flags |= LCL_NFSV42;
4620 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4621 clp->lc_flags |= LCL_NAME;
4622 clp->lc_namelen = nd->nd_princlen;
4623 clp->lc_name = &clp->lc_id[idlen];
4624 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4625 } else {
4626 clp->lc_uid = nd->nd_cred->cr_uid;
4627 clp->lc_gid = nd->nd_cred->cr_gid;
4628 }
4629 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4630 v41flags = fxdr_unsigned(uint32_t, *tl++);
4631 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4632 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4633 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4634 nd->nd_repstat = NFSERR_INVAL;
4635 goto nfsmout;
4636 }
4637 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4638 confirm.lval[1] = 1;
4639 else
4640 confirm.lval[1] = 0;
4641 if (nfsrv_devidcnt == 0)
4642 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4643 else
4644 v41flags = NFSV4EXCH_USEPNFSMDS;
4645 sp4type = fxdr_unsigned(uint32_t, *tl);
4646 if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4647 if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 ||
4648 nd->nd_princlen == 0)
4649 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
4650 if (nd->nd_repstat == 0)
4651 nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL);
4652 if (nd->nd_repstat == 0)
4653 nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL);
4654 if (nd->nd_repstat != 0)
4655 goto nfsmout;
4656 NFSOPBIT_CLRNOTMUST(&mustops);
4657 NFSSET_OPBIT(&clp->lc_mustops, &mustops);
4658 NFSOPBIT_CLRNOTALLOWED(&allowops);
4659 NFSSET_OPBIT(&clp->lc_allowops, &allowops);
4660 clp->lc_flags |= LCL_MACHCRED;
4661 } else if (sp4type != NFSV4EXCH_SP4NONE) {
4662 nd->nd_repstat = NFSERR_NOTSUPP;
4663 goto nfsmout;
4664 }
4665
4666 /*
4667 * nfsrv_setclient() does the actual work of adding it to the
4668 * client list. If there is no error, the structure has been
4669 * linked into the client list and clp should no longer be used
4670 * here. When an error is returned, it has not been linked in,
4671 * so it should be free'd.
4672 */
4673 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4674 if (clp != NULL) {
4675 free(clp->lc_req.nr_nam, M_SONAME);
4676 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4677 free(clp->lc_stateid, M_NFSDCLIENT);
4678 free(clp, M_NFSDCLIENT);
4679 }
4680 if (nd->nd_repstat == 0) {
4681 if (confirm.lval[1] != 0)
4682 v41flags |= NFSV4EXCH_CONFIRMEDR;
4683 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
4684 *tl++ = clientid.lval[0]; /* ClientID */
4685 *tl++ = clientid.lval[1];
4686 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4687 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4688 *tl = txdr_unsigned(sp4type); /* No SSV */
4689 if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4690 nfsrv_putopbit(nd, &mustops);
4691 nfsrv_putopbit(nd, &allowops);
4692 }
4693 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER);
4694 txdr_hyper(nfsrv_owner_minor, tl); /* Owner Minor */
4695 if (nfsrv_owner_major[0] != 0)
4696 s = nfsrv_owner_major;
4697 else
4698 s = nd->nd_cred->cr_prison->pr_hostuuid;
4699 nfsm_strtom(nd, s, strlen(s)); /* Owner Major */
4700 if (nfsrv_scope[0] != 0)
4701 s = nfsrv_scope;
4702 else
4703 s = nd->nd_cred->cr_prison->pr_hostuuid;
4704 nfsm_strtom(nd, s, strlen(s) ); /* Scope */
4705 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4706 *tl = txdr_unsigned(1);
4707 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4708 (void)nfsm_strtom(nd, version, strlen(version));
4709 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4710 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4711 verstime.tv_nsec = 0;
4712 txdr_nfsv4time(&verstime, tl);
4713 }
4714 NFSEXITCODE2(0, nd);
4715 return (0);
4716 nfsmout:
4717 if (clp != NULL) {
4718 free(clp->lc_req.nr_nam, M_SONAME);
4719 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4720 free(clp->lc_stateid, M_NFSDCLIENT);
4721 free(clp, M_NFSDCLIENT);
4722 }
4723 NFSEXITCODE2(error, nd);
4724 return (error);
4725 }
4726
4727 /*
4728 * nfsv4 create session service
4729 */
4730 int
nfsrvd_createsession(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4731 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4732 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4733 {
4734 uint32_t *tl;
4735 int error = 0;
4736 nfsquad_t clientid, confirm;
4737 struct nfsdsession *sep = NULL;
4738 uint32_t rdmacnt;
4739 struct thread *p = curthread;
4740 static bool do_printf = true;
4741
4742 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4743 goto nfsmout;
4744 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4745 M_NFSDSESSION, M_WAITOK | M_ZERO);
4746 sep->sess_refcnt = 1;
4747 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4748 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4749 clientid.lval[0] = *tl++;
4750 clientid.lval[1] = *tl++;
4751 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4752 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4753 /* Persistent sessions and RDMA are not supported. */
4754 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4755
4756 /* Fore channel attributes. */
4757 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4758 tl++; /* Header pad always 0. */
4759 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4760 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4761 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4762 if (do_printf)
4763 printf("Consider increasing kern.ipc.maxsockbuf\n");
4764 do_printf = false;
4765 }
4766 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4767 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4768 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
4769 if (do_printf)
4770 printf("Consider increasing kern.ipc.maxsockbuf\n");
4771 do_printf = false;
4772 }
4773 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4774 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4775 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4776 if (sep->sess_maxslots > NFSV4_SLOTS)
4777 sep->sess_maxslots = NFSV4_SLOTS;
4778 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4779 if (rdmacnt > 1) {
4780 nd->nd_repstat = NFSERR_BADXDR;
4781 goto nfsmout;
4782 } else if (rdmacnt == 1)
4783 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4784
4785 /* Back channel attributes. */
4786 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4787 tl++; /* Header pad always 0. */
4788 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4789 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4790 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4791 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4792 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4793 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4794 if (rdmacnt > 1) {
4795 nd->nd_repstat = NFSERR_BADXDR;
4796 goto nfsmout;
4797 } else if (rdmacnt == 1)
4798 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4799
4800 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4801 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4802
4803 /*
4804 * nfsrv_getclient() searches the client list for a match and
4805 * returns the appropriate NFSERR status.
4806 */
4807 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4808 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4809 if (nd->nd_repstat == 0) {
4810 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4811 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4812 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4813 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4814 *tl++ = txdr_unsigned(sep->sess_crflags);
4815
4816 /* Fore channel attributes. */
4817 *tl++ = 0;
4818 *tl++ = txdr_unsigned(sep->sess_maxreq);
4819 *tl++ = txdr_unsigned(sep->sess_maxresp);
4820 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4821 *tl++ = txdr_unsigned(sep->sess_maxops);
4822 *tl++ = txdr_unsigned(sep->sess_maxslots);
4823 *tl++ = txdr_unsigned(1);
4824 *tl++ = txdr_unsigned(0); /* No RDMA. */
4825
4826 /* Back channel attributes. */
4827 *tl++ = 0;
4828 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4829 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4830 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4831 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4832 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4833 *tl++ = txdr_unsigned(1);
4834 *tl = txdr_unsigned(0); /* No RDMA. */
4835 }
4836 nfsmout:
4837 if (nd->nd_repstat != 0 && sep != NULL)
4838 free(sep, M_NFSDSESSION);
4839 NFSEXITCODE2(error, nd);
4840 return (error);
4841 }
4842
4843 /*
4844 * nfsv4 sequence service
4845 */
4846 int
nfsrvd_sequence(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4847 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4848 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4849 {
4850 uint32_t *tl;
4851 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4852 int cache_this, error = 0;
4853 struct thread *p = curthread;
4854
4855 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4856 goto nfsmout;
4857 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4858 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4859 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4860 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4861 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4862 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4863 if (*tl == newnfs_true)
4864 cache_this = 1;
4865 else
4866 cache_this = 0;
4867 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4868 &target_highest_slotid, cache_this, &sflags, p);
4869 if (nd->nd_repstat != NFSERR_BADSLOT)
4870 nd->nd_flag |= ND_HASSEQUENCE;
4871 if (nd->nd_repstat == 0) {
4872 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4873 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4874 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4875 *tl++ = txdr_unsigned(sequenceid);
4876 *tl++ = txdr_unsigned(nd->nd_slotid);
4877 *tl++ = txdr_unsigned(highest_slotid);
4878 *tl++ = txdr_unsigned(target_highest_slotid);
4879 *tl = txdr_unsigned(sflags);
4880 }
4881 nfsmout:
4882 NFSEXITCODE2(error, nd);
4883 return (error);
4884 }
4885
4886 /*
4887 * nfsv4 reclaim complete service
4888 */
4889 int
nfsrvd_reclaimcomplete(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4890 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4891 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4892 {
4893 uint32_t *tl;
4894 int error = 0, onefs;
4895
4896 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4897 /*
4898 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4899 * to be used after a file system has been transferred to a different
4900 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4901 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4902 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4903 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4904 * NFS_OK without doing anything.
4905 */
4906 onefs = 0;
4907 if (*tl == newnfs_true)
4908 onefs = 1;
4909 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4910 nfsmout:
4911 NFSEXITCODE2(error, nd);
4912 return (error);
4913 }
4914
4915 /*
4916 * nfsv4 destroy clientid service
4917 */
4918 int
nfsrvd_destroyclientid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4919 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4920 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4921 {
4922 uint32_t *tl;
4923 nfsquad_t clientid;
4924 int error = 0;
4925 struct thread *p = curthread;
4926
4927 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4928 goto nfsmout;
4929 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4930 clientid.lval[0] = *tl++;
4931 clientid.lval[1] = *tl;
4932 nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p);
4933 nfsmout:
4934 NFSEXITCODE2(error, nd);
4935 return (error);
4936 }
4937
4938 /*
4939 * nfsv4 bind connection to session service
4940 */
4941 int
nfsrvd_bindconnsess(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4942 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4943 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4944 {
4945 uint32_t *tl;
4946 uint8_t sessid[NFSX_V4SESSIONID];
4947 int error = 0, foreaft;
4948
4949 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4950 goto nfsmout;
4951 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4952 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4953 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4954 foreaft = fxdr_unsigned(int, *tl++);
4955 if (*tl == newnfs_true) {
4956 /* RDMA is not supported. */
4957 nd->nd_repstat = NFSERR_NOTSUPP;
4958 goto nfsmout;
4959 }
4960
4961 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4962 if (nd->nd_repstat == 0) {
4963 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4964 NFSX_UNSIGNED);
4965 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4966 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4967 *tl++ = txdr_unsigned(foreaft);
4968 *tl = newnfs_false;
4969 }
4970 nfsmout:
4971 NFSEXITCODE2(error, nd);
4972 return (error);
4973 }
4974
4975 /*
4976 * nfsv4 destroy session service
4977 */
4978 int
nfsrvd_destroysession(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4979 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4980 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4981 {
4982 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4983 int error = 0;
4984
4985 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4986 goto nfsmout;
4987 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4988 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4989 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4990 nfsmout:
4991 NFSEXITCODE2(error, nd);
4992 return (error);
4993 }
4994
4995 /*
4996 * nfsv4 free stateid service
4997 */
4998 int
nfsrvd_freestateid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4999 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
5000 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5001 {
5002 uint32_t *tl;
5003 nfsv4stateid_t stateid;
5004 int error = 0;
5005 struct thread *p = curthread;
5006
5007 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5008 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5009 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5010
5011 /*
5012 * For the special stateid of other all 0s and seqid == 1, set the
5013 * stateid to the current stateid, if it is set.
5014 */
5015 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5016 stateid.other[1] == 0 && stateid.other[2] == 0) {
5017 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5018 stateid = nd->nd_curstateid;
5019 stateid.seqid = 0;
5020 } else {
5021 nd->nd_repstat = NFSERR_BADSTATEID;
5022 goto nfsmout;
5023 }
5024 }
5025
5026 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
5027
5028 /* If the current stateid has been free'd, unset it. */
5029 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
5030 stateid.other[0] == nd->nd_curstateid.other[0] &&
5031 stateid.other[1] == nd->nd_curstateid.other[1] &&
5032 stateid.other[2] == nd->nd_curstateid.other[2])
5033 nd->nd_flag &= ~ND_CURSTATEID;
5034 nfsmout:
5035 NFSEXITCODE2(error, nd);
5036 return (error);
5037 }
5038
5039 /*
5040 * nfsv4 layoutget service
5041 */
5042 int
nfsrvd_layoutget(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5043 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
5044 vnode_t vp, struct nfsexstuff *exp)
5045 {
5046 uint32_t *tl;
5047 nfsv4stateid_t stateid;
5048 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
5049 uint64_t offset, len, minlen;
5050 char *layp;
5051 struct thread *p = curthread;
5052
5053 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
5054 NFSX_STATEID);
5055 tl++; /* Signal layout available. Ignore for now. */
5056 layouttype = fxdr_unsigned(int, *tl++);
5057 iomode = fxdr_unsigned(int, *tl++);
5058 offset = fxdr_hyper(tl); tl += 2;
5059 len = fxdr_hyper(tl); tl += 2;
5060 minlen = fxdr_hyper(tl); tl += 2;
5061 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5062 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5063 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5064 maxcnt = fxdr_unsigned(int, *tl);
5065 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
5066 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
5067 (uintmax_t)minlen);
5068 if (len < minlen ||
5069 (minlen != UINT64_MAX && offset + minlen < offset) ||
5070 (len != UINT64_MAX && offset + len < offset)) {
5071 nd->nd_repstat = NFSERR_INVAL;
5072 goto nfsmout;
5073 }
5074
5075 /*
5076 * For the special stateid of other all 0s and seqid == 1, set the
5077 * stateid to the current stateid, if it is set.
5078 */
5079 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5080 stateid.other[1] == 0 && stateid.other[2] == 0) {
5081 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5082 stateid = nd->nd_curstateid;
5083 stateid.seqid = 0;
5084 } else {
5085 nd->nd_repstat = NFSERR_BADSTATEID;
5086 goto nfsmout;
5087 }
5088 }
5089
5090 layp = NULL;
5091 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
5092 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
5093 else if (layouttype == NFSLAYOUT_FLEXFILE)
5094 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
5095 M_WAITOK);
5096 else
5097 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
5098 if (layp != NULL)
5099 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
5100 &iomode, &offset, &len, minlen, &stateid, maxcnt,
5101 &retonclose, &layoutlen, layp, nd->nd_cred, p);
5102 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
5103 layoutlen);
5104 if (nd->nd_repstat == 0) {
5105 /* For NFSv4.1, set the Current StateID. */
5106 if ((nd->nd_flag & ND_NFSV41) != 0) {
5107 nd->nd_curstateid = stateid;
5108 nd->nd_flag |= ND_CURSTATEID;
5109 }
5110 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
5111 2 * NFSX_HYPER);
5112 *tl++ = txdr_unsigned(retonclose);
5113 *tl++ = txdr_unsigned(stateid.seqid);
5114 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5115 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5116 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
5117 txdr_hyper(offset, tl); tl += 2;
5118 txdr_hyper(len, tl); tl += 2;
5119 *tl++ = txdr_unsigned(iomode);
5120 *tl = txdr_unsigned(layouttype);
5121 nfsm_strtom(nd, layp, layoutlen);
5122 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
5123 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5124 *tl = newnfs_false;
5125 }
5126 free(layp, M_TEMP);
5127 nfsmout:
5128 vput(vp);
5129 NFSEXITCODE2(error, nd);
5130 return (error);
5131 }
5132
5133 /*
5134 * nfsv4 layoutcommit service
5135 */
5136 int
nfsrvd_layoutcommit(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5137 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
5138 vnode_t vp, struct nfsexstuff *exp)
5139 {
5140 uint32_t *tl;
5141 nfsv4stateid_t stateid;
5142 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
5143 int hasnewsize;
5144 uint64_t offset, len, newoff = 0, newsize;
5145 struct timespec newmtime;
5146 char *layp;
5147 struct thread *p = curthread;
5148
5149 layp = NULL;
5150 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
5151 NFSX_STATEID);
5152 offset = fxdr_hyper(tl); tl += 2;
5153 len = fxdr_hyper(tl); tl += 2;
5154 reclaim = fxdr_unsigned(int, *tl++);
5155 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5156 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5157 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5158 /*
5159 * For the special stateid of other all 0s and seqid == 1, set the
5160 * stateid to the current stateid, if it is set.
5161 */
5162 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5163 stateid.other[1] == 0 && stateid.other[2] == 0) {
5164 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5165 stateid = nd->nd_curstateid;
5166 stateid.seqid = 0;
5167 } else {
5168 nd->nd_repstat = NFSERR_BADSTATEID;
5169 goto nfsmout;
5170 }
5171 }
5172
5173 hasnewoff = fxdr_unsigned(int, *tl);
5174 if (hasnewoff != 0) {
5175 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
5176 newoff = fxdr_hyper(tl); tl += 2;
5177 } else
5178 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5179 hasnewmtime = fxdr_unsigned(int, *tl);
5180 if (hasnewmtime != 0) {
5181 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
5182 fxdr_nfsv4time(tl, &newmtime);
5183 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
5184 } else
5185 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5186 layouttype = fxdr_unsigned(int, *tl++);
5187 maxcnt = fxdr_unsigned(int, *tl);
5188 /* There is no limit in the RFC, so use 1000 as a sanity limit. */
5189 if (maxcnt < 0 || maxcnt > 1000) {
5190 error = NFSERR_BADXDR;
5191 goto nfsmout;
5192 }
5193 if (maxcnt > 0) {
5194 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5195 error = nfsrv_mtostr(nd, layp, maxcnt);
5196 if (error != 0)
5197 goto nfsmout;
5198 }
5199 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
5200 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
5201 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
5202 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
5203 if (nd->nd_repstat == 0) {
5204 if (hasnewsize != 0) {
5205 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5206 *tl++ = newnfs_true;
5207 txdr_hyper(newsize, tl);
5208 } else {
5209 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5210 *tl = newnfs_false;
5211 }
5212 }
5213 nfsmout:
5214 free(layp, M_TEMP);
5215 vput(vp);
5216 NFSEXITCODE2(error, nd);
5217 return (error);
5218 }
5219
5220 /*
5221 * nfsv4 layoutreturn service
5222 */
5223 int
nfsrvd_layoutreturn(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5224 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
5225 vnode_t vp, struct nfsexstuff *exp)
5226 {
5227 uint32_t *tl, *layp;
5228 nfsv4stateid_t stateid;
5229 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
5230 uint64_t offset, len;
5231 struct thread *p = curthread;
5232
5233 layp = NULL;
5234 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
5235 reclaim = *tl++;
5236 layouttype = fxdr_unsigned(int, *tl++);
5237 iomode = fxdr_unsigned(int, *tl++);
5238 kind = fxdr_unsigned(int, *tl);
5239 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
5240 layouttype, iomode, kind);
5241 if (kind == NFSV4LAYOUTRET_FILE) {
5242 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5243 NFSX_UNSIGNED);
5244 offset = fxdr_hyper(tl); tl += 2;
5245 len = fxdr_hyper(tl); tl += 2;
5246 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5247 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5248 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5249
5250 /*
5251 * For the special stateid of other all 0s and seqid == 1, set
5252 * the stateid to the current stateid, if it is set.
5253 */
5254 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5255 stateid.other[1] == 0 && stateid.other[2] == 0) {
5256 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5257 stateid = nd->nd_curstateid;
5258 stateid.seqid = 0;
5259 } else {
5260 nd->nd_repstat = NFSERR_BADSTATEID;
5261 goto nfsmout;
5262 }
5263 }
5264
5265 maxcnt = fxdr_unsigned(int, *tl);
5266 /*
5267 * There is no fixed upper bound defined in the RFCs,
5268 * but 128Kbytes should be more than sufficient.
5269 */
5270 if (maxcnt < 0 || maxcnt > 131072)
5271 maxcnt = 0;
5272 if (maxcnt > 0) {
5273 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5274 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
5275 if (error != 0)
5276 goto nfsmout;
5277 }
5278 } else {
5279 if (reclaim == newnfs_true) {
5280 nd->nd_repstat = NFSERR_INVAL;
5281 goto nfsmout;
5282 }
5283 offset = len = 0;
5284 maxcnt = 0;
5285 }
5286 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
5287 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
5288 nd->nd_cred, p);
5289 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
5290 fnd);
5291 if (nd->nd_repstat == 0) {
5292 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5293 if (fnd != 0) {
5294 *tl = newnfs_true;
5295 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
5296 *tl++ = txdr_unsigned(stateid.seqid);
5297 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5298 } else
5299 *tl = newnfs_false;
5300 }
5301 nfsmout:
5302 free(layp, M_TEMP);
5303 vput(vp);
5304 NFSEXITCODE2(error, nd);
5305 return (error);
5306 }
5307
5308 /*
5309 * nfsv4 layout error service
5310 */
5311 int
nfsrvd_layouterror(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5312 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
5313 vnode_t vp, struct nfsexstuff *exp)
5314 {
5315 uint32_t *tl;
5316 nfsv4stateid_t stateid;
5317 int cnt, error = 0, i, stat;
5318 int opnum __unused;
5319 char devid[NFSX_V4DEVICEID];
5320 uint64_t offset, len;
5321
5322 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5323 NFSX_UNSIGNED);
5324 offset = fxdr_hyper(tl); tl += 2;
5325 len = fxdr_hyper(tl); tl += 2;
5326 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5327 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5328 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5329 cnt = fxdr_unsigned(int, *tl);
5330 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
5331 (uintmax_t)len, cnt);
5332 /*
5333 * For the special stateid of other all 0s and seqid == 1, set
5334 * the stateid to the current stateid, if it is set.
5335 */
5336 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5337 stateid.other[1] == 0 && stateid.other[2] == 0) {
5338 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5339 stateid = nd->nd_curstateid;
5340 stateid.seqid = 0;
5341 } else {
5342 nd->nd_repstat = NFSERR_BADSTATEID;
5343 goto nfsmout;
5344 }
5345 }
5346
5347 /*
5348 * Ignore offset, len and stateid for now.
5349 */
5350 for (i = 0; i < cnt; i++) {
5351 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
5352 NFSX_UNSIGNED);
5353 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5354 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5355 stat = fxdr_unsigned(int, *tl++);
5356 opnum = fxdr_unsigned(int, *tl);
5357 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
5358 /*
5359 * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC
5360 * errors, disable the mirror.
5361 */
5362 if (stat != NFSERR_ACCES && stat != NFSERR_STALE &&
5363 stat != NFSERR_NOSPC)
5364 nfsrv_delds(devid, curthread);
5365
5366 /* For NFSERR_NOSPC, mark all deviceids and layouts. */
5367 if (stat == NFSERR_NOSPC)
5368 nfsrv_marknospc(devid, true);
5369 }
5370 nfsmout:
5371 vput(vp);
5372 NFSEXITCODE2(error, nd);
5373 return (error);
5374 }
5375
5376 /*
5377 * nfsv4 layout stats service
5378 */
5379 int
nfsrvd_layoutstats(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5380 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
5381 vnode_t vp, struct nfsexstuff *exp)
5382 {
5383 uint32_t *tl;
5384 nfsv4stateid_t stateid;
5385 int cnt, error = 0;
5386 int layouttype __unused;
5387 char devid[NFSX_V4DEVICEID] __unused;
5388 uint64_t offset __unused, len __unused, readcount __unused;
5389 uint64_t readbytes __unused, writecount __unused, writebytes __unused;
5390
5391 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
5392 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
5393 offset = fxdr_hyper(tl); tl += 2;
5394 len = fxdr_hyper(tl); tl += 2;
5395 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5396 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5397 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5398 readcount = fxdr_hyper(tl); tl += 2;
5399 readbytes = fxdr_hyper(tl); tl += 2;
5400 writecount = fxdr_hyper(tl); tl += 2;
5401 writebytes = fxdr_hyper(tl); tl += 2;
5402 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5403 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5404 layouttype = fxdr_unsigned(int, *tl++);
5405 cnt = fxdr_unsigned(int, *tl);
5406 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
5407 if (error != 0)
5408 goto nfsmout;
5409 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
5410 /*
5411 * For the special stateid of other all 0s and seqid == 1, set
5412 * the stateid to the current stateid, if it is set.
5413 */
5414 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5415 stateid.other[1] == 0 && stateid.other[2] == 0) {
5416 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5417 stateid = nd->nd_curstateid;
5418 stateid.seqid = 0;
5419 } else {
5420 nd->nd_repstat = NFSERR_BADSTATEID;
5421 goto nfsmout;
5422 }
5423 }
5424
5425 /*
5426 * No use for the stats for now.
5427 */
5428 nfsmout:
5429 vput(vp);
5430 NFSEXITCODE2(error, nd);
5431 return (error);
5432 }
5433
5434 /*
5435 * nfsv4 io_advise service
5436 */
5437 int
nfsrvd_ioadvise(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5438 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
5439 vnode_t vp, struct nfsexstuff *exp)
5440 {
5441 uint32_t *tl;
5442 nfsv4stateid_t stateid;
5443 nfsattrbit_t hints;
5444 int error = 0, ret;
5445 off_t offset, len;
5446
5447 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5448 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5449 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5450 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5451 offset = fxdr_hyper(tl); tl += 2;
5452 len = fxdr_hyper(tl);
5453 error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
5454 if (error != 0)
5455 goto nfsmout;
5456 /*
5457 * For the special stateid of other all 0s and seqid == 1, set
5458 * the stateid to the current stateid, if it is set.
5459 */
5460 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5461 stateid.other[1] == 0 && stateid.other[2] == 0) {
5462 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5463 stateid = nd->nd_curstateid;
5464 stateid.seqid = 0;
5465 } else {
5466 nd->nd_repstat = NFSERR_BADSTATEID;
5467 goto nfsmout;
5468 }
5469 }
5470
5471 if (offset < 0) {
5472 nd->nd_repstat = NFSERR_INVAL;
5473 goto nfsmout;
5474 }
5475 if (len < 0)
5476 len = 0;
5477 if (vp->v_type != VREG) {
5478 if (vp->v_type == VDIR)
5479 nd->nd_repstat = NFSERR_ISDIR;
5480 else
5481 nd->nd_repstat = NFSERR_WRONGTYPE;
5482 goto nfsmout;
5483 }
5484
5485 /*
5486 * For now, we can only handle WILLNEED and DONTNEED and don't use
5487 * the stateid.
5488 */
5489 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
5490 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
5491 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
5492 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
5493 NFSVOPUNLOCK(vp);
5494 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
5495 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
5496 NFSZERO_ATTRBIT(&hints);
5497 if (ret == 0)
5498 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
5499 else
5500 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5501 } else {
5502 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
5503 NFSZERO_ATTRBIT(&hints);
5504 if (ret == 0)
5505 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
5506 else
5507 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5508 }
5509 vrele(vp);
5510 } else {
5511 NFSZERO_ATTRBIT(&hints);
5512 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5513 vput(vp);
5514 }
5515 nfsrv_putattrbit(nd, &hints);
5516 NFSEXITCODE2(error, nd);
5517 return (error);
5518 nfsmout:
5519 vput(vp);
5520 NFSEXITCODE2(error, nd);
5521 return (error);
5522 }
5523
5524 /*
5525 * nfsv4 getdeviceinfo service
5526 */
5527 int
nfsrvd_getdevinfo(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)5528 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5529 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5530 {
5531 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5532 int cnt, devaddrlen, error = 0, i, layouttype;
5533 char devid[NFSX_V4DEVICEID], *devaddr;
5534 time_t dev_time;
5535
5536 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5537 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5538 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5539 layouttype = fxdr_unsigned(int, *tl++);
5540 maxcnt = fxdr_unsigned(uint32_t, *tl++);
5541 cnt = fxdr_unsigned(int, *tl);
5542 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5543 maxcnt, cnt);
5544 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5545 nd->nd_repstat = NFSERR_INVAL;
5546 goto nfsmout;
5547 }
5548 if (cnt > 0) {
5549 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5550 for (i = 0; i < cnt; i++)
5551 notify[i] = fxdr_unsigned(uint32_t, *tl++);
5552 }
5553 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5554 notify[i] = 0;
5555
5556 /*
5557 * Check that the device id is not stale. Device ids are recreated
5558 * each time the nfsd threads are restarted.
5559 */
5560 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5561 if (dev_time != nfsdev_time) {
5562 nd->nd_repstat = NFSERR_NOENT;
5563 goto nfsmout;
5564 }
5565
5566 /* Look for the device id. */
5567 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5568 notify, &devaddrlen, &devaddr);
5569 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5570 if (nd->nd_repstat == 0) {
5571 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5572 *tl = txdr_unsigned(layouttype);
5573 nfsm_strtom(nd, devaddr, devaddrlen);
5574 cnt = 0;
5575 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5576 if (notify[i] != 0)
5577 cnt = i + 1;
5578 }
5579 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5580 *tl++ = txdr_unsigned(cnt);
5581 for (i = 0; i < cnt; i++)
5582 *tl++ = txdr_unsigned(notify[i]);
5583 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5584 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5585 *tl = txdr_unsigned(maxcnt);
5586 }
5587 nfsmout:
5588 NFSEXITCODE2(error, nd);
5589 return (error);
5590 }
5591
5592 /*
5593 * nfsv4 test stateid service
5594 */
5595 int
nfsrvd_teststateid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)5596 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5597 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5598 {
5599 uint32_t *tl;
5600 nfsv4stateid_t *stateidp = NULL, *tstateidp;
5601 int cnt, error = 0, i, ret;
5602 struct thread *p = curthread;
5603
5604 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5605 cnt = fxdr_unsigned(int, *tl);
5606 if (cnt <= 0 || cnt > 1024) {
5607 nd->nd_repstat = NFSERR_BADXDR;
5608 goto nfsmout;
5609 }
5610 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5611 tstateidp = stateidp;
5612 for (i = 0; i < cnt; i++) {
5613 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5614 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5615 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5616 tstateidp++;
5617 }
5618 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5619 *tl = txdr_unsigned(cnt);
5620 tstateidp = stateidp;
5621 for (i = 0; i < cnt; i++) {
5622 ret = nfsrv_teststateid(nd, tstateidp, p);
5623 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5624 *tl = txdr_unsigned(ret);
5625 tstateidp++;
5626 }
5627 nfsmout:
5628 free(stateidp, M_TEMP);
5629 NFSEXITCODE2(error, nd);
5630 return (error);
5631 }
5632
5633 /*
5634 * nfs allocate service
5635 */
5636 int
nfsrvd_allocate(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5637 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5638 vnode_t vp, struct nfsexstuff *exp)
5639 {
5640 uint32_t *tl;
5641 struct nfsvattr forat;
5642 int error = 0, forat_ret = 1, gotproxystateid;
5643 off_t off, len;
5644 struct nfsstate st, *stp = &st;
5645 struct nfslock lo, *lop = &lo;
5646 nfsv4stateid_t stateid;
5647 nfsquad_t clientid;
5648 nfsattrbit_t attrbits;
5649
5650 if (!nfsrv_doallocate) {
5651 /*
5652 * If any exported file system, such as a ZFS one, cannot
5653 * do VOP_ALLOCATE(), this operation cannot be supported
5654 * for NFSv4.2. This cannot be done 'per filesystem', but
5655 * must be for the entire nfsd NFSv4.2 service.
5656 */
5657 nd->nd_repstat = NFSERR_NOTSUPP;
5658 goto nfsmout;
5659 }
5660 gotproxystateid = 0;
5661 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5662 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5663 lop->lo_flags = NFSLCK_WRITE;
5664 stp->ls_ownerlen = 0;
5665 stp->ls_op = NULL;
5666 stp->ls_uid = nd->nd_cred->cr_uid;
5667 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5668 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5669 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5670 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5671 if ((nd->nd_flag & ND_NFSV41) != 0)
5672 clientid.qval = nd->nd_clientid.qval;
5673 else if (nd->nd_clientid.qval != clientid.qval)
5674 printf("EEK2 multiple clids\n");
5675 } else {
5676 if ((nd->nd_flag & ND_NFSV41) != 0)
5677 printf("EEK! no clientid from session\n");
5678 nd->nd_flag |= ND_IMPLIEDCLID;
5679 nd->nd_clientid.qval = clientid.qval;
5680 }
5681 stp->ls_stateid.other[2] = *tl++;
5682 /*
5683 * Don't allow this to be done for a DS.
5684 */
5685 if ((nd->nd_flag & ND_DSSERVER) != 0)
5686 nd->nd_repstat = NFSERR_NOTSUPP;
5687 /* However, allow the proxy stateid. */
5688 if (stp->ls_stateid.seqid == 0xffffffff &&
5689 stp->ls_stateid.other[0] == 0x55555555 &&
5690 stp->ls_stateid.other[1] == 0x55555555 &&
5691 stp->ls_stateid.other[2] == 0x55555555)
5692 gotproxystateid = 1;
5693 off = fxdr_hyper(tl); tl += 2;
5694 lop->lo_first = off;
5695 len = fxdr_hyper(tl);
5696 lop->lo_end = lop->lo_first + len;
5697 /*
5698 * Sanity check the offset and length.
5699 * off and len are off_t (signed int64_t) whereas
5700 * lo_first and lo_end are uint64_t and, as such,
5701 * if off >= 0 && len > 0, lo_end cannot overflow
5702 * unless off_t is changed to something other than
5703 * int64_t. Check lo_end < lo_first in case that
5704 * is someday the case.
5705 */
5706 if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end >
5707 OFF_MAX || lop->lo_end < lop->lo_first))
5708 nd->nd_repstat = NFSERR_INVAL;
5709
5710 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5711 nd->nd_repstat = NFSERR_WRONGTYPE;
5712 NFSZERO_ATTRBIT(&attrbits);
5713 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5714 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5715 if (nd->nd_repstat == 0)
5716 nd->nd_repstat = forat_ret;
5717 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5718 NFSVNO_EXSTRICTACCESS(exp)))
5719 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5720 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5721 NULL);
5722 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5723 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5724 &stateid, exp, nd, curthread);
5725
5726 NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n",
5727 (intmax_t)off, (intmax_t)len, nd->nd_repstat);
5728 if (nd->nd_repstat == 0)
5729 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5730 curthread);
5731 NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n",
5732 nd->nd_repstat);
5733 vput(vp);
5734 NFSEXITCODE2(0, nd);
5735 return (0);
5736 nfsmout:
5737 vput(vp);
5738 NFSEXITCODE2(error, nd);
5739 return (error);
5740 }
5741
5742 /*
5743 * nfs deallocate service
5744 */
5745 int
nfsrvd_deallocate(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5746 nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram,
5747 vnode_t vp, struct nfsexstuff *exp)
5748 {
5749 uint32_t *tl;
5750 struct nfsvattr forat;
5751 int error = 0, forat_ret = 1, gotproxystateid;
5752 off_t off, len;
5753 struct nfsstate st, *stp = &st;
5754 struct nfslock lo, *lop = &lo;
5755 nfsv4stateid_t stateid;
5756 nfsquad_t clientid;
5757 nfsattrbit_t attrbits;
5758
5759 gotproxystateid = 0;
5760 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5761 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5762 lop->lo_flags = NFSLCK_WRITE;
5763 stp->ls_ownerlen = 0;
5764 stp->ls_op = NULL;
5765 stp->ls_uid = nd->nd_cred->cr_uid;
5766 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5767 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5768 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5769 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5770 if ((nd->nd_flag & ND_NFSV41) != 0)
5771 clientid.qval = nd->nd_clientid.qval;
5772 else if (nd->nd_clientid.qval != clientid.qval)
5773 printf("EEK2 multiple clids\n");
5774 } else {
5775 if ((nd->nd_flag & ND_NFSV41) != 0)
5776 printf("EEK! no clientid from session\n");
5777 nd->nd_flag |= ND_IMPLIEDCLID;
5778 nd->nd_clientid.qval = clientid.qval;
5779 }
5780 stp->ls_stateid.other[2] = *tl++;
5781 /*
5782 * Don't allow this to be done for a DS.
5783 */
5784 if ((nd->nd_flag & ND_DSSERVER) != 0)
5785 nd->nd_repstat = NFSERR_NOTSUPP;
5786 /* However, allow the proxy stateid. */
5787 if (stp->ls_stateid.seqid == 0xffffffff &&
5788 stp->ls_stateid.other[0] == 0x55555555 &&
5789 stp->ls_stateid.other[1] == 0x55555555 &&
5790 stp->ls_stateid.other[2] == 0x55555555)
5791 gotproxystateid = 1;
5792 off = fxdr_hyper(tl); tl += 2;
5793 lop->lo_first = off;
5794 len = fxdr_hyper(tl);
5795 if (len < 0)
5796 len = OFF_MAX;
5797 NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off,
5798 (intmax_t)len);
5799 lop->lo_end = lop->lo_first + len;
5800 /*
5801 * Sanity check the offset and length.
5802 * off and len are off_t (signed int64_t) whereas
5803 * lo_first and lo_end are uint64_t and, as such,
5804 * if off >= 0 && len > 0, lo_end cannot overflow
5805 * unless off_t is changed to something other than
5806 * int64_t. Check lo_end < lo_first in case that
5807 * is someday the case.
5808 * The error to return is not specified by RFC 7862 so I
5809 * made this compatible with the Linux knfsd.
5810 */
5811 if (nd->nd_repstat == 0) {
5812 if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE)
5813 nd->nd_repstat = NFSERR_FBIG;
5814 else if (len == 0 || lop->lo_end < lop->lo_first)
5815 nd->nd_repstat = NFSERR_INVAL;
5816 }
5817
5818 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5819 nd->nd_repstat = NFSERR_WRONGTYPE;
5820 NFSZERO_ATTRBIT(&attrbits);
5821 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5822 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5823 if (nd->nd_repstat == 0)
5824 nd->nd_repstat = forat_ret;
5825 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5826 NFSVNO_EXSTRICTACCESS(exp)))
5827 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5828 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5829 NULL);
5830 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5831 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5832 &stateid, exp, nd, curthread);
5833
5834 if (nd->nd_repstat == 0)
5835 nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred,
5836 curthread);
5837 vput(vp);
5838 NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat);
5839 NFSEXITCODE2(0, nd);
5840 return (0);
5841 nfsmout:
5842 vput(vp);
5843 NFSEXITCODE2(error, nd);
5844 return (error);
5845 }
5846
5847 /*
5848 * nfs copy service
5849 */
5850 int
nfsrvd_copy_file_range(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,vnode_t tovp,struct nfsexstuff * exp,struct nfsexstuff * toexp)5851 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5852 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5853 {
5854 uint32_t *tl;
5855 struct nfsvattr at;
5856 int cnt, error = 0, ret;
5857 off_t inoff, outoff;
5858 uint64_t len;
5859 size_t xfer;
5860 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5861 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5862 nfsquad_t clientid;
5863 nfsv4stateid_t stateid;
5864 nfsattrbit_t attrbits;
5865 void *rl_rcookie, *rl_wcookie;
5866
5867 rl_rcookie = rl_wcookie = NULL;
5868 if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0) {
5869 /*
5870 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5871 * will do the copy via I/O on the DS(s).
5872 * If vfs.nfsd.maxcopyrange set to 0, disable Copy.
5873 */
5874 nd->nd_repstat = NFSERR_NOTSUPP;
5875 goto nfsmout;
5876 }
5877 if (vp == tovp) {
5878 /* Copying a byte range within the same file is not allowed. */
5879 nd->nd_repstat = NFSERR_INVAL;
5880 goto nfsmout;
5881 }
5882 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5883 3 * NFSX_UNSIGNED);
5884 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5885 inlop->lo_flags = NFSLCK_READ;
5886 instp->ls_ownerlen = 0;
5887 instp->ls_op = NULL;
5888 instp->ls_uid = nd->nd_cred->cr_uid;
5889 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5890 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5891 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5892 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5893 clientid.qval = nd->nd_clientid.qval;
5894 instp->ls_stateid.other[2] = *tl++;
5895 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5896 outlop->lo_flags = NFSLCK_WRITE;
5897 outstp->ls_ownerlen = 0;
5898 outstp->ls_op = NULL;
5899 outstp->ls_uid = nd->nd_cred->cr_uid;
5900 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5901 outstp->ls_stateid.other[0] = *tl++;
5902 outstp->ls_stateid.other[1] = *tl++;
5903 outstp->ls_stateid.other[2] = *tl++;
5904 inoff = fxdr_hyper(tl); tl += 2;
5905 inlop->lo_first = inoff;
5906 outoff = fxdr_hyper(tl); tl += 2;
5907 outlop->lo_first = outoff;
5908 len = fxdr_hyper(tl); tl += 2;
5909 if (len == 0) {
5910 /* len == 0 means to EOF. */
5911 inlop->lo_end = OFF_MAX;
5912 outlop->lo_end = OFF_MAX;
5913 } else {
5914 inlop->lo_end = inlop->lo_first + len;
5915 outlop->lo_end = outlop->lo_first + len;
5916 }
5917
5918 /*
5919 * At this time only consecutive, synchronous copy is supported,
5920 * so ca_consecutive and ca_synchronous can be ignored.
5921 */
5922 tl += 2;
5923
5924 cnt = fxdr_unsigned(int, *tl);
5925 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5926 nd->nd_repstat = NFSERR_NOTSUPP;
5927 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5928 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5929 inlop->lo_end < inlop->lo_first || outlop->lo_end <
5930 outlop->lo_first))
5931 nd->nd_repstat = NFSERR_INVAL;
5932
5933 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5934 nd->nd_repstat = NFSERR_WRONGTYPE;
5935
5936 /* Check permissions for the input file. */
5937 NFSZERO_ATTRBIT(&attrbits);
5938 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5939 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5940 if (nd->nd_repstat == 0)
5941 nd->nd_repstat = ret;
5942 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5943 NFSVNO_EXSTRICTACCESS(exp)))
5944 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5945 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5946 NULL);
5947 if (nd->nd_repstat == 0)
5948 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5949 clientid, &stateid, exp, nd, curthread);
5950 NFSVOPUNLOCK(vp);
5951 if (nd->nd_repstat != 0)
5952 goto out;
5953
5954 error = NFSVOPLOCK(tovp, LK_SHARED);
5955 if (error != 0)
5956 goto out;
5957 if (tovp->v_type != VREG)
5958 nd->nd_repstat = NFSERR_WRONGTYPE;
5959
5960 /* For the output file, we only need the Owner attribute. */
5961 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5962 if (nd->nd_repstat == 0)
5963 nd->nd_repstat = ret;
5964 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5965 NFSVNO_EXSTRICTACCESS(exp)))
5966 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5967 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5968 NULL);
5969 if (nd->nd_repstat == 0)
5970 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5971 clientid, &stateid, toexp, nd, curthread);
5972 NFSVOPUNLOCK(tovp);
5973
5974 /* Range lock the byte ranges for both invp and outvp. */
5975 if (nd->nd_repstat == 0) {
5976 for (;;) {
5977 if (len == 0) {
5978 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5979 OFF_MAX);
5980 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5981 OFF_MAX);
5982 } else {
5983 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5984 outoff + len);
5985 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5986 inoff + len);
5987 }
5988 if (rl_rcookie != NULL)
5989 break;
5990 vn_rangelock_unlock(tovp, rl_wcookie);
5991 if (len == 0)
5992 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5993 OFF_MAX);
5994 else
5995 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5996 inoff + len);
5997 vn_rangelock_unlock(vp, rl_rcookie);
5998 }
5999
6000 error = NFSVOPLOCK(vp, LK_SHARED);
6001 if (error == 0) {
6002 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
6003 if (ret == 0) {
6004 /*
6005 * Since invp is range locked, na_size should
6006 * not change.
6007 */
6008 if (len == 0 && at.na_size > inoff) {
6009 /*
6010 * If len == 0, set it based on invp's
6011 * size. If offset is past EOF, just
6012 * leave len == 0.
6013 */
6014 len = at.na_size - inoff;
6015 } else if (nfsrv_linux42server == 0 &&
6016 inoff + len > at.na_size) {
6017 /*
6018 * RFC-7862 says that NFSERR_INVAL must
6019 * be returned when inoff + len exceeds
6020 * the file size, however the NFSv4.2
6021 * Linux client likes to do this, so
6022 * only check if nfsrv_linux42server
6023 * is not set.
6024 */
6025 nd->nd_repstat = NFSERR_INVAL;
6026 }
6027 }
6028 NFSVOPUNLOCK(vp);
6029 if (ret != 0 && nd->nd_repstat == 0)
6030 nd->nd_repstat = ret;
6031 } else if (nd->nd_repstat == 0)
6032 nd->nd_repstat = error;
6033 }
6034
6035 /*
6036 * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
6037 * This size limit can be set to limit the time a copy RPC will
6038 * take.
6039 */
6040 if (len > nfsrv_maxcopyrange)
6041 xfer = nfsrv_maxcopyrange;
6042 else
6043 xfer = len;
6044 if (nd->nd_repstat == 0) {
6045 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
6046 &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred,
6047 NULL);
6048 if (nd->nd_repstat == 0)
6049 len = xfer;
6050 }
6051
6052 /* Unlock the ranges. */
6053 if (rl_rcookie != NULL)
6054 vn_rangelock_unlock(vp, rl_rcookie);
6055 if (rl_wcookie != NULL)
6056 vn_rangelock_unlock(tovp, rl_wcookie);
6057
6058 if (nd->nd_repstat == 0) {
6059 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
6060 NFSX_VERF);
6061 *tl++ = txdr_unsigned(0); /* No callback ids. */
6062 txdr_hyper(len, tl); tl += 2;
6063 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
6064 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
6065 *tl++ = txdr_unsigned(nfsboottime.tv_usec);
6066 *tl++ = newnfs_true;
6067 *tl = newnfs_true;
6068 }
6069 out:
6070 vrele(vp);
6071 vrele(tovp);
6072 NFSEXITCODE2(error, nd);
6073 return (error);
6074 nfsmout:
6075 vput(vp);
6076 vrele(tovp);
6077 NFSEXITCODE2(error, nd);
6078 return (error);
6079 }
6080
6081 /*
6082 * nfs clone service
6083 */
6084 int
nfsrvd_clone(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,vnode_t tovp,struct nfsexstuff * exp,struct nfsexstuff * toexp)6085 nfsrvd_clone(struct nfsrv_descript *nd, __unused int isdgram,
6086 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
6087 {
6088 uint32_t *tl;
6089 struct nfsvattr at;
6090 int error = 0, ret;
6091 off_t inoff, outoff;
6092 uint64_t len;
6093 size_t xfer;
6094 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
6095 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
6096 nfsquad_t clientid;
6097 nfsv4stateid_t stateid;
6098 nfsattrbit_t attrbits;
6099 void *rl_rcookie, *rl_wcookie;
6100 long pathval;
6101
6102 rl_rcookie = rl_wcookie = NULL;
6103 pathval = 0;
6104 if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0 ||
6105 VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE, &pathval) != 0 ||
6106 pathval == 0) {
6107 /*
6108 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
6109 * will not do the clone and will do I/O on the DS(s).
6110 * If vfs.nfsd.maxcopyrange set to 0, disable Clone.
6111 */
6112 nd->nd_repstat = NFSERR_NOTSUPP;
6113 goto nfsmout;
6114 }
6115 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER);
6116 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
6117 inlop->lo_flags = NFSLCK_READ;
6118 instp->ls_ownerlen = 0;
6119 instp->ls_op = NULL;
6120 instp->ls_uid = nd->nd_cred->cr_uid;
6121 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
6122 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
6123 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
6124 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
6125 clientid.qval = nd->nd_clientid.qval;
6126 instp->ls_stateid.other[2] = *tl++;
6127 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
6128 outlop->lo_flags = NFSLCK_WRITE;
6129 outstp->ls_ownerlen = 0;
6130 outstp->ls_op = NULL;
6131 outstp->ls_uid = nd->nd_cred->cr_uid;
6132 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
6133 outstp->ls_stateid.other[0] = *tl++;
6134 outstp->ls_stateid.other[1] = *tl++;
6135 outstp->ls_stateid.other[2] = *tl++;
6136 inoff = fxdr_hyper(tl); tl += 2;
6137 inlop->lo_first = inoff;
6138 outoff = fxdr_hyper(tl); tl += 2;
6139 outlop->lo_first = outoff;
6140 len = fxdr_hyper(tl);
6141 if (len == 0) {
6142 /* len == 0 means to EOF. */
6143 inlop->lo_end = OFF_MAX;
6144 outlop->lo_end = OFF_MAX;
6145 } else {
6146 inlop->lo_end = inlop->lo_first + len;
6147 outlop->lo_end = outlop->lo_first + len;
6148 }
6149
6150 if ((inoff > OFF_MAX || outoff > OFF_MAX ||
6151 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
6152 inlop->lo_end < inlop->lo_first || outlop->lo_end <
6153 outlop->lo_first))
6154 nd->nd_repstat = NFSERR_INVAL;
6155
6156 if (nd->nd_repstat == 0 && vp->v_type != VREG)
6157 nd->nd_repstat = NFSERR_WRONGTYPE;
6158
6159 /* Check permissions for the input file. */
6160 NFSZERO_ATTRBIT(&attrbits);
6161 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
6162 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
6163 if (nd->nd_repstat == 0)
6164 nd->nd_repstat = ret;
6165 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6166 NFSVNO_EXSTRICTACCESS(exp)))
6167 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
6168 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6169 NULL);
6170 if (nd->nd_repstat == 0)
6171 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
6172 clientid, &stateid, exp, nd, curthread);
6173 if (vp != tovp) {
6174 NFSVOPUNLOCK(vp);
6175 if (nd->nd_repstat != 0)
6176 goto out;
6177
6178 error = NFSVOPLOCK(tovp, LK_SHARED);
6179 if (error != 0)
6180 goto out;
6181 pathval = 0;
6182 if (VOP_PATHCONF(tovp, _PC_CLONE_BLKSIZE, &pathval) != 0 ||
6183 pathval == 0)
6184 nd->nd_repstat = NFSERR_NOTSUPP;
6185 else if (tovp->v_type != VREG)
6186 nd->nd_repstat = NFSERR_WRONGTYPE;
6187 }
6188
6189 /* For the output file, we only need the Owner attribute. */
6190 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
6191 if (nd->nd_repstat == 0)
6192 nd->nd_repstat = ret;
6193 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6194 NFSVNO_EXSTRICTACCESS(exp)))
6195 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
6196 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6197 NULL);
6198 if (nd->nd_repstat == 0)
6199 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
6200 clientid, &stateid, toexp, nd, curthread);
6201 NFSVOPUNLOCK(tovp);
6202
6203 /* Range lock the byte ranges for both invp and outvp. */
6204 if (nd->nd_repstat == 0) {
6205 for (;;) {
6206 if (len == 0)
6207 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6208 OFF_MAX);
6209 else
6210 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
6211 outoff + len);
6212 if (vp != tovp) {
6213 if (len == 0)
6214 rl_rcookie = vn_rangelock_tryrlock(vp,
6215 inoff, OFF_MAX);
6216 else
6217 rl_rcookie = vn_rangelock_tryrlock(vp,
6218 inoff, inoff + len);
6219 if (rl_rcookie != NULL)
6220 break;
6221 } else {
6222 rl_rcookie = NULL;
6223 break;
6224 }
6225 vn_rangelock_unlock(tovp, rl_wcookie);
6226 if (len == 0)
6227 rl_rcookie = vn_rangelock_rlock(vp, inoff,
6228 OFF_MAX);
6229 else
6230 rl_rcookie = vn_rangelock_rlock(vp, inoff,
6231 inoff + len);
6232 vn_rangelock_unlock(vp, rl_rcookie);
6233 }
6234
6235 error = NFSVOPLOCK(vp, LK_SHARED);
6236 if (error == 0) {
6237 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
6238 if (ret == 0) {
6239 /*
6240 * Since invp is range locked, na_size should
6241 * not change.
6242 */
6243 if (len == 0 && at.na_size > inoff)
6244 len = SSIZE_MAX; /* To EOF. */
6245 else if (inoff + len > at.na_size)
6246 nd->nd_repstat = NFSERR_INVAL;
6247 }
6248 NFSVOPUNLOCK(vp);
6249 if (ret != 0 && nd->nd_repstat == 0)
6250 nd->nd_repstat = ret;
6251 } else if (nd->nd_repstat == 0)
6252 nd->nd_repstat = error;
6253 }
6254
6255 /*
6256 * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
6257 * This size limit can be set to limit the time a copy RPC will
6258 * take.
6259 */
6260 xfer = len;
6261 if (nd->nd_repstat == 0) {
6262 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
6263 &xfer, COPY_FILE_RANGE_CLONE, nd->nd_cred, nd->nd_cred,
6264 NULL);
6265 if (nd->nd_repstat == ENOSYS)
6266 nd->nd_repstat = NFSERR_INVAL;
6267 }
6268
6269 /* Unlock the ranges. */
6270 if (rl_rcookie != NULL)
6271 vn_rangelock_unlock(vp, rl_rcookie);
6272 if (rl_wcookie != NULL)
6273 vn_rangelock_unlock(tovp, rl_wcookie);
6274
6275 out:
6276 vrele(vp);
6277 vrele(tovp);
6278 NFSEXITCODE2(error, nd);
6279 return (error);
6280 nfsmout:
6281 vput(vp);
6282 vrele(tovp);
6283 NFSEXITCODE2(error, nd);
6284 return (error);
6285 }
6286
6287 /*
6288 * nfs seek service
6289 */
6290 int
nfsrvd_seek(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)6291 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
6292 vnode_t vp, struct nfsexstuff *exp)
6293 {
6294 uint32_t *tl;
6295 struct nfsvattr at;
6296 int content, error = 0;
6297 off_t off;
6298 u_long cmd;
6299 nfsattrbit_t attrbits;
6300 bool eof;
6301
6302 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
6303 /* Ignore the stateid for now. */
6304 tl += (NFSX_STATEID / NFSX_UNSIGNED);
6305 off = fxdr_hyper(tl); tl += 2;
6306 content = fxdr_unsigned(int, *tl);
6307 if (content == NFSV4CONTENT_DATA)
6308 cmd = FIOSEEKDATA;
6309 else if (content == NFSV4CONTENT_HOLE)
6310 cmd = FIOSEEKHOLE;
6311 else
6312 nd->nd_repstat = NFSERR_BADXDR;
6313 if (nd->nd_repstat == 0 && vp->v_type == VDIR)
6314 nd->nd_repstat = NFSERR_ISDIR;
6315 if (nd->nd_repstat == 0 && vp->v_type != VREG)
6316 nd->nd_repstat = NFSERR_WRONGTYPE;
6317 if (nd->nd_repstat == 0 && off < 0)
6318 nd->nd_repstat = NFSERR_NXIO;
6319 if (nd->nd_repstat == 0) {
6320 /* Check permissions for the input file. */
6321 NFSZERO_ATTRBIT(&attrbits);
6322 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
6323 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
6324 &attrbits);
6325 }
6326 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
6327 NFSVNO_EXSTRICTACCESS(exp)))
6328 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
6329 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
6330 NULL);
6331 if (nd->nd_repstat != 0)
6332 goto nfsmout;
6333
6334 /* nfsvno_seek() unlocks and vrele()s the vp. */
6335 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
6336 nd->nd_cred, curthread);
6337 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
6338 nfsrv_linux42server != 0)
6339 nd->nd_repstat = NFSERR_NXIO;
6340 if (nd->nd_repstat == 0) {
6341 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
6342 if (eof)
6343 *tl++ = newnfs_true;
6344 else
6345 *tl++ = newnfs_false;
6346 txdr_hyper(off, tl);
6347 }
6348 NFSEXITCODE2(error, nd);
6349 return (error);
6350 nfsmout:
6351 vput(vp);
6352 NFSEXITCODE2(error, nd);
6353 return (error);
6354 }
6355
6356 /*
6357 * nfs get extended attribute service
6358 */
6359 int
nfsrvd_getxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6360 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
6361 vnode_t vp, __unused struct nfsexstuff *exp)
6362 {
6363 uint32_t *tl;
6364 struct mbuf *mp = NULL, *mpend = NULL;
6365 int error, len;
6366 char *name;
6367 struct thread *p = curthread;
6368 uint16_t off;
6369
6370 error = 0;
6371 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6372 len = fxdr_unsigned(int, *tl);
6373 if (len <= 0) {
6374 nd->nd_repstat = NFSERR_BADXDR;
6375 goto nfsmout;
6376 }
6377 if (len > EXTATTR_MAXNAMELEN) {
6378 nd->nd_repstat = NFSERR_NOXATTR;
6379 goto nfsmout;
6380 }
6381 name = malloc(len + 1, M_TEMP, M_WAITOK);
6382 nd->nd_repstat = nfsrv_mtostr(nd, name, len);
6383 if (nd->nd_repstat == 0)
6384 nd->nd_repstat = nfsvno_getxattr(vp, name,
6385 nd->nd_maxresp, nd->nd_cred, nd->nd_flag,
6386 nd->nd_maxextsiz, p, &mp, &mpend, &len);
6387 if (nd->nd_repstat == ENOATTR)
6388 nd->nd_repstat = NFSERR_NOXATTR;
6389 else if (nd->nd_repstat == EOPNOTSUPP)
6390 nd->nd_repstat = NFSERR_NOTSUPP;
6391 if (nd->nd_repstat == 0) {
6392 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6393 *tl = txdr_unsigned(len);
6394 if (len > 0) {
6395 nd->nd_mb->m_next = mp;
6396 nd->nd_mb = mpend;
6397 if ((mpend->m_flags & M_EXTPG) != 0) {
6398 nd->nd_flag |= ND_EXTPG;
6399 nd->nd_bextpg = mpend->m_epg_npgs - 1;
6400 nd->nd_bpos = (char *)(void *)
6401 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
6402 off = (nd->nd_bextpg == 0) ?
6403 mpend->m_epg_1st_off : 0;
6404 nd->nd_bpos += off + mpend->m_epg_last_len;
6405 nd->nd_bextpgsiz = PAGE_SIZE -
6406 mpend->m_epg_last_len - off;
6407 } else
6408 nd->nd_bpos = mtod(mpend, char *) +
6409 mpend->m_len;
6410 }
6411 }
6412 free(name, M_TEMP);
6413
6414 nfsmout:
6415 if (nd->nd_repstat == 0)
6416 nd->nd_repstat = error;
6417 vput(vp);
6418 NFSEXITCODE2(0, nd);
6419 return (0);
6420 }
6421
6422 /*
6423 * nfs set extended attribute service
6424 */
6425 int
nfsrvd_setxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6426 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
6427 vnode_t vp, __unused struct nfsexstuff *exp)
6428 {
6429 uint32_t *tl;
6430 struct nfsvattr ova, nva;
6431 nfsattrbit_t attrbits;
6432 int error, len, opt;
6433 char *name;
6434 size_t siz;
6435 struct thread *p = curthread;
6436
6437 error = 0;
6438 name = NULL;
6439 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
6440 opt = fxdr_unsigned(int, *tl++);
6441 len = fxdr_unsigned(int, *tl);
6442 if (len <= 0) {
6443 nd->nd_repstat = NFSERR_BADXDR;
6444 goto nfsmout;
6445 }
6446 if (len > EXTATTR_MAXNAMELEN) {
6447 nd->nd_repstat = NFSERR_NOXATTR;
6448 goto nfsmout;
6449 }
6450 name = malloc(len + 1, M_TEMP, M_WAITOK);
6451 error = nfsrv_mtostr(nd, name, len);
6452 if (error != 0)
6453 goto nfsmout;
6454 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6455 len = fxdr_unsigned(int, *tl);
6456 if (len < 0 || len > IOSIZE_MAX) {
6457 nd->nd_repstat = NFSERR_XATTR2BIG;
6458 goto nfsmout;
6459 }
6460 switch (opt) {
6461 case NFSV4SXATTR_CREATE:
6462 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6463 &siz, nd->nd_cred, p);
6464 if (error != ENOATTR)
6465 nd->nd_repstat = NFSERR_EXIST;
6466 error = 0;
6467 break;
6468 case NFSV4SXATTR_REPLACE:
6469 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6470 &siz, nd->nd_cred, p);
6471 if (error != 0)
6472 nd->nd_repstat = NFSERR_NOXATTR;
6473 break;
6474 case NFSV4SXATTR_EITHER:
6475 break;
6476 default:
6477 nd->nd_repstat = NFSERR_BADXDR;
6478 }
6479 if (nd->nd_repstat != 0)
6480 goto nfsmout;
6481
6482 /* Now, do the Set Extended attribute, with Change before and after. */
6483 NFSZERO_ATTRBIT(&attrbits);
6484 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6485 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6486 if (nd->nd_repstat == 0) {
6487 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
6488 nd->nd_dpos, nd->nd_cred, p);
6489 if (nd->nd_repstat == ENXIO)
6490 nd->nd_repstat = NFSERR_XATTR2BIG;
6491 }
6492 if (nd->nd_repstat == 0 && len > 0)
6493 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
6494 if (nd->nd_repstat == 0)
6495 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6496 if (nd->nd_repstat == 0) {
6497 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6498 *tl++ = newnfs_true;
6499 txdr_hyper(ova.na_filerev, tl); tl += 2;
6500 txdr_hyper(nva.na_filerev, tl);
6501 }
6502
6503 nfsmout:
6504 free(name, M_TEMP);
6505 if (nd->nd_repstat == 0)
6506 nd->nd_repstat = error;
6507 vput(vp);
6508 NFSEXITCODE2(0, nd);
6509 return (0);
6510 }
6511
6512 /*
6513 * nfs remove extended attribute service
6514 */
6515 int
nfsrvd_rmxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6516 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
6517 vnode_t vp, __unused struct nfsexstuff *exp)
6518 {
6519 uint32_t *tl;
6520 struct nfsvattr ova, nva;
6521 nfsattrbit_t attrbits;
6522 int error, len;
6523 char *name;
6524 struct thread *p = curthread;
6525
6526 error = 0;
6527 name = NULL;
6528 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6529 len = fxdr_unsigned(int, *tl);
6530 if (len <= 0) {
6531 nd->nd_repstat = NFSERR_BADXDR;
6532 goto nfsmout;
6533 }
6534 if (len > EXTATTR_MAXNAMELEN) {
6535 nd->nd_repstat = NFSERR_NOXATTR;
6536 goto nfsmout;
6537 }
6538 name = malloc(len + 1, M_TEMP, M_WAITOK);
6539 error = nfsrv_mtostr(nd, name, len);
6540 if (error != 0)
6541 goto nfsmout;
6542
6543 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
6544 printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
6545 error = NFSERR_NOXATTR;
6546 goto nfsmout;
6547 }
6548 /*
6549 * Now, do the Remove Extended attribute, with Change before and
6550 * after.
6551 */
6552 NFSZERO_ATTRBIT(&attrbits);
6553 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6554 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6555 if (nd->nd_repstat == 0) {
6556 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
6557 if (nd->nd_repstat == ENOATTR)
6558 nd->nd_repstat = NFSERR_NOXATTR;
6559 }
6560 if (nd->nd_repstat == 0)
6561 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6562 if (nd->nd_repstat == 0) {
6563 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6564 *tl++ = newnfs_true;
6565 txdr_hyper(ova.na_filerev, tl); tl += 2;
6566 txdr_hyper(nva.na_filerev, tl);
6567 }
6568
6569 nfsmout:
6570 free(name, M_TEMP);
6571 if (nd->nd_repstat == 0)
6572 nd->nd_repstat = error;
6573 vput(vp);
6574 NFSEXITCODE2(0, nd);
6575 return (0);
6576 }
6577
6578 /*
6579 * nfs list extended attribute service
6580 */
6581 int
nfsrvd_listxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6582 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
6583 vnode_t vp, __unused struct nfsexstuff *exp)
6584 {
6585 uint32_t cnt, *tl, len, len2, i, pos, retlen;
6586 int error;
6587 uint64_t cookie, cookie2;
6588 u_char *buf;
6589 bool eof;
6590 struct thread *p = curthread;
6591
6592 error = 0;
6593 buf = NULL;
6594 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6595 /*
6596 * The cookie doesn't need to be in net byte order, but FreeBSD
6597 * does so to make it more readable in packet traces.
6598 */
6599 cookie = fxdr_hyper(tl); tl += 2;
6600 len = fxdr_unsigned(uint32_t, *tl);
6601 if (len == 0 || cookie >= IOSIZE_MAX) {
6602 nd->nd_repstat = NFSERR_BADXDR;
6603 goto nfsmout;
6604 }
6605 if (len > nd->nd_maxresp - NFS_MAXXDR)
6606 len = nd->nd_maxresp - NFS_MAXXDR;
6607 len2 = len;
6608 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
6609 &len, &eof);
6610 if (nd->nd_repstat == EOPNOTSUPP)
6611 nd->nd_repstat = NFSERR_NOTSUPP;
6612 if (nd->nd_repstat == 0) {
6613 cookie2 = cookie + len;
6614 if (cookie2 < cookie)
6615 nd->nd_repstat = NFSERR_BADXDR;
6616 }
6617 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
6618 if (nd->nd_repstat == 0 && len2 < retlen)
6619 nd->nd_repstat = NFSERR_TOOSMALL;
6620 if (nd->nd_repstat == 0) {
6621 /* Now copy the entries out. */
6622 if (len == 0) {
6623 /* The cookie was at eof. */
6624 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
6625 NFSX_UNSIGNED);
6626 txdr_hyper(cookie2, tl); tl += 2;
6627 *tl++ = txdr_unsigned(0);
6628 *tl = newnfs_true;
6629 goto nfsmout;
6630 }
6631
6632 /* Sanity check the cookie. */
6633 for (pos = 0; pos < len; pos += (i + 1)) {
6634 if (pos == cookie)
6635 break;
6636 i = buf[pos];
6637 }
6638 if (pos != cookie) {
6639 nd->nd_repstat = NFSERR_INVAL;
6640 goto nfsmout;
6641 }
6642
6643 /* Loop around copying the entrie(s) out. */
6644 cnt = 0;
6645 len -= cookie;
6646 i = buf[pos];
6647 while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
6648 NFSX_UNSIGNED) {
6649 if (cnt == 0) {
6650 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
6651 NFSX_UNSIGNED);
6652 txdr_hyper(cookie2, tl); tl += 2;
6653 }
6654 retlen += nfsm_strtom(nd, &buf[pos + 1], i);
6655 len -= (i + 1);
6656 pos += (i + 1);
6657 i = buf[pos];
6658 cnt++;
6659 }
6660 /*
6661 * eof is set true/false by nfsvno_listxattr(), but if we
6662 * can't copy all entries returned by nfsvno_listxattr(),
6663 * we are not at eof.
6664 */
6665 if (len > 0)
6666 eof = false;
6667 if (cnt > 0) {
6668 /* *tl is set above. */
6669 *tl = txdr_unsigned(cnt);
6670 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6671 if (eof)
6672 *tl = newnfs_true;
6673 else
6674 *tl = newnfs_false;
6675 } else
6676 nd->nd_repstat = NFSERR_TOOSMALL;
6677 }
6678
6679 nfsmout:
6680 free(buf, M_TEMP);
6681 if (nd->nd_repstat == 0)
6682 nd->nd_repstat = error;
6683 vput(vp);
6684 NFSEXITCODE2(0, nd);
6685 return (0);
6686 }
6687
6688 /*
6689 * nfsv4 service not supported
6690 */
6691 int
nfsrvd_notsupp(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)6692 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
6693 __unused vnode_t vp, __unused struct nfsexstuff *exp)
6694 {
6695
6696 nd->nd_repstat = NFSERR_NOTSUPP;
6697 NFSEXITCODE2(0, nd);
6698 return (0);
6699 }
6700