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