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