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