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