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