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