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