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