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