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