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