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