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