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