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