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