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