1 /*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 /*
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 /*
1450 * Unlock dp in this code section, so it is unlocked before
1451 * tdp gets locked. This avoids a potential LOR if tdp is the
1452 * parent directory of dp.
1453 */
1454 if (nd->nd_flag & ND_NFSV4) {
1455 tdp = todp;
1456 tnes = *toexp;
1457 if (dp != tdp) {
1458 NFSVOPUNLOCK(dp, 0);
1459 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1460 p, 0); /* Might lock tdp. */
1461 } else {
1462 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1463 p, 1);
1464 NFSVOPUNLOCK(dp, 0);
1465 }
1466 } else {
1467 tfh.nfsrvfh_len = 0;
1468 error = nfsrv_mtofh(nd, &tfh);
1469 if (error == 0)
1470 error = nfsvno_getfh(dp, &fh, p);
1471 if (error) {
1472 vput(dp);
1473 /* todp is always NULL except NFSv4 */
1474 nfsvno_relpathbuf(&fromnd);
1475 goto out;
1476 }
1477
1478 /* If this is the same file handle, just VREF() the vnode. */
1479 if (tfh.nfsrvfh_len == NFSX_MYFH &&
1480 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
1481 VREF(dp);
1482 tdp = dp;
1483 tnes = *exp;
1484 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred,
1485 p, 1);
1486 NFSVOPUNLOCK(dp, 0);
1487 } else {
1488 NFSVOPUNLOCK(dp, 0);
1489 nd->nd_cred->cr_uid = nd->nd_saveduid;
1490 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
1491 0, p); /* Locks tdp. */
1492 if (tdp) {
1493 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor,
1494 nd->nd_cred, p, 1);
1495 NFSVOPUNLOCK(tdp, 0);
1496 }
1497 }
1498 }
1499 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
1500 nfsvno_setpathbuf(&tond, &tbufp, &hashp);
1501 if (!nd->nd_repstat) {
1502 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
1503 if (error) {
1504 if (tdp)
1505 vrele(tdp);
1506 vrele(dp);
1507 nfsvno_relpathbuf(&fromnd);
1508 nfsvno_relpathbuf(&tond);
1509 goto out;
1510 }
1511 }
1512 if (nd->nd_repstat) {
1513 if (nd->nd_flag & ND_NFSV3) {
1514 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1515 &fdiraft);
1516 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1517 &tdiraft);
1518 }
1519 if (tdp)
1520 vrele(tdp);
1521 vrele(dp);
1522 nfsvno_relpathbuf(&fromnd);
1523 nfsvno_relpathbuf(&tond);
1524 goto out;
1525 }
1526
1527 /*
1528 * Done parsing, now down to business.
1529 */
1530 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
1531 if (nd->nd_repstat) {
1532 if (nd->nd_flag & ND_NFSV3) {
1533 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
1534 &fdiraft);
1535 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
1536 &tdiraft);
1537 }
1538 if (fdirp)
1539 vrele(fdirp);
1540 if (tdp)
1541 vrele(tdp);
1542 nfsvno_relpathbuf(&tond);
1543 goto out;
1544 }
1545 if (vnode_vtype(fromnd.ni_vp) == VDIR)
1546 tond.ni_cnd.cn_flags |= WILLBEDIR;
1547 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
1548 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
1549 nd->nd_flag, nd->nd_cred, p);
1550 if (fdirp)
1551 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p,
1552 0);
1553 if (tdirp)
1554 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p,
1555 0);
1556 if (fdirp)
1557 vrele(fdirp);
1558 if (tdirp)
1559 vrele(tdirp);
1560 if (nd->nd_flag & ND_NFSV3) {
1561 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1562 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1563 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1564 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
1565 *tl++ = newnfs_false;
1566 txdr_hyper(fdirfor.na_filerev, tl);
1567 tl += 2;
1568 txdr_hyper(fdiraft.na_filerev, tl);
1569 tl += 2;
1570 *tl++ = newnfs_false;
1571 txdr_hyper(tdirfor.na_filerev, tl);
1572 tl += 2;
1573 txdr_hyper(tdiraft.na_filerev, tl);
1574 }
1575
1576 out:
1577 NFSEXITCODE2(error, nd);
1578 return (error);
1579 }
1580
1581 /*
1582 * nfs link service
1583 */
1584 APPLESTATIC int
1585 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
1586 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp,
1587 struct nfsexstuff *toexp)
1588 {
1589 struct nameidata named;
1590 u_int32_t *tl;
1591 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
1592 vnode_t dirp = NULL, dp = NULL;
1593 struct nfsvattr dirfor, diraft, at;
1594 struct nfsexstuff tnes;
1595 struct nfsrvfh dfh;
1596 char *bufp;
1597 u_long *hashp;
1598
1599 if (nd->nd_repstat) {
1600 nfsrv_postopattr(nd, getret, &at);
1601 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1602 goto out;
1603 }
1604 NFSVOPUNLOCK(vp, 0);
1605 if (vnode_vtype(vp) == VDIR) {
1606 if (nd->nd_flag & ND_NFSV4)
1607 nd->nd_repstat = NFSERR_ISDIR;
1608 else
1609 nd->nd_repstat = NFSERR_INVAL;
1610 if (tovp)
1611 vrele(tovp);
1612 } else if (vnode_vtype(vp) == VLNK) {
1613 if (nd->nd_flag & ND_NFSV2)
1614 nd->nd_repstat = NFSERR_INVAL;
1615 else
1616 nd->nd_repstat = NFSERR_NOTSUPP;
1617 if (tovp)
1618 vrele(tovp);
1619 }
1620 if (!nd->nd_repstat) {
1621 if (nd->nd_flag & ND_NFSV4) {
1622 dp = tovp;
1623 tnes = *toexp;
1624 } else {
1625 error = nfsrv_mtofh(nd, &dfh);
1626 if (error) {
1627 vrele(vp);
1628 /* tovp is always NULL unless NFSv4 */
1629 goto out;
1630 }
1631 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0,
1632 p);
1633 if (dp)
1634 NFSVOPUNLOCK(dp, 0);
1635 }
1636 }
1637 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1638 LOCKPARENT | SAVENAME);
1639 if (!nd->nd_repstat) {
1640 nfsvno_setpathbuf(&named, &bufp, &hashp);
1641 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1642 if (error) {
1643 vrele(vp);
1644 if (dp)
1645 vrele(dp);
1646 nfsvno_relpathbuf(&named);
1647 goto out;
1648 }
1649 if (!nd->nd_repstat) {
1650 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
1651 p, &dirp);
1652 } else {
1653 if (dp)
1654 vrele(dp);
1655 nfsvno_relpathbuf(&named);
1656 }
1657 }
1658 if (dirp) {
1659 if (nd->nd_flag & ND_NFSV2) {
1660 vrele(dirp);
1661 dirp = NULL;
1662 } else {
1663 dirfor_ret = nfsvno_getattr(dirp, &dirfor,
1664 nd->nd_cred, p, 0);
1665 }
1666 }
1667 if (!nd->nd_repstat)
1668 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
1669 if (nd->nd_flag & ND_NFSV3)
1670 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0);
1671 if (dirp) {
1672 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0);
1673 vrele(dirp);
1674 }
1675 vrele(vp);
1676 if (nd->nd_flag & ND_NFSV3) {
1677 nfsrv_postopattr(nd, getret, &at);
1678 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1679 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1680 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1681 *tl++ = newnfs_false;
1682 txdr_hyper(dirfor.na_filerev, tl);
1683 tl += 2;
1684 txdr_hyper(diraft.na_filerev, tl);
1685 }
1686
1687 out:
1688 NFSEXITCODE2(error, nd);
1689 return (error);
1690 }
1691
1692 /*
1693 * nfs symbolic link service
1694 */
1695 APPLESTATIC int
1696 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
1697 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1698 struct nfsexstuff *exp)
1699 {
1700 struct nfsvattr nva, dirfor, diraft;
1701 struct nameidata named;
1702 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
1703 vnode_t dirp = NULL;
1704 char *bufp, *pathcp = NULL;
1705 u_long *hashp;
1706
1707 if (nd->nd_repstat) {
1708 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1709 goto out;
1710 }
1711 if (vpp)
1712 *vpp = NULL;
1713 NFSVNO_ATTRINIT(&nva);
1714 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1715 LOCKPARENT | SAVESTART);
1716 nfsvno_setpathbuf(&named, &bufp, &hashp);
1717 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1718 if (!error && !nd->nd_repstat)
1719 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
1720 if (error) {
1721 vrele(dp);
1722 nfsvno_relpathbuf(&named);
1723 goto out;
1724 }
1725 if (!nd->nd_repstat) {
1726 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1727 } else {
1728 vrele(dp);
1729 nfsvno_relpathbuf(&named);
1730 }
1731 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1732 vrele(dirp);
1733 dirp = NULL;
1734 }
1735
1736 /*
1737 * And call nfsrvd_symlinksub() to do the common code. It will
1738 * return EBADRPC upon a parsing error, 0 otherwise.
1739 */
1740 if (!nd->nd_repstat) {
1741 if (dirp != NULL)
1742 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1743 p, 0);
1744 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
1745 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
1746 pathcp, pathlen);
1747 } else if (dirp != NULL) {
1748 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1749 vrele(dirp);
1750 }
1751 if (pathcp)
1752 FREE(pathcp, M_TEMP);
1753
1754 if (nd->nd_flag & ND_NFSV3) {
1755 if (!nd->nd_repstat) {
1756 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1757 nfsrv_postopattr(nd, 0, &nva);
1758 }
1759 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1760 }
1761
1762 out:
1763 NFSEXITCODE2(error, nd);
1764 return (error);
1765 }
1766
1767 /*
1768 * Common code for creating a symbolic link.
1769 */
1770 static void
1771 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
1772 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1773 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1774 int *diraft_retp, nfsattrbit_t *attrbitp,
1775 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
1776 int pathlen)
1777 {
1778 u_int32_t *tl;
1779
1780 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
1781 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
1782 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
1783 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
1784 if (nd->nd_flag & ND_NFSV3) {
1785 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
1786 if (!nd->nd_repstat)
1787 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
1788 nvap, nd->nd_cred, p, 1);
1789 }
1790 if (vpp != NULL && nd->nd_repstat == 0) {
1791 NFSVOPUNLOCK(ndp->ni_vp, 0);
1792 *vpp = ndp->ni_vp;
1793 } else
1794 vput(ndp->ni_vp);
1795 }
1796 if (dirp) {
1797 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1798 vrele(dirp);
1799 }
1800 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1801 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1802 *tl++ = newnfs_false;
1803 txdr_hyper(dirforp->na_filerev, tl);
1804 tl += 2;
1805 txdr_hyper(diraftp->na_filerev, tl);
1806 (void) nfsrv_putattrbit(nd, attrbitp);
1807 }
1808
1809 NFSEXITCODE2(0, nd);
1810 }
1811
1812 /*
1813 * nfs mkdir service
1814 */
1815 APPLESTATIC int
1816 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
1817 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p,
1818 struct nfsexstuff *exp)
1819 {
1820 struct nfsvattr nva, dirfor, diraft;
1821 struct nameidata named;
1822 u_int32_t *tl;
1823 int error = 0, dirfor_ret = 1, diraft_ret = 1;
1824 vnode_t dirp = NULL;
1825 char *bufp;
1826 u_long *hashp;
1827
1828 if (nd->nd_repstat) {
1829 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1830 goto out;
1831 }
1832 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
1833 LOCKPARENT | SAVENAME);
1834 nfsvno_setpathbuf(&named, &bufp, &hashp);
1835 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
1836 if (error)
1837 goto nfsmout;
1838 if (!nd->nd_repstat) {
1839 NFSVNO_ATTRINIT(&nva);
1840 if (nd->nd_flag & ND_NFSV3) {
1841 error = nfsrv_sattr(nd, &nva, NULL, NULL, p);
1842 if (error)
1843 goto nfsmout;
1844 } else {
1845 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1846 nva.na_mode = nfstov_mode(*tl++);
1847 }
1848 }
1849 if (!nd->nd_repstat) {
1850 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
1851 } else {
1852 vrele(dp);
1853 nfsvno_relpathbuf(&named);
1854 }
1855 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
1856 vrele(dirp);
1857 dirp = NULL;
1858 }
1859 if (nd->nd_repstat) {
1860 if (dirp != NULL) {
1861 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred,
1862 p, 0);
1863 vrele(dirp);
1864 }
1865 if (nd->nd_flag & ND_NFSV3)
1866 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
1867 &diraft);
1868 goto out;
1869 }
1870 if (dirp != NULL)
1871 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0);
1872
1873 /*
1874 * Call nfsrvd_mkdirsub() for the code common to V4 as well.
1875 */
1876 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
1877 &diraft_ret, NULL, NULL, p, exp);
1878
1879 if (nd->nd_flag & ND_NFSV3) {
1880 if (!nd->nd_repstat) {
1881 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
1882 nfsrv_postopattr(nd, 0, &nva);
1883 }
1884 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
1885 } else if (!nd->nd_repstat) {
1886 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
1887 nfsrv_fillattr(nd, &nva);
1888 }
1889
1890 out:
1891 NFSEXITCODE2(0, nd);
1892 return (0);
1893 nfsmout:
1894 vrele(dp);
1895 nfsvno_relpathbuf(&named);
1896 NFSEXITCODE2(error, nd);
1897 return (error);
1898 }
1899
1900 /*
1901 * Code common to mkdir for V2,3 and 4.
1902 */
1903 static void
1904 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
1905 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
1906 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
1907 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
1908 NFSPROC_T *p, struct nfsexstuff *exp)
1909 {
1910 vnode_t vp;
1911 u_int32_t *tl;
1912
1913 NFSVNO_SETATTRVAL(nvap, type, VDIR);
1914 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
1915 nd->nd_cred, p, exp);
1916 if (!nd->nd_repstat) {
1917 vp = ndp->ni_vp;
1918 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
1919 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
1920 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
1921 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred,
1922 p, 1);
1923 if (vpp && !nd->nd_repstat) {
1924 NFSVOPUNLOCK(vp, 0);
1925 *vpp = vp;
1926 } else {
1927 vput(vp);
1928 }
1929 }
1930 if (dirp) {
1931 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0);
1932 vrele(dirp);
1933 }
1934 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
1935 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
1936 *tl++ = newnfs_false;
1937 txdr_hyper(dirforp->na_filerev, tl);
1938 tl += 2;
1939 txdr_hyper(diraftp->na_filerev, tl);
1940 (void) nfsrv_putattrbit(nd, attrbitp);
1941 }
1942
1943 NFSEXITCODE2(0, nd);
1944 }
1945
1946 /*
1947 * nfs commit service
1948 */
1949 APPLESTATIC int
1950 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
1951 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1952 {
1953 struct nfsvattr bfor, aft;
1954 u_int32_t *tl;
1955 int error = 0, for_ret = 1, aft_ret = 1, cnt;
1956 u_int64_t off;
1957
1958 if (nd->nd_repstat) {
1959 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1960 goto out;
1961 }
1962 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
1963 /*
1964 * XXX At this time VOP_FSYNC() does not accept offset and byte
1965 * count parameters, so these arguments are useless (someday maybe).
1966 */
1967 off = fxdr_hyper(tl);
1968 tl += 2;
1969 cnt = fxdr_unsigned(int, *tl);
1970 if (nd->nd_flag & ND_NFSV3)
1971 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1);
1972 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
1973 if (nd->nd_flag & ND_NFSV3) {
1974 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1);
1975 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
1976 }
1977 vput(vp);
1978 if (!nd->nd_repstat) {
1979 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
1980 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
1981 *tl = txdr_unsigned(nfsboottime.tv_usec);
1982 }
1983
1984 out:
1985 NFSEXITCODE2(0, nd);
1986 return (0);
1987 nfsmout:
1988 vput(vp);
1989 NFSEXITCODE2(error, nd);
1990 return (error);
1991 }
1992
1993 /*
1994 * nfs statfs service
1995 */
1996 APPLESTATIC int
1997 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
1998 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
1999 {
2000 struct statfs *sf;
2001 u_int32_t *tl;
2002 int getret = 1;
2003 struct nfsvattr at;
2004 struct statfs sfs;
2005 u_quad_t tval;
2006
2007 if (nd->nd_repstat) {
2008 nfsrv_postopattr(nd, getret, &at);
2009 goto out;
2010 }
2011 sf = &sfs;
2012 nd->nd_repstat = nfsvno_statfs(vp, sf);
2013 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2014 vput(vp);
2015 if (nd->nd_flag & ND_NFSV3)
2016 nfsrv_postopattr(nd, getret, &at);
2017 if (nd->nd_repstat)
2018 goto out;
2019 if (nd->nd_flag & ND_NFSV2) {
2020 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
2021 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
2022 *tl++ = txdr_unsigned(sf->f_bsize);
2023 *tl++ = txdr_unsigned(sf->f_blocks);
2024 *tl++ = txdr_unsigned(sf->f_bfree);
2025 *tl = txdr_unsigned(sf->f_bavail);
2026 } else {
2027 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
2028 tval = (u_quad_t)sf->f_blocks;
2029 tval *= (u_quad_t)sf->f_bsize;
2030 txdr_hyper(tval, tl); tl += 2;
2031 tval = (u_quad_t)sf->f_bfree;
2032 tval *= (u_quad_t)sf->f_bsize;
2033 txdr_hyper(tval, tl); tl += 2;
2034 tval = (u_quad_t)sf->f_bavail;
2035 tval *= (u_quad_t)sf->f_bsize;
2036 txdr_hyper(tval, tl); tl += 2;
2037 tval = (u_quad_t)sf->f_files;
2038 txdr_hyper(tval, tl); tl += 2;
2039 tval = (u_quad_t)sf->f_ffree;
2040 txdr_hyper(tval, tl); tl += 2;
2041 tval = (u_quad_t)sf->f_ffree;
2042 txdr_hyper(tval, tl); tl += 2;
2043 *tl = 0;
2044 }
2045
2046 out:
2047 NFSEXITCODE2(0, nd);
2048 return (0);
2049 }
2050
2051 /*
2052 * nfs fsinfo service
2053 */
2054 APPLESTATIC int
2055 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
2056 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2057 {
2058 u_int32_t *tl;
2059 struct nfsfsinfo fs;
2060 int getret = 1;
2061 struct nfsvattr at;
2062
2063 if (nd->nd_repstat) {
2064 nfsrv_postopattr(nd, getret, &at);
2065 goto out;
2066 }
2067 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2068 nfsvno_getfs(&fs, isdgram);
2069 vput(vp);
2070 nfsrv_postopattr(nd, getret, &at);
2071 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
2072 *tl++ = txdr_unsigned(fs.fs_rtmax);
2073 *tl++ = txdr_unsigned(fs.fs_rtpref);
2074 *tl++ = txdr_unsigned(fs.fs_rtmult);
2075 *tl++ = txdr_unsigned(fs.fs_wtmax);
2076 *tl++ = txdr_unsigned(fs.fs_wtpref);
2077 *tl++ = txdr_unsigned(fs.fs_wtmult);
2078 *tl++ = txdr_unsigned(fs.fs_dtpref);
2079 txdr_hyper(fs.fs_maxfilesize, tl);
2080 tl += 2;
2081 txdr_nfsv3time(&fs.fs_timedelta, tl);
2082 tl += 2;
2083 *tl = txdr_unsigned(fs.fs_properties);
2084
2085 out:
2086 NFSEXITCODE2(0, nd);
2087 return (0);
2088 }
2089
2090 /*
2091 * nfs pathconf service
2092 */
2093 APPLESTATIC int
2094 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
2095 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2096 {
2097 struct nfsv3_pathconf *pc;
2098 int getret = 1;
2099 register_t linkmax, namemax, chownres, notrunc;
2100 struct nfsvattr at;
2101
2102 if (nd->nd_repstat) {
2103 nfsrv_postopattr(nd, getret, &at);
2104 goto out;
2105 }
2106 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
2107 nd->nd_cred, p);
2108 if (!nd->nd_repstat)
2109 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
2110 nd->nd_cred, p);
2111 if (!nd->nd_repstat)
2112 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
2113 &chownres, nd->nd_cred, p);
2114 if (!nd->nd_repstat)
2115 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc,
2116 nd->nd_cred, p);
2117 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
2118 vput(vp);
2119 nfsrv_postopattr(nd, getret, &at);
2120 if (!nd->nd_repstat) {
2121 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
2122 pc->pc_linkmax = txdr_unsigned(linkmax);
2123 pc->pc_namemax = txdr_unsigned(namemax);
2124 pc->pc_notrunc = txdr_unsigned(notrunc);
2125 pc->pc_chownrestricted = txdr_unsigned(chownres);
2126
2127 /*
2128 * These should probably be supported by VOP_PATHCONF(), but
2129 * until msdosfs is exportable (why would you want to?), the
2130 * Unix defaults should be ok.
2131 */
2132 pc->pc_caseinsensitive = newnfs_false;
2133 pc->pc_casepreserving = newnfs_true;
2134 }
2135
2136 out:
2137 NFSEXITCODE2(0, nd);
2138 return (0);
2139 }
2140
2141 /*
2142 * nfsv4 lock service
2143 */
2144 APPLESTATIC int
2145 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
2146 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2147 {
2148 u_int32_t *tl;
2149 int i;
2150 struct nfsstate *stp = NULL;
2151 struct nfslock *lop;
2152 struct nfslockconflict cf;
2153 int error = 0;
2154 u_short flags = NFSLCK_LOCK, lflags;
2155 u_int64_t offset, len;
2156 nfsv4stateid_t stateid;
2157 nfsquad_t clientid;
2158
2159 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2160 i = fxdr_unsigned(int, *tl++);
2161 switch (i) {
2162 case NFSV4LOCKT_READW:
2163 flags |= NFSLCK_BLOCKING;
2164 case NFSV4LOCKT_READ:
2165 lflags = NFSLCK_READ;
2166 break;
2167 case NFSV4LOCKT_WRITEW:
2168 flags |= NFSLCK_BLOCKING;
2169 case NFSV4LOCKT_WRITE:
2170 lflags = NFSLCK_WRITE;
2171 break;
2172 default:
2173 nd->nd_repstat = NFSERR_BADXDR;
2174 goto nfsmout;
2175 };
2176 if (*tl++ == newnfs_true)
2177 flags |= NFSLCK_RECLAIM;
2178 offset = fxdr_hyper(tl);
2179 tl += 2;
2180 len = fxdr_hyper(tl);
2181 tl += 2;
2182 if (*tl == newnfs_true)
2183 flags |= NFSLCK_OPENTOLOCK;
2184 if (flags & NFSLCK_OPENTOLOCK) {
2185 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
2186 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
2187 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2188 nd->nd_repstat = NFSERR_BADXDR;
2189 goto nfsmout;
2190 }
2191 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2192 M_NFSDSTATE, M_WAITOK);
2193 stp->ls_ownerlen = i;
2194 stp->ls_op = nd->nd_rp;
2195 stp->ls_seq = fxdr_unsigned(int, *tl++);
2196 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2197 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2198 NFSX_STATEIDOTHER);
2199 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2200 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
2201 clientid.lval[0] = *tl++;
2202 clientid.lval[1] = *tl++;
2203 if (nd->nd_flag & ND_IMPLIEDCLID) {
2204 if (nd->nd_clientid.qval != clientid.qval)
2205 printf("EEK! multiple clids\n");
2206 } else {
2207 nd->nd_flag |= ND_IMPLIEDCLID;
2208 nd->nd_clientid.qval = clientid.qval;
2209 }
2210 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2211 if (error)
2212 goto nfsmout;
2213 } else {
2214 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
2215 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2216 M_NFSDSTATE, M_WAITOK);
2217 stp->ls_ownerlen = 0;
2218 stp->ls_op = nd->nd_rp;
2219 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2220 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2221 NFSX_STATEIDOTHER);
2222 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2223 stp->ls_seq = fxdr_unsigned(int, *tl);
2224 clientid.lval[0] = stp->ls_stateid.other[0];
2225 clientid.lval[1] = stp->ls_stateid.other[1];
2226 if (nd->nd_flag & ND_IMPLIEDCLID) {
2227 if (nd->nd_clientid.qval != clientid.qval)
2228 printf("EEK! multiple clids\n");
2229 } else {
2230 nd->nd_flag |= ND_IMPLIEDCLID;
2231 nd->nd_clientid.qval = clientid.qval;
2232 }
2233 }
2234 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2235 M_NFSDLOCK, M_WAITOK);
2236 lop->lo_first = offset;
2237 if (len == NFS64BITSSET) {
2238 lop->lo_end = NFS64BITSSET;
2239 } else {
2240 lop->lo_end = offset + len;
2241 if (lop->lo_end <= lop->lo_first)
2242 nd->nd_repstat = NFSERR_INVAL;
2243 }
2244 lop->lo_flags = lflags;
2245 stp->ls_flags = flags;
2246 stp->ls_uid = nd->nd_cred->cr_uid;
2247
2248 /*
2249 * Do basic access checking.
2250 */
2251 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2252 if (vnode_vtype(vp) == VDIR)
2253 nd->nd_repstat = NFSERR_ISDIR;
2254 else
2255 nd->nd_repstat = NFSERR_INVAL;
2256 }
2257 if (!nd->nd_repstat) {
2258 if (lflags & NFSLCK_WRITE) {
2259 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
2260 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2261 NFSACCCHK_VPISLOCKED, NULL);
2262 } else {
2263 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
2264 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2265 NFSACCCHK_VPISLOCKED, NULL);
2266 if (nd->nd_repstat)
2267 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2268 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2269 NFSACCCHK_VPISLOCKED, NULL);
2270 }
2271 }
2272
2273 /*
2274 * We call nfsrv_lockctrl() even if nd_repstat set, so that the
2275 * seqid# gets updated. nfsrv_lockctrl() will return the value
2276 * of nd_repstat, if it gets that far.
2277 */
2278 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2279 &stateid, exp, nd, p);
2280 if (lop)
2281 FREE((caddr_t)lop, M_NFSDLOCK);
2282 if (stp)
2283 FREE((caddr_t)stp, M_NFSDSTATE);
2284 if (!nd->nd_repstat) {
2285 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2286 *tl++ = txdr_unsigned(stateid.seqid);
2287 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2288 } else if (nd->nd_repstat == NFSERR_DENIED) {
2289 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2290 txdr_hyper(cf.cl_first, tl);
2291 tl += 2;
2292 if (cf.cl_end == NFS64BITSSET)
2293 len = NFS64BITSSET;
2294 else
2295 len = cf.cl_end - cf.cl_first;
2296 txdr_hyper(len, tl);
2297 tl += 2;
2298 if (cf.cl_flags == NFSLCK_WRITE)
2299 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2300 else
2301 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2302 *tl++ = stateid.other[0];
2303 *tl = stateid.other[1];
2304 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2305 }
2306 vput(vp);
2307 NFSEXITCODE2(0, nd);
2308 return (0);
2309 nfsmout:
2310 vput(vp);
2311 if (stp)
2312 free((caddr_t)stp, M_NFSDSTATE);
2313 NFSEXITCODE2(error, nd);
2314 return (error);
2315 }
2316
2317 /*
2318 * nfsv4 lock test service
2319 */
2320 APPLESTATIC int
2321 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
2322 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2323 {
2324 u_int32_t *tl;
2325 int i;
2326 struct nfsstate *stp = NULL;
2327 struct nfslock lo, *lop = &lo;
2328 struct nfslockconflict cf;
2329 int error = 0;
2330 nfsv4stateid_t stateid;
2331 nfsquad_t clientid;
2332 u_int64_t len;
2333
2334 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
2335 i = fxdr_unsigned(int, *(tl + 7));
2336 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2337 nd->nd_repstat = NFSERR_BADXDR;
2338 goto nfsmout;
2339 }
2340 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2341 M_NFSDSTATE, M_WAITOK);
2342 stp->ls_ownerlen = i;
2343 stp->ls_op = NULL;
2344 stp->ls_flags = NFSLCK_TEST;
2345 stp->ls_uid = nd->nd_cred->cr_uid;
2346 i = fxdr_unsigned(int, *tl++);
2347 switch (i) {
2348 case NFSV4LOCKT_READW:
2349 stp->ls_flags |= NFSLCK_BLOCKING;
2350 case NFSV4LOCKT_READ:
2351 lo.lo_flags = NFSLCK_READ;
2352 break;
2353 case NFSV4LOCKT_WRITEW:
2354 stp->ls_flags |= NFSLCK_BLOCKING;
2355 case NFSV4LOCKT_WRITE:
2356 lo.lo_flags = NFSLCK_WRITE;
2357 break;
2358 default:
2359 nd->nd_repstat = NFSERR_BADXDR;
2360 goto nfsmout;
2361 };
2362 lo.lo_first = fxdr_hyper(tl);
2363 tl += 2;
2364 len = fxdr_hyper(tl);
2365 if (len == NFS64BITSSET) {
2366 lo.lo_end = NFS64BITSSET;
2367 } else {
2368 lo.lo_end = lo.lo_first + len;
2369 if (lo.lo_end <= lo.lo_first)
2370 nd->nd_repstat = NFSERR_INVAL;
2371 }
2372 tl += 2;
2373 clientid.lval[0] = *tl++;
2374 clientid.lval[1] = *tl;
2375 if (nd->nd_flag & ND_IMPLIEDCLID) {
2376 if (nd->nd_clientid.qval != clientid.qval)
2377 printf("EEK! multiple clids\n");
2378 } else {
2379 nd->nd_flag |= ND_IMPLIEDCLID;
2380 nd->nd_clientid.qval = clientid.qval;
2381 }
2382 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2383 if (error)
2384 goto nfsmout;
2385 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2386 if (vnode_vtype(vp) == VDIR)
2387 nd->nd_repstat = NFSERR_ISDIR;
2388 else
2389 nd->nd_repstat = NFSERR_INVAL;
2390 }
2391 if (!nd->nd_repstat)
2392 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
2393 &stateid, exp, nd, p);
2394 if (stp)
2395 FREE((caddr_t)stp, M_NFSDSTATE);
2396 if (nd->nd_repstat) {
2397 if (nd->nd_repstat == NFSERR_DENIED) {
2398 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2399 txdr_hyper(cf.cl_first, tl);
2400 tl += 2;
2401 if (cf.cl_end == NFS64BITSSET)
2402 len = NFS64BITSSET;
2403 else
2404 len = cf.cl_end - cf.cl_first;
2405 txdr_hyper(len, tl);
2406 tl += 2;
2407 if (cf.cl_flags == NFSLCK_WRITE)
2408 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
2409 else
2410 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
2411 *tl++ = stp->ls_stateid.other[0];
2412 *tl = stp->ls_stateid.other[1];
2413 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
2414 }
2415 }
2416 vput(vp);
2417 NFSEXITCODE2(0, nd);
2418 return (0);
2419 nfsmout:
2420 vput(vp);
2421 if (stp)
2422 free((caddr_t)stp, M_NFSDSTATE);
2423 NFSEXITCODE2(error, nd);
2424 return (error);
2425 }
2426
2427 /*
2428 * nfsv4 unlock service
2429 */
2430 APPLESTATIC int
2431 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
2432 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp)
2433 {
2434 u_int32_t *tl;
2435 int i;
2436 struct nfsstate *stp;
2437 struct nfslock *lop;
2438 int error = 0;
2439 nfsv4stateid_t stateid;
2440 nfsquad_t clientid;
2441 u_int64_t len;
2442
2443 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
2444 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate),
2445 M_NFSDSTATE, M_WAITOK);
2446 MALLOC(lop, struct nfslock *, sizeof (struct nfslock),
2447 M_NFSDLOCK, M_WAITOK);
2448 stp->ls_flags = NFSLCK_UNLOCK;
2449 lop->lo_flags = NFSLCK_UNLOCK;
2450 stp->ls_op = nd->nd_rp;
2451 i = fxdr_unsigned(int, *tl++);
2452 switch (i) {
2453 case NFSV4LOCKT_READW:
2454 stp->ls_flags |= NFSLCK_BLOCKING;
2455 case NFSV4LOCKT_READ:
2456 break;
2457 case NFSV4LOCKT_WRITEW:
2458 stp->ls_flags |= NFSLCK_BLOCKING;
2459 case NFSV4LOCKT_WRITE:
2460 break;
2461 default:
2462 nd->nd_repstat = NFSERR_BADXDR;
2463 free(stp, M_NFSDSTATE);
2464 free(lop, M_NFSDLOCK);
2465 goto nfsmout;
2466 };
2467 stp->ls_ownerlen = 0;
2468 stp->ls_uid = nd->nd_cred->cr_uid;
2469 stp->ls_seq = fxdr_unsigned(int, *tl++);
2470 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2471 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2472 NFSX_STATEIDOTHER);
2473 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2474 lop->lo_first = fxdr_hyper(tl);
2475 tl += 2;
2476 len = fxdr_hyper(tl);
2477 if (len == NFS64BITSSET) {
2478 lop->lo_end = NFS64BITSSET;
2479 } else {
2480 lop->lo_end = lop->lo_first + len;
2481 if (lop->lo_end <= lop->lo_first)
2482 nd->nd_repstat = NFSERR_INVAL;
2483 }
2484 clientid.lval[0] = stp->ls_stateid.other[0];
2485 clientid.lval[1] = stp->ls_stateid.other[1];
2486 if (nd->nd_flag & ND_IMPLIEDCLID) {
2487 if (nd->nd_clientid.qval != clientid.qval)
2488 printf("EEK! multiple clids\n");
2489 } else {
2490 nd->nd_flag |= ND_IMPLIEDCLID;
2491 nd->nd_clientid.qval = clientid.qval;
2492 }
2493 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2494 if (vnode_vtype(vp) == VDIR)
2495 nd->nd_repstat = NFSERR_ISDIR;
2496 else
2497 nd->nd_repstat = NFSERR_INVAL;
2498 }
2499 /*
2500 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
2501 * seqid# gets incremented. nfsrv_lockctrl() will return the
2502 * value of nd_repstat, if it gets that far.
2503 */
2504 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
2505 &stateid, exp, nd, p);
2506 if (stp)
2507 FREE((caddr_t)stp, M_NFSDSTATE);
2508 if (lop)
2509 free((caddr_t)lop, M_NFSDLOCK);
2510 if (!nd->nd_repstat) {
2511 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2512 *tl++ = txdr_unsigned(stateid.seqid);
2513 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2514 }
2515 nfsmout:
2516 vput(vp);
2517 NFSEXITCODE2(error, nd);
2518 return (error);
2519 }
2520
2521 /*
2522 * nfsv4 open service
2523 */
2524 APPLESTATIC int
2525 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
2526 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p,
2527 struct nfsexstuff *exp)
2528 {
2529 u_int32_t *tl;
2530 int i;
2531 struct nfsstate *stp = NULL;
2532 int error = 0, create, claim, exclusive_flag = 0;
2533 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
2534 int how = NFSCREATE_UNCHECKED;
2535 int32_t cverf[2], tverf[2] = { 0, 0 };
2536 vnode_t vp = NULL, dirp = NULL;
2537 struct nfsvattr nva, dirfor, diraft;
2538 struct nameidata named;
2539 nfsv4stateid_t stateid, delegstateid;
2540 nfsattrbit_t attrbits;
2541 nfsquad_t clientid;
2542 char *bufp = NULL;
2543 u_long *hashp;
2544 NFSACL_T *aclp = NULL;
2545
2546 #ifdef NFS4_ACL_EXTATTR_NAME
2547 aclp = acl_alloc(M_WAITOK);
2548 aclp->acl_cnt = 0;
2549 #endif
2550 NFSZERO_ATTRBIT(&attrbits);
2551 named.ni_startdir = NULL;
2552 named.ni_cnd.cn_nameiop = 0;
2553 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
2554 i = fxdr_unsigned(int, *(tl + 5));
2555 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
2556 nd->nd_repstat = NFSERR_BADXDR;
2557 goto nfsmout;
2558 }
2559 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i,
2560 M_NFSDSTATE, M_WAITOK);
2561 stp->ls_ownerlen = i;
2562 stp->ls_op = nd->nd_rp;
2563 stp->ls_flags = NFSLCK_OPEN;
2564 stp->ls_uid = nd->nd_cred->cr_uid;
2565 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2566 i = fxdr_unsigned(int, *tl++);
2567 switch (i) {
2568 case NFSV4OPEN_ACCESSREAD:
2569 stp->ls_flags |= NFSLCK_READACCESS;
2570 break;
2571 case NFSV4OPEN_ACCESSWRITE:
2572 stp->ls_flags |= NFSLCK_WRITEACCESS;
2573 break;
2574 case NFSV4OPEN_ACCESSBOTH:
2575 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2576 break;
2577 default:
2578 nd->nd_repstat = NFSERR_INVAL;
2579 };
2580 i = fxdr_unsigned(int, *tl++);
2581 switch (i) {
2582 case NFSV4OPEN_DENYNONE:
2583 break;
2584 case NFSV4OPEN_DENYREAD:
2585 stp->ls_flags |= NFSLCK_READDENY;
2586 break;
2587 case NFSV4OPEN_DENYWRITE:
2588 stp->ls_flags |= NFSLCK_WRITEDENY;
2589 break;
2590 case NFSV4OPEN_DENYBOTH:
2591 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
2592 break;
2593 default:
2594 nd->nd_repstat = NFSERR_INVAL;
2595 };
2596 clientid.lval[0] = *tl++;
2597 clientid.lval[1] = *tl;
2598 if (nd->nd_flag & ND_IMPLIEDCLID) {
2599 if (nd->nd_clientid.qval != clientid.qval)
2600 printf("EEK! multiple clids\n");
2601 } else {
2602 nd->nd_flag |= ND_IMPLIEDCLID;
2603 nd->nd_clientid.qval = clientid.qval;
2604 }
2605 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
2606 if (error)
2607 goto nfsmout;
2608 NFSVNO_ATTRINIT(&nva);
2609 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2610 create = fxdr_unsigned(int, *tl);
2611 if (!nd->nd_repstat)
2612 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0);
2613 if (create == NFSV4OPEN_CREATE) {
2614 nva.na_type = VREG;
2615 nva.na_mode = 0;
2616 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2617 how = fxdr_unsigned(int, *tl);
2618 switch (how) {
2619 case NFSCREATE_UNCHECKED:
2620 case NFSCREATE_GUARDED:
2621 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p);
2622 if (error)
2623 goto nfsmout;
2624 /*
2625 * If the na_gid being set is the same as that of
2626 * the directory it is going in, clear it, since
2627 * that is what will be set by default. This allows
2628 * a user that isn't in that group to do the create.
2629 */
2630 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
2631 nva.na_gid == dirfor.na_gid)
2632 NFSVNO_UNSET(&nva, gid);
2633 if (!nd->nd_repstat)
2634 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
2635 break;
2636 case NFSCREATE_EXCLUSIVE:
2637 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
2638 cverf[0] = *tl++;
2639 cverf[1] = *tl;
2640 break;
2641 default:
2642 nd->nd_repstat = NFSERR_BADXDR;
2643 goto nfsmout;
2644 };
2645 } else if (create != NFSV4OPEN_NOCREATE) {
2646 nd->nd_repstat = NFSERR_BADXDR;
2647 goto nfsmout;
2648 }
2649
2650 /*
2651 * Now, handle the claim, which usually includes looking up a
2652 * name in the directory referenced by dp. The exception is
2653 * NFSV4OPEN_CLAIMPREVIOUS.
2654 */
2655 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2656 claim = fxdr_unsigned(int, *tl);
2657 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) {
2658 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2659 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2660 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
2661 stp->ls_flags |= NFSLCK_DELEGCUR;
2662 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2663 stp->ls_flags |= NFSLCK_DELEGPREV;
2664 }
2665 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
2666 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
2667 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
2668 claim != NFSV4OPEN_CLAIMNULL)
2669 nd->nd_repstat = NFSERR_INVAL;
2670 if (nd->nd_repstat) {
2671 nd->nd_repstat = nfsrv_opencheck(clientid,
2672 &stateid, stp, NULL, nd, p, nd->nd_repstat);
2673 goto nfsmout;
2674 }
2675 if (create == NFSV4OPEN_CREATE)
2676 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
2677 LOCKPARENT | LOCKLEAF | SAVESTART);
2678 else
2679 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
2680 LOCKLEAF | SAVESTART);
2681 nfsvno_setpathbuf(&named, &bufp, &hashp);
2682 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
2683 if (error) {
2684 vrele(dp);
2685 #ifdef NFS4_ACL_EXTATTR_NAME
2686 acl_free(aclp);
2687 #endif
2688 FREE((caddr_t)stp, M_NFSDSTATE);
2689 nfsvno_relpathbuf(&named);
2690 NFSEXITCODE2(error, nd);
2691 return (error);
2692 }
2693 if (!nd->nd_repstat) {
2694 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
2695 p, &dirp);
2696 } else {
2697 vrele(dp);
2698 nfsvno_relpathbuf(&named);
2699 }
2700 if (create == NFSV4OPEN_CREATE) {
2701 switch (how) {
2702 case NFSCREATE_UNCHECKED:
2703 if (named.ni_vp) {
2704 /*
2705 * Clear the setable attribute bits, except
2706 * for Size, if it is being truncated.
2707 */
2708 NFSZERO_ATTRBIT(&attrbits);
2709 if (NFSVNO_ISSETSIZE(&nva))
2710 NFSSETBIT_ATTRBIT(&attrbits,
2711 NFSATTRBIT_SIZE);
2712 }
2713 break;
2714 case NFSCREATE_GUARDED:
2715 if (named.ni_vp && !nd->nd_repstat)
2716 nd->nd_repstat = EEXIST;
2717 break;
2718 case NFSCREATE_EXCLUSIVE:
2719 exclusive_flag = 1;
2720 if (!named.ni_vp)
2721 nva.na_mode = 0;
2722 };
2723 }
2724 nfsvno_open(nd, &named, clientid, &stateid, stp,
2725 &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
2726 nd->nd_cred, p, exp, &vp);
2727 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2728 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2729 i = fxdr_unsigned(int, *tl);
2730 switch (i) {
2731 case NFSV4OPEN_DELEGATEREAD:
2732 stp->ls_flags |= NFSLCK_DELEGREAD;
2733 break;
2734 case NFSV4OPEN_DELEGATEWRITE:
2735 stp->ls_flags |= NFSLCK_DELEGWRITE;
2736 case NFSV4OPEN_DELEGATENONE:
2737 break;
2738 default:
2739 nd->nd_repstat = NFSERR_BADXDR;
2740 goto nfsmout;
2741 };
2742 stp->ls_flags |= NFSLCK_RECLAIM;
2743 vp = dp;
2744 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2745 if ((vp->v_iflag & VI_DOOMED) == 0)
2746 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
2747 stp, vp, nd, p, nd->nd_repstat);
2748 else
2749 nd->nd_repstat = NFSERR_PERM;
2750 } else {
2751 nd->nd_repstat = NFSERR_BADXDR;
2752 goto nfsmout;
2753 }
2754
2755 /*
2756 * Do basic access checking.
2757 */
2758 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
2759 /*
2760 * The IETF working group decided that this is the correct
2761 * error return for all non-regular files.
2762 */
2763 nd->nd_repstat = NFSERR_SYMLINK;
2764 }
2765 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
2766 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
2767 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2768 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
2769 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
2770 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
2771 if (nd->nd_repstat)
2772 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
2773 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
2774 NFSACCCHK_VPISLOCKED, NULL);
2775 }
2776
2777 if (!nd->nd_repstat) {
2778 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
2779 if (!nd->nd_repstat) {
2780 tverf[0] = nva.na_atime.tv_sec;
2781 tverf[1] = nva.na_atime.tv_nsec;
2782 }
2783 }
2784 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
2785 cverf[1] != tverf[1]))
2786 nd->nd_repstat = EEXIST;
2787 /*
2788 * Do the open locking/delegation stuff.
2789 */
2790 if (!nd->nd_repstat)
2791 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
2792 &delegstateid, &rflags, exp, p, nva.na_filerev);
2793
2794 /*
2795 * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
2796 * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
2797 * (ie: Leave the NFSVOPUNLOCK() about here.)
2798 */
2799 if (vp)
2800 NFSVOPUNLOCK(vp, 0);
2801 if (stp)
2802 FREE((caddr_t)stp, M_NFSDSTATE);
2803 if (!nd->nd_repstat && dirp)
2804 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p,
2805 0);
2806 if (!nd->nd_repstat) {
2807 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
2808 *tl++ = txdr_unsigned(stateid.seqid);
2809 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2810 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2811 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
2812 *tl++ = newnfs_true;
2813 *tl++ = 0;
2814 *tl++ = 0;
2815 *tl++ = 0;
2816 *tl++ = 0;
2817 } else {
2818 *tl++ = newnfs_false; /* Since dirp is not locked */
2819 txdr_hyper(dirfor.na_filerev, tl);
2820 tl += 2;
2821 txdr_hyper(diraft.na_filerev, tl);
2822 tl += 2;
2823 }
2824 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
2825 (void) nfsrv_putattrbit(nd, &attrbits);
2826 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2827 if (rflags & NFSV4OPEN_READDELEGATE)
2828 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
2829 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
2830 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
2831 else
2832 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
2833 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
2834 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
2835 *tl++ = txdr_unsigned(delegstateid.seqid);
2836 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
2837 NFSX_STATEIDOTHER);
2838 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
2839 if (rflags & NFSV4OPEN_RECALL)
2840 *tl = newnfs_true;
2841 else
2842 *tl = newnfs_false;
2843 if (rflags & NFSV4OPEN_WRITEDELEGATE) {
2844 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2845 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
2846 txdr_hyper(nva.na_size, tl);
2847 }
2848 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
2849 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
2850 *tl++ = txdr_unsigned(0x0);
2851 acemask = NFSV4ACE_ALLFILESMASK;
2852 if (nva.na_mode & S_IRUSR)
2853 acemask |= NFSV4ACE_READMASK;
2854 if (nva.na_mode & S_IWUSR)
2855 acemask |= NFSV4ACE_WRITEMASK;
2856 if (nva.na_mode & S_IXUSR)
2857 acemask |= NFSV4ACE_EXECUTEMASK;
2858 *tl = txdr_unsigned(acemask);
2859 (void) nfsm_strtom(nd, "OWNER@", 6);
2860 }
2861 *vpp = vp;
2862 } else if (vp) {
2863 vrele(vp);
2864 }
2865 if (dirp)
2866 vrele(dirp);
2867 #ifdef NFS4_ACL_EXTATTR_NAME
2868 acl_free(aclp);
2869 #endif
2870 NFSEXITCODE2(0, nd);
2871 return (0);
2872 nfsmout:
2873 vrele(dp);
2874 #ifdef NFS4_ACL_EXTATTR_NAME
2875 acl_free(aclp);
2876 #endif
2877 if (stp)
2878 FREE((caddr_t)stp, M_NFSDSTATE);
2879 NFSEXITCODE2(error, nd);
2880 return (error);
2881 }
2882
2883 /*
2884 * nfsv4 close service
2885 */
2886 APPLESTATIC int
2887 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
2888 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2889 {
2890 u_int32_t *tl;
2891 struct nfsstate st, *stp = &st;
2892 int error = 0;
2893 nfsv4stateid_t stateid;
2894 nfsquad_t clientid;
2895
2896 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
2897 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
2898 stp->ls_ownerlen = 0;
2899 stp->ls_op = nd->nd_rp;
2900 stp->ls_uid = nd->nd_cred->cr_uid;
2901 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2902 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
2903 NFSX_STATEIDOTHER);
2904 stp->ls_flags = NFSLCK_CLOSE;
2905 clientid.lval[0] = stp->ls_stateid.other[0];
2906 clientid.lval[1] = stp->ls_stateid.other[1];
2907 if (nd->nd_flag & ND_IMPLIEDCLID) {
2908 if (nd->nd_clientid.qval != clientid.qval)
2909 printf("EEK! multiple clids\n");
2910 } else {
2911 nd->nd_flag |= ND_IMPLIEDCLID;
2912 nd->nd_clientid.qval = clientid.qval;
2913 }
2914 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
2915 vput(vp);
2916 if (!nd->nd_repstat) {
2917 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
2918 *tl++ = txdr_unsigned(stateid.seqid);
2919 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
2920 }
2921 NFSEXITCODE2(0, nd);
2922 return (0);
2923 nfsmout:
2924 vput(vp);
2925 NFSEXITCODE2(error, nd);
2926 return (error);
2927 }
2928
2929 /*
2930 * nfsv4 delegpurge service
2931 */
2932 APPLESTATIC int
2933 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
2934 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
2935 {
2936 u_int32_t *tl;
2937 int error = 0;
2938 nfsquad_t clientid;
2939
2940 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
2941 nd->nd_repstat = NFSERR_WRONGSEC;
2942 goto nfsmout;
2943 }
2944 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2945 clientid.lval[0] = *tl++;
2946 clientid.lval[1] = *tl;
2947 if (nd->nd_flag & ND_IMPLIEDCLID) {
2948 if (nd->nd_clientid.qval != clientid.qval)
2949 printf("EEK! multiple clids\n");
2950 } else {
2951 nd->nd_flag |= ND_IMPLIEDCLID;
2952 nd->nd_clientid.qval = clientid.qval;
2953 }
2954 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL,
2955 NFSV4OP_DELEGPURGE, nd->nd_cred, p);
2956 nfsmout:
2957 NFSEXITCODE2(error, nd);
2958 return (error);
2959 }
2960
2961 /*
2962 * nfsv4 delegreturn service
2963 */
2964 APPLESTATIC int
2965 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
2966 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2967 {
2968 u_int32_t *tl;
2969 int error = 0;
2970 nfsv4stateid_t stateid;
2971 nfsquad_t clientid;
2972
2973 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
2974 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
2975 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
2976 clientid.lval[0] = stateid.other[0];
2977 clientid.lval[1] = stateid.other[1];
2978 if (nd->nd_flag & ND_IMPLIEDCLID) {
2979 if (nd->nd_clientid.qval != clientid.qval)
2980 printf("EEK! multiple clids\n");
2981 } else {
2982 nd->nd_flag |= ND_IMPLIEDCLID;
2983 nd->nd_clientid.qval = clientid.qval;
2984 }
2985 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp,
2986 NFSV4OP_DELEGRETURN, nd->nd_cred, p);
2987 nfsmout:
2988 vput(vp);
2989 NFSEXITCODE2(error, nd);
2990 return (error);
2991 }
2992
2993 /*
2994 * nfsv4 get file handle service
2995 */
2996 APPLESTATIC int
2997 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
2998 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
2999 {
3000 fhandle_t fh;
3001
3002 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3003 vput(vp);
3004 if (!nd->nd_repstat)
3005 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
3006 NFSEXITCODE2(0, nd);
3007 return (0);
3008 }
3009
3010 /*
3011 * nfsv4 open confirm service
3012 */
3013 APPLESTATIC int
3014 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
3015 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3016 {
3017 u_int32_t *tl;
3018 struct nfsstate st, *stp = &st;
3019 int error = 0;
3020 nfsv4stateid_t stateid;
3021 nfsquad_t clientid;
3022
3023 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
3024 stp->ls_ownerlen = 0;
3025 stp->ls_op = nd->nd_rp;
3026 stp->ls_uid = nd->nd_cred->cr_uid;
3027 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3028 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3029 NFSX_STATEIDOTHER);
3030 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3031 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
3032 stp->ls_flags = NFSLCK_CONFIRM;
3033 clientid.lval[0] = stp->ls_stateid.other[0];
3034 clientid.lval[1] = stp->ls_stateid.other[1];
3035 if (nd->nd_flag & ND_IMPLIEDCLID) {
3036 if (nd->nd_clientid.qval != clientid.qval)
3037 printf("EEK! multiple clids\n");
3038 } else {
3039 nd->nd_flag |= ND_IMPLIEDCLID;
3040 nd->nd_clientid.qval = clientid.qval;
3041 }
3042 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p);
3043 if (!nd->nd_repstat) {
3044 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3045 *tl++ = txdr_unsigned(stateid.seqid);
3046 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3047 }
3048 nfsmout:
3049 vput(vp);
3050 NFSEXITCODE2(error, nd);
3051 return (error);
3052 }
3053
3054 /*
3055 * nfsv4 open downgrade service
3056 */
3057 APPLESTATIC int
3058 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
3059 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3060 {
3061 u_int32_t *tl;
3062 int i;
3063 struct nfsstate st, *stp = &st;
3064 int error = 0;
3065 nfsv4stateid_t stateid;
3066 nfsquad_t clientid;
3067
3068 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
3069 stp->ls_ownerlen = 0;
3070 stp->ls_op = nd->nd_rp;
3071 stp->ls_uid = nd->nd_cred->cr_uid;
3072 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
3073 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
3074 NFSX_STATEIDOTHER);
3075 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3076 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
3077 i = fxdr_unsigned(int, *tl++);
3078 switch (i) {
3079 case NFSV4OPEN_ACCESSREAD:
3080 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
3081 break;
3082 case NFSV4OPEN_ACCESSWRITE:
3083 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
3084 break;
3085 case NFSV4OPEN_ACCESSBOTH:
3086 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
3087 NFSLCK_DOWNGRADE);
3088 break;
3089 default:
3090 nd->nd_repstat = NFSERR_BADXDR;
3091 };
3092 i = fxdr_unsigned(int, *tl);
3093 switch (i) {
3094 case NFSV4OPEN_DENYNONE:
3095 break;
3096 case NFSV4OPEN_DENYREAD:
3097 stp->ls_flags |= NFSLCK_READDENY;
3098 break;
3099 case NFSV4OPEN_DENYWRITE:
3100 stp->ls_flags |= NFSLCK_WRITEDENY;
3101 break;
3102 case NFSV4OPEN_DENYBOTH:
3103 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
3104 break;
3105 default:
3106 nd->nd_repstat = NFSERR_BADXDR;
3107 };
3108
3109 clientid.lval[0] = stp->ls_stateid.other[0];
3110 clientid.lval[1] = stp->ls_stateid.other[1];
3111 if (nd->nd_flag & ND_IMPLIEDCLID) {
3112 if (nd->nd_clientid.qval != clientid.qval)
3113 printf("EEK! multiple clids\n");
3114 } else {
3115 nd->nd_flag |= ND_IMPLIEDCLID;
3116 nd->nd_clientid.qval = clientid.qval;
3117 }
3118 if (!nd->nd_repstat)
3119 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
3120 nd, p);
3121 if (!nd->nd_repstat) {
3122 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
3123 *tl++ = txdr_unsigned(stateid.seqid);
3124 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
3125 }
3126 nfsmout:
3127 vput(vp);
3128 NFSEXITCODE2(error, nd);
3129 return (error);
3130 }
3131
3132 /*
3133 * nfsv4 renew lease service
3134 */
3135 APPLESTATIC int
3136 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
3137 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3138 {
3139 u_int32_t *tl;
3140 int error = 0;
3141 nfsquad_t clientid;
3142
3143 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3144 nd->nd_repstat = NFSERR_WRONGSEC;
3145 goto nfsmout;
3146 }
3147 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
3148 clientid.lval[0] = *tl++;
3149 clientid.lval[1] = *tl;
3150 if (nd->nd_flag & ND_IMPLIEDCLID) {
3151 if (nd->nd_clientid.qval != clientid.qval)
3152 printf("EEK! multiple clids\n");
3153 } else {
3154 nd->nd_flag |= ND_IMPLIEDCLID;
3155 nd->nd_clientid.qval = clientid.qval;
3156 }
3157 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
3158 NULL, (nfsquad_t)((u_quad_t)0), nd, p);
3159 nfsmout:
3160 NFSEXITCODE2(error, nd);
3161 return (error);
3162 }
3163
3164 /*
3165 * nfsv4 security info service
3166 */
3167 APPLESTATIC int
3168 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
3169 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp)
3170 {
3171 u_int32_t *tl;
3172 int len;
3173 struct nameidata named;
3174 vnode_t dirp = NULL, vp;
3175 struct nfsrvfh fh;
3176 struct nfsexstuff retnes;
3177 u_int32_t *sizp;
3178 int error = 0, savflag, i;
3179 char *bufp;
3180 u_long *hashp;
3181
3182 /*
3183 * All this just to get the export flags for the name.
3184 */
3185 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
3186 LOCKLEAF | SAVESTART);
3187 nfsvno_setpathbuf(&named, &bufp, &hashp);
3188 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
3189 if (error) {
3190 vput(dp);
3191 nfsvno_relpathbuf(&named);
3192 goto out;
3193 }
3194 if (!nd->nd_repstat) {
3195 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
3196 } else {
3197 vput(dp);
3198 nfsvno_relpathbuf(&named);
3199 }
3200 if (dirp)
3201 vrele(dirp);
3202 if (nd->nd_repstat)
3203 goto out;
3204 vrele(named.ni_startdir);
3205 nfsvno_relpathbuf(&named);
3206 fh.nfsrvfh_len = NFSX_MYFH;
3207 vp = named.ni_vp;
3208 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
3209 vput(vp);
3210 savflag = nd->nd_flag;
3211 if (!nd->nd_repstat) {
3212 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p);
3213 if (vp)
3214 vput(vp);
3215 }
3216 nd->nd_flag = savflag;
3217 if (nd->nd_repstat)
3218 goto out;
3219
3220 /*
3221 * Finally have the export flags for name, so we can create
3222 * the security info.
3223 */
3224 len = 0;
3225 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
3226 for (i = 0; i < retnes.nes_numsecflavor; i++) {
3227 if (retnes.nes_secflavors[i] == AUTH_SYS) {
3228 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3229 *tl = txdr_unsigned(RPCAUTH_UNIX);
3230 len++;
3231 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
3232 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3233 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3234 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3235 nfsgss_mechlist[KERBV_MECH].len);
3236 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3237 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3238 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
3239 len++;
3240 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
3241 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3242 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3243 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3244 nfsgss_mechlist[KERBV_MECH].len);
3245 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3246 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3247 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
3248 len++;
3249 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
3250 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3251 *tl++ = txdr_unsigned(RPCAUTH_GSS);
3252 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
3253 nfsgss_mechlist[KERBV_MECH].len);
3254 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3255 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
3256 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
3257 len++;
3258 }
3259 }
3260 *sizp = txdr_unsigned(len);
3261
3262 out:
3263 NFSEXITCODE2(error, nd);
3264 return (error);
3265 }
3266
3267 /*
3268 * nfsv4 set client id service
3269 */
3270 APPLESTATIC int
3271 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
3272 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3273 {
3274 u_int32_t *tl;
3275 int i;
3276 int error = 0, idlen;
3277 struct nfsclient *clp = NULL;
3278 struct sockaddr_in *rad;
3279 u_char *verf, *ucp, *ucp2, addrbuf[24];
3280 nfsquad_t clientid, confirm;
3281
3282 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3283 nd->nd_repstat = NFSERR_WRONGSEC;
3284 goto out;
3285 }
3286 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
3287 verf = (u_char *)tl;
3288 tl += (NFSX_VERF / NFSX_UNSIGNED);
3289 i = fxdr_unsigned(int, *tl);
3290 if (i > NFSV4_OPAQUELIMIT || i <= 0) {
3291 nd->nd_repstat = NFSERR_BADXDR;
3292 goto nfsmout;
3293 }
3294 idlen = i;
3295 if (nd->nd_flag & ND_GSS)
3296 i += nd->nd_princlen;
3297 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i,
3298 M_NFSDCLIENT, M_WAITOK);
3299 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i);
3300 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
3301 NFSSOCKADDRALLOC(clp->lc_req.nr_nam);
3302 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
3303 clp->lc_req.nr_cred = NULL;
3304 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
3305 clp->lc_idlen = idlen;
3306 error = nfsrv_mtostr(nd, clp->lc_id, idlen);
3307 if (error)
3308 goto nfsmout;
3309 if (nd->nd_flag & ND_GSS) {
3310 clp->lc_flags = LCL_GSS;
3311 if (nd->nd_flag & ND_GSSINTEGRITY)
3312 clp->lc_flags |= LCL_GSSINTEGRITY;
3313 else if (nd->nd_flag & ND_GSSPRIVACY)
3314 clp->lc_flags |= LCL_GSSPRIVACY;
3315 } else {
3316 clp->lc_flags = 0;
3317 }
3318 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
3319 clp->lc_flags |= LCL_NAME;
3320 clp->lc_namelen = nd->nd_princlen;
3321 clp->lc_name = &clp->lc_id[idlen];
3322 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
3323 } else {
3324 clp->lc_uid = nd->nd_cred->cr_uid;
3325 clp->lc_gid = nd->nd_cred->cr_gid;
3326 }
3327 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3328 clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
3329 error = nfsrv_getclientipaddr(nd, clp);
3330 if (error)
3331 goto nfsmout;
3332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3333 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
3334
3335 /*
3336 * nfsrv_setclient() does the actual work of adding it to the
3337 * client list. If there is no error, the structure has been
3338 * linked into the client list and clp should no longer be used
3339 * here. When an error is returned, it has not been linked in,
3340 * so it should be free'd.
3341 */
3342 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
3343 if (nd->nd_repstat == NFSERR_CLIDINUSE) {
3344 if (clp->lc_flags & LCL_TCPCALLBACK)
3345 (void) nfsm_strtom(nd, "tcp", 3);
3346 else
3347 (void) nfsm_strtom(nd, "udp", 3);
3348 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3349 ucp = (u_char *)&rad->sin_addr.s_addr;
3350 ucp2 = (u_char *)&rad->sin_port;
3351 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
3352 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
3353 ucp2[0] & 0xff, ucp2[1] & 0xff);
3354 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
3355 }
3356 if (clp) {
3357 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3358 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3359 free((caddr_t)clp, M_NFSDCLIENT);
3360 }
3361 if (!nd->nd_repstat) {
3362 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
3363 *tl++ = clientid.lval[0];
3364 *tl++ = clientid.lval[1];
3365 *tl++ = confirm.lval[0];
3366 *tl = confirm.lval[1];
3367 }
3368
3369 out:
3370 NFSEXITCODE2(0, nd);
3371 return (0);
3372 nfsmout:
3373 if (clp) {
3374 NFSSOCKADDRFREE(clp->lc_req.nr_nam);
3375 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
3376 free((caddr_t)clp, M_NFSDCLIENT);
3377 }
3378 NFSEXITCODE2(error, nd);
3379 return (error);
3380 }
3381
3382 /*
3383 * nfsv4 set client id confirm service
3384 */
3385 APPLESTATIC int
3386 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
3387 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p,
3388 __unused struct nfsexstuff *exp)
3389 {
3390 u_int32_t *tl;
3391 int error = 0;
3392 nfsquad_t clientid, confirm;
3393
3394 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3395 nd->nd_repstat = NFSERR_WRONGSEC;
3396 goto nfsmout;
3397 }
3398 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
3399 clientid.lval[0] = *tl++;
3400 clientid.lval[1] = *tl++;
3401 confirm.lval[0] = *tl++;
3402 confirm.lval[1] = *tl;
3403
3404 /*
3405 * nfsrv_getclient() searches the client list for a match and
3406 * returns the appropriate NFSERR status.
3407 */
3408 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
3409 NULL, confirm, nd, p);
3410 nfsmout:
3411 NFSEXITCODE2(error, nd);
3412 return (error);
3413 }
3414
3415 /*
3416 * nfsv4 verify service
3417 */
3418 APPLESTATIC int
3419 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
3420 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3421 {
3422 int error = 0, ret, fhsize = NFSX_MYFH;
3423 struct nfsvattr nva;
3424 struct statfs sf;
3425 struct nfsfsinfo fs;
3426 fhandle_t fh;
3427
3428 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1);
3429 if (!nd->nd_repstat)
3430 nd->nd_repstat = nfsvno_statfs(vp, &sf);
3431 if (!nd->nd_repstat)
3432 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
3433 if (!nd->nd_repstat) {
3434 nfsvno_getfs(&fs, isdgram);
3435 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
3436 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
3437 if (!error) {
3438 if (nd->nd_procnum == NFSV4OP_NVERIFY) {
3439 if (ret == 0)
3440 nd->nd_repstat = NFSERR_SAME;
3441 else if (ret != NFSERR_NOTSAME)
3442 nd->nd_repstat = ret;
3443 } else if (ret)
3444 nd->nd_repstat = ret;
3445 }
3446 }
3447 vput(vp);
3448 NFSEXITCODE2(error, nd);
3449 return (error);
3450 }
3451
3452 /*
3453 * nfs openattr rpc
3454 */
3455 APPLESTATIC int
3456 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
3457 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
3458 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp)
3459 {
3460 u_int32_t *tl;
3461 int error = 0, createdir;
3462
3463 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3464 createdir = fxdr_unsigned(int, *tl);
3465 nd->nd_repstat = NFSERR_NOTSUPP;
3466 nfsmout:
3467 vrele(dp);
3468 NFSEXITCODE2(error, nd);
3469 return (error);
3470 }
3471
3472 /*
3473 * nfsv4 release lock owner service
3474 */
3475 APPLESTATIC int
3476 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
3477 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp)
3478 {
3479 u_int32_t *tl;
3480 struct nfsstate *stp = NULL;
3481 int error = 0, len;
3482 nfsquad_t clientid;
3483
3484 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
3485 nd->nd_repstat = NFSERR_WRONGSEC;
3486 goto nfsmout;
3487 }
3488 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3489 len = fxdr_unsigned(int, *(tl + 2));
3490 if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
3491 nd->nd_repstat = NFSERR_BADXDR;
3492 goto nfsmout;
3493 }
3494 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len,
3495 M_NFSDSTATE, M_WAITOK);
3496 stp->ls_ownerlen = len;
3497 stp->ls_op = NULL;
3498 stp->ls_flags = NFSLCK_RELEASE;
3499 stp->ls_uid = nd->nd_cred->cr_uid;
3500 clientid.lval[0] = *tl++;
3501 clientid.lval[1] = *tl;
3502 if (nd->nd_flag & ND_IMPLIEDCLID) {
3503 if (nd->nd_clientid.qval != clientid.qval)
3504 printf("EEK! multiple clids\n");
3505 } else {
3506 nd->nd_flag |= ND_IMPLIEDCLID;
3507 nd->nd_clientid.qval = clientid.qval;
3508 }
3509 error = nfsrv_mtostr(nd, stp->ls_owner, len);
3510 if (error)
3511 goto nfsmout;
3512 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
3513 FREE((caddr_t)stp, M_NFSDSTATE);
3514
3515 NFSEXITCODE2(0, nd);
3516 return (0);
3517 nfsmout:
3518 if (stp)
3519 free((caddr_t)stp, M_NFSDSTATE);
3520 NFSEXITCODE2(error, nd);
3521 return (error);
3522 }
Cache object: 304028348335faae77193bd15ceebf6a
|