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