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