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