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