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