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 if (nd->nd_repstat) {
379 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
380 goto out;
381 }
382 #ifdef NFS4_ACL_EXTATTR_NAME
383 aclp = acl_alloc(M_WAITOK);
384 aclp->acl_cnt = 0;
385 #endif
386 gotproxystateid = 0;
387 NFSVNO_ATTRINIT(&nva);
388 if (nd->nd_flag & ND_NFSV4) {
389 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
390 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
391 stateid.other[0] = *tl++;
392 stateid.other[1] = *tl++;
393 stateid.other[2] = *tl;
394 if (stateid.other[0] == 0x55555555 &&
395 stateid.other[1] == 0x55555555 &&
396 stateid.other[2] == 0x55555555 &&
397 stateid.seqid == 0xffffffff)
398 gotproxystateid = 1;
399 }
400 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
401 if (error)
402 goto nfsmout;
403
404 /* For NFSv4, only va_uid is used from nva2. */
405 NFSZERO_ATTRBIT(&retbits);
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 {
3248 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3249 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
3250 }
3251 } else
3252 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
3253 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
3254 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
3255 *tl++ = txdr_unsigned(delegstateid.seqid);
3256 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
3257 NFSX_STATEIDOTHER);
3258 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3259 if (rflags & NFSV4OPEN_RECALL)
3260 *tl = newnfs_true;
3261 else
3262 *tl = newnfs_false;
3263 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
3264 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3265 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
3266 txdr_hyper(nva.na_size, tl);
3267 }
3268 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3269 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
3270 *tl++ = txdr_unsigned(0x0);
3271 acemask = NFSV4ACE_ALLFILESMASK;
3272 if (nva.na_mode & S_IRUSR)
3273 acemask |= NFSV4ACE_READMASK;
3274 if (nva.na_mode & S_IWUSR)
3275 acemask |= NFSV4ACE_WRITEMASK;
3276 if (nva.na_mode & S_IXUSR)
3277 acemask |= NFSV4ACE_EXECUTEMASK;
3278 *tl = txdr_unsigned(acemask);
3279 (void) nfsm_strtom(nd, "OWNER@", 6);
3280 }
3281 *vpp = vp;
3282 } else if (vp) {
3283 vrele(vp);
3284 }
3285 if (dirp)
3286 vrele(dirp);
3287 #ifdef NFS4_ACL_EXTATTR_NAME
3288 acl_free(aclp);
3289 #endif
3290 NFSEXITCODE2(0, nd);
3291 return (0);
3292 nfsmout:
3293 vrele(dp);
3294 #ifdef NFS4_ACL_EXTATTR_NAME
3295 acl_free(aclp);
3296 #endif
3297 if (stp)
3298 free(stp, M_NFSDSTATE);
3299 NFSEXITCODE2(error, nd);
3300 return (error);
3301 }
3302
3303 /*
3304 * nfsv4 close service
3305 */
3306 int
nfsrvd_close(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3307 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
3308 vnode_t vp, __unused struct nfsexstuff *exp)
3309 {
3310 u_int32_t *tl;
3311 struct nfsstate st, *stp = &st;
3312 int error = 0, writeacc;
3313 nfsv4stateid_t stateid;
3314 nfsquad_t clientid;
3315 struct nfsvattr na;
3316 struct thread *p = curthread;
3317
3318 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
3319 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3320 stp->ls_ownerlen = 0;
3321 stp->ls_op = nd->nd_rp;
3322 stp->ls_uid = nd->nd_cred->cr_uid;
3323 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3324 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3325 NFSX_STATEIDOTHER);
3326
3327 /*
3328 * For the special stateid of other all 0s and seqid == 1, set the
3329 * stateid to the current stateid, if it is set.
3330 */
3331 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3332 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3333 stp->ls_stateid.other[2] == 0) {
3334 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3335 stp->ls_stateid = nd->nd_curstateid;
3336 else {
3337 nd->nd_repstat = NFSERR_BADSTATEID;
3338 goto nfsmout;
3339 }
3340 }
3341
3342 stp->ls_flags = NFSLCK_CLOSE;
3343 clientid.lval[0] = stp->ls_stateid.other[0];
3344 clientid.lval[1] = stp->ls_stateid.other[1];
3345 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3346 if ((nd->nd_flag & ND_NFSV41) != 0)
3347 clientid.qval = nd->nd_clientid.qval;
3348 else if (nd->nd_clientid.qval != clientid.qval)
3349 printf("EEK8 multiple clids\n");
3350 } else {
3351 if ((nd->nd_flag & ND_NFSV41) != 0)
3352 printf("EEK! no clientid from session\n");
3353 nd->nd_flag |= ND_IMPLIEDCLID;
3354 nd->nd_clientid.qval = clientid.qval;
3355 }
3356 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3357 &writeacc);
3358 /* For pNFS, update the attributes. */
3359 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3360 nfsrv_updatemdsattr(vp, &na, p);
3361 vput(vp);
3362 if (!nd->nd_repstat) {
3363 /*
3364 * If the stateid that has been closed is the current stateid,
3365 * unset it.
3366 */
3367 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
3368 stateid.other[0] == nd->nd_curstateid.other[0] &&
3369 stateid.other[1] == nd->nd_curstateid.other[1] &&
3370 stateid.other[2] == nd->nd_curstateid.other[2])
3371 nd->nd_flag &= ~ND_CURSTATEID;
3372 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3373 *tl++ = txdr_unsigned(stateid.seqid);
3374 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3375 }
3376 NFSEXITCODE2(0, nd);
3377 return (0);
3378 nfsmout:
3379 vput(vp);
3380 NFSEXITCODE2(error, nd);
3381 return (error);
3382 }
3383
3384 /*
3385 * nfsv4 delegpurge service
3386 */
3387 int
nfsrvd_delegpurge(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)3388 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
3389 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3390 {
3391 u_int32_t *tl;
3392 int error = 0;
3393 nfsquad_t clientid;
3394 struct thread *p = curthread;
3395
3396 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3397 goto nfsmout;
3398 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3399 clientid.lval[0] = *tl++;
3400 clientid.lval[1] = *tl;
3401 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3402 if ((nd->nd_flag & ND_NFSV41) != 0)
3403 clientid.qval = nd->nd_clientid.qval;
3404 else if (nd->nd_clientid.qval != clientid.qval)
3405 printf("EEK9 multiple clids\n");
3406 } else {
3407 if ((nd->nd_flag & ND_NFSV41) != 0)
3408 printf("EEK! no clientid from session\n");
3409 nd->nd_flag |= ND_IMPLIEDCLID;
3410 nd->nd_clientid.qval = clientid.qval;
3411 }
3412 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
3413 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
3414 nfsmout:
3415 NFSEXITCODE2(error, nd);
3416 return (error);
3417 }
3418
3419 /*
3420 * nfsv4 delegreturn service
3421 */
3422 int
nfsrvd_delegreturn(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3423 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
3424 vnode_t vp, __unused struct nfsexstuff *exp)
3425 {
3426 u_int32_t *tl;
3427 int error = 0, writeacc;
3428 nfsv4stateid_t stateid;
3429 nfsquad_t clientid;
3430 struct nfsvattr na;
3431 struct thread *p = curthread;
3432
3433 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
3434 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3435 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
3436 clientid.lval[0] = stateid.other[0];
3437 clientid.lval[1] = stateid.other[1];
3438 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3439 if ((nd->nd_flag & ND_NFSV41) != 0)
3440 clientid.qval = nd->nd_clientid.qval;
3441 else if (nd->nd_clientid.qval != clientid.qval)
3442 printf("EEK10 multiple clids\n");
3443 } else {
3444 if ((nd->nd_flag & ND_NFSV41) != 0)
3445 printf("EEK! no clientid from session\n");
3446 nd->nd_flag |= ND_IMPLIEDCLID;
3447 nd->nd_clientid.qval = clientid.qval;
3448 }
3449 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
3450 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
3451 /* For pNFS, update the attributes. */
3452 if (writeacc != 0 || nfsrv_pnfsatime != 0)
3453 nfsrv_updatemdsattr(vp, &na, p);
3454 nfsmout:
3455 vput(vp);
3456 NFSEXITCODE2(error, nd);
3457 return (error);
3458 }
3459
3460 /*
3461 * nfsv4 get file handle service
3462 */
3463 int
nfsrvd_getfh(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3464 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
3465 vnode_t vp, __unused struct nfsexstuff *exp)
3466 {
3467 fhandle_t fh;
3468 struct thread *p = curthread;
3469
3470 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3471 vput(vp);
3472 if (!nd->nd_repstat)
3473 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
3474 NFSEXITCODE2(0, nd);
3475 return (0);
3476 }
3477
3478 /*
3479 * nfsv4 open confirm service
3480 */
3481 int
nfsrvd_openconfirm(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3482 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3483 vnode_t vp, __unused struct nfsexstuff *exp)
3484 {
3485 u_int32_t *tl;
3486 struct nfsstate st, *stp = &st;
3487 int error = 0;
3488 nfsv4stateid_t stateid;
3489 nfsquad_t clientid;
3490 struct thread *p = curthread;
3491
3492 if ((nd->nd_flag & ND_NFSV41) != 0) {
3493 nd->nd_repstat = NFSERR_NOTSUPP;
3494 goto nfsmout;
3495 }
3496 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3497 stp->ls_ownerlen = 0;
3498 stp->ls_op = nd->nd_rp;
3499 stp->ls_uid = nd->nd_cred->cr_uid;
3500 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3501 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3502 NFSX_STATEIDOTHER);
3503 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3504 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3505 stp->ls_flags = NFSLCK_CONFIRM;
3506 clientid.lval[0] = stp->ls_stateid.other[0];
3507 clientid.lval[1] = stp->ls_stateid.other[1];
3508 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3509 if ((nd->nd_flag & ND_NFSV41) != 0)
3510 clientid.qval = nd->nd_clientid.qval;
3511 else if (nd->nd_clientid.qval != clientid.qval)
3512 printf("EEK11 multiple clids\n");
3513 } else {
3514 if ((nd->nd_flag & ND_NFSV41) != 0)
3515 printf("EEK! no clientid from session\n");
3516 nd->nd_flag |= ND_IMPLIEDCLID;
3517 nd->nd_clientid.qval = clientid.qval;
3518 }
3519 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
3520 NULL);
3521 if (!nd->nd_repstat) {
3522 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3523 *tl++ = txdr_unsigned(stateid.seqid);
3524 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3525 }
3526 nfsmout:
3527 vput(vp);
3528 NFSEXITCODE2(error, nd);
3529 return (error);
3530 }
3531
3532 /*
3533 * nfsv4 open downgrade service
3534 */
3535 int
nfsrvd_opendowngrade(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)3536 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3537 vnode_t vp, __unused struct nfsexstuff *exp)
3538 {
3539 u_int32_t *tl;
3540 int i;
3541 struct nfsstate st, *stp = &st;
3542 int error = 0;
3543 nfsv4stateid_t stateid;
3544 nfsquad_t clientid;
3545 struct thread *p = curthread;
3546
3547 /* opendowngrade can only work on a file object.*/
3548 if (vp->v_type != VREG) {
3549 error = NFSERR_INVAL;
3550 goto nfsmout;
3551 }
3552 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3553 stp->ls_ownerlen = 0;
3554 stp->ls_op = nd->nd_rp;
3555 stp->ls_uid = nd->nd_cred->cr_uid;
3556 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3557 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3558 NFSX_STATEIDOTHER);
3559 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3560
3561 /*
3562 * For the special stateid of other all 0s and seqid == 1, set the
3563 * stateid to the current stateid, if it is set.
3564 */
3565 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
3566 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
3567 stp->ls_stateid.other[2] == 0) {
3568 if ((nd->nd_flag & ND_CURSTATEID) != 0)
3569 stp->ls_stateid = nd->nd_curstateid;
3570 else {
3571 nd->nd_repstat = NFSERR_BADSTATEID;
3572 goto nfsmout;
3573 }
3574 }
3575
3576 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3577 i = fxdr_unsigned(int, *tl++);
3578 if ((nd->nd_flag & ND_NFSV41) != 0)
3579 i &= ~NFSV4OPEN_WANTDELEGMASK;
3580 switch (i) {
3581 case NFSV4OPEN_ACCESSREAD:
3582 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3583 break;
3584 case NFSV4OPEN_ACCESSWRITE:
3585 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3586 break;
3587 case NFSV4OPEN_ACCESSBOTH:
3588 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3589 NFSLCK_DOWNGRADE);
3590 break;
3591 default:
3592 nd->nd_repstat = NFSERR_INVAL;
3593 }
3594 i = fxdr_unsigned(int, *tl);
3595 switch (i) {
3596 case NFSV4OPEN_DENYNONE:
3597 break;
3598 case NFSV4OPEN_DENYREAD:
3599 stp->ls_flags |= NFSLCK_READDENY;
3600 break;
3601 case NFSV4OPEN_DENYWRITE:
3602 stp->ls_flags |= NFSLCK_WRITEDENY;
3603 break;
3604 case NFSV4OPEN_DENYBOTH:
3605 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3606 break;
3607 default:
3608 nd->nd_repstat = NFSERR_INVAL;
3609 }
3610
3611 clientid.lval[0] = stp->ls_stateid.other[0];
3612 clientid.lval[1] = stp->ls_stateid.other[1];
3613 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3614 if ((nd->nd_flag & ND_NFSV41) != 0)
3615 clientid.qval = nd->nd_clientid.qval;
3616 else if (nd->nd_clientid.qval != clientid.qval)
3617 printf("EEK12 multiple clids\n");
3618 } else {
3619 if ((nd->nd_flag & ND_NFSV41) != 0)
3620 printf("EEK! no clientid from session\n");
3621 nd->nd_flag |= ND_IMPLIEDCLID;
3622 nd->nd_clientid.qval = clientid.qval;
3623 }
3624 if (!nd->nd_repstat)
3625 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3626 nd, p, NULL);
3627 if (!nd->nd_repstat) {
3628 /* For NFSv4.1, set the Current StateID. */
3629 if ((nd->nd_flag & ND_NFSV41) != 0) {
3630 nd->nd_curstateid = stateid;
3631 nd->nd_flag |= ND_CURSTATEID;
3632 }
3633 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3634 *tl++ = txdr_unsigned(stateid.seqid);
3635 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3636 }
3637 nfsmout:
3638 vput(vp);
3639 NFSEXITCODE2(error, nd);
3640 return (error);
3641 }
3642
3643 /*
3644 * nfsv4 renew lease service
3645 */
3646 int
nfsrvd_renew(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)3647 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3648 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3649 {
3650 u_int32_t *tl;
3651 int error = 0;
3652 nfsquad_t clientid;
3653 struct thread *p = curthread;
3654
3655 if ((nd->nd_flag & ND_NFSV41) != 0) {
3656 nd->nd_repstat = NFSERR_NOTSUPP;
3657 goto nfsmout;
3658 }
3659 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3660 goto nfsmout;
3661 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3662 clientid.lval[0] = *tl++;
3663 clientid.lval[1] = *tl;
3664 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
3665 if ((nd->nd_flag & ND_NFSV41) != 0)
3666 clientid.qval = nd->nd_clientid.qval;
3667 else if (nd->nd_clientid.qval != clientid.qval)
3668 printf("EEK13 multiple clids\n");
3669 } else {
3670 if ((nd->nd_flag & ND_NFSV41) != 0)
3671 printf("EEK! no clientid from session\n");
3672 nd->nd_flag |= ND_IMPLIEDCLID;
3673 nd->nd_clientid.qval = clientid.qval;
3674 }
3675 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3676 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
3677 nfsmout:
3678 NFSEXITCODE2(error, nd);
3679 return (error);
3680 }
3681
3682 /*
3683 * nfsv4 security info service
3684 */
3685 int
nfsrvd_secinfo(struct nfsrv_descript * nd,int isdgram,vnode_t dp,struct nfsexstuff * exp)3686 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3687 vnode_t dp, struct nfsexstuff *exp)
3688 {
3689 u_int32_t *tl;
3690 int len;
3691 struct nameidata named;
3692 vnode_t dirp = NULL, vp;
3693 struct nfsrvfh fh;
3694 struct nfsexstuff retnes;
3695 u_int32_t *sizp;
3696 int error = 0, i;
3697 uint64_t savflag;
3698 char *bufp;
3699 u_long *hashp;
3700 struct thread *p = curthread;
3701
3702 /*
3703 * All this just to get the export flags for the name.
3704 */
3705 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3706 LOCKLEAF);
3707 nfsvno_setpathbuf(&named, &bufp, &hashp);
3708 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3709 if (error) {
3710 vput(dp);
3711 nfsvno_relpathbuf(&named);
3712 goto out;
3713 }
3714 if (!nd->nd_repstat) {
3715 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
3716 } else {
3717 vput(dp);
3718 nfsvno_relpathbuf(&named);
3719 }
3720 if (dirp)
3721 vrele(dirp);
3722 if (nd->nd_repstat)
3723 goto out;
3724 nfsvno_relpathbuf(&named);
3725 fh.nfsrvfh_len = NFSX_MYFH;
3726 vp = named.ni_vp;
3727 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3728 vput(vp);
3729 savflag = nd->nd_flag;
3730 if (!nd->nd_repstat) {
3731 /*
3732 * Pretend the next op is Secinfo, so that no wrongsec
3733 * test will be done.
3734 */
3735 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
3736 NFSV4OP_SECINFO);
3737 if (vp)
3738 vput(vp);
3739 }
3740 nd->nd_flag = savflag;
3741 if (nd->nd_repstat)
3742 goto out;
3743
3744 /*
3745 * Finally have the export flags for name, so we can create
3746 * the security info.
3747 */
3748 len = 0;
3749 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3750
3751 /* If nes_numsecflavor == 0, all are allowed. */
3752 if (retnes.nes_numsecflavor == 0) {
3753 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3754 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
3755 *tl = txdr_unsigned(RPCAUTH_GSS);
3756 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3757 nfsgss_mechlist[KERBV_MECH].len);
3758 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3759 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3760 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3761 *tl = txdr_unsigned(RPCAUTH_GSS);
3762 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3763 nfsgss_mechlist[KERBV_MECH].len);
3764 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3765 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3766 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3767 *tl = txdr_unsigned(RPCAUTH_GSS);
3768 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3769 nfsgss_mechlist[KERBV_MECH].len);
3770 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3771 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3772 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3773 len = 4;
3774 }
3775 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3776 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3777 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3778 *tl = txdr_unsigned(RPCAUTH_UNIX);
3779 len++;
3780 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3781 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3782 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3783 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3784 nfsgss_mechlist[KERBV_MECH].len);
3785 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3786 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3787 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3788 len++;
3789 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3790 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3791 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3792 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3793 nfsgss_mechlist[KERBV_MECH].len);
3794 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3795 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3796 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3797 len++;
3798 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3799 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3800 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3801 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3802 nfsgss_mechlist[KERBV_MECH].len);
3803 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3804 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3805 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3806 len++;
3807 }
3808 }
3809 *sizp = txdr_unsigned(len);
3810
3811 out:
3812 NFSEXITCODE2(error, nd);
3813 return (error);
3814 }
3815
3816 /*
3817 * nfsv4 security info no name service
3818 */
3819 int
nfsrvd_secinfononame(struct nfsrv_descript * nd,int isdgram,vnode_t dp,struct nfsexstuff * exp)3820 nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram,
3821 vnode_t dp, struct nfsexstuff *exp)
3822 {
3823 uint32_t *tl, *sizp;
3824 struct nameidata named;
3825 vnode_t dirp = NULL, vp;
3826 struct nfsrvfh fh;
3827 struct nfsexstuff retnes;
3828 int error = 0, fhstyle, i, len;
3829 uint64_t savflag;
3830 char *bufp;
3831 u_long *hashp;
3832 struct thread *p = curthread;
3833
3834 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
3835 fhstyle = fxdr_unsigned(int, *tl);
3836 switch (fhstyle) {
3837 case NFSSECINFONONAME_PARENT:
3838 if (dp->v_type != VDIR) {
3839 vput(dp);
3840 nd->nd_repstat = NFSERR_NOTDIR;
3841 goto nfsmout;
3842 }
3843 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3844 LOCKLEAF);
3845 nfsvno_setpathbuf(&named, &bufp, &hashp);
3846 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3847 if (error != 0) {
3848 vput(dp);
3849 nfsvno_relpathbuf(&named);
3850 goto nfsmout;
3851 }
3852 if (nd->nd_repstat == 0)
3853 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp);
3854 else
3855 vput(dp);
3856 if (dirp != NULL)
3857 vrele(dirp);
3858 nfsvno_relpathbuf(&named);
3859 vp = named.ni_vp;
3860 break;
3861 case NFSSECINFONONAME_CURFH:
3862 vp = dp;
3863 break;
3864 default:
3865 nd->nd_repstat = NFSERR_INVAL;
3866 vput(dp);
3867 }
3868 if (nd->nd_repstat != 0)
3869 goto nfsmout;
3870 fh.nfsrvfh_len = NFSX_MYFH;
3871 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3872 vput(vp);
3873 savflag = nd->nd_flag;
3874 if (nd->nd_repstat == 0) {
3875 /*
3876 * Pretend the next op is Secinfo, so that no wrongsec
3877 * test will be done.
3878 */
3879 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
3880 NFSV4OP_SECINFO);
3881 if (vp != NULL)
3882 vput(vp);
3883 }
3884 nd->nd_flag = savflag;
3885 if (nd->nd_repstat != 0)
3886 goto nfsmout;
3887
3888 /*
3889 * Finally have the export flags for fh/parent, so we can create
3890 * the security info.
3891 */
3892 len = 0;
3893 NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED);
3894
3895 /* If nes_numsecflavor == 0, all are allowed. */
3896 if (retnes.nes_numsecflavor == 0) {
3897 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3898 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
3899 *tl = txdr_unsigned(RPCAUTH_GSS);
3900 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3901 nfsgss_mechlist[KERBV_MECH].len);
3902 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3903 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3904 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3905 *tl = txdr_unsigned(RPCAUTH_GSS);
3906 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3907 nfsgss_mechlist[KERBV_MECH].len);
3908 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
3909 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3910 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3911 *tl = txdr_unsigned(RPCAUTH_GSS);
3912 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3913 nfsgss_mechlist[KERBV_MECH].len);
3914 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3915 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3916 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3917 len = 4;
3918 }
3919 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3920 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3921 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3922 *tl = txdr_unsigned(RPCAUTH_UNIX);
3923 len++;
3924 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3925 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3926 *tl = txdr_unsigned(RPCAUTH_GSS);
3927 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3928 nfsgss_mechlist[KERBV_MECH].len);
3929 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3930 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3931 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3932 len++;
3933 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3934 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3935 *tl = txdr_unsigned(RPCAUTH_GSS);
3936 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3937 nfsgss_mechlist[KERBV_MECH].len);
3938 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3939 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3940 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3941 len++;
3942 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3943 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
3944 *tl = txdr_unsigned(RPCAUTH_GSS);
3945 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3946 nfsgss_mechlist[KERBV_MECH].len);
3947 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
3948 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3949 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3950 len++;
3951 }
3952 }
3953 *sizp = txdr_unsigned(len);
3954
3955 nfsmout:
3956 NFSEXITCODE2(error, nd);
3957 return (error);
3958 }
3959
3960 /*
3961 * nfsv4 set client id service
3962 */
3963 int
nfsrvd_setclientid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)3964 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3965 __unused vnode_t vp, __unused struct nfsexstuff *exp)
3966 {
3967 u_int32_t *tl;
3968 int i;
3969 int error = 0, idlen;
3970 struct nfsclient *clp = NULL;
3971 #ifdef INET
3972 struct sockaddr_in *rin;
3973 #endif
3974 #ifdef INET6
3975 struct sockaddr_in6 *rin6;
3976 #endif
3977 #if defined(INET) || defined(INET6)
3978 u_char *ucp, *ucp2;
3979 #endif
3980 u_char *verf, *addrbuf;
3981 nfsquad_t clientid, confirm;
3982 struct thread *p = curthread;
3983
3984 if ((nd->nd_flag & ND_NFSV41) != 0) {
3985 nd->nd_repstat = NFSERR_NOTSUPP;
3986 goto nfsmout;
3987 }
3988 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
3989 goto out;
3990 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3991 verf = (u_char *)tl;
3992 tl += (NFSX_VERF / NFSX_UNSIGNED);
3993 i = fxdr_unsigned(int, *tl);
3994 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3995 nd->nd_repstat = NFSERR_BADXDR;
3996 goto nfsmout;
3997 }
3998 idlen = i;
3999 if (nd->nd_flag & ND_GSS)
4000 i += nd->nd_princlen;
4001 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4002 M_ZERO);
4003 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4004 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4005 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4006 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4007 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4008 M_WAITOK | M_ZERO);
4009 clp->lc_req.nr_cred = NULL;
4010 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4011 clp->lc_idlen = idlen;
4012 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4013 if (error)
4014 goto nfsmout;
4015 if (nd->nd_flag & ND_GSS) {
4016 clp->lc_flags = LCL_GSS;
4017 if (nd->nd_flag & ND_GSSINTEGRITY)
4018 clp->lc_flags |= LCL_GSSINTEGRITY;
4019 else if (nd->nd_flag & ND_GSSPRIVACY)
4020 clp->lc_flags |= LCL_GSSPRIVACY;
4021 } else {
4022 clp->lc_flags = 0;
4023 }
4024 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
4025 clp->lc_flags |= LCL_NAME;
4026 clp->lc_namelen = nd->nd_princlen;
4027 clp->lc_name = &clp->lc_id[idlen];
4028 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4029 } else {
4030 clp->lc_uid = nd->nd_cred->cr_uid;
4031 clp->lc_gid = nd->nd_cred->cr_gid;
4032 }
4033
4034 /* If the client is using TLS, do so for the callback connection. */
4035 if (nd->nd_flag & ND_TLS)
4036 clp->lc_flags |= LCL_TLSCB;
4037
4038 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4039 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
4040 error = nfsrv_getclientipaddr(nd, clp);
4041 if (error)
4042 goto nfsmout;
4043 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4044 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
4045
4046 /*
4047 * nfsrv_setclient() does the actual work of adding it to the
4048 * client list. If there is no error, the structure has been
4049 * linked into the client list and clp should no longer be used
4050 * here. When an error is returned, it has not been linked in,
4051 * so it should be free'd.
4052 */
4053 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4054 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
4055 /*
4056 * 8 is the maximum length of the port# string.
4057 */
4058 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
4059 switch (clp->lc_req.nr_nam->sa_family) {
4060 #ifdef INET
4061 case AF_INET:
4062 if (clp->lc_flags & LCL_TCPCALLBACK)
4063 (void) nfsm_strtom(nd, "tcp", 3);
4064 else
4065 (void) nfsm_strtom(nd, "udp", 3);
4066 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4067 ucp = (u_char *)&rin->sin_addr.s_addr;
4068 ucp2 = (u_char *)&rin->sin_port;
4069 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
4070 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
4071 ucp2[0] & 0xff, ucp2[1] & 0xff);
4072 break;
4073 #endif
4074 #ifdef INET6
4075 case AF_INET6:
4076 if (clp->lc_flags & LCL_TCPCALLBACK)
4077 (void) nfsm_strtom(nd, "tcp6", 4);
4078 else
4079 (void) nfsm_strtom(nd, "udp6", 4);
4080 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4081 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
4082 INET6_ADDRSTRLEN);
4083 if (ucp != NULL)
4084 i = strlen(ucp);
4085 else
4086 i = 0;
4087 ucp2 = (u_char *)&rin6->sin6_port;
4088 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
4089 ucp2[1] & 0xff);
4090 break;
4091 #endif
4092 }
4093 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
4094 free(addrbuf, M_TEMP);
4095 }
4096 if (clp) {
4097 free(clp->lc_req.nr_nam, M_SONAME);
4098 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4099 free(clp->lc_stateid, M_NFSDCLIENT);
4100 free(clp, M_NFSDCLIENT);
4101 }
4102 if (!nd->nd_repstat) {
4103 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
4104 *tl++ = clientid.lval[0];
4105 *tl++ = clientid.lval[1];
4106 *tl++ = confirm.lval[0];
4107 *tl = confirm.lval[1];
4108 }
4109
4110 out:
4111 NFSEXITCODE2(0, nd);
4112 return (0);
4113 nfsmout:
4114 if (clp) {
4115 free(clp->lc_req.nr_nam, M_SONAME);
4116 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4117 free(clp->lc_stateid, M_NFSDCLIENT);
4118 free(clp, M_NFSDCLIENT);
4119 }
4120 NFSEXITCODE2(error, nd);
4121 return (error);
4122 }
4123
4124 /*
4125 * nfsv4 set client id confirm service
4126 */
4127 int
nfsrvd_setclientidcfrm(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4128 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
4129 __unused int isdgram, __unused vnode_t vp,
4130 __unused struct nfsexstuff *exp)
4131 {
4132 u_int32_t *tl;
4133 int error = 0;
4134 nfsquad_t clientid, confirm;
4135 struct thread *p = curthread;
4136
4137 if ((nd->nd_flag & ND_NFSV41) != 0) {
4138 nd->nd_repstat = NFSERR_NOTSUPP;
4139 goto nfsmout;
4140 }
4141 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4142 goto nfsmout;
4143 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
4144 clientid.lval[0] = *tl++;
4145 clientid.lval[1] = *tl++;
4146 confirm.lval[0] = *tl++;
4147 confirm.lval[1] = *tl;
4148
4149 /*
4150 * nfsrv_getclient() searches the client list for a match and
4151 * returns the appropriate NFSERR status.
4152 */
4153 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
4154 NULL, NULL, confirm, 0, nd, p);
4155 nfsmout:
4156 NFSEXITCODE2(error, nd);
4157 return (error);
4158 }
4159
4160 /*
4161 * nfsv4 verify service
4162 */
4163 int
nfsrvd_verify(struct nfsrv_descript * nd,int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)4164 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
4165 vnode_t vp, __unused struct nfsexstuff *exp)
4166 {
4167 int error = 0, ret, fhsize = NFSX_MYFH;
4168 struct nfsvattr nva;
4169 struct statfs *sf;
4170 struct nfsfsinfo fs;
4171 fhandle_t fh;
4172 struct thread *p = curthread;
4173
4174 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
4175 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
4176 if (!nd->nd_repstat)
4177 nd->nd_repstat = nfsvno_statfs(vp, sf);
4178 if (!nd->nd_repstat)
4179 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
4180 if (!nd->nd_repstat) {
4181 nfsvno_getfs(&fs, isdgram);
4182 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
4183 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
4184 if (!error) {
4185 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
4186 if (ret == 0)
4187 nd->nd_repstat = NFSERR_SAME;
4188 else if (ret != NFSERR_NOTSAME)
4189 nd->nd_repstat = ret;
4190 } else if (ret)
4191 nd->nd_repstat = ret;
4192 }
4193 }
4194 vput(vp);
4195 free(sf, M_STATFS);
4196 NFSEXITCODE2(error, nd);
4197 return (error);
4198 }
4199
4200 /*
4201 * nfs openattr rpc
4202 */
4203 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)4204 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
4205 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
4206 __unused struct nfsexstuff *exp)
4207 {
4208 u_int32_t *tl;
4209 int error = 0, createdir __unused;
4210
4211 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
4212 createdir = fxdr_unsigned(int, *tl);
4213 nd->nd_repstat = NFSERR_NOTSUPP;
4214 nfsmout:
4215 vrele(dp);
4216 NFSEXITCODE2(error, nd);
4217 return (error);
4218 }
4219
4220 /*
4221 * nfsv4 release lock owner service
4222 */
4223 int
nfsrvd_releaselckown(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4224 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
4225 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4226 {
4227 u_int32_t *tl;
4228 struct nfsstate *stp = NULL;
4229 int error = 0, len;
4230 nfsquad_t clientid;
4231 struct thread *p = curthread;
4232
4233 if ((nd->nd_flag & ND_NFSV41) != 0) {
4234 nd->nd_repstat = NFSERR_NOTSUPP;
4235 goto nfsmout;
4236 }
4237 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4238 goto nfsmout;
4239 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
4240 len = fxdr_unsigned(int, *(tl + 2));
4241 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
4242 nd->nd_repstat = NFSERR_BADXDR;
4243 goto nfsmout;
4244 }
4245 stp = malloc(sizeof (struct nfsstate) + len,
4246 M_NFSDSTATE, M_WAITOK);
4247 stp->ls_ownerlen = len;
4248 stp->ls_op = NULL;
4249 stp->ls_flags = NFSLCK_RELEASE;
4250 stp->ls_uid = nd->nd_cred->cr_uid;
4251 clientid.lval[0] = *tl++;
4252 clientid.lval[1] = *tl;
4253 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
4254 if ((nd->nd_flag & ND_NFSV41) != 0)
4255 clientid.qval = nd->nd_clientid.qval;
4256 else if (nd->nd_clientid.qval != clientid.qval)
4257 printf("EEK14 multiple clids\n");
4258 } else {
4259 if ((nd->nd_flag & ND_NFSV41) != 0)
4260 printf("EEK! no clientid from session\n");
4261 nd->nd_flag |= ND_IMPLIEDCLID;
4262 nd->nd_clientid.qval = clientid.qval;
4263 }
4264 error = nfsrv_mtostr(nd, stp->ls_owner, len);
4265 if (error)
4266 goto nfsmout;
4267 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
4268 free(stp, M_NFSDSTATE);
4269
4270 NFSEXITCODE2(0, nd);
4271 return (0);
4272 nfsmout:
4273 if (stp)
4274 free(stp, M_NFSDSTATE);
4275 NFSEXITCODE2(error, nd);
4276 return (error);
4277 }
4278
4279 /*
4280 * nfsv4 exchange_id service
4281 */
4282 int
nfsrvd_exchangeid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4283 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
4284 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4285 {
4286 uint32_t *tl;
4287 int error = 0, i, idlen;
4288 struct nfsclient *clp = NULL;
4289 nfsquad_t clientid, confirm;
4290 uint8_t *verf;
4291 uint32_t sp4type, v41flags;
4292 struct timespec verstime;
4293 nfsopbit_t mustops, allowops;
4294 #ifdef INET
4295 struct sockaddr_in *sin, *rin;
4296 #endif
4297 #ifdef INET6
4298 struct sockaddr_in6 *sin6, *rin6;
4299 #endif
4300 struct thread *p = curthread;
4301 char *s;
4302
4303 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4304 goto nfsmout;
4305 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
4306 verf = (uint8_t *)tl;
4307 tl += (NFSX_VERF / NFSX_UNSIGNED);
4308 i = fxdr_unsigned(int, *tl);
4309 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
4310 nd->nd_repstat = NFSERR_BADXDR;
4311 goto nfsmout;
4312 }
4313 idlen = i;
4314 if (nd->nd_flag & ND_GSS)
4315 i += nd->nd_princlen;
4316 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
4317 M_ZERO);
4318 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
4319 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
4320 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
4321 /* Allocated large enough for an AF_INET or AF_INET6 socket. */
4322 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
4323 M_WAITOK | M_ZERO);
4324 switch (nd->nd_nam->sa_family) {
4325 #ifdef INET
4326 case AF_INET:
4327 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
4328 sin = (struct sockaddr_in *)nd->nd_nam;
4329 rin->sin_family = AF_INET;
4330 rin->sin_len = sizeof(struct sockaddr_in);
4331 rin->sin_port = 0;
4332 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
4333 break;
4334 #endif
4335 #ifdef INET6
4336 case AF_INET6:
4337 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
4338 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
4339 rin6->sin6_family = AF_INET6;
4340 rin6->sin6_len = sizeof(struct sockaddr_in6);
4341 rin6->sin6_port = 0;
4342 rin6->sin6_addr = sin6->sin6_addr;
4343 break;
4344 #endif
4345 }
4346 clp->lc_req.nr_cred = NULL;
4347 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
4348 clp->lc_idlen = idlen;
4349 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
4350 if (error != 0)
4351 goto nfsmout;
4352 if ((nd->nd_flag & ND_GSS) != 0) {
4353 clp->lc_flags = LCL_GSS | LCL_NFSV41;
4354 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
4355 clp->lc_flags |= LCL_GSSINTEGRITY;
4356 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
4357 clp->lc_flags |= LCL_GSSPRIVACY;
4358 } else
4359 clp->lc_flags = LCL_NFSV41;
4360 if ((nd->nd_flag & ND_NFSV42) != 0)
4361 clp->lc_flags |= LCL_NFSV42;
4362 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
4363 clp->lc_flags |= LCL_NAME;
4364 clp->lc_namelen = nd->nd_princlen;
4365 clp->lc_name = &clp->lc_id[idlen];
4366 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
4367 } else {
4368 clp->lc_uid = nd->nd_cred->cr_uid;
4369 clp->lc_gid = nd->nd_cred->cr_gid;
4370 }
4371 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
4372 v41flags = fxdr_unsigned(uint32_t, *tl++);
4373 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
4374 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
4375 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
4376 nd->nd_repstat = NFSERR_INVAL;
4377 goto nfsmout;
4378 }
4379 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
4380 confirm.lval[1] = 1;
4381 else
4382 confirm.lval[1] = 0;
4383 if (nfsrv_devidcnt == 0)
4384 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
4385 else
4386 v41flags = NFSV4EXCH_USEPNFSMDS;
4387 sp4type = fxdr_unsigned(uint32_t, *tl);
4388 if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4389 if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 ||
4390 nd->nd_princlen == 0)
4391 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
4392 if (nd->nd_repstat == 0)
4393 nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL);
4394 if (nd->nd_repstat == 0)
4395 nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL);
4396 if (nd->nd_repstat != 0)
4397 goto nfsmout;
4398 NFSOPBIT_CLRNOTMUST(&mustops);
4399 NFSSET_OPBIT(&clp->lc_mustops, &mustops);
4400 NFSOPBIT_CLRNOTALLOWED(&allowops);
4401 NFSSET_OPBIT(&clp->lc_allowops, &allowops);
4402 clp->lc_flags |= LCL_MACHCRED;
4403 } else if (sp4type != NFSV4EXCH_SP4NONE) {
4404 nd->nd_repstat = NFSERR_NOTSUPP;
4405 goto nfsmout;
4406 }
4407
4408 /*
4409 * nfsrv_setclient() does the actual work of adding it to the
4410 * client list. If there is no error, the structure has been
4411 * linked into the client list and clp should no longer be used
4412 * here. When an error is returned, it has not been linked in,
4413 * so it should be free'd.
4414 */
4415 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
4416 if (clp != NULL) {
4417 free(clp->lc_req.nr_nam, M_SONAME);
4418 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4419 free(clp->lc_stateid, M_NFSDCLIENT);
4420 free(clp, M_NFSDCLIENT);
4421 }
4422 if (nd->nd_repstat == 0) {
4423 if (confirm.lval[1] != 0)
4424 v41flags |= NFSV4EXCH_CONFIRMEDR;
4425 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
4426 *tl++ = clientid.lval[0]; /* ClientID */
4427 *tl++ = clientid.lval[1];
4428 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */
4429 *tl++ = txdr_unsigned(v41flags); /* Exch flags */
4430 *tl = txdr_unsigned(sp4type); /* No SSV */
4431 if (sp4type == NFSV4EXCH_SP4MACHCRED) {
4432 nfsrv_putopbit(nd, &mustops);
4433 nfsrv_putopbit(nd, &allowops);
4434 }
4435 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER);
4436 txdr_hyper(nfsrv_owner_minor, tl); /* Owner Minor */
4437 if (nfsrv_owner_major[0] != 0)
4438 s = nfsrv_owner_major;
4439 else
4440 s = nd->nd_cred->cr_prison->pr_hostuuid;
4441 nfsm_strtom(nd, s, strlen(s)); /* Owner Major */
4442 if (nfsrv_scope[0] != 0)
4443 s = nfsrv_scope;
4444 else
4445 s = nd->nd_cred->cr_prison->pr_hostuuid;
4446 nfsm_strtom(nd, s, strlen(s) ); /* Scope */
4447 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4448 *tl = txdr_unsigned(1);
4449 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
4450 (void)nfsm_strtom(nd, version, strlen(version));
4451 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
4452 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */
4453 verstime.tv_nsec = 0;
4454 txdr_nfsv4time(&verstime, tl);
4455 }
4456 NFSEXITCODE2(0, nd);
4457 return (0);
4458 nfsmout:
4459 if (clp != NULL) {
4460 free(clp->lc_req.nr_nam, M_SONAME);
4461 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
4462 free(clp->lc_stateid, M_NFSDCLIENT);
4463 free(clp, M_NFSDCLIENT);
4464 }
4465 NFSEXITCODE2(error, nd);
4466 return (error);
4467 }
4468
4469 /*
4470 * nfsv4 create session service
4471 */
4472 int
nfsrvd_createsession(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4473 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
4474 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4475 {
4476 uint32_t *tl;
4477 int error = 0;
4478 nfsquad_t clientid, confirm;
4479 struct nfsdsession *sep = NULL;
4480 uint32_t rdmacnt;
4481 struct thread *p = curthread;
4482 static bool do_printf = true;
4483
4484 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4485 goto nfsmout;
4486 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
4487 M_NFSDSESSION, M_WAITOK | M_ZERO);
4488 sep->sess_refcnt = 1;
4489 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
4490 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
4491 clientid.lval[0] = *tl++;
4492 clientid.lval[1] = *tl++;
4493 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
4494 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
4495 /* Persistent sessions and RDMA are not supported. */
4496 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
4497
4498 /* Fore channel attributes. */
4499 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4500 tl++; /* Header pad always 0. */
4501 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
4502 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
4503 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
4504 if (do_printf)
4505 printf("Consider increasing kern.ipc.maxsockbuf\n");
4506 do_printf = false;
4507 }
4508 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
4509 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
4510 sep->sess_maxresp = 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_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
4516 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
4517 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
4518 if (sep->sess_maxslots > NFSV4_SLOTS)
4519 sep->sess_maxslots = NFSV4_SLOTS;
4520 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4521 if (rdmacnt > 1) {
4522 nd->nd_repstat = NFSERR_BADXDR;
4523 goto nfsmout;
4524 } else if (rdmacnt == 1)
4525 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4526
4527 /* Back channel attributes. */
4528 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
4529 tl++; /* Header pad always 0. */
4530 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
4531 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
4532 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
4533 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
4534 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
4535 rdmacnt = fxdr_unsigned(uint32_t, *tl);
4536 if (rdmacnt > 1) {
4537 nd->nd_repstat = NFSERR_BADXDR;
4538 goto nfsmout;
4539 } else if (rdmacnt == 1)
4540 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4541
4542 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4543 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
4544
4545 /*
4546 * nfsrv_getclient() searches the client list for a match and
4547 * returns the appropriate NFSERR status.
4548 */
4549 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
4550 NULL, sep, confirm, sep->sess_cbprogram, nd, p);
4551 if (nd->nd_repstat == 0) {
4552 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4553 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
4554 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
4555 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
4556 *tl++ = txdr_unsigned(sep->sess_crflags);
4557
4558 /* Fore channel attributes. */
4559 *tl++ = 0;
4560 *tl++ = txdr_unsigned(sep->sess_maxreq);
4561 *tl++ = txdr_unsigned(sep->sess_maxresp);
4562 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
4563 *tl++ = txdr_unsigned(sep->sess_maxops);
4564 *tl++ = txdr_unsigned(sep->sess_maxslots);
4565 *tl++ = txdr_unsigned(1);
4566 *tl++ = txdr_unsigned(0); /* No RDMA. */
4567
4568 /* Back channel attributes. */
4569 *tl++ = 0;
4570 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
4571 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
4572 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
4573 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
4574 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
4575 *tl++ = txdr_unsigned(1);
4576 *tl = txdr_unsigned(0); /* No RDMA. */
4577 }
4578 nfsmout:
4579 if (nd->nd_repstat != 0 && sep != NULL)
4580 free(sep, M_NFSDSESSION);
4581 NFSEXITCODE2(error, nd);
4582 return (error);
4583 }
4584
4585 /*
4586 * nfsv4 sequence service
4587 */
4588 int
nfsrvd_sequence(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4589 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
4590 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4591 {
4592 uint32_t *tl;
4593 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
4594 int cache_this, error = 0;
4595 struct thread *p = curthread;
4596
4597 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4598 goto nfsmout;
4599 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
4600 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
4601 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4602 sequenceid = fxdr_unsigned(uint32_t, *tl++);
4603 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
4604 highest_slotid = fxdr_unsigned(uint32_t, *tl++);
4605 if (*tl == newnfs_true)
4606 cache_this = 1;
4607 else
4608 cache_this = 0;
4609 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
4610 &target_highest_slotid, cache_this, &sflags, p);
4611 if (nd->nd_repstat != NFSERR_BADSLOT)
4612 nd->nd_flag |= ND_HASSEQUENCE;
4613 if (nd->nd_repstat == 0) {
4614 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
4615 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
4616 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
4617 *tl++ = txdr_unsigned(sequenceid);
4618 *tl++ = txdr_unsigned(nd->nd_slotid);
4619 *tl++ = txdr_unsigned(highest_slotid);
4620 *tl++ = txdr_unsigned(target_highest_slotid);
4621 *tl = txdr_unsigned(sflags);
4622 }
4623 nfsmout:
4624 NFSEXITCODE2(error, nd);
4625 return (error);
4626 }
4627
4628 /*
4629 * nfsv4 reclaim complete service
4630 */
4631 int
nfsrvd_reclaimcomplete(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4632 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
4633 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4634 {
4635 uint32_t *tl;
4636 int error = 0, onefs;
4637
4638 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4639 /*
4640 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
4641 * to be used after a file system has been transferred to a different
4642 * file server. However, RFC5661 is somewhat vague w.r.t. this and
4643 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
4644 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
4645 * Therefore, just ignore the rca_one_fs == TRUE operation and return
4646 * NFS_OK without doing anything.
4647 */
4648 onefs = 0;
4649 if (*tl == newnfs_true)
4650 onefs = 1;
4651 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
4652 nfsmout:
4653 NFSEXITCODE2(error, nd);
4654 return (error);
4655 }
4656
4657 /*
4658 * nfsv4 destroy clientid service
4659 */
4660 int
nfsrvd_destroyclientid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4661 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
4662 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4663 {
4664 uint32_t *tl;
4665 nfsquad_t clientid;
4666 int error = 0;
4667 struct thread *p = curthread;
4668
4669 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4670 goto nfsmout;
4671 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4672 clientid.lval[0] = *tl++;
4673 clientid.lval[1] = *tl;
4674 nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p);
4675 nfsmout:
4676 NFSEXITCODE2(error, nd);
4677 return (error);
4678 }
4679
4680 /*
4681 * nfsv4 bind connection to session service
4682 */
4683 int
nfsrvd_bindconnsess(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4684 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
4685 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4686 {
4687 uint32_t *tl;
4688 uint8_t sessid[NFSX_V4SESSIONID];
4689 int error = 0, foreaft;
4690
4691 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4692 goto nfsmout;
4693 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
4694 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
4695 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4696 foreaft = fxdr_unsigned(int, *tl++);
4697 if (*tl == newnfs_true) {
4698 /* RDMA is not supported. */
4699 nd->nd_repstat = NFSERR_NOTSUPP;
4700 goto nfsmout;
4701 }
4702
4703 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
4704 if (nd->nd_repstat == 0) {
4705 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
4706 NFSX_UNSIGNED);
4707 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
4708 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
4709 *tl++ = txdr_unsigned(foreaft);
4710 *tl = newnfs_false;
4711 }
4712 nfsmout:
4713 NFSEXITCODE2(error, nd);
4714 return (error);
4715 }
4716
4717 /*
4718 * nfsv4 destroy session service
4719 */
4720 int
nfsrvd_destroysession(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4721 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
4722 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4723 {
4724 uint8_t *cp, sessid[NFSX_V4SESSIONID];
4725 int error = 0;
4726
4727 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
4728 goto nfsmout;
4729 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
4730 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
4731 nd->nd_repstat = nfsrv_destroysession(nd, sessid);
4732 nfsmout:
4733 NFSEXITCODE2(error, nd);
4734 return (error);
4735 }
4736
4737 /*
4738 * nfsv4 free stateid service
4739 */
4740 int
nfsrvd_freestateid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)4741 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
4742 __unused vnode_t vp, __unused struct nfsexstuff *exp)
4743 {
4744 uint32_t *tl;
4745 nfsv4stateid_t stateid;
4746 int error = 0;
4747 struct thread *p = curthread;
4748
4749 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
4750 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4751 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4752
4753 /*
4754 * For the special stateid of other all 0s and seqid == 1, set the
4755 * stateid to the current stateid, if it is set.
4756 */
4757 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4758 stateid.other[1] == 0 && stateid.other[2] == 0) {
4759 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4760 stateid = nd->nd_curstateid;
4761 stateid.seqid = 0;
4762 } else {
4763 nd->nd_repstat = NFSERR_BADSTATEID;
4764 goto nfsmout;
4765 }
4766 }
4767
4768 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
4769
4770 /* If the current stateid has been free'd, unset it. */
4771 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
4772 stateid.other[0] == nd->nd_curstateid.other[0] &&
4773 stateid.other[1] == nd->nd_curstateid.other[1] &&
4774 stateid.other[2] == nd->nd_curstateid.other[2])
4775 nd->nd_flag &= ~ND_CURSTATEID;
4776 nfsmout:
4777 NFSEXITCODE2(error, nd);
4778 return (error);
4779 }
4780
4781 /*
4782 * nfsv4 layoutget service
4783 */
4784 int
nfsrvd_layoutget(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)4785 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
4786 vnode_t vp, struct nfsexstuff *exp)
4787 {
4788 uint32_t *tl;
4789 nfsv4stateid_t stateid;
4790 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
4791 uint64_t offset, len, minlen;
4792 char *layp;
4793 struct thread *p = curthread;
4794
4795 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
4796 NFSX_STATEID);
4797 tl++; /* Signal layout available. Ignore for now. */
4798 layouttype = fxdr_unsigned(int, *tl++);
4799 iomode = fxdr_unsigned(int, *tl++);
4800 offset = fxdr_hyper(tl); tl += 2;
4801 len = fxdr_hyper(tl); tl += 2;
4802 minlen = fxdr_hyper(tl); tl += 2;
4803 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4804 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4805 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4806 maxcnt = fxdr_unsigned(int, *tl);
4807 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
4808 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
4809 (uintmax_t)minlen);
4810 if (len < minlen ||
4811 (minlen != UINT64_MAX && offset + minlen < offset) ||
4812 (len != UINT64_MAX && offset + len < offset)) {
4813 nd->nd_repstat = NFSERR_INVAL;
4814 goto nfsmout;
4815 }
4816
4817 /*
4818 * For the special stateid of other all 0s and seqid == 1, set the
4819 * stateid to the current stateid, if it is set.
4820 */
4821 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4822 stateid.other[1] == 0 && stateid.other[2] == 0) {
4823 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4824 stateid = nd->nd_curstateid;
4825 stateid.seqid = 0;
4826 } else {
4827 nd->nd_repstat = NFSERR_BADSTATEID;
4828 goto nfsmout;
4829 }
4830 }
4831
4832 layp = NULL;
4833 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
4834 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
4835 else if (layouttype == NFSLAYOUT_FLEXFILE)
4836 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
4837 M_WAITOK);
4838 else
4839 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
4840 if (layp != NULL)
4841 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
4842 &iomode, &offset, &len, minlen, &stateid, maxcnt,
4843 &retonclose, &layoutlen, layp, nd->nd_cred, p);
4844 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
4845 layoutlen);
4846 if (nd->nd_repstat == 0) {
4847 /* For NFSv4.1, set the Current StateID. */
4848 if ((nd->nd_flag & ND_NFSV41) != 0) {
4849 nd->nd_curstateid = stateid;
4850 nd->nd_flag |= ND_CURSTATEID;
4851 }
4852 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
4853 2 * NFSX_HYPER);
4854 *tl++ = txdr_unsigned(retonclose);
4855 *tl++ = txdr_unsigned(stateid.seqid);
4856 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
4857 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4858 *tl++ = txdr_unsigned(1); /* Only returns one layout. */
4859 txdr_hyper(offset, tl); tl += 2;
4860 txdr_hyper(len, tl); tl += 2;
4861 *tl++ = txdr_unsigned(iomode);
4862 *tl = txdr_unsigned(layouttype);
4863 nfsm_strtom(nd, layp, layoutlen);
4864 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
4865 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4866 *tl = newnfs_false;
4867 }
4868 free(layp, M_TEMP);
4869 nfsmout:
4870 vput(vp);
4871 NFSEXITCODE2(error, nd);
4872 return (error);
4873 }
4874
4875 /*
4876 * nfsv4 layoutcommit service
4877 */
4878 int
nfsrvd_layoutcommit(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)4879 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
4880 vnode_t vp, struct nfsexstuff *exp)
4881 {
4882 uint32_t *tl;
4883 nfsv4stateid_t stateid;
4884 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
4885 int hasnewsize;
4886 uint64_t offset, len, newoff = 0, newsize;
4887 struct timespec newmtime;
4888 char *layp;
4889 struct thread *p = curthread;
4890
4891 layp = NULL;
4892 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
4893 NFSX_STATEID);
4894 offset = fxdr_hyper(tl); tl += 2;
4895 len = fxdr_hyper(tl); tl += 2;
4896 reclaim = fxdr_unsigned(int, *tl++);
4897 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4898 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4899 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4900 /*
4901 * For the special stateid of other all 0s and seqid == 1, set the
4902 * stateid to the current stateid, if it is set.
4903 */
4904 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4905 stateid.other[1] == 0 && stateid.other[2] == 0) {
4906 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4907 stateid = nd->nd_curstateid;
4908 stateid.seqid = 0;
4909 } else {
4910 nd->nd_repstat = NFSERR_BADSTATEID;
4911 goto nfsmout;
4912 }
4913 }
4914
4915 hasnewoff = fxdr_unsigned(int, *tl);
4916 if (hasnewoff != 0) {
4917 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
4918 newoff = fxdr_hyper(tl); tl += 2;
4919 } else
4920 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
4921 hasnewmtime = fxdr_unsigned(int, *tl);
4922 if (hasnewmtime != 0) {
4923 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
4924 fxdr_nfsv4time(tl, &newmtime);
4925 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
4926 } else
4927 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
4928 layouttype = fxdr_unsigned(int, *tl++);
4929 maxcnt = fxdr_unsigned(int, *tl);
4930 if (maxcnt > 0) {
4931 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
4932 error = nfsrv_mtostr(nd, layp, maxcnt);
4933 if (error != 0)
4934 goto nfsmout;
4935 }
4936 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
4937 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
4938 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
4939 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
4940 if (nd->nd_repstat == 0) {
4941 if (hasnewsize != 0) {
4942 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
4943 *tl++ = newnfs_true;
4944 txdr_hyper(newsize, tl);
4945 } else {
4946 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
4947 *tl = newnfs_false;
4948 }
4949 }
4950 nfsmout:
4951 free(layp, M_TEMP);
4952 vput(vp);
4953 NFSEXITCODE2(error, nd);
4954 return (error);
4955 }
4956
4957 /*
4958 * nfsv4 layoutreturn service
4959 */
4960 int
nfsrvd_layoutreturn(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)4961 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
4962 vnode_t vp, struct nfsexstuff *exp)
4963 {
4964 uint32_t *tl, *layp;
4965 nfsv4stateid_t stateid;
4966 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
4967 uint64_t offset, len;
4968 struct thread *p = curthread;
4969
4970 layp = NULL;
4971 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4972 reclaim = *tl++;
4973 layouttype = fxdr_unsigned(int, *tl++);
4974 iomode = fxdr_unsigned(int, *tl++);
4975 kind = fxdr_unsigned(int, *tl);
4976 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
4977 layouttype, iomode, kind);
4978 if (kind == NFSV4LAYOUTRET_FILE) {
4979 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
4980 NFSX_UNSIGNED);
4981 offset = fxdr_hyper(tl); tl += 2;
4982 len = fxdr_hyper(tl); tl += 2;
4983 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
4984 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
4985 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4986
4987 /*
4988 * For the special stateid of other all 0s and seqid == 1, set
4989 * the stateid to the current stateid, if it is set.
4990 */
4991 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
4992 stateid.other[1] == 0 && stateid.other[2] == 0) {
4993 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
4994 stateid = nd->nd_curstateid;
4995 stateid.seqid = 0;
4996 } else {
4997 nd->nd_repstat = NFSERR_BADSTATEID;
4998 goto nfsmout;
4999 }
5000 }
5001
5002 maxcnt = fxdr_unsigned(int, *tl);
5003 /*
5004 * There is no fixed upper bound defined in the RFCs,
5005 * but 128Kbytes should be more than sufficient.
5006 */
5007 if (maxcnt < 0 || maxcnt > 131072)
5008 maxcnt = 0;
5009 if (maxcnt > 0) {
5010 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
5011 error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
5012 if (error != 0)
5013 goto nfsmout;
5014 }
5015 } else {
5016 if (reclaim == newnfs_true) {
5017 nd->nd_repstat = NFSERR_INVAL;
5018 goto nfsmout;
5019 }
5020 offset = len = 0;
5021 maxcnt = 0;
5022 }
5023 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
5024 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
5025 nd->nd_cred, p);
5026 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
5027 fnd);
5028 if (nd->nd_repstat == 0) {
5029 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5030 if (fnd != 0) {
5031 *tl = newnfs_true;
5032 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
5033 *tl++ = txdr_unsigned(stateid.seqid);
5034 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
5035 } else
5036 *tl = newnfs_false;
5037 }
5038 nfsmout:
5039 free(layp, M_TEMP);
5040 vput(vp);
5041 NFSEXITCODE2(error, nd);
5042 return (error);
5043 }
5044
5045 /*
5046 * nfsv4 layout error service
5047 */
5048 int
nfsrvd_layouterror(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5049 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
5050 vnode_t vp, struct nfsexstuff *exp)
5051 {
5052 uint32_t *tl;
5053 nfsv4stateid_t stateid;
5054 int cnt, error = 0, i, stat;
5055 int opnum __unused;
5056 char devid[NFSX_V4DEVICEID];
5057 uint64_t offset, len;
5058
5059 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
5060 NFSX_UNSIGNED);
5061 offset = fxdr_hyper(tl); tl += 2;
5062 len = fxdr_hyper(tl); tl += 2;
5063 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5064 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5065 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5066 cnt = fxdr_unsigned(int, *tl);
5067 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
5068 (uintmax_t)len, cnt);
5069 /*
5070 * For the special stateid of other all 0s and seqid == 1, set
5071 * the stateid to the current stateid, if it is set.
5072 */
5073 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5074 stateid.other[1] == 0 && stateid.other[2] == 0) {
5075 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5076 stateid = nd->nd_curstateid;
5077 stateid.seqid = 0;
5078 } else {
5079 nd->nd_repstat = NFSERR_BADSTATEID;
5080 goto nfsmout;
5081 }
5082 }
5083
5084 /*
5085 * Ignore offset, len and stateid for now.
5086 */
5087 for (i = 0; i < cnt; i++) {
5088 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
5089 NFSX_UNSIGNED);
5090 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5091 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5092 stat = fxdr_unsigned(int, *tl++);
5093 opnum = fxdr_unsigned(int, *tl);
5094 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
5095 /*
5096 * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC
5097 * errors, disable the mirror.
5098 */
5099 if (stat != NFSERR_ACCES && stat != NFSERR_STALE &&
5100 stat != NFSERR_NOSPC)
5101 nfsrv_delds(devid, curthread);
5102
5103 /* For NFSERR_NOSPC, mark all deviceids and layouts. */
5104 if (stat == NFSERR_NOSPC)
5105 nfsrv_marknospc(devid, true);
5106 }
5107 nfsmout:
5108 vput(vp);
5109 NFSEXITCODE2(error, nd);
5110 return (error);
5111 }
5112
5113 /*
5114 * nfsv4 layout stats service
5115 */
5116 int
nfsrvd_layoutstats(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5117 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
5118 vnode_t vp, struct nfsexstuff *exp)
5119 {
5120 uint32_t *tl;
5121 nfsv4stateid_t stateid;
5122 int cnt, error = 0;
5123 int layouttype __unused;
5124 char devid[NFSX_V4DEVICEID] __unused;
5125 uint64_t offset __unused, len __unused, readcount __unused;
5126 uint64_t readbytes __unused, writecount __unused, writebytes __unused;
5127
5128 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
5129 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
5130 offset = fxdr_hyper(tl); tl += 2;
5131 len = fxdr_hyper(tl); tl += 2;
5132 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5133 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5134 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5135 readcount = fxdr_hyper(tl); tl += 2;
5136 readbytes = fxdr_hyper(tl); tl += 2;
5137 writecount = fxdr_hyper(tl); tl += 2;
5138 writebytes = fxdr_hyper(tl); tl += 2;
5139 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5140 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5141 layouttype = fxdr_unsigned(int, *tl++);
5142 cnt = fxdr_unsigned(int, *tl);
5143 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
5144 if (error != 0)
5145 goto nfsmout;
5146 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt);
5147 /*
5148 * For the special stateid of other all 0s and seqid == 1, set
5149 * the stateid to the current stateid, if it is set.
5150 */
5151 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5152 stateid.other[1] == 0 && stateid.other[2] == 0) {
5153 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5154 stateid = nd->nd_curstateid;
5155 stateid.seqid = 0;
5156 } else {
5157 nd->nd_repstat = NFSERR_BADSTATEID;
5158 goto nfsmout;
5159 }
5160 }
5161
5162 /*
5163 * No use for the stats for now.
5164 */
5165 nfsmout:
5166 vput(vp);
5167 NFSEXITCODE2(error, nd);
5168 return (error);
5169 }
5170
5171 /*
5172 * nfsv4 io_advise service
5173 */
5174 int
nfsrvd_ioadvise(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5175 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram,
5176 vnode_t vp, struct nfsexstuff *exp)
5177 {
5178 uint32_t *tl;
5179 nfsv4stateid_t stateid;
5180 nfsattrbit_t hints;
5181 int error = 0, ret;
5182 off_t offset, len;
5183
5184 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5185 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5186 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
5187 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
5188 offset = fxdr_hyper(tl); tl += 2;
5189 len = fxdr_hyper(tl);
5190 error = nfsrv_getattrbits(nd, &hints, NULL, NULL);
5191 if (error != 0)
5192 goto nfsmout;
5193 /*
5194 * For the special stateid of other all 0s and seqid == 1, set
5195 * the stateid to the current stateid, if it is set.
5196 */
5197 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
5198 stateid.other[1] == 0 && stateid.other[2] == 0) {
5199 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
5200 stateid = nd->nd_curstateid;
5201 stateid.seqid = 0;
5202 } else {
5203 nd->nd_repstat = NFSERR_BADSTATEID;
5204 goto nfsmout;
5205 }
5206 }
5207
5208 if (offset < 0) {
5209 nd->nd_repstat = NFSERR_INVAL;
5210 goto nfsmout;
5211 }
5212 if (len < 0)
5213 len = 0;
5214 if (vp->v_type != VREG) {
5215 if (vp->v_type == VDIR)
5216 nd->nd_repstat = NFSERR_ISDIR;
5217 else
5218 nd->nd_repstat = NFSERR_WRONGTYPE;
5219 goto nfsmout;
5220 }
5221
5222 /*
5223 * For now, we can only handle WILLNEED and DONTNEED and don't use
5224 * the stateid.
5225 */
5226 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) &&
5227 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) ||
5228 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) &&
5229 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) {
5230 NFSVOPUNLOCK(vp);
5231 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) {
5232 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED);
5233 NFSZERO_ATTRBIT(&hints);
5234 if (ret == 0)
5235 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED);
5236 else
5237 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5238 } else {
5239 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED);
5240 NFSZERO_ATTRBIT(&hints);
5241 if (ret == 0)
5242 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED);
5243 else
5244 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5245 }
5246 vrele(vp);
5247 } else {
5248 NFSZERO_ATTRBIT(&hints);
5249 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL);
5250 vput(vp);
5251 }
5252 nfsrv_putattrbit(nd, &hints);
5253 NFSEXITCODE2(error, nd);
5254 return (error);
5255 nfsmout:
5256 vput(vp);
5257 NFSEXITCODE2(error, nd);
5258 return (error);
5259 }
5260
5261 /*
5262 * nfsv4 getdeviceinfo service
5263 */
5264 int
nfsrvd_getdevinfo(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)5265 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram,
5266 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5267 {
5268 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP];
5269 int cnt, devaddrlen, error = 0, i, layouttype;
5270 char devid[NFSX_V4DEVICEID], *devaddr;
5271 time_t dev_time;
5272
5273 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID);
5274 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
5275 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
5276 layouttype = fxdr_unsigned(int, *tl++);
5277 maxcnt = fxdr_unsigned(uint32_t, *tl++);
5278 cnt = fxdr_unsigned(int, *tl);
5279 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype,
5280 maxcnt, cnt);
5281 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) {
5282 nd->nd_repstat = NFSERR_INVAL;
5283 goto nfsmout;
5284 }
5285 if (cnt > 0) {
5286 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED);
5287 for (i = 0; i < cnt; i++)
5288 notify[i] = fxdr_unsigned(uint32_t, *tl++);
5289 }
5290 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++)
5291 notify[i] = 0;
5292
5293 /*
5294 * Check that the device id is not stale. Device ids are recreated
5295 * each time the nfsd threads are restarted.
5296 */
5297 NFSBCOPY(devid, &dev_time, sizeof(dev_time));
5298 if (dev_time != nfsdev_time) {
5299 nd->nd_repstat = NFSERR_NOENT;
5300 goto nfsmout;
5301 }
5302
5303 /* Look for the device id. */
5304 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt,
5305 notify, &devaddrlen, &devaddr);
5306 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat);
5307 if (nd->nd_repstat == 0) {
5308 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5309 *tl = txdr_unsigned(layouttype);
5310 nfsm_strtom(nd, devaddr, devaddrlen);
5311 cnt = 0;
5312 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) {
5313 if (notify[i] != 0)
5314 cnt = i + 1;
5315 }
5316 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED);
5317 *tl++ = txdr_unsigned(cnt);
5318 for (i = 0; i < cnt; i++)
5319 *tl++ = txdr_unsigned(notify[i]);
5320 } else if (nd->nd_repstat == NFSERR_TOOSMALL) {
5321 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5322 *tl = txdr_unsigned(maxcnt);
5323 }
5324 nfsmout:
5325 NFSEXITCODE2(error, nd);
5326 return (error);
5327 }
5328
5329 /*
5330 * nfsv4 test stateid service
5331 */
5332 int
nfsrvd_teststateid(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)5333 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram,
5334 __unused vnode_t vp, __unused struct nfsexstuff *exp)
5335 {
5336 uint32_t *tl;
5337 nfsv4stateid_t *stateidp = NULL, *tstateidp;
5338 int cnt, error = 0, i, ret;
5339 struct thread *p = curthread;
5340
5341 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5342 cnt = fxdr_unsigned(int, *tl);
5343 if (cnt <= 0 || cnt > 1024) {
5344 nd->nd_repstat = NFSERR_BADXDR;
5345 goto nfsmout;
5346 }
5347 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK);
5348 tstateidp = stateidp;
5349 for (i = 0; i < cnt; i++) {
5350 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
5351 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
5352 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER);
5353 tstateidp++;
5354 }
5355 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5356 *tl = txdr_unsigned(cnt);
5357 tstateidp = stateidp;
5358 for (i = 0; i < cnt; i++) {
5359 ret = nfsrv_teststateid(nd, tstateidp, p);
5360 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5361 *tl = txdr_unsigned(ret);
5362 tstateidp++;
5363 }
5364 nfsmout:
5365 free(stateidp, M_TEMP);
5366 NFSEXITCODE2(error, nd);
5367 return (error);
5368 }
5369
5370 /*
5371 * nfs allocate service
5372 */
5373 int
nfsrvd_allocate(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5374 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram,
5375 vnode_t vp, struct nfsexstuff *exp)
5376 {
5377 uint32_t *tl;
5378 struct nfsvattr forat;
5379 int error = 0, forat_ret = 1, gotproxystateid;
5380 off_t off, len;
5381 struct nfsstate st, *stp = &st;
5382 struct nfslock lo, *lop = &lo;
5383 nfsv4stateid_t stateid;
5384 nfsquad_t clientid;
5385 nfsattrbit_t attrbits;
5386
5387 if (!nfsrv_doallocate) {
5388 /*
5389 * If any exported file system, such as a ZFS one, cannot
5390 * do VOP_ALLOCATE(), this operation cannot be supported
5391 * for NFSv4.2. This cannot be done 'per filesystem', but
5392 * must be for the entire nfsd NFSv4.2 service.
5393 */
5394 nd->nd_repstat = NFSERR_NOTSUPP;
5395 goto nfsmout;
5396 }
5397 gotproxystateid = 0;
5398 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5399 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5400 lop->lo_flags = NFSLCK_WRITE;
5401 stp->ls_ownerlen = 0;
5402 stp->ls_op = NULL;
5403 stp->ls_uid = nd->nd_cred->cr_uid;
5404 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5405 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5406 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5407 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5408 if ((nd->nd_flag & ND_NFSV41) != 0)
5409 clientid.qval = nd->nd_clientid.qval;
5410 else if (nd->nd_clientid.qval != clientid.qval)
5411 printf("EEK2 multiple clids\n");
5412 } else {
5413 if ((nd->nd_flag & ND_NFSV41) != 0)
5414 printf("EEK! no clientid from session\n");
5415 nd->nd_flag |= ND_IMPLIEDCLID;
5416 nd->nd_clientid.qval = clientid.qval;
5417 }
5418 stp->ls_stateid.other[2] = *tl++;
5419 /*
5420 * Don't allow this to be done for a DS.
5421 */
5422 if ((nd->nd_flag & ND_DSSERVER) != 0)
5423 nd->nd_repstat = NFSERR_NOTSUPP;
5424 /* However, allow the proxy stateid. */
5425 if (stp->ls_stateid.seqid == 0xffffffff &&
5426 stp->ls_stateid.other[0] == 0x55555555 &&
5427 stp->ls_stateid.other[1] == 0x55555555 &&
5428 stp->ls_stateid.other[2] == 0x55555555)
5429 gotproxystateid = 1;
5430 off = fxdr_hyper(tl); tl += 2;
5431 lop->lo_first = off;
5432 len = fxdr_hyper(tl);
5433 lop->lo_end = lop->lo_first + len;
5434 /*
5435 * Sanity check the offset and length.
5436 * off and len are off_t (signed int64_t) whereas
5437 * lo_first and lo_end are uint64_t and, as such,
5438 * if off >= 0 && len > 0, lo_end cannot overflow
5439 * unless off_t is changed to something other than
5440 * int64_t. Check lo_end < lo_first in case that
5441 * is someday the case.
5442 */
5443 if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end >
5444 OFF_MAX || lop->lo_end < lop->lo_first))
5445 nd->nd_repstat = NFSERR_INVAL;
5446
5447 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5448 nd->nd_repstat = NFSERR_WRONGTYPE;
5449 NFSZERO_ATTRBIT(&attrbits);
5450 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5451 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5452 if (nd->nd_repstat == 0)
5453 nd->nd_repstat = forat_ret;
5454 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5455 NFSVNO_EXSTRICTACCESS(exp)))
5456 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5457 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5458 NULL);
5459 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5460 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5461 &stateid, exp, nd, curthread);
5462
5463 NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n",
5464 (intmax_t)off, (intmax_t)len, nd->nd_repstat);
5465 if (nd->nd_repstat == 0)
5466 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred,
5467 curthread);
5468 NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n",
5469 nd->nd_repstat);
5470 vput(vp);
5471 NFSEXITCODE2(0, nd);
5472 return (0);
5473 nfsmout:
5474 vput(vp);
5475 NFSEXITCODE2(error, nd);
5476 return (error);
5477 }
5478
5479 /*
5480 * nfs deallocate service
5481 */
5482 int
nfsrvd_deallocate(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5483 nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram,
5484 vnode_t vp, struct nfsexstuff *exp)
5485 {
5486 uint32_t *tl;
5487 struct nfsvattr forat;
5488 int error = 0, forat_ret = 1, gotproxystateid;
5489 off_t off, len;
5490 struct nfsstate st, *stp = &st;
5491 struct nfslock lo, *lop = &lo;
5492 nfsv4stateid_t stateid;
5493 nfsquad_t clientid;
5494 nfsattrbit_t attrbits;
5495
5496 gotproxystateid = 0;
5497 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER);
5498 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5499 lop->lo_flags = NFSLCK_WRITE;
5500 stp->ls_ownerlen = 0;
5501 stp->ls_op = NULL;
5502 stp->ls_uid = nd->nd_cred->cr_uid;
5503 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
5504 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
5505 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
5506 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
5507 if ((nd->nd_flag & ND_NFSV41) != 0)
5508 clientid.qval = nd->nd_clientid.qval;
5509 else if (nd->nd_clientid.qval != clientid.qval)
5510 printf("EEK2 multiple clids\n");
5511 } else {
5512 if ((nd->nd_flag & ND_NFSV41) != 0)
5513 printf("EEK! no clientid from session\n");
5514 nd->nd_flag |= ND_IMPLIEDCLID;
5515 nd->nd_clientid.qval = clientid.qval;
5516 }
5517 stp->ls_stateid.other[2] = *tl++;
5518 /*
5519 * Don't allow this to be done for a DS.
5520 */
5521 if ((nd->nd_flag & ND_DSSERVER) != 0)
5522 nd->nd_repstat = NFSERR_NOTSUPP;
5523 /* However, allow the proxy stateid. */
5524 if (stp->ls_stateid.seqid == 0xffffffff &&
5525 stp->ls_stateid.other[0] == 0x55555555 &&
5526 stp->ls_stateid.other[1] == 0x55555555 &&
5527 stp->ls_stateid.other[2] == 0x55555555)
5528 gotproxystateid = 1;
5529 off = fxdr_hyper(tl); tl += 2;
5530 lop->lo_first = off;
5531 len = fxdr_hyper(tl);
5532 if (len < 0)
5533 len = OFF_MAX;
5534 NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off,
5535 (intmax_t)len);
5536 lop->lo_end = lop->lo_first + len;
5537 /*
5538 * Sanity check the offset and length.
5539 * off and len are off_t (signed int64_t) whereas
5540 * lo_first and lo_end are uint64_t and, as such,
5541 * if off >= 0 && len > 0, lo_end cannot overflow
5542 * unless off_t is changed to something other than
5543 * int64_t. Check lo_end < lo_first in case that
5544 * is someday the case.
5545 * The error to return is not specified by RFC 7862 so I
5546 * made this compatible with the Linux knfsd.
5547 */
5548 if (nd->nd_repstat == 0) {
5549 if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE)
5550 nd->nd_repstat = NFSERR_FBIG;
5551 else if (len == 0 || lop->lo_end < lop->lo_first)
5552 nd->nd_repstat = NFSERR_INVAL;
5553 }
5554
5555 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5556 nd->nd_repstat = NFSERR_WRONGTYPE;
5557 NFSZERO_ATTRBIT(&attrbits);
5558 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5559 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits);
5560 if (nd->nd_repstat == 0)
5561 nd->nd_repstat = forat_ret;
5562 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid ||
5563 NFSVNO_EXSTRICTACCESS(exp)))
5564 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp,
5565 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5566 NULL);
5567 if (nd->nd_repstat == 0 && gotproxystateid == 0)
5568 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5569 &stateid, exp, nd, curthread);
5570
5571 if (nd->nd_repstat == 0)
5572 nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred,
5573 curthread);
5574 vput(vp);
5575 NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat);
5576 NFSEXITCODE2(0, nd);
5577 return (0);
5578 nfsmout:
5579 vput(vp);
5580 NFSEXITCODE2(error, nd);
5581 return (error);
5582 }
5583
5584 /*
5585 * nfs copy service
5586 */
5587 int
nfsrvd_copy_file_range(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,vnode_t tovp,struct nfsexstuff * exp,struct nfsexstuff * toexp)5588 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram,
5589 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
5590 {
5591 uint32_t *tl;
5592 struct nfsvattr at;
5593 int cnt, error = 0, ret;
5594 off_t inoff, outoff;
5595 uint64_t len;
5596 size_t xfer;
5597 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst;
5598 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo;
5599 nfsquad_t clientid;
5600 nfsv4stateid_t stateid;
5601 nfsattrbit_t attrbits;
5602 void *rl_rcookie, *rl_wcookie;
5603
5604 rl_rcookie = rl_wcookie = NULL;
5605 if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0) {
5606 /*
5607 * For a pNFS server, reply NFSERR_NOTSUPP so that the client
5608 * will do the copy via I/O on the DS(s).
5609 * If vfs.nfsd.maxcopyrange set to 0, disable Copy.
5610 */
5611 nd->nd_repstat = NFSERR_NOTSUPP;
5612 goto nfsmout;
5613 }
5614 if (vp == tovp) {
5615 /* Copying a byte range within the same file is not allowed. */
5616 nd->nd_repstat = NFSERR_INVAL;
5617 goto nfsmout;
5618 }
5619 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER +
5620 3 * NFSX_UNSIGNED);
5621 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
5622 inlop->lo_flags = NFSLCK_READ;
5623 instp->ls_ownerlen = 0;
5624 instp->ls_op = NULL;
5625 instp->ls_uid = nd->nd_cred->cr_uid;
5626 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5627 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++;
5628 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++;
5629 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0)
5630 clientid.qval = nd->nd_clientid.qval;
5631 instp->ls_stateid.other[2] = *tl++;
5632 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5633 outlop->lo_flags = NFSLCK_WRITE;
5634 outstp->ls_ownerlen = 0;
5635 outstp->ls_op = NULL;
5636 outstp->ls_uid = nd->nd_cred->cr_uid;
5637 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
5638 outstp->ls_stateid.other[0] = *tl++;
5639 outstp->ls_stateid.other[1] = *tl++;
5640 outstp->ls_stateid.other[2] = *tl++;
5641 inoff = fxdr_hyper(tl); tl += 2;
5642 inlop->lo_first = inoff;
5643 outoff = fxdr_hyper(tl); tl += 2;
5644 outlop->lo_first = outoff;
5645 len = fxdr_hyper(tl); tl += 2;
5646 if (len == 0) {
5647 /* len == 0 means to EOF. */
5648 inlop->lo_end = OFF_MAX;
5649 outlop->lo_end = OFF_MAX;
5650 } else {
5651 inlop->lo_end = inlop->lo_first + len;
5652 outlop->lo_end = outlop->lo_first + len;
5653 }
5654
5655 /*
5656 * At this time only consecutive, synchronous copy is supported,
5657 * so ca_consecutive and ca_synchronous can be ignored.
5658 */
5659 tl += 2;
5660
5661 cnt = fxdr_unsigned(int, *tl);
5662 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0)
5663 nd->nd_repstat = NFSERR_NOTSUPP;
5664 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX ||
5665 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX ||
5666 inlop->lo_end < inlop->lo_first || outlop->lo_end <
5667 outlop->lo_first))
5668 nd->nd_repstat = NFSERR_INVAL;
5669
5670 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5671 nd->nd_repstat = NFSERR_WRONGTYPE;
5672
5673 /* Check permissions for the input file. */
5674 NFSZERO_ATTRBIT(&attrbits);
5675 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5676 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits);
5677 if (nd->nd_repstat == 0)
5678 nd->nd_repstat = ret;
5679 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5680 NFSVNO_EXSTRICTACCESS(exp)))
5681 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5682 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5683 NULL);
5684 if (nd->nd_repstat == 0)
5685 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL,
5686 clientid, &stateid, exp, nd, curthread);
5687 NFSVOPUNLOCK(vp);
5688 if (nd->nd_repstat != 0)
5689 goto out;
5690
5691 error = NFSVOPLOCK(tovp, LK_SHARED);
5692 if (error != 0)
5693 goto out;
5694 if (tovp->v_type != VREG)
5695 nd->nd_repstat = NFSERR_WRONGTYPE;
5696
5697 /* For the output file, we only need the Owner attribute. */
5698 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits);
5699 if (nd->nd_repstat == 0)
5700 nd->nd_repstat = ret;
5701 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5702 NFSVNO_EXSTRICTACCESS(exp)))
5703 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp,
5704 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5705 NULL);
5706 if (nd->nd_repstat == 0)
5707 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL,
5708 clientid, &stateid, toexp, nd, curthread);
5709 NFSVOPUNLOCK(tovp);
5710
5711 /* Range lock the byte ranges for both invp and outvp. */
5712 if (nd->nd_repstat == 0) {
5713 for (;;) {
5714 if (len == 0) {
5715 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5716 OFF_MAX);
5717 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5718 OFF_MAX);
5719 } else {
5720 rl_wcookie = vn_rangelock_wlock(tovp, outoff,
5721 outoff + len);
5722 rl_rcookie = vn_rangelock_tryrlock(vp, inoff,
5723 inoff + len);
5724 }
5725 if (rl_rcookie != NULL)
5726 break;
5727 vn_rangelock_unlock(tovp, rl_wcookie);
5728 if (len == 0)
5729 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5730 OFF_MAX);
5731 else
5732 rl_rcookie = vn_rangelock_rlock(vp, inoff,
5733 inoff + len);
5734 vn_rangelock_unlock(vp, rl_rcookie);
5735 }
5736
5737 error = NFSVOPLOCK(vp, LK_SHARED);
5738 if (error == 0) {
5739 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL);
5740 if (ret == 0) {
5741 /*
5742 * Since invp is range locked, na_size should
5743 * not change.
5744 */
5745 if (len == 0 && at.na_size > inoff) {
5746 /*
5747 * If len == 0, set it based on invp's
5748 * size. If offset is past EOF, just
5749 * leave len == 0.
5750 */
5751 len = at.na_size - inoff;
5752 } else if (nfsrv_linux42server == 0 &&
5753 inoff + len > at.na_size) {
5754 /*
5755 * RFC-7862 says that NFSERR_INVAL must
5756 * be returned when inoff + len exceeds
5757 * the file size, however the NFSv4.2
5758 * Linux client likes to do this, so
5759 * only check if nfsrv_linux42server
5760 * is not set.
5761 */
5762 nd->nd_repstat = NFSERR_INVAL;
5763 }
5764 }
5765 NFSVOPUNLOCK(vp);
5766 if (ret != 0 && nd->nd_repstat == 0)
5767 nd->nd_repstat = ret;
5768 } else if (nd->nd_repstat == 0)
5769 nd->nd_repstat = error;
5770 }
5771
5772 /*
5773 * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange.
5774 * This size limit can be set to limit the time a copy RPC will
5775 * take.
5776 */
5777 if (len > nfsrv_maxcopyrange)
5778 xfer = nfsrv_maxcopyrange;
5779 else
5780 xfer = len;
5781 if (nd->nd_repstat == 0) {
5782 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff,
5783 &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred,
5784 NULL);
5785 if (nd->nd_repstat == 0)
5786 len = xfer;
5787 }
5788
5789 /* Unlock the ranges. */
5790 if (rl_rcookie != NULL)
5791 vn_rangelock_unlock(vp, rl_rcookie);
5792 if (rl_wcookie != NULL)
5793 vn_rangelock_unlock(tovp, rl_wcookie);
5794
5795 if (nd->nd_repstat == 0) {
5796 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER +
5797 NFSX_VERF);
5798 *tl++ = txdr_unsigned(0); /* No callback ids. */
5799 txdr_hyper(len, tl); tl += 2;
5800 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE);
5801 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
5802 *tl++ = txdr_unsigned(nfsboottime.tv_usec);
5803 *tl++ = newnfs_true;
5804 *tl = newnfs_true;
5805 }
5806 out:
5807 vrele(vp);
5808 vrele(tovp);
5809 NFSEXITCODE2(error, nd);
5810 return (error);
5811 nfsmout:
5812 vput(vp);
5813 vrele(tovp);
5814 NFSEXITCODE2(error, nd);
5815 return (error);
5816 }
5817
5818 /*
5819 * nfs seek service
5820 */
5821 int
nfsrvd_seek(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,struct nfsexstuff * exp)5822 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram,
5823 vnode_t vp, struct nfsexstuff *exp)
5824 {
5825 uint32_t *tl;
5826 struct nfsvattr at;
5827 int content, error = 0;
5828 off_t off;
5829 u_long cmd;
5830 nfsattrbit_t attrbits;
5831 bool eof;
5832
5833 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED);
5834 /* Ignore the stateid for now. */
5835 tl += (NFSX_STATEID / NFSX_UNSIGNED);
5836 off = fxdr_hyper(tl); tl += 2;
5837 content = fxdr_unsigned(int, *tl);
5838 if (content == NFSV4CONTENT_DATA)
5839 cmd = FIOSEEKDATA;
5840 else if (content == NFSV4CONTENT_HOLE)
5841 cmd = FIOSEEKHOLE;
5842 else
5843 nd->nd_repstat = NFSERR_BADXDR;
5844 if (nd->nd_repstat == 0 && vp->v_type == VDIR)
5845 nd->nd_repstat = NFSERR_ISDIR;
5846 if (nd->nd_repstat == 0 && vp->v_type != VREG)
5847 nd->nd_repstat = NFSERR_WRONGTYPE;
5848 if (nd->nd_repstat == 0 && off < 0)
5849 nd->nd_repstat = NFSERR_NXIO;
5850 if (nd->nd_repstat == 0) {
5851 /* Check permissions for the input file. */
5852 NFSZERO_ATTRBIT(&attrbits);
5853 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
5854 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1,
5855 &attrbits);
5856 }
5857 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid ||
5858 NFSVNO_EXSTRICTACCESS(exp)))
5859 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp,
5860 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED,
5861 NULL);
5862 if (nd->nd_repstat != 0)
5863 goto nfsmout;
5864
5865 /* nfsvno_seek() unlocks and vrele()s the vp. */
5866 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof,
5867 nd->nd_cred, curthread);
5868 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA &&
5869 nfsrv_linux42server != 0)
5870 nd->nd_repstat = NFSERR_NXIO;
5871 if (nd->nd_repstat == 0) {
5872 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
5873 if (eof)
5874 *tl++ = newnfs_true;
5875 else
5876 *tl++ = newnfs_false;
5877 txdr_hyper(off, tl);
5878 }
5879 NFSEXITCODE2(error, nd);
5880 return (error);
5881 nfsmout:
5882 vput(vp);
5883 NFSEXITCODE2(error, nd);
5884 return (error);
5885 }
5886
5887 /*
5888 * nfs get extended attribute service
5889 */
5890 int
nfsrvd_getxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)5891 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram,
5892 vnode_t vp, __unused struct nfsexstuff *exp)
5893 {
5894 uint32_t *tl;
5895 struct mbuf *mp = NULL, *mpend = NULL;
5896 int error, len;
5897 char *name;
5898 struct thread *p = curthread;
5899 uint16_t off;
5900
5901 error = 0;
5902 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5903 len = fxdr_unsigned(int, *tl);
5904 if (len <= 0) {
5905 nd->nd_repstat = NFSERR_BADXDR;
5906 goto nfsmout;
5907 }
5908 if (len > EXTATTR_MAXNAMELEN) {
5909 nd->nd_repstat = NFSERR_NOXATTR;
5910 goto nfsmout;
5911 }
5912 name = malloc(len + 1, M_TEMP, M_WAITOK);
5913 nd->nd_repstat = nfsrv_mtostr(nd, name, len);
5914 if (nd->nd_repstat == 0)
5915 nd->nd_repstat = nfsvno_getxattr(vp, name,
5916 nd->nd_maxresp, nd->nd_cred, nd->nd_flag,
5917 nd->nd_maxextsiz, p, &mp, &mpend, &len);
5918 if (nd->nd_repstat == ENOATTR)
5919 nd->nd_repstat = NFSERR_NOXATTR;
5920 else if (nd->nd_repstat == EOPNOTSUPP)
5921 nd->nd_repstat = NFSERR_NOTSUPP;
5922 if (nd->nd_repstat == 0) {
5923 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
5924 *tl = txdr_unsigned(len);
5925 if (len > 0) {
5926 nd->nd_mb->m_next = mp;
5927 nd->nd_mb = mpend;
5928 if ((mpend->m_flags & M_EXTPG) != 0) {
5929 nd->nd_flag |= ND_EXTPG;
5930 nd->nd_bextpg = mpend->m_epg_npgs - 1;
5931 nd->nd_bpos = (char *)(void *)
5932 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
5933 off = (nd->nd_bextpg == 0) ?
5934 mpend->m_epg_1st_off : 0;
5935 nd->nd_bpos += off + mpend->m_epg_last_len;
5936 nd->nd_bextpgsiz = PAGE_SIZE -
5937 mpend->m_epg_last_len - off;
5938 } else
5939 nd->nd_bpos = mtod(mpend, char *) +
5940 mpend->m_len;
5941 }
5942 }
5943 free(name, M_TEMP);
5944
5945 nfsmout:
5946 if (nd->nd_repstat == 0)
5947 nd->nd_repstat = error;
5948 vput(vp);
5949 NFSEXITCODE2(0, nd);
5950 return (0);
5951 }
5952
5953 /*
5954 * nfs set extended attribute service
5955 */
5956 int
nfsrvd_setxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)5957 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram,
5958 vnode_t vp, __unused struct nfsexstuff *exp)
5959 {
5960 uint32_t *tl;
5961 struct nfsvattr ova, nva;
5962 nfsattrbit_t attrbits;
5963 int error, len, opt;
5964 char *name;
5965 size_t siz;
5966 struct thread *p = curthread;
5967
5968 error = 0;
5969 name = NULL;
5970 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
5971 opt = fxdr_unsigned(int, *tl++);
5972 len = fxdr_unsigned(int, *tl);
5973 if (len <= 0) {
5974 nd->nd_repstat = NFSERR_BADXDR;
5975 goto nfsmout;
5976 }
5977 if (len > EXTATTR_MAXNAMELEN) {
5978 nd->nd_repstat = NFSERR_NOXATTR;
5979 goto nfsmout;
5980 }
5981 name = malloc(len + 1, M_TEMP, M_WAITOK);
5982 error = nfsrv_mtostr(nd, name, len);
5983 if (error != 0)
5984 goto nfsmout;
5985 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
5986 len = fxdr_unsigned(int, *tl);
5987 if (len < 0 || len > IOSIZE_MAX) {
5988 nd->nd_repstat = NFSERR_XATTR2BIG;
5989 goto nfsmout;
5990 }
5991 switch (opt) {
5992 case NFSV4SXATTR_CREATE:
5993 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
5994 &siz, nd->nd_cred, p);
5995 if (error != ENOATTR)
5996 nd->nd_repstat = NFSERR_EXIST;
5997 error = 0;
5998 break;
5999 case NFSV4SXATTR_REPLACE:
6000 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL,
6001 &siz, nd->nd_cred, p);
6002 if (error != 0)
6003 nd->nd_repstat = NFSERR_NOXATTR;
6004 break;
6005 case NFSV4SXATTR_EITHER:
6006 break;
6007 default:
6008 nd->nd_repstat = NFSERR_BADXDR;
6009 }
6010 if (nd->nd_repstat != 0)
6011 goto nfsmout;
6012
6013 /* Now, do the Set Extended attribute, with Change before and after. */
6014 NFSZERO_ATTRBIT(&attrbits);
6015 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6016 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6017 if (nd->nd_repstat == 0) {
6018 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md,
6019 nd->nd_dpos, nd->nd_cred, p);
6020 if (nd->nd_repstat == ENXIO)
6021 nd->nd_repstat = NFSERR_XATTR2BIG;
6022 }
6023 if (nd->nd_repstat == 0 && len > 0)
6024 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1);
6025 if (nd->nd_repstat == 0)
6026 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6027 if (nd->nd_repstat == 0) {
6028 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6029 *tl++ = newnfs_true;
6030 txdr_hyper(ova.na_filerev, tl); tl += 2;
6031 txdr_hyper(nva.na_filerev, tl);
6032 }
6033
6034 nfsmout:
6035 free(name, M_TEMP);
6036 if (nd->nd_repstat == 0)
6037 nd->nd_repstat = error;
6038 vput(vp);
6039 NFSEXITCODE2(0, nd);
6040 return (0);
6041 }
6042
6043 /*
6044 * nfs remove extended attribute service
6045 */
6046 int
nfsrvd_rmxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6047 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram,
6048 vnode_t vp, __unused struct nfsexstuff *exp)
6049 {
6050 uint32_t *tl;
6051 struct nfsvattr ova, nva;
6052 nfsattrbit_t attrbits;
6053 int error, len;
6054 char *name;
6055 struct thread *p = curthread;
6056
6057 error = 0;
6058 name = NULL;
6059 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
6060 len = fxdr_unsigned(int, *tl);
6061 if (len <= 0) {
6062 nd->nd_repstat = NFSERR_BADXDR;
6063 goto nfsmout;
6064 }
6065 if (len > EXTATTR_MAXNAMELEN) {
6066 nd->nd_repstat = NFSERR_NOXATTR;
6067 goto nfsmout;
6068 }
6069 name = malloc(len + 1, M_TEMP, M_WAITOK);
6070 error = nfsrv_mtostr(nd, name, len);
6071 if (error != 0)
6072 goto nfsmout;
6073
6074 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) {
6075 printf("EEK! nfsrvd_rmxattr: no implied clientid\n");
6076 error = NFSERR_NOXATTR;
6077 goto nfsmout;
6078 }
6079 /*
6080 * Now, do the Remove Extended attribute, with Change before and
6081 * after.
6082 */
6083 NFSZERO_ATTRBIT(&attrbits);
6084 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
6085 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits);
6086 if (nd->nd_repstat == 0) {
6087 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p);
6088 if (nd->nd_repstat == ENOATTR)
6089 nd->nd_repstat = NFSERR_NOXATTR;
6090 }
6091 if (nd->nd_repstat == 0)
6092 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
6093 if (nd->nd_repstat == 0) {
6094 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED);
6095 *tl++ = newnfs_true;
6096 txdr_hyper(ova.na_filerev, tl); tl += 2;
6097 txdr_hyper(nva.na_filerev, tl);
6098 }
6099
6100 nfsmout:
6101 free(name, M_TEMP);
6102 if (nd->nd_repstat == 0)
6103 nd->nd_repstat = error;
6104 vput(vp);
6105 NFSEXITCODE2(0, nd);
6106 return (0);
6107 }
6108
6109 /*
6110 * nfs list extended attribute service
6111 */
6112 int
nfsrvd_listxattr(struct nfsrv_descript * nd,__unused int isdgram,vnode_t vp,__unused struct nfsexstuff * exp)6113 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram,
6114 vnode_t vp, __unused struct nfsexstuff *exp)
6115 {
6116 uint32_t cnt, *tl, len, len2, i, pos, retlen;
6117 int error;
6118 uint64_t cookie, cookie2;
6119 u_char *buf;
6120 bool eof;
6121 struct thread *p = curthread;
6122
6123 error = 0;
6124 buf = NULL;
6125 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
6126 /*
6127 * The cookie doesn't need to be in net byte order, but FreeBSD
6128 * does so to make it more readable in packet traces.
6129 */
6130 cookie = fxdr_hyper(tl); tl += 2;
6131 len = fxdr_unsigned(uint32_t, *tl);
6132 if (len == 0 || cookie >= IOSIZE_MAX) {
6133 nd->nd_repstat = NFSERR_BADXDR;
6134 goto nfsmout;
6135 }
6136 if (len > nd->nd_maxresp - NFS_MAXXDR)
6137 len = nd->nd_maxresp - NFS_MAXXDR;
6138 len2 = len;
6139 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf,
6140 &len, &eof);
6141 if (nd->nd_repstat == EOPNOTSUPP)
6142 nd->nd_repstat = NFSERR_NOTSUPP;
6143 if (nd->nd_repstat == 0) {
6144 cookie2 = cookie + len;
6145 if (cookie2 < cookie)
6146 nd->nd_repstat = NFSERR_BADXDR;
6147 }
6148 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED;
6149 if (nd->nd_repstat == 0 && len2 < retlen)
6150 nd->nd_repstat = NFSERR_TOOSMALL;
6151 if (nd->nd_repstat == 0) {
6152 /* Now copy the entries out. */
6153 if (len == 0) {
6154 /* The cookie was at eof. */
6155 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 *
6156 NFSX_UNSIGNED);
6157 txdr_hyper(cookie2, tl); tl += 2;
6158 *tl++ = txdr_unsigned(0);
6159 *tl = newnfs_true;
6160 goto nfsmout;
6161 }
6162
6163 /* Sanity check the cookie. */
6164 for (pos = 0; pos < len; pos += (i + 1)) {
6165 if (pos == cookie)
6166 break;
6167 i = buf[pos];
6168 }
6169 if (pos != cookie) {
6170 nd->nd_repstat = NFSERR_INVAL;
6171 goto nfsmout;
6172 }
6173
6174 /* Loop around copying the entrie(s) out. */
6175 cnt = 0;
6176 len -= cookie;
6177 i = buf[pos];
6178 while (i < len && len2 >= retlen + NFSM_RNDUP(i) +
6179 NFSX_UNSIGNED) {
6180 if (cnt == 0) {
6181 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER +
6182 NFSX_UNSIGNED);
6183 txdr_hyper(cookie2, tl); tl += 2;
6184 }
6185 retlen += nfsm_strtom(nd, &buf[pos + 1], i);
6186 len -= (i + 1);
6187 pos += (i + 1);
6188 i = buf[pos];
6189 cnt++;
6190 }
6191 /*
6192 * eof is set true/false by nfsvno_listxattr(), but if we
6193 * can't copy all entries returned by nfsvno_listxattr(),
6194 * we are not at eof.
6195 */
6196 if (len > 0)
6197 eof = false;
6198 if (cnt > 0) {
6199 /* *tl is set above. */
6200 *tl = txdr_unsigned(cnt);
6201 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
6202 if (eof)
6203 *tl = newnfs_true;
6204 else
6205 *tl = newnfs_false;
6206 } else
6207 nd->nd_repstat = NFSERR_TOOSMALL;
6208 }
6209
6210 nfsmout:
6211 free(buf, M_TEMP);
6212 if (nd->nd_repstat == 0)
6213 nd->nd_repstat = error;
6214 vput(vp);
6215 NFSEXITCODE2(0, nd);
6216 return (0);
6217 }
6218
6219 /*
6220 * nfsv4 service not supported
6221 */
6222 int
nfsrvd_notsupp(struct nfsrv_descript * nd,__unused int isdgram,__unused vnode_t vp,__unused struct nfsexstuff * exp)6223 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram,
6224 __unused vnode_t vp, __unused struct nfsexstuff *exp)
6225 {
6226
6227 nd->nd_repstat = NFSERR_NOTSUPP;
6228 NFSEXITCODE2(0, nd);
6229 return (0);
6230 }
6231