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