1 /* $NetBSD: nfs_commonsubs.c,v 1.1.1.1 2013/09/30 07:19:38 dholland Exp $ */
2 /*-
3 * Copyright (c) 1989, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Rick Macklem at The University of Guelph.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 */
34
35 #include <sys/cdefs.h>
36 /* __FBSDID("FreeBSD: head/sys/fs/nfs/nfs_commonsubs.c 253506 2013-07-20 22:35:32Z rmacklem "); */
37 __RCSID("$NetBSD: nfs_commonsubs.c,v 1.1.1.1 2013/09/30 07:19:38 dholland Exp $");
38
39 /*
40 * These functions support the macros and help fiddle mbuf chains for
41 * the nfs op functions. They do things like create the rpc header and
42 * copy data between mbuf chains and uio lists.
43 */
44 #ifndef APPLEKEXT
45 #include "opt_inet6.h"
46
47 #include <fs/nfs/nfsport.h>
48
49 /*
50 * Data items converted to xdr at startup, since they are constant
51 * This is kinda hokey, but may save a little time doing byte swaps
52 */
53 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
54
55 /* And other global data */
56 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
57 NFFIFO, NFNON };
58 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
59 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
60 struct timeval nfsboottime; /* Copy boottime once, so it never changes */
61 int nfscl_ticks;
62 int nfsrv_useacl = 1;
63 struct nfssockreq nfsrv_nfsuserdsock;
64 int nfsrv_nfsuserd = 0;
65 struct nfsreqhead nfsd_reqq;
66 uid_t nfsrv_defaultuid;
67 gid_t nfsrv_defaultgid;
68 int nfsrv_lease = NFSRV_LEASE;
69 int ncl_mbuf_mlen = MLEN;
70 NFSNAMEIDMUTEX;
71 NFSSOCKMUTEX;
72
73 /*
74 * This array of structures indicates, for V4:
75 * retfh - which of 3 types of calling args are used
76 * 0 - doesn't change cfh or use a sfh
77 * 1 - replaces cfh with a new one (unless it returns an error status)
78 * 2 - uses cfh and sfh
79 * needscfh - if the op wants a cfh and premtime
80 * 0 - doesn't use a cfh
81 * 1 - uses a cfh, but doesn't want pre-op attributes
82 * 2 - uses a cfh and wants pre-op attributes
83 * savereply - indicates a non-idempotent Op
84 * 0 - not non-idempotent
85 * 1 - non-idempotent
86 * Ops that are ordered via seqid# are handled separately from these
87 * non-idempotent Ops.
88 * Define it here, since it is used by both the client and server.
89 */
90 struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = {
91 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
92 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
93 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */
94 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Access */
95 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Close */
96 { 0, 2, 0, 1, LK_EXCLUSIVE, 1 }, /* Commit */
97 { 1, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Create */
98 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegpurge */
99 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegreturn */
100 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Getattr */
101 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* GetFH */
102 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Link */
103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lock */
104 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockT */
105 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockU */
106 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */
107 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookupp */
108 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* NVerify */
109 { 1, 1, 0, 1, LK_EXCLUSIVE, 1 }, /* Open */
110 { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenAttr */
111 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenConfirm */
112 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenDowngrade */
113 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutFH */
114 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutPubFH */
115 { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutRootFH */
116 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Read */
117 { 0, 1, 0, 0, LK_SHARED, 1 }, /* Readdir */
118 { 0, 1, 0, 0, LK_SHARED, 1 }, /* ReadLink */
119 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Remove */
120 { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Rename */
121 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Renew */
122 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* RestoreFH */
123 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SaveFH */
124 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SecInfo */
125 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Setattr */
126 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientID */
127 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientIDConfirm */
128 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Verify */
129 { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Write */
130 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* ReleaseLockOwner */
131 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Backchannel Ctrl */
132 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Bind Conn to Sess */
133 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Exchange ID */
134 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Create Session */
135 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy Session */
136 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Free StateID */
137 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Dir Deleg */
138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device Info */
139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device List */
140 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Commit */
141 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Get */
142 { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Return */
143 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Secinfo No name */
144 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Sequence */
145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Set SSV */
146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Test StateID */
147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Want Delegation */
148 { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy ClientID */
149 { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Reclaim Complete */
150 };
151 #endif /* !APPLEKEXT */
152
153 static int ncl_mbuf_mhlen = MHLEN;
154 static int nfsrv_usercnt = 0;
155 static int nfsrv_dnsnamelen;
156 static u_char *nfsrv_dnsname = NULL;
157 static int nfsrv_usermax = 999999999;
158 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE];
159 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE];
160 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE];
161 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE];
162 static struct nfsuserlruhead nfsuserlruhead;
163
164 /*
165 * This static array indicates whether or not the RPC generates a large
166 * reply. This is used by nfs_reply() to decide whether or not an mbuf
167 * cluster should be allocated. (If a cluster is required by an RPC
168 * marked 0 in this array, the code will still work, just not quite as
169 * efficiently.)
170 */
171 int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
172 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 };
174
175 /* local functions */
176 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
177 static void nfsv4_wanted(struct nfsv4lock *lp);
178 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
179 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name,
180 NFSPROC_T *p);
181 static void nfsrv_removeuser(struct nfsusrgrp *usrp);
182 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
183 int *, int *);
184 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
185
186
187 #ifndef APPLE
188 /*
189 * copies mbuf chain to the uio scatter/gather list
190 */
191 int
nfsm_mbufuio(struct nfsrv_descript * nd,struct uio * uiop,int siz)192 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
193 {
194 char *mbufcp, *uiocp;
195 int xfer, left, len;
196 mbuf_t mp;
197 long uiosiz, rem;
198 int error = 0;
199
200 mp = nd->nd_md;
201 mbufcp = nd->nd_dpos;
202 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp;
203 rem = NFSM_RNDUP(siz) - siz;
204 while (siz > 0) {
205 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
206 error = EBADRPC;
207 goto out;
208 }
209 left = uiop->uio_iov->iov_len;
210 uiocp = uiop->uio_iov->iov_base;
211 if (left > siz)
212 left = siz;
213 uiosiz = left;
214 while (left > 0) {
215 while (len == 0) {
216 mp = mbuf_next(mp);
217 if (mp == NULL) {
218 error = EBADRPC;
219 goto out;
220 }
221 mbufcp = NFSMTOD(mp, caddr_t);
222 len = mbuf_len(mp);
223 KASSERT(len > 0, ("len %d", len));
224 }
225 xfer = (left > len) ? len : left;
226 #ifdef notdef
227 /* Not Yet.. */
228 if (uiop->uio_iov->iov_op != NULL)
229 (*(uiop->uio_iov->iov_op))
230 (mbufcp, uiocp, xfer);
231 else
232 #endif
233 if (uiop->uio_segflg == UIO_SYSSPACE)
234 NFSBCOPY(mbufcp, uiocp, xfer);
235 else
236 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
237 left -= xfer;
238 len -= xfer;
239 mbufcp += xfer;
240 uiocp += xfer;
241 uiop->uio_offset += xfer;
242 uiop->uio_resid -= xfer;
243 }
244 if (uiop->uio_iov->iov_len <= siz) {
245 uiop->uio_iovcnt--;
246 uiop->uio_iov++;
247 } else {
248 uiop->uio_iov->iov_base = (void *)
249 ((char *)uiop->uio_iov->iov_base + uiosiz);
250 uiop->uio_iov->iov_len -= uiosiz;
251 }
252 siz -= uiosiz;
253 }
254 nd->nd_dpos = mbufcp;
255 nd->nd_md = mp;
256 if (rem > 0) {
257 if (len < rem)
258 error = nfsm_advance(nd, rem, len);
259 else
260 nd->nd_dpos += rem;
261 }
262
263 out:
264 NFSEXITCODE2(error, nd);
265 return (error);
266 }
267 #endif /* !APPLE */
268
269 /*
270 * Help break down an mbuf chain by setting the first siz bytes contiguous
271 * pointed to by returned val.
272 * This is used by the macro NFSM_DISSECT for tough
273 * cases.
274 */
275 APPLESTATIC void *
nfsm_dissct(struct nfsrv_descript * nd,int siz,int how)276 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
277 {
278 mbuf_t mp2;
279 int siz2, xfer;
280 caddr_t p;
281 int left;
282 caddr_t retp;
283
284 retp = NULL;
285 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos;
286 while (left == 0) {
287 nd->nd_md = mbuf_next(nd->nd_md);
288 if (nd->nd_md == NULL)
289 return (retp);
290 left = mbuf_len(nd->nd_md);
291 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
292 }
293 if (left >= siz) {
294 retp = nd->nd_dpos;
295 nd->nd_dpos += siz;
296 } else if (mbuf_next(nd->nd_md) == NULL) {
297 return (retp);
298 } else if (siz > ncl_mbuf_mhlen) {
299 panic("nfs S too big");
300 } else {
301 MGET(mp2, MT_DATA, how);
302 if (mp2 == NULL)
303 return (NULL);
304 mbuf_setnext(mp2, mbuf_next(nd->nd_md));
305 mbuf_setnext(nd->nd_md, mp2);
306 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left);
307 nd->nd_md = mp2;
308 retp = p = NFSMTOD(mp2, caddr_t);
309 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
310 siz2 = siz - left;
311 p += left;
312 mp2 = mbuf_next(mp2);
313 /* Loop around copying up the siz2 bytes */
314 while (siz2 > 0) {
315 if (mp2 == NULL)
316 return (NULL);
317 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2;
318 if (xfer > 0) {
319 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer);
320 NFSM_DATAP(mp2, xfer);
321 mbuf_setlen(mp2, mbuf_len(mp2) - xfer);
322 p += xfer;
323 siz2 -= xfer;
324 }
325 if (siz2 > 0)
326 mp2 = mbuf_next(mp2);
327 }
328 mbuf_setlen(nd->nd_md, siz);
329 nd->nd_md = mp2;
330 nd->nd_dpos = NFSMTOD(mp2, caddr_t);
331 }
332 return (retp);
333 }
334
335 /*
336 * Advance the position in the mbuf chain.
337 * If offs == 0, this is a no-op, but it is simpler to just return from
338 * here than check for offs > 0 for all calls to nfsm_advance.
339 * If left == -1, it should be calculated here.
340 */
341 APPLESTATIC int
nfsm_advance(struct nfsrv_descript * nd,int offs,int left)342 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
343 {
344 int error = 0;
345
346 if (offs == 0)
347 goto out;
348 /*
349 * A negative offs should be considered a serious problem.
350 */
351 if (offs < 0)
352 panic("nfsrv_advance");
353
354 /*
355 * If left == -1, calculate it here.
356 */
357 if (left == -1)
358 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) -
359 nd->nd_dpos;
360
361 /*
362 * Loop around, advancing over the mbuf data.
363 */
364 while (offs > left) {
365 offs -= left;
366 nd->nd_md = mbuf_next(nd->nd_md);
367 if (nd->nd_md == NULL) {
368 error = EBADRPC;
369 goto out;
370 }
371 left = mbuf_len(nd->nd_md);
372 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t);
373 }
374 nd->nd_dpos += offs;
375
376 out:
377 NFSEXITCODE(error);
378 return (error);
379 }
380
381 /*
382 * Copy a string into mbuf(s).
383 * Return the number of bytes output, including XDR overheads.
384 */
385 APPLESTATIC int
nfsm_strtom(struct nfsrv_descript * nd,const char * cp,int siz)386 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
387 {
388 mbuf_t m2;
389 int xfer, left;
390 mbuf_t m1;
391 int rem, bytesize;
392 u_int32_t *tl;
393 char *cp2;
394
395 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
396 *tl = txdr_unsigned(siz);
397 rem = NFSM_RNDUP(siz) - siz;
398 bytesize = NFSX_UNSIGNED + siz + rem;
399 m2 = nd->nd_mb;
400 cp2 = nd->nd_bpos;
401 left = M_TRAILINGSPACE(m2);
402
403 /*
404 * Loop around copying the string to mbuf(s).
405 */
406 while (siz > 0) {
407 if (left == 0) {
408 if (siz > ncl_mbuf_mlen)
409 NFSMCLGET(m1, M_WAITOK);
410 else
411 NFSMGET(m1);
412 mbuf_setlen(m1, 0);
413 mbuf_setnext(m2, m1);
414 m2 = m1;
415 cp2 = NFSMTOD(m2, caddr_t);
416 left = M_TRAILINGSPACE(m2);
417 }
418 if (left >= siz)
419 xfer = siz;
420 else
421 xfer = left;
422 NFSBCOPY(cp, cp2, xfer);
423 cp += xfer;
424 mbuf_setlen(m2, mbuf_len(m2) + xfer);
425 siz -= xfer;
426 left -= xfer;
427 if (siz == 0 && rem) {
428 if (left < rem)
429 panic("nfsm_strtom");
430 NFSBZERO(cp2 + xfer, rem);
431 mbuf_setlen(m2, mbuf_len(m2) + rem);
432 }
433 }
434 nd->nd_mb = m2;
435 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2);
436 return (bytesize);
437 }
438
439 /*
440 * Called once to initialize data structures...
441 */
442 APPLESTATIC void
newnfs_init(void)443 newnfs_init(void)
444 {
445 static int nfs_inited = 0;
446
447 if (nfs_inited)
448 return;
449 nfs_inited = 1;
450
451 newnfs_true = txdr_unsigned(TRUE);
452 newnfs_false = txdr_unsigned(FALSE);
453 newnfs_xdrneg1 = txdr_unsigned(-1);
454 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
455 if (nfscl_ticks < 1)
456 nfscl_ticks = 1;
457 NFSSETBOOTTIME(nfsboottime);
458
459 /*
460 * Initialize reply list and start timer
461 */
462 TAILQ_INIT(&nfsd_reqq);
463 NFS_TIMERINIT;
464 }
465
466 /*
467 * Put a file handle in an mbuf list.
468 * If the size argument == 0, just use the default size.
469 * set_true == 1 if there should be an newnfs_true prepended on the file handle.
470 * Return the number of bytes output, including XDR overhead.
471 */
472 APPLESTATIC int
nfsm_fhtom(struct nfsrv_descript * nd,u_int8_t * fhp,int size,int set_true)473 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
474 {
475 u_int32_t *tl;
476 u_int8_t *cp;
477 int fullsiz, rem, bytesize = 0;
478
479 if (size == 0)
480 size = NFSX_MYFH;
481 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
482 case ND_NFSV2:
483 if (size > NFSX_V2FH)
484 panic("fh size > NFSX_V2FH for NFSv2");
485 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
486 NFSBCOPY(fhp, cp, size);
487 if (size < NFSX_V2FH)
488 NFSBZERO(cp + size, NFSX_V2FH - size);
489 bytesize = NFSX_V2FH;
490 break;
491 case ND_NFSV3:
492 case ND_NFSV4:
493 fullsiz = NFSM_RNDUP(size);
494 rem = fullsiz - size;
495 if (set_true) {
496 bytesize = 2 * NFSX_UNSIGNED + fullsiz;
497 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
498 *tl = newnfs_true;
499 } else {
500 bytesize = NFSX_UNSIGNED + fullsiz;
501 }
502 (void) nfsm_strtom(nd, fhp, size);
503 break;
504 };
505 return (bytesize);
506 }
507
508 /*
509 * This function compares two net addresses by family and returns TRUE
510 * if they are the same host.
511 * If there is any doubt, return FALSE.
512 * The AF_INET family is handled as a special case so that address mbufs
513 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
514 */
515 APPLESTATIC int
nfsaddr_match(int family,union nethostaddr * haddr,NFSSOCKADDR_T nam)516 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
517 {
518 struct sockaddr_in *inetaddr;
519
520 switch (family) {
521 case AF_INET:
522 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
523 if (inetaddr->sin_family == AF_INET &&
524 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
525 return (1);
526 break;
527 #ifdef INET6
528 case AF_INET6:
529 {
530 struct sockaddr_in6 *inetaddr6;
531
532 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
533 /* XXX - should test sin6_scope_id ? */
534 if (inetaddr6->sin6_family == AF_INET6 &&
535 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
536 &haddr->had_inet6))
537 return (1);
538 }
539 break;
540 #endif
541 };
542 return (0);
543 }
544
545 /*
546 * Similar to the above, but takes to NFSSOCKADDR_T args.
547 */
548 APPLESTATIC int
nfsaddr2_match(NFSSOCKADDR_T nam1,NFSSOCKADDR_T nam2)549 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
550 {
551 struct sockaddr_in *addr1, *addr2;
552 struct sockaddr *inaddr;
553
554 inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
555 switch (inaddr->sa_family) {
556 case AF_INET:
557 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
558 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
559 if (addr2->sin_family == AF_INET &&
560 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
561 return (1);
562 break;
563 #ifdef INET6
564 case AF_INET6:
565 {
566 struct sockaddr_in6 *inet6addr1, *inet6addr2;
567
568 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
569 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
570 /* XXX - should test sin6_scope_id ? */
571 if (inet6addr2->sin6_family == AF_INET6 &&
572 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
573 &inet6addr2->sin6_addr))
574 return (1);
575 }
576 break;
577 #endif
578 };
579 return (0);
580 }
581
582
583 /*
584 * Trim the stuff already dissected off the mbuf list.
585 */
586 APPLESTATIC void
newnfs_trimleading(nd)587 newnfs_trimleading(nd)
588 struct nfsrv_descript *nd;
589 {
590 mbuf_t m, n;
591 int offs;
592
593 /*
594 * First, free up leading mbufs.
595 */
596 if (nd->nd_mrep != nd->nd_md) {
597 m = nd->nd_mrep;
598 while (mbuf_next(m) != nd->nd_md) {
599 if (mbuf_next(m) == NULL)
600 panic("nfsm trim leading");
601 m = mbuf_next(m);
602 }
603 mbuf_setnext(m, NULL);
604 mbuf_freem(nd->nd_mrep);
605 }
606 m = nd->nd_md;
607
608 /*
609 * Now, adjust this mbuf, based on nd_dpos.
610 */
611 offs = nd->nd_dpos - NFSMTOD(m, caddr_t);
612 if (offs == mbuf_len(m)) {
613 n = m;
614 m = mbuf_next(m);
615 if (m == NULL)
616 panic("nfsm trim leading2");
617 mbuf_setnext(n, NULL);
618 mbuf_freem(n);
619 } else if (offs > 0) {
620 mbuf_setlen(m, mbuf_len(m) - offs);
621 NFSM_DATAP(m, offs);
622 } else if (offs < 0)
623 panic("nfsm trimleading offs");
624 nd->nd_mrep = m;
625 nd->nd_md = m;
626 nd->nd_dpos = NFSMTOD(m, caddr_t);
627 }
628
629 /*
630 * Trim trailing data off the mbuf list being built.
631 */
632 APPLESTATIC void
newnfs_trimtrailing(nd,mb,bpos)633 newnfs_trimtrailing(nd, mb, bpos)
634 struct nfsrv_descript *nd;
635 mbuf_t mb;
636 caddr_t bpos;
637 {
638
639 if (mbuf_next(mb)) {
640 mbuf_freem(mbuf_next(mb));
641 mbuf_setnext(mb, NULL);
642 }
643 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t));
644 nd->nd_mb = mb;
645 nd->nd_bpos = bpos;
646 }
647
648 /*
649 * Dissect a file handle on the client.
650 */
651 APPLESTATIC int
nfsm_getfh(struct nfsrv_descript * nd,struct nfsfh ** nfhpp)652 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
653 {
654 u_int32_t *tl;
655 struct nfsfh *nfhp;
656 int error, len;
657
658 *nfhpp = NULL;
659 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
660 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
661 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
662 len > NFSX_FHMAX) {
663 error = EBADRPC;
664 goto nfsmout;
665 }
666 } else
667 len = NFSX_V2FH;
668 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len,
669 M_NFSFH, M_WAITOK);
670 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
671 if (error) {
672 FREE((caddr_t)nfhp, M_NFSFH);
673 goto nfsmout;
674 }
675 nfhp->nfh_len = len;
676 *nfhpp = nfhp;
677 nfsmout:
678 NFSEXITCODE2(error, nd);
679 return (error);
680 }
681
682 /*
683 * Break down the nfsv4 acl.
684 * If the aclp == NULL or won't fit in an acl, just discard the acl info.
685 */
686 APPLESTATIC int
nfsrv_dissectacl(struct nfsrv_descript * nd,NFSACL_T * aclp,int * aclerrp,int * aclsizep,__unused NFSPROC_T * p)687 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp,
688 int *aclsizep, __unused NFSPROC_T *p)
689 {
690 u_int32_t *tl;
691 int i, aclsize;
692 int acecnt, error = 0, aceerr = 0, acesize;
693
694 *aclerrp = 0;
695 if (aclp)
696 aclp->acl_cnt = 0;
697 /*
698 * Parse out the ace entries and expect them to conform to
699 * what can be supported by R/W/X bits.
700 */
701 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
702 aclsize = NFSX_UNSIGNED;
703 acecnt = fxdr_unsigned(int, *tl);
704 if (acecnt > ACL_MAX_ENTRIES)
705 aceerr = NFSERR_ATTRNOTSUPP;
706 if (nfsrv_useacl == 0)
707 aceerr = NFSERR_ATTRNOTSUPP;
708 for (i = 0; i < acecnt; i++) {
709 if (aclp && !aceerr)
710 error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
711 &aceerr, &acesize, p);
712 else
713 error = nfsrv_skipace(nd, &acesize);
714 if (error)
715 goto nfsmout;
716 aclsize += acesize;
717 }
718 if (aclp && !aceerr)
719 aclp->acl_cnt = acecnt;
720 if (aceerr)
721 *aclerrp = aceerr;
722 if (aclsizep)
723 *aclsizep = aclsize;
724 nfsmout:
725 NFSEXITCODE2(error, nd);
726 return (error);
727 }
728
729 /*
730 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
731 */
732 static int
nfsrv_skipace(struct nfsrv_descript * nd,int * acesizep)733 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
734 {
735 u_int32_t *tl;
736 int error, len = 0;
737
738 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
739 len = fxdr_unsigned(int, *(tl + 3));
740 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
741 nfsmout:
742 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
743 NFSEXITCODE2(error, nd);
744 return (error);
745 }
746
747 /*
748 * Get attribute bits from an mbuf list.
749 * Returns EBADRPC for a parsing error, 0 otherwise.
750 * If the clearinvalid flag is set, clear the bits not supported.
751 */
752 APPLESTATIC int
nfsrv_getattrbits(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp,int * cntp,int * retnotsupp)753 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
754 int *retnotsupp)
755 {
756 u_int32_t *tl;
757 int cnt, i, outcnt;
758 int error = 0;
759
760 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
761 cnt = fxdr_unsigned(int, *tl);
762 if (cnt < 0) {
763 error = NFSERR_BADXDR;
764 goto nfsmout;
765 }
766 if (cnt > NFSATTRBIT_MAXWORDS)
767 outcnt = NFSATTRBIT_MAXWORDS;
768 else
769 outcnt = cnt;
770 NFSZERO_ATTRBIT(attrbitp);
771 if (outcnt > 0) {
772 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
773 for (i = 0; i < outcnt; i++)
774 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
775 }
776 for (i = 0; i < (cnt - outcnt); i++) {
777 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
778 if (retnotsupp != NULL && *tl != 0)
779 *retnotsupp = NFSERR_ATTRNOTSUPP;
780 }
781 if (cntp)
782 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
783 nfsmout:
784 NFSEXITCODE2(error, nd);
785 return (error);
786 }
787
788 /*
789 * Get the attributes for V4.
790 * If the compare flag is true, test for any attribute changes,
791 * otherwise return the attribute values.
792 * These attributes cover fields in "struct vattr", "struct statfs",
793 * "struct nfsfsinfo", the file handle and the lease duration.
794 * The value of retcmpp is set to 1 if all attributes are the same,
795 * and 0 otherwise.
796 * Returns EBADRPC if it can't be parsed, 0 otherwise.
797 */
798 APPLESTATIC int
nfsv4_loadattr(struct nfsrv_descript * nd,vnode_t vp,struct nfsvattr * nap,struct nfsfh ** nfhpp,fhandle_t * fhp,int fhsize,struct nfsv3_pathconf * pc,struct statfs * sbp,struct nfsstatfs * sfp,struct nfsfsinfo * fsp,NFSACL_T * aclp,int compare,int * retcmpp,u_int32_t * leasep,u_int32_t * rderrp,NFSPROC_T * p,struct ucred * cred)799 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
800 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
801 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
802 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
803 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
804 {
805 u_int32_t *tl;
806 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
807 int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
808 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
809 nfsattrbit_t attrbits, retattrbits, checkattrbits;
810 struct nfsfh *tnfhp;
811 struct nfsreferral *refp;
812 u_quad_t tquad;
813 nfsquad_t tnfsquad;
814 struct timespec temptime;
815 uid_t uid;
816 gid_t gid;
817 long fid;
818 u_int32_t freenum = 0, tuint;
819 u_int64_t uquad = 0, thyp, thyp2;
820 #ifdef QUOTA
821 struct dqblk dqb;
822 uid_t savuid;
823 #endif
824
825 if (compare) {
826 retnotsup = 0;
827 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
828 } else {
829 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
830 }
831 if (error)
832 goto nfsmout;
833
834 if (compare) {
835 *retcmpp = retnotsup;
836 } else {
837 /*
838 * Just set default values to some of the important ones.
839 */
840 if (nap != NULL) {
841 nap->na_type = VREG;
842 nap->na_mode = 0;
843 nap->na_rdev = (NFSDEV_T)0;
844 nap->na_mtime.tv_sec = 0;
845 nap->na_mtime.tv_nsec = 0;
846 nap->na_gen = 0;
847 nap->na_flags = 0;
848 nap->na_blocksize = NFS_FABLKSIZE;
849 }
850 if (sbp != NULL) {
851 sbp->f_bsize = NFS_FABLKSIZE;
852 sbp->f_blocks = 0;
853 sbp->f_bfree = 0;
854 sbp->f_bavail = 0;
855 sbp->f_files = 0;
856 sbp->f_ffree = 0;
857 }
858 if (fsp != NULL) {
859 fsp->fs_rtmax = 8192;
860 fsp->fs_rtpref = 8192;
861 fsp->fs_maxname = NFS_MAXNAMLEN;
862 fsp->fs_wtmax = 8192;
863 fsp->fs_wtpref = 8192;
864 fsp->fs_wtmult = NFS_FABLKSIZE;
865 fsp->fs_dtpref = 8192;
866 fsp->fs_maxfilesize = 0xffffffffffffffffull;
867 fsp->fs_timedelta.tv_sec = 0;
868 fsp->fs_timedelta.tv_nsec = 1;
869 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
870 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
871 }
872 if (pc != NULL) {
873 pc->pc_linkmax = LINK_MAX;
874 pc->pc_namemax = NAME_MAX;
875 pc->pc_notrunc = 0;
876 pc->pc_chownrestricted = 0;
877 pc->pc_caseinsensitive = 0;
878 pc->pc_casepreserving = 1;
879 }
880 }
881
882 /*
883 * Loop around getting the attributes.
884 */
885 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
886 attrsize = fxdr_unsigned(int, *tl);
887 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
888 if (attrsum > attrsize) {
889 error = NFSERR_BADXDR;
890 goto nfsmout;
891 }
892 if (NFSISSET_ATTRBIT(&attrbits, bitpos))
893 switch (bitpos) {
894 case NFSATTRBIT_SUPPORTEDATTRS:
895 retnotsup = 0;
896 if (compare || nap == NULL)
897 error = nfsrv_getattrbits(nd, &retattrbits,
898 &cnt, &retnotsup);
899 else
900 error = nfsrv_getattrbits(nd, &nap->na_suppattr,
901 &cnt, &retnotsup);
902 if (error)
903 goto nfsmout;
904 if (compare && !(*retcmpp)) {
905 NFSSETSUPP_ATTRBIT(&checkattrbits);
906 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
907 || retnotsup)
908 *retcmpp = NFSERR_NOTSAME;
909 }
910 attrsum += cnt;
911 break;
912 case NFSATTRBIT_TYPE:
913 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
914 if (compare) {
915 if (!(*retcmpp)) {
916 if (nap->na_type != nfsv34tov_type(*tl))
917 *retcmpp = NFSERR_NOTSAME;
918 }
919 } else if (nap != NULL) {
920 nap->na_type = nfsv34tov_type(*tl);
921 }
922 attrsum += NFSX_UNSIGNED;
923 break;
924 case NFSATTRBIT_FHEXPIRETYPE:
925 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
926 if (compare && !(*retcmpp)) {
927 if (fxdr_unsigned(int, *tl) !=
928 NFSV4FHTYPE_PERSISTENT)
929 *retcmpp = NFSERR_NOTSAME;
930 }
931 attrsum += NFSX_UNSIGNED;
932 break;
933 case NFSATTRBIT_CHANGE:
934 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
935 if (compare) {
936 if (!(*retcmpp)) {
937 if (nap->na_filerev != fxdr_hyper(tl))
938 *retcmpp = NFSERR_NOTSAME;
939 }
940 } else if (nap != NULL) {
941 nap->na_filerev = fxdr_hyper(tl);
942 }
943 attrsum += NFSX_HYPER;
944 break;
945 case NFSATTRBIT_SIZE:
946 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
947 if (compare) {
948 if (!(*retcmpp)) {
949 if (nap->na_size != fxdr_hyper(tl))
950 *retcmpp = NFSERR_NOTSAME;
951 }
952 } else if (nap != NULL) {
953 nap->na_size = fxdr_hyper(tl);
954 }
955 attrsum += NFSX_HYPER;
956 break;
957 case NFSATTRBIT_LINKSUPPORT:
958 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
959 if (compare) {
960 if (!(*retcmpp)) {
961 if (fsp->fs_properties & NFSV3_FSFLINK) {
962 if (*tl == newnfs_false)
963 *retcmpp = NFSERR_NOTSAME;
964 } else {
965 if (*tl == newnfs_true)
966 *retcmpp = NFSERR_NOTSAME;
967 }
968 }
969 } else if (fsp != NULL) {
970 if (*tl == newnfs_true)
971 fsp->fs_properties |= NFSV3_FSFLINK;
972 else
973 fsp->fs_properties &= ~NFSV3_FSFLINK;
974 }
975 attrsum += NFSX_UNSIGNED;
976 break;
977 case NFSATTRBIT_SYMLINKSUPPORT:
978 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
979 if (compare) {
980 if (!(*retcmpp)) {
981 if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
982 if (*tl == newnfs_false)
983 *retcmpp = NFSERR_NOTSAME;
984 } else {
985 if (*tl == newnfs_true)
986 *retcmpp = NFSERR_NOTSAME;
987 }
988 }
989 } else if (fsp != NULL) {
990 if (*tl == newnfs_true)
991 fsp->fs_properties |= NFSV3_FSFSYMLINK;
992 else
993 fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
994 }
995 attrsum += NFSX_UNSIGNED;
996 break;
997 case NFSATTRBIT_NAMEDATTR:
998 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
999 if (compare && !(*retcmpp)) {
1000 if (*tl != newnfs_false)
1001 *retcmpp = NFSERR_NOTSAME;
1002 }
1003 attrsum += NFSX_UNSIGNED;
1004 break;
1005 case NFSATTRBIT_FSID:
1006 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
1007 thyp = fxdr_hyper(tl);
1008 tl += 2;
1009 thyp2 = fxdr_hyper(tl);
1010 if (compare) {
1011 if (*retcmpp == 0) {
1012 if (thyp != (u_int64_t)
1013 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] ||
1014 thyp2 != (u_int64_t)
1015 vfs_statfs(vnode_mount(vp))->f_fsid.val[1])
1016 *retcmpp = NFSERR_NOTSAME;
1017 }
1018 } else if (nap != NULL) {
1019 nap->na_filesid[0] = thyp;
1020 nap->na_filesid[1] = thyp2;
1021 }
1022 attrsum += (4 * NFSX_UNSIGNED);
1023 break;
1024 case NFSATTRBIT_UNIQUEHANDLES:
1025 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1026 if (compare && !(*retcmpp)) {
1027 if (*tl != newnfs_true)
1028 *retcmpp = NFSERR_NOTSAME;
1029 }
1030 attrsum += NFSX_UNSIGNED;
1031 break;
1032 case NFSATTRBIT_LEASETIME:
1033 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1034 if (compare) {
1035 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
1036 !(*retcmpp))
1037 *retcmpp = NFSERR_NOTSAME;
1038 } else if (leasep != NULL) {
1039 *leasep = fxdr_unsigned(u_int32_t, *tl);
1040 }
1041 attrsum += NFSX_UNSIGNED;
1042 break;
1043 case NFSATTRBIT_RDATTRERROR:
1044 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1045 if (compare) {
1046 if (!(*retcmpp))
1047 *retcmpp = NFSERR_INVAL;
1048 } else if (rderrp != NULL) {
1049 *rderrp = fxdr_unsigned(u_int32_t, *tl);
1050 }
1051 attrsum += NFSX_UNSIGNED;
1052 break;
1053 case NFSATTRBIT_ACL:
1054 if (compare) {
1055 if (!(*retcmpp)) {
1056 if (nfsrv_useacl) {
1057 NFSACL_T *naclp;
1058
1059 naclp = acl_alloc(M_WAITOK);
1060 error = nfsrv_dissectacl(nd, naclp, &aceerr,
1061 &cnt, p);
1062 if (error) {
1063 acl_free(naclp);
1064 goto nfsmout;
1065 }
1066 if (aceerr || aclp == NULL ||
1067 nfsrv_compareacl(aclp, naclp))
1068 *retcmpp = NFSERR_NOTSAME;
1069 acl_free(naclp);
1070 } else {
1071 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1072 &cnt, p);
1073 *retcmpp = NFSERR_ATTRNOTSUPP;
1074 }
1075 }
1076 } else {
1077 if (vp != NULL && aclp != NULL)
1078 error = nfsrv_dissectacl(nd, aclp, &aceerr,
1079 &cnt, p);
1080 else
1081 error = nfsrv_dissectacl(nd, NULL, &aceerr,
1082 &cnt, p);
1083 if (error)
1084 goto nfsmout;
1085 }
1086 attrsum += cnt;
1087 break;
1088 case NFSATTRBIT_ACLSUPPORT:
1089 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1090 if (compare && !(*retcmpp)) {
1091 if (nfsrv_useacl) {
1092 if (fxdr_unsigned(u_int32_t, *tl) !=
1093 NFSV4ACE_SUPTYPES)
1094 *retcmpp = NFSERR_NOTSAME;
1095 } else {
1096 *retcmpp = NFSERR_ATTRNOTSUPP;
1097 }
1098 }
1099 attrsum += NFSX_UNSIGNED;
1100 break;
1101 case NFSATTRBIT_ARCHIVE:
1102 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1103 if (compare && !(*retcmpp))
1104 *retcmpp = NFSERR_ATTRNOTSUPP;
1105 attrsum += NFSX_UNSIGNED;
1106 break;
1107 case NFSATTRBIT_CANSETTIME:
1108 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1109 if (compare) {
1110 if (!(*retcmpp)) {
1111 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
1112 if (*tl == newnfs_false)
1113 *retcmpp = NFSERR_NOTSAME;
1114 } else {
1115 if (*tl == newnfs_true)
1116 *retcmpp = NFSERR_NOTSAME;
1117 }
1118 }
1119 } else if (fsp != NULL) {
1120 if (*tl == newnfs_true)
1121 fsp->fs_properties |= NFSV3_FSFCANSETTIME;
1122 else
1123 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
1124 }
1125 attrsum += NFSX_UNSIGNED;
1126 break;
1127 case NFSATTRBIT_CASEINSENSITIVE:
1128 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1129 if (compare) {
1130 if (!(*retcmpp)) {
1131 if (*tl != newnfs_false)
1132 *retcmpp = NFSERR_NOTSAME;
1133 }
1134 } else if (pc != NULL) {
1135 pc->pc_caseinsensitive =
1136 fxdr_unsigned(u_int32_t, *tl);
1137 }
1138 attrsum += NFSX_UNSIGNED;
1139 break;
1140 case NFSATTRBIT_CASEPRESERVING:
1141 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1142 if (compare) {
1143 if (!(*retcmpp)) {
1144 if (*tl != newnfs_true)
1145 *retcmpp = NFSERR_NOTSAME;
1146 }
1147 } else if (pc != NULL) {
1148 pc->pc_casepreserving =
1149 fxdr_unsigned(u_int32_t, *tl);
1150 }
1151 attrsum += NFSX_UNSIGNED;
1152 break;
1153 case NFSATTRBIT_CHOWNRESTRICTED:
1154 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1155 if (compare) {
1156 if (!(*retcmpp)) {
1157 if (*tl != newnfs_true)
1158 *retcmpp = NFSERR_NOTSAME;
1159 }
1160 } else if (pc != NULL) {
1161 pc->pc_chownrestricted =
1162 fxdr_unsigned(u_int32_t, *tl);
1163 }
1164 attrsum += NFSX_UNSIGNED;
1165 break;
1166 case NFSATTRBIT_FILEHANDLE:
1167 error = nfsm_getfh(nd, &tnfhp);
1168 if (error)
1169 goto nfsmout;
1170 tfhsize = tnfhp->nfh_len;
1171 if (compare) {
1172 if (!(*retcmpp) &&
1173 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
1174 fhp, fhsize))
1175 *retcmpp = NFSERR_NOTSAME;
1176 FREE((caddr_t)tnfhp, M_NFSFH);
1177 } else if (nfhpp != NULL) {
1178 *nfhpp = tnfhp;
1179 } else {
1180 FREE((caddr_t)tnfhp, M_NFSFH);
1181 }
1182 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
1183 break;
1184 case NFSATTRBIT_FILEID:
1185 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1186 thyp = fxdr_hyper(tl);
1187 if (compare) {
1188 if (!(*retcmpp)) {
1189 if ((u_int64_t)nap->na_fileid != thyp)
1190 *retcmpp = NFSERR_NOTSAME;
1191 }
1192 } else if (nap != NULL) {
1193 if (*tl++)
1194 printf("NFSv4 fileid > 32bits\n");
1195 nap->na_fileid = thyp;
1196 }
1197 attrsum += NFSX_HYPER;
1198 break;
1199 case NFSATTRBIT_FILESAVAIL:
1200 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1201 if (compare) {
1202 if (!(*retcmpp) &&
1203 sfp->sf_afiles != fxdr_hyper(tl))
1204 *retcmpp = NFSERR_NOTSAME;
1205 } else if (sfp != NULL) {
1206 sfp->sf_afiles = fxdr_hyper(tl);
1207 }
1208 attrsum += NFSX_HYPER;
1209 break;
1210 case NFSATTRBIT_FILESFREE:
1211 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1212 if (compare) {
1213 if (!(*retcmpp) &&
1214 sfp->sf_ffiles != fxdr_hyper(tl))
1215 *retcmpp = NFSERR_NOTSAME;
1216 } else if (sfp != NULL) {
1217 sfp->sf_ffiles = fxdr_hyper(tl);
1218 }
1219 attrsum += NFSX_HYPER;
1220 break;
1221 case NFSATTRBIT_FILESTOTAL:
1222 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1223 if (compare) {
1224 if (!(*retcmpp) &&
1225 sfp->sf_tfiles != fxdr_hyper(tl))
1226 *retcmpp = NFSERR_NOTSAME;
1227 } else if (sfp != NULL) {
1228 sfp->sf_tfiles = fxdr_hyper(tl);
1229 }
1230 attrsum += NFSX_HYPER;
1231 break;
1232 case NFSATTRBIT_FSLOCATIONS:
1233 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
1234 if (error)
1235 goto nfsmout;
1236 attrsum += l;
1237 if (compare && !(*retcmpp)) {
1238 refp = nfsv4root_getreferral(vp, NULL, 0);
1239 if (refp != NULL) {
1240 if (cp == NULL || cp2 == NULL ||
1241 strcmp(cp, "/") ||
1242 strcmp(cp2, refp->nfr_srvlist))
1243 *retcmpp = NFSERR_NOTSAME;
1244 } else if (m == 0) {
1245 *retcmpp = NFSERR_NOTSAME;
1246 }
1247 }
1248 if (cp != NULL)
1249 free(cp, M_NFSSTRING);
1250 if (cp2 != NULL)
1251 free(cp2, M_NFSSTRING);
1252 break;
1253 case NFSATTRBIT_HIDDEN:
1254 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1255 if (compare && !(*retcmpp))
1256 *retcmpp = NFSERR_ATTRNOTSUPP;
1257 attrsum += NFSX_UNSIGNED;
1258 break;
1259 case NFSATTRBIT_HOMOGENEOUS:
1260 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1261 if (compare) {
1262 if (!(*retcmpp)) {
1263 if (fsp->fs_properties &
1264 NFSV3_FSFHOMOGENEOUS) {
1265 if (*tl == newnfs_false)
1266 *retcmpp = NFSERR_NOTSAME;
1267 } else {
1268 if (*tl == newnfs_true)
1269 *retcmpp = NFSERR_NOTSAME;
1270 }
1271 }
1272 } else if (fsp != NULL) {
1273 if (*tl == newnfs_true)
1274 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
1275 else
1276 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
1277 }
1278 attrsum += NFSX_UNSIGNED;
1279 break;
1280 case NFSATTRBIT_MAXFILESIZE:
1281 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1282 tnfsquad.qval = fxdr_hyper(tl);
1283 if (compare) {
1284 if (!(*retcmpp)) {
1285 tquad = NFSRV_MAXFILESIZE;
1286 if (tquad != tnfsquad.qval)
1287 *retcmpp = NFSERR_NOTSAME;
1288 }
1289 } else if (fsp != NULL) {
1290 fsp->fs_maxfilesize = tnfsquad.qval;
1291 }
1292 attrsum += NFSX_HYPER;
1293 break;
1294 case NFSATTRBIT_MAXLINK:
1295 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1296 if (compare) {
1297 if (!(*retcmpp)) {
1298 if (fxdr_unsigned(int, *tl) != LINK_MAX)
1299 *retcmpp = NFSERR_NOTSAME;
1300 }
1301 } else if (pc != NULL) {
1302 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
1303 }
1304 attrsum += NFSX_UNSIGNED;
1305 break;
1306 case NFSATTRBIT_MAXNAME:
1307 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1308 if (compare) {
1309 if (!(*retcmpp)) {
1310 if (fsp->fs_maxname !=
1311 fxdr_unsigned(u_int32_t, *tl))
1312 *retcmpp = NFSERR_NOTSAME;
1313 }
1314 } else {
1315 tuint = fxdr_unsigned(u_int32_t, *tl);
1316 /*
1317 * Some Linux NFSv4 servers report this
1318 * as 0 or 4billion, so I'll set it to
1319 * NFS_MAXNAMLEN. If a server actually creates
1320 * a name longer than NFS_MAXNAMLEN, it will
1321 * get an error back.
1322 */
1323 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
1324 tuint = NFS_MAXNAMLEN;
1325 if (fsp != NULL)
1326 fsp->fs_maxname = tuint;
1327 if (pc != NULL)
1328 pc->pc_namemax = tuint;
1329 }
1330 attrsum += NFSX_UNSIGNED;
1331 break;
1332 case NFSATTRBIT_MAXREAD:
1333 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1334 if (compare) {
1335 if (!(*retcmpp)) {
1336 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
1337 *(tl + 1)) || *tl != 0)
1338 *retcmpp = NFSERR_NOTSAME;
1339 }
1340 } else if (fsp != NULL) {
1341 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
1342 fsp->fs_rtpref = fsp->fs_rtmax;
1343 fsp->fs_dtpref = fsp->fs_rtpref;
1344 }
1345 attrsum += NFSX_HYPER;
1346 break;
1347 case NFSATTRBIT_MAXWRITE:
1348 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1349 if (compare) {
1350 if (!(*retcmpp)) {
1351 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
1352 *(tl + 1)) || *tl != 0)
1353 *retcmpp = NFSERR_NOTSAME;
1354 }
1355 } else if (fsp != NULL) {
1356 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
1357 fsp->fs_wtpref = fsp->fs_wtmax;
1358 }
1359 attrsum += NFSX_HYPER;
1360 break;
1361 case NFSATTRBIT_MIMETYPE:
1362 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1363 i = fxdr_unsigned(int, *tl);
1364 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
1365 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
1366 if (error)
1367 goto nfsmout;
1368 if (compare && !(*retcmpp))
1369 *retcmpp = NFSERR_ATTRNOTSUPP;
1370 break;
1371 case NFSATTRBIT_MODE:
1372 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1373 if (compare) {
1374 if (!(*retcmpp)) {
1375 if (nap->na_mode != nfstov_mode(*tl))
1376 *retcmpp = NFSERR_NOTSAME;
1377 }
1378 } else if (nap != NULL) {
1379 nap->na_mode = nfstov_mode(*tl);
1380 }
1381 attrsum += NFSX_UNSIGNED;
1382 break;
1383 case NFSATTRBIT_NOTRUNC:
1384 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1385 if (compare) {
1386 if (!(*retcmpp)) {
1387 if (*tl != newnfs_true)
1388 *retcmpp = NFSERR_NOTSAME;
1389 }
1390 } else if (pc != NULL) {
1391 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
1392 }
1393 attrsum += NFSX_UNSIGNED;
1394 break;
1395 case NFSATTRBIT_NUMLINKS:
1396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1397 tuint = fxdr_unsigned(u_int32_t, *tl);
1398 if (compare) {
1399 if (!(*retcmpp)) {
1400 if ((u_int32_t)nap->na_nlink != tuint)
1401 *retcmpp = NFSERR_NOTSAME;
1402 }
1403 } else if (nap != NULL) {
1404 nap->na_nlink = tuint;
1405 }
1406 attrsum += NFSX_UNSIGNED;
1407 break;
1408 case NFSATTRBIT_OWNER:
1409 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1410 j = fxdr_unsigned(int, *tl);
1411 if (j < 0) {
1412 error = NFSERR_BADXDR;
1413 goto nfsmout;
1414 }
1415 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1416 if (j > NFSV4_SMALLSTR)
1417 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1418 else
1419 cp = namestr;
1420 error = nfsrv_mtostr(nd, cp, j);
1421 if (error) {
1422 if (j > NFSV4_SMALLSTR)
1423 free(cp, M_NFSSTRING);
1424 goto nfsmout;
1425 }
1426 if (compare) {
1427 if (!(*retcmpp)) {
1428 if (nfsv4_strtouid(nd, cp, j, &uid, p) ||
1429 nap->na_uid != uid)
1430 *retcmpp = NFSERR_NOTSAME;
1431 }
1432 } else if (nap != NULL) {
1433 if (nfsv4_strtouid(nd, cp, j, &uid, p))
1434 nap->na_uid = nfsrv_defaultuid;
1435 else
1436 nap->na_uid = uid;
1437 }
1438 if (j > NFSV4_SMALLSTR)
1439 free(cp, M_NFSSTRING);
1440 break;
1441 case NFSATTRBIT_OWNERGROUP:
1442 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1443 j = fxdr_unsigned(int, *tl);
1444 if (j < 0) {
1445 error = NFSERR_BADXDR;
1446 goto nfsmout;
1447 }
1448 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
1449 if (j > NFSV4_SMALLSTR)
1450 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
1451 else
1452 cp = namestr;
1453 error = nfsrv_mtostr(nd, cp, j);
1454 if (error) {
1455 if (j > NFSV4_SMALLSTR)
1456 free(cp, M_NFSSTRING);
1457 goto nfsmout;
1458 }
1459 if (compare) {
1460 if (!(*retcmpp)) {
1461 if (nfsv4_strtogid(nd, cp, j, &gid, p) ||
1462 nap->na_gid != gid)
1463 *retcmpp = NFSERR_NOTSAME;
1464 }
1465 } else if (nap != NULL) {
1466 if (nfsv4_strtogid(nd, cp, j, &gid, p))
1467 nap->na_gid = nfsrv_defaultgid;
1468 else
1469 nap->na_gid = gid;
1470 }
1471 if (j > NFSV4_SMALLSTR)
1472 free(cp, M_NFSSTRING);
1473 break;
1474 case NFSATTRBIT_QUOTAHARD:
1475 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1476 if (sbp != NULL) {
1477 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1478 freenum = sbp->f_bfree;
1479 else
1480 freenum = sbp->f_bavail;
1481 #ifdef QUOTA
1482 /*
1483 * ufs_quotactl() insists that the uid argument
1484 * equal p_ruid for non-root quota access, so
1485 * we'll just make sure that's the case.
1486 */
1487 savuid = p->p_cred->p_ruid;
1488 p->p_cred->p_ruid = cred->cr_uid;
1489 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1490 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1491 freenum = min(dqb.dqb_bhardlimit, freenum);
1492 p->p_cred->p_ruid = savuid;
1493 #endif /* QUOTA */
1494 uquad = (u_int64_t)freenum;
1495 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1496 }
1497 if (compare && !(*retcmpp)) {
1498 if (uquad != fxdr_hyper(tl))
1499 *retcmpp = NFSERR_NOTSAME;
1500 }
1501 attrsum += NFSX_HYPER;
1502 break;
1503 case NFSATTRBIT_QUOTASOFT:
1504 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1505 if (sbp != NULL) {
1506 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
1507 freenum = sbp->f_bfree;
1508 else
1509 freenum = sbp->f_bavail;
1510 #ifdef QUOTA
1511 /*
1512 * ufs_quotactl() insists that the uid argument
1513 * equal p_ruid for non-root quota access, so
1514 * we'll just make sure that's the case.
1515 */
1516 savuid = p->p_cred->p_ruid;
1517 p->p_cred->p_ruid = cred->cr_uid;
1518 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1519 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1520 freenum = min(dqb.dqb_bsoftlimit, freenum);
1521 p->p_cred->p_ruid = savuid;
1522 #endif /* QUOTA */
1523 uquad = (u_int64_t)freenum;
1524 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1525 }
1526 if (compare && !(*retcmpp)) {
1527 if (uquad != fxdr_hyper(tl))
1528 *retcmpp = NFSERR_NOTSAME;
1529 }
1530 attrsum += NFSX_HYPER;
1531 break;
1532 case NFSATTRBIT_QUOTAUSED:
1533 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1534 if (sbp != NULL) {
1535 freenum = 0;
1536 #ifdef QUOTA
1537 /*
1538 * ufs_quotactl() insists that the uid argument
1539 * equal p_ruid for non-root quota access, so
1540 * we'll just make sure that's the case.
1541 */
1542 savuid = p->p_cred->p_ruid;
1543 p->p_cred->p_ruid = cred->cr_uid;
1544 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,
1545 USRQUOTA), cred->cr_uid, (caddr_t)&dqb))
1546 freenum = dqb.dqb_curblocks;
1547 p->p_cred->p_ruid = savuid;
1548 #endif /* QUOTA */
1549 uquad = (u_int64_t)freenum;
1550 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
1551 }
1552 if (compare && !(*retcmpp)) {
1553 if (uquad != fxdr_hyper(tl))
1554 *retcmpp = NFSERR_NOTSAME;
1555 }
1556 attrsum += NFSX_HYPER;
1557 break;
1558 case NFSATTRBIT_RAWDEV:
1559 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
1560 j = fxdr_unsigned(int, *tl++);
1561 k = fxdr_unsigned(int, *tl);
1562 if (compare) {
1563 if (!(*retcmpp)) {
1564 if (nap->na_rdev != NFSMAKEDEV(j, k))
1565 *retcmpp = NFSERR_NOTSAME;
1566 }
1567 } else if (nap != NULL) {
1568 nap->na_rdev = NFSMAKEDEV(j, k);
1569 }
1570 attrsum += NFSX_V4SPECDATA;
1571 break;
1572 case NFSATTRBIT_SPACEAVAIL:
1573 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1574 if (compare) {
1575 if (!(*retcmpp) &&
1576 sfp->sf_abytes != fxdr_hyper(tl))
1577 *retcmpp = NFSERR_NOTSAME;
1578 } else if (sfp != NULL) {
1579 sfp->sf_abytes = fxdr_hyper(tl);
1580 }
1581 attrsum += NFSX_HYPER;
1582 break;
1583 case NFSATTRBIT_SPACEFREE:
1584 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1585 if (compare) {
1586 if (!(*retcmpp) &&
1587 sfp->sf_fbytes != fxdr_hyper(tl))
1588 *retcmpp = NFSERR_NOTSAME;
1589 } else if (sfp != NULL) {
1590 sfp->sf_fbytes = fxdr_hyper(tl);
1591 }
1592 attrsum += NFSX_HYPER;
1593 break;
1594 case NFSATTRBIT_SPACETOTAL:
1595 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1596 if (compare) {
1597 if (!(*retcmpp) &&
1598 sfp->sf_tbytes != fxdr_hyper(tl))
1599 *retcmpp = NFSERR_NOTSAME;
1600 } else if (sfp != NULL) {
1601 sfp->sf_tbytes = fxdr_hyper(tl);
1602 }
1603 attrsum += NFSX_HYPER;
1604 break;
1605 case NFSATTRBIT_SPACEUSED:
1606 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1607 thyp = fxdr_hyper(tl);
1608 if (compare) {
1609 if (!(*retcmpp)) {
1610 if ((u_int64_t)nap->na_bytes != thyp)
1611 *retcmpp = NFSERR_NOTSAME;
1612 }
1613 } else if (nap != NULL) {
1614 nap->na_bytes = thyp;
1615 }
1616 attrsum += NFSX_HYPER;
1617 break;
1618 case NFSATTRBIT_SYSTEM:
1619 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1620 if (compare && !(*retcmpp))
1621 *retcmpp = NFSERR_ATTRNOTSUPP;
1622 attrsum += NFSX_UNSIGNED;
1623 break;
1624 case NFSATTRBIT_TIMEACCESS:
1625 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1626 fxdr_nfsv4time(tl, &temptime);
1627 if (compare) {
1628 if (!(*retcmpp)) {
1629 if (!NFS_CMPTIME(temptime, nap->na_atime))
1630 *retcmpp = NFSERR_NOTSAME;
1631 }
1632 } else if (nap != NULL) {
1633 nap->na_atime = temptime;
1634 }
1635 attrsum += NFSX_V4TIME;
1636 break;
1637 case NFSATTRBIT_TIMEACCESSSET:
1638 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1639 attrsum += NFSX_UNSIGNED;
1640 i = fxdr_unsigned(int, *tl);
1641 if (i == NFSV4SATTRTIME_TOCLIENT) {
1642 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1643 attrsum += NFSX_V4TIME;
1644 }
1645 if (compare && !(*retcmpp))
1646 *retcmpp = NFSERR_INVAL;
1647 break;
1648 case NFSATTRBIT_TIMEBACKUP:
1649 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1650 if (compare && !(*retcmpp))
1651 *retcmpp = NFSERR_ATTRNOTSUPP;
1652 attrsum += NFSX_V4TIME;
1653 break;
1654 case NFSATTRBIT_TIMECREATE:
1655 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1656 if (compare && !(*retcmpp))
1657 *retcmpp = NFSERR_ATTRNOTSUPP;
1658 attrsum += NFSX_V4TIME;
1659 break;
1660 case NFSATTRBIT_TIMEDELTA:
1661 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1662 if (fsp != NULL) {
1663 if (compare) {
1664 if (!(*retcmpp)) {
1665 if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
1666 fxdr_unsigned(u_int32_t, *(tl + 1)) ||
1667 (u_int32_t)fsp->fs_timedelta.tv_nsec !=
1668 (fxdr_unsigned(u_int32_t, *(tl + 2)) %
1669 1000000000) ||
1670 *tl != 0)
1671 *retcmpp = NFSERR_NOTSAME;
1672 }
1673 } else {
1674 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
1675 }
1676 }
1677 attrsum += NFSX_V4TIME;
1678 break;
1679 case NFSATTRBIT_TIMEMETADATA:
1680 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1681 fxdr_nfsv4time(tl, &temptime);
1682 if (compare) {
1683 if (!(*retcmpp)) {
1684 if (!NFS_CMPTIME(temptime, nap->na_ctime))
1685 *retcmpp = NFSERR_NOTSAME;
1686 }
1687 } else if (nap != NULL) {
1688 nap->na_ctime = temptime;
1689 }
1690 attrsum += NFSX_V4TIME;
1691 break;
1692 case NFSATTRBIT_TIMEMODIFY:
1693 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1694 fxdr_nfsv4time(tl, &temptime);
1695 if (compare) {
1696 if (!(*retcmpp)) {
1697 if (!NFS_CMPTIME(temptime, nap->na_mtime))
1698 *retcmpp = NFSERR_NOTSAME;
1699 }
1700 } else if (nap != NULL) {
1701 nap->na_mtime = temptime;
1702 }
1703 attrsum += NFSX_V4TIME;
1704 break;
1705 case NFSATTRBIT_TIMEMODIFYSET:
1706 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
1707 attrsum += NFSX_UNSIGNED;
1708 i = fxdr_unsigned(int, *tl);
1709 if (i == NFSV4SATTRTIME_TOCLIENT) {
1710 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
1711 attrsum += NFSX_V4TIME;
1712 }
1713 if (compare && !(*retcmpp))
1714 *retcmpp = NFSERR_INVAL;
1715 break;
1716 case NFSATTRBIT_MOUNTEDONFILEID:
1717 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
1718 thyp = fxdr_hyper(tl);
1719 if (compare) {
1720 if (!(*retcmpp)) {
1721 if (*tl++) {
1722 *retcmpp = NFSERR_NOTSAME;
1723 } else {
1724 if (!vp || !nfsrv_atroot(vp, &fid))
1725 fid = nap->na_fileid;
1726 if ((u_int64_t)fid != thyp)
1727 *retcmpp = NFSERR_NOTSAME;
1728 }
1729 }
1730 } else if (nap != NULL) {
1731 if (*tl++)
1732 printf("NFSv4 mounted on fileid > 32bits\n");
1733 nap->na_mntonfileno = thyp;
1734 }
1735 attrsum += NFSX_HYPER;
1736 break;
1737 default:
1738 printf("EEK! nfsv4_loadattr unknown attr=%d\n",
1739 bitpos);
1740 if (compare && !(*retcmpp))
1741 *retcmpp = NFSERR_ATTRNOTSUPP;
1742 /*
1743 * and get out of the loop, since we can't parse
1744 * the unknown attrbute data.
1745 */
1746 bitpos = NFSATTRBIT_MAX;
1747 break;
1748 };
1749 }
1750
1751 /*
1752 * some clients pad the attrlist, so we need to skip over the
1753 * padding.
1754 */
1755 if (attrsum > attrsize) {
1756 error = NFSERR_BADXDR;
1757 } else {
1758 attrsize = NFSM_RNDUP(attrsize);
1759 if (attrsum < attrsize)
1760 error = nfsm_advance(nd, attrsize - attrsum, -1);
1761 }
1762 nfsmout:
1763 NFSEXITCODE2(error, nd);
1764 return (error);
1765 }
1766
1767 /*
1768 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
1769 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
1770 * The first argument is a pointer to an nfsv4lock structure.
1771 * The second argument is 1 iff a blocking lock is wanted.
1772 * If this argument is 0, the call waits until no thread either wants nor
1773 * holds an exclusive lock.
1774 * It returns 1 if the lock was acquired, 0 otherwise.
1775 * If several processes call this function concurrently wanting the exclusive
1776 * lock, one will get the lock and the rest will return without getting the
1777 * lock. (If the caller must have the lock, it simply calls this function in a
1778 * loop until the function returns 1 to indicate the lock was acquired.)
1779 * Any usecnt must be decremented by calling nfsv4_relref() before
1780 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
1781 * be called in a loop.
1782 * The isleptp argument is set to indicate if the call slept, iff not NULL
1783 * and the mp argument indicates to check for a forced dismount, iff not
1784 * NULL.
1785 */
1786 APPLESTATIC int
nfsv4_lock(struct nfsv4lock * lp,int iwantlock,int * isleptp,void * mutex,struct mount * mp)1787 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
1788 void *mutex, struct mount *mp)
1789 {
1790
1791 if (isleptp)
1792 *isleptp = 0;
1793 /*
1794 * If a lock is wanted, loop around until the lock is acquired by
1795 * someone and then released. If I want the lock, try to acquire it.
1796 * For a lock to be issued, no lock must be in force and the usecnt
1797 * must be zero.
1798 */
1799 if (iwantlock) {
1800 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1801 lp->nfslock_usecnt == 0) {
1802 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1803 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1804 return (1);
1805 }
1806 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
1807 }
1808 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
1809 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1810 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1811 return (0);
1812 }
1813 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1814 if (isleptp)
1815 *isleptp = 1;
1816 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1817 PZERO - 1, "nfsv4lck", NULL);
1818 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
1819 lp->nfslock_usecnt == 0) {
1820 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
1821 lp->nfslock_lock |= NFSV4LOCK_LOCK;
1822 return (1);
1823 }
1824 }
1825 return (0);
1826 }
1827
1828 /*
1829 * Release the lock acquired by nfsv4_lock().
1830 * The second argument is set to 1 to indicate the nfslock_usecnt should be
1831 * incremented, as well.
1832 */
1833 APPLESTATIC void
nfsv4_unlock(struct nfsv4lock * lp,int incref)1834 nfsv4_unlock(struct nfsv4lock *lp, int incref)
1835 {
1836
1837 lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
1838 if (incref)
1839 lp->nfslock_usecnt++;
1840 nfsv4_wanted(lp);
1841 }
1842
1843 /*
1844 * Release a reference cnt.
1845 */
1846 APPLESTATIC void
nfsv4_relref(struct nfsv4lock * lp)1847 nfsv4_relref(struct nfsv4lock *lp)
1848 {
1849
1850 if (lp->nfslock_usecnt <= 0)
1851 panic("nfsv4root ref cnt");
1852 lp->nfslock_usecnt--;
1853 if (lp->nfslock_usecnt == 0)
1854 nfsv4_wanted(lp);
1855 }
1856
1857 /*
1858 * Get a reference cnt.
1859 * This function will wait for any exclusive lock to be released, but will
1860 * not wait for threads that want the exclusive lock. If priority needs
1861 * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
1862 * with the 2nd argument == 0 should be done before calling nfsv4_getref().
1863 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and
1864 * return without getting a refcnt for that case.
1865 */
1866 APPLESTATIC void
nfsv4_getref(struct nfsv4lock * lp,int * isleptp,void * mutex,struct mount * mp)1867 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex,
1868 struct mount *mp)
1869 {
1870
1871 if (isleptp)
1872 *isleptp = 0;
1873
1874 /*
1875 * Wait for a lock held.
1876 */
1877 while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
1878 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1879 return;
1880 lp->nfslock_lock |= NFSV4LOCK_WANTED;
1881 if (isleptp)
1882 *isleptp = 1;
1883 (void) nfsmsleep(&lp->nfslock_lock, mutex,
1884 PZERO - 1, "nfsv4gr", NULL);
1885 }
1886 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0)
1887 return;
1888
1889 lp->nfslock_usecnt++;
1890 }
1891
1892 /*
1893 * Get a reference as above, but return failure instead of sleeping if
1894 * an exclusive lock is held.
1895 */
1896 APPLESTATIC int
nfsv4_getref_nonblock(struct nfsv4lock * lp)1897 nfsv4_getref_nonblock(struct nfsv4lock *lp)
1898 {
1899
1900 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
1901 return (0);
1902
1903 lp->nfslock_usecnt++;
1904 return (1);
1905 }
1906
1907 /*
1908 * Test for a lock. Return 1 if locked, 0 otherwise.
1909 */
1910 APPLESTATIC int
nfsv4_testlock(struct nfsv4lock * lp)1911 nfsv4_testlock(struct nfsv4lock *lp)
1912 {
1913
1914 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
1915 lp->nfslock_usecnt == 0)
1916 return (0);
1917 return (1);
1918 }
1919
1920 /*
1921 * Wake up anyone sleeping, waiting for this lock.
1922 */
1923 static void
nfsv4_wanted(struct nfsv4lock * lp)1924 nfsv4_wanted(struct nfsv4lock *lp)
1925 {
1926
1927 if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
1928 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
1929 wakeup((caddr_t)&lp->nfslock_lock);
1930 }
1931 }
1932
1933 /*
1934 * Copy a string from an mbuf list into a character array.
1935 * Return EBADRPC if there is an mbuf error,
1936 * 0 otherwise.
1937 */
1938 APPLESTATIC int
nfsrv_mtostr(struct nfsrv_descript * nd,char * str,int siz)1939 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
1940 {
1941 char *cp;
1942 int xfer, len;
1943 mbuf_t mp;
1944 int rem, error = 0;
1945
1946 mp = nd->nd_md;
1947 cp = nd->nd_dpos;
1948 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp;
1949 rem = NFSM_RNDUP(siz) - siz;
1950 while (siz > 0) {
1951 if (len > siz)
1952 xfer = siz;
1953 else
1954 xfer = len;
1955 NFSBCOPY(cp, str, xfer);
1956 str += xfer;
1957 siz -= xfer;
1958 if (siz > 0) {
1959 mp = mbuf_next(mp);
1960 if (mp == NULL) {
1961 error = EBADRPC;
1962 goto out;
1963 }
1964 cp = NFSMTOD(mp, caddr_t);
1965 len = mbuf_len(mp);
1966 } else {
1967 cp += xfer;
1968 len -= xfer;
1969 }
1970 }
1971 *str = '\0';
1972 nd->nd_dpos = cp;
1973 nd->nd_md = mp;
1974 if (rem > 0) {
1975 if (len < rem)
1976 error = nfsm_advance(nd, rem, len);
1977 else
1978 nd->nd_dpos += rem;
1979 }
1980
1981 out:
1982 NFSEXITCODE2(error, nd);
1983 return (error);
1984 }
1985
1986 /*
1987 * Fill in the attributes as marked by the bitmap (V4).
1988 */
1989 APPLESTATIC int
nfsv4_fillattr(struct nfsrv_descript * nd,struct mount * mp,vnode_t vp,NFSACL_T * saclp,struct vattr * vap,fhandle_t * fhp,int rderror,nfsattrbit_t * attrbitp,struct ucred * cred,NFSPROC_T * p,int isdgram,int reterr,int supports_nfsv4acls,int at_root,uint64_t mounted_on_fileno)1990 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
1991 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
1992 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
1993 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
1994 {
1995 int bitpos, retnum = 0;
1996 u_int32_t *tl;
1997 int siz, prefixnum, error;
1998 u_char *cp, namestr[NFSV4_SMALLSTR];
1999 nfsattrbit_t attrbits, retbits;
2000 nfsattrbit_t *retbitp = &retbits;
2001 u_int32_t freenum, *retnump;
2002 u_int64_t uquad;
2003 struct statfs fs;
2004 struct nfsfsinfo fsinf;
2005 struct timespec temptime;
2006 NFSACL_T *aclp, *naclp = NULL;
2007 #ifdef QUOTA
2008 struct dqblk dqb;
2009 uid_t savuid;
2010 #endif
2011
2012 /*
2013 * First, set the bits that can be filled and get fsinfo.
2014 */
2015 NFSSET_ATTRBIT(retbitp, attrbitp);
2016 /* If p and cred are NULL, it is a client side call */
2017 if (p == NULL && cred == NULL) {
2018 NFSCLRNOTSETABLE_ATTRBIT(retbitp);
2019 aclp = saclp;
2020 } else {
2021 NFSCLRNOTFILLABLE_ATTRBIT(retbitp);
2022 naclp = acl_alloc(M_WAITOK);
2023 aclp = naclp;
2024 }
2025 nfsvno_getfs(&fsinf, isdgram);
2026 #ifndef APPLE
2027 /*
2028 * Get the VFS_STATFS(), since some attributes need them.
2029 */
2030 if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
2031 error = VFS_STATFS(mp, &fs);
2032 if (error != 0) {
2033 if (reterr) {
2034 nd->nd_repstat = NFSERR_ACCES;
2035 return (0);
2036 }
2037 NFSCLRSTATFS_ATTRBIT(retbitp);
2038 }
2039 }
2040 #endif
2041
2042 /*
2043 * And the NFSv4 ACL...
2044 */
2045 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
2046 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2047 supports_nfsv4acls == 0))) {
2048 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
2049 }
2050 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
2051 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
2052 supports_nfsv4acls == 0)) {
2053 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2054 } else if (naclp != NULL) {
2055 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
2056 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
2057 if (error == 0)
2058 error = VOP_GETACL(vp, ACL_TYPE_NFS4,
2059 naclp, cred, p);
2060 NFSVOPUNLOCK(vp, 0);
2061 } else
2062 error = NFSERR_PERM;
2063 if (error != 0) {
2064 if (reterr) {
2065 nd->nd_repstat = NFSERR_ACCES;
2066 return (0);
2067 }
2068 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
2069 }
2070 }
2071 }
2072 /*
2073 * Put out the attribute bitmap for the ones being filled in
2074 * and get the field for the number of attributes returned.
2075 */
2076 prefixnum = nfsrv_putattrbit(nd, retbitp);
2077 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
2078 prefixnum += NFSX_UNSIGNED;
2079
2080 /*
2081 * Now, loop around filling in the attributes for each bit set.
2082 */
2083 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
2084 if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
2085 switch (bitpos) {
2086 case NFSATTRBIT_SUPPORTEDATTRS:
2087 NFSSETSUPP_ATTRBIT(&attrbits);
2088 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
2089 && supports_nfsv4acls == 0)) {
2090 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
2091 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
2092 }
2093 retnum += nfsrv_putattrbit(nd, &attrbits);
2094 break;
2095 case NFSATTRBIT_TYPE:
2096 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2097 *tl = vtonfsv34_type(vap->va_type);
2098 retnum += NFSX_UNSIGNED;
2099 break;
2100 case NFSATTRBIT_FHEXPIRETYPE:
2101 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2102 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
2103 retnum += NFSX_UNSIGNED;
2104 break;
2105 case NFSATTRBIT_CHANGE:
2106 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2107 txdr_hyper(vap->va_filerev, tl);
2108 retnum += NFSX_HYPER;
2109 break;
2110 case NFSATTRBIT_SIZE:
2111 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2112 txdr_hyper(vap->va_size, tl);
2113 retnum += NFSX_HYPER;
2114 break;
2115 case NFSATTRBIT_LINKSUPPORT:
2116 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2117 if (fsinf.fs_properties & NFSV3FSINFO_LINK)
2118 *tl = newnfs_true;
2119 else
2120 *tl = newnfs_false;
2121 retnum += NFSX_UNSIGNED;
2122 break;
2123 case NFSATTRBIT_SYMLINKSUPPORT:
2124 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2125 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
2126 *tl = newnfs_true;
2127 else
2128 *tl = newnfs_false;
2129 retnum += NFSX_UNSIGNED;
2130 break;
2131 case NFSATTRBIT_NAMEDATTR:
2132 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2133 *tl = newnfs_false;
2134 retnum += NFSX_UNSIGNED;
2135 break;
2136 case NFSATTRBIT_FSID:
2137 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
2138 *tl++ = 0;
2139 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
2140 *tl++ = 0;
2141 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
2142 retnum += NFSX_V4FSID;
2143 break;
2144 case NFSATTRBIT_UNIQUEHANDLES:
2145 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2146 *tl = newnfs_true;
2147 retnum += NFSX_UNSIGNED;
2148 break;
2149 case NFSATTRBIT_LEASETIME:
2150 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2151 *tl = txdr_unsigned(nfsrv_lease);
2152 retnum += NFSX_UNSIGNED;
2153 break;
2154 case NFSATTRBIT_RDATTRERROR:
2155 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2156 *tl = txdr_unsigned(rderror);
2157 retnum += NFSX_UNSIGNED;
2158 break;
2159 /*
2160 * Recommended Attributes. (Only the supported ones.)
2161 */
2162 case NFSATTRBIT_ACL:
2163 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p);
2164 break;
2165 case NFSATTRBIT_ACLSUPPORT:
2166 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2167 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
2168 retnum += NFSX_UNSIGNED;
2169 break;
2170 case NFSATTRBIT_CANSETTIME:
2171 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2172 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
2173 *tl = newnfs_true;
2174 else
2175 *tl = newnfs_false;
2176 retnum += NFSX_UNSIGNED;
2177 break;
2178 case NFSATTRBIT_CASEINSENSITIVE:
2179 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2180 *tl = newnfs_false;
2181 retnum += NFSX_UNSIGNED;
2182 break;
2183 case NFSATTRBIT_CASEPRESERVING:
2184 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2185 *tl = newnfs_true;
2186 retnum += NFSX_UNSIGNED;
2187 break;
2188 case NFSATTRBIT_CHOWNRESTRICTED:
2189 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2190 *tl = newnfs_true;
2191 retnum += NFSX_UNSIGNED;
2192 break;
2193 case NFSATTRBIT_FILEHANDLE:
2194 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
2195 break;
2196 case NFSATTRBIT_FILEID:
2197 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2198 *tl++ = 0;
2199 *tl = txdr_unsigned(vap->va_fileid);
2200 retnum += NFSX_HYPER;
2201 break;
2202 case NFSATTRBIT_FILESAVAIL:
2203 /*
2204 * Check quota and use min(quota, f_ffree).
2205 */
2206 freenum = fs.f_ffree;
2207 #ifdef QUOTA
2208 /*
2209 * ufs_quotactl() insists that the uid argument
2210 * equal p_ruid for non-root quota access, so
2211 * we'll just make sure that's the case.
2212 */
2213 savuid = p->p_cred->p_ruid;
2214 p->p_cred->p_ruid = cred->cr_uid;
2215 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2216 cred->cr_uid, (caddr_t)&dqb))
2217 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
2218 freenum);
2219 p->p_cred->p_ruid = savuid;
2220 #endif /* QUOTA */
2221 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2222 *tl++ = 0;
2223 *tl = txdr_unsigned(freenum);
2224 retnum += NFSX_HYPER;
2225 break;
2226 case NFSATTRBIT_FILESFREE:
2227 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2228 *tl++ = 0;
2229 *tl = txdr_unsigned(fs.f_ffree);
2230 retnum += NFSX_HYPER;
2231 break;
2232 case NFSATTRBIT_FILESTOTAL:
2233 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2234 *tl++ = 0;
2235 *tl = txdr_unsigned(fs.f_files);
2236 retnum += NFSX_HYPER;
2237 break;
2238 case NFSATTRBIT_FSLOCATIONS:
2239 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
2240 *tl++ = 0;
2241 *tl = 0;
2242 retnum += 2 * NFSX_UNSIGNED;
2243 break;
2244 case NFSATTRBIT_HOMOGENEOUS:
2245 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2246 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
2247 *tl = newnfs_true;
2248 else
2249 *tl = newnfs_false;
2250 retnum += NFSX_UNSIGNED;
2251 break;
2252 case NFSATTRBIT_MAXFILESIZE:
2253 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2254 uquad = NFSRV_MAXFILESIZE;
2255 txdr_hyper(uquad, tl);
2256 retnum += NFSX_HYPER;
2257 break;
2258 case NFSATTRBIT_MAXLINK:
2259 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2260 *tl = txdr_unsigned(LINK_MAX);
2261 retnum += NFSX_UNSIGNED;
2262 break;
2263 case NFSATTRBIT_MAXNAME:
2264 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2265 *tl = txdr_unsigned(NFS_MAXNAMLEN);
2266 retnum += NFSX_UNSIGNED;
2267 break;
2268 case NFSATTRBIT_MAXREAD:
2269 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2270 *tl++ = 0;
2271 *tl = txdr_unsigned(fsinf.fs_rtmax);
2272 retnum += NFSX_HYPER;
2273 break;
2274 case NFSATTRBIT_MAXWRITE:
2275 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2276 *tl++ = 0;
2277 *tl = txdr_unsigned(fsinf.fs_wtmax);
2278 retnum += NFSX_HYPER;
2279 break;
2280 case NFSATTRBIT_MODE:
2281 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2282 *tl = vtonfsv34_mode(vap->va_mode);
2283 retnum += NFSX_UNSIGNED;
2284 break;
2285 case NFSATTRBIT_NOTRUNC:
2286 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2287 *tl = newnfs_true;
2288 retnum += NFSX_UNSIGNED;
2289 break;
2290 case NFSATTRBIT_NUMLINKS:
2291 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2292 *tl = txdr_unsigned(vap->va_nlink);
2293 retnum += NFSX_UNSIGNED;
2294 break;
2295 case NFSATTRBIT_OWNER:
2296 cp = namestr;
2297 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p);
2298 retnum += nfsm_strtom(nd, cp, siz);
2299 if (cp != namestr)
2300 free(cp, M_NFSSTRING);
2301 break;
2302 case NFSATTRBIT_OWNERGROUP:
2303 cp = namestr;
2304 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p);
2305 retnum += nfsm_strtom(nd, cp, siz);
2306 if (cp != namestr)
2307 free(cp, M_NFSSTRING);
2308 break;
2309 case NFSATTRBIT_QUOTAHARD:
2310 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2311 freenum = fs.f_bfree;
2312 else
2313 freenum = fs.f_bavail;
2314 #ifdef QUOTA
2315 /*
2316 * ufs_quotactl() insists that the uid argument
2317 * equal p_ruid for non-root quota access, so
2318 * we'll just make sure that's the case.
2319 */
2320 savuid = p->p_cred->p_ruid;
2321 p->p_cred->p_ruid = cred->cr_uid;
2322 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2323 cred->cr_uid, (caddr_t)&dqb))
2324 freenum = min(dqb.dqb_bhardlimit, freenum);
2325 p->p_cred->p_ruid = savuid;
2326 #endif /* QUOTA */
2327 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2328 uquad = (u_int64_t)freenum;
2329 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2330 txdr_hyper(uquad, tl);
2331 retnum += NFSX_HYPER;
2332 break;
2333 case NFSATTRBIT_QUOTASOFT:
2334 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0))
2335 freenum = fs.f_bfree;
2336 else
2337 freenum = fs.f_bavail;
2338 #ifdef QUOTA
2339 /*
2340 * ufs_quotactl() insists that the uid argument
2341 * equal p_ruid for non-root quota access, so
2342 * we'll just make sure that's the case.
2343 */
2344 savuid = p->p_cred->p_ruid;
2345 p->p_cred->p_ruid = cred->cr_uid;
2346 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2347 cred->cr_uid, (caddr_t)&dqb))
2348 freenum = min(dqb.dqb_bsoftlimit, freenum);
2349 p->p_cred->p_ruid = savuid;
2350 #endif /* QUOTA */
2351 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2352 uquad = (u_int64_t)freenum;
2353 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2354 txdr_hyper(uquad, tl);
2355 retnum += NFSX_HYPER;
2356 break;
2357 case NFSATTRBIT_QUOTAUSED:
2358 freenum = 0;
2359 #ifdef QUOTA
2360 /*
2361 * ufs_quotactl() insists that the uid argument
2362 * equal p_ruid for non-root quota access, so
2363 * we'll just make sure that's the case.
2364 */
2365 savuid = p->p_cred->p_ruid;
2366 p->p_cred->p_ruid = cred->cr_uid;
2367 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
2368 cred->cr_uid, (caddr_t)&dqb))
2369 freenum = dqb.dqb_curblocks;
2370 p->p_cred->p_ruid = savuid;
2371 #endif /* QUOTA */
2372 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2373 uquad = (u_int64_t)freenum;
2374 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize);
2375 txdr_hyper(uquad, tl);
2376 retnum += NFSX_HYPER;
2377 break;
2378 case NFSATTRBIT_RAWDEV:
2379 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
2380 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
2381 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
2382 retnum += NFSX_V4SPECDATA;
2383 break;
2384 case NFSATTRBIT_SPACEAVAIL:
2385 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2386 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0))
2387 uquad = (u_int64_t)fs.f_bfree;
2388 else
2389 uquad = (u_int64_t)fs.f_bavail;
2390 uquad *= fs.f_bsize;
2391 txdr_hyper(uquad, tl);
2392 retnum += NFSX_HYPER;
2393 break;
2394 case NFSATTRBIT_SPACEFREE:
2395 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2396 uquad = (u_int64_t)fs.f_bfree;
2397 uquad *= fs.f_bsize;
2398 txdr_hyper(uquad, tl);
2399 retnum += NFSX_HYPER;
2400 break;
2401 case NFSATTRBIT_SPACETOTAL:
2402 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2403 uquad = (u_int64_t)fs.f_blocks;
2404 uquad *= fs.f_bsize;
2405 txdr_hyper(uquad, tl);
2406 retnum += NFSX_HYPER;
2407 break;
2408 case NFSATTRBIT_SPACEUSED:
2409 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2410 txdr_hyper(vap->va_bytes, tl);
2411 retnum += NFSX_HYPER;
2412 break;
2413 case NFSATTRBIT_TIMEACCESS:
2414 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2415 txdr_nfsv4time(&vap->va_atime, tl);
2416 retnum += NFSX_V4TIME;
2417 break;
2418 case NFSATTRBIT_TIMEACCESSSET:
2419 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2420 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2421 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2422 txdr_nfsv4time(&vap->va_atime, tl);
2423 retnum += NFSX_V4SETTIME;
2424 } else {
2425 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2426 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2427 retnum += NFSX_UNSIGNED;
2428 }
2429 break;
2430 case NFSATTRBIT_TIMEDELTA:
2431 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2432 temptime.tv_sec = 0;
2433 temptime.tv_nsec = 1000000000 / hz;
2434 txdr_nfsv4time(&temptime, tl);
2435 retnum += NFSX_V4TIME;
2436 break;
2437 case NFSATTRBIT_TIMEMETADATA:
2438 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2439 txdr_nfsv4time(&vap->va_ctime, tl);
2440 retnum += NFSX_V4TIME;
2441 break;
2442 case NFSATTRBIT_TIMEMODIFY:
2443 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
2444 txdr_nfsv4time(&vap->va_mtime, tl);
2445 retnum += NFSX_V4TIME;
2446 break;
2447 case NFSATTRBIT_TIMEMODIFYSET:
2448 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
2449 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
2450 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
2451 txdr_nfsv4time(&vap->va_mtime, tl);
2452 retnum += NFSX_V4SETTIME;
2453 } else {
2454 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
2455 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
2456 retnum += NFSX_UNSIGNED;
2457 }
2458 break;
2459 case NFSATTRBIT_MOUNTEDONFILEID:
2460 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
2461 if (at_root != 0)
2462 uquad = mounted_on_fileno;
2463 else
2464 uquad = (u_int64_t)vap->va_fileid;
2465 txdr_hyper(uquad, tl);
2466 retnum += NFSX_HYPER;
2467 break;
2468 default:
2469 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
2470 };
2471 }
2472 }
2473 if (naclp != NULL)
2474 acl_free(naclp);
2475 *retnump = txdr_unsigned(retnum);
2476 return (retnum + prefixnum);
2477 }
2478
2479 /*
2480 * Put the attribute bits onto an mbuf list.
2481 * Return the number of bytes of output generated.
2482 */
2483 APPLESTATIC int
nfsrv_putattrbit(struct nfsrv_descript * nd,nfsattrbit_t * attrbitp)2484 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
2485 {
2486 u_int32_t *tl;
2487 int cnt, i, bytesize;
2488
2489 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
2490 if (attrbitp->bits[cnt - 1])
2491 break;
2492 bytesize = (cnt + 1) * NFSX_UNSIGNED;
2493 NFSM_BUILD(tl, u_int32_t *, bytesize);
2494 *tl++ = txdr_unsigned(cnt);
2495 for (i = 0; i < cnt; i++)
2496 *tl++ = txdr_unsigned(attrbitp->bits[i]);
2497 return (bytesize);
2498 }
2499
2500 /*
2501 * Convert a uid to a string.
2502 * If the lookup fails, just output the digits.
2503 * uid - the user id
2504 * cpp - points to a buffer of size NFSV4_SMALLSTR
2505 * (malloc a larger one, as required)
2506 * retlenp - pointer to length to be returned
2507 */
2508 APPLESTATIC void
nfsv4_uidtostr(uid_t uid,u_char ** cpp,int * retlenp,NFSPROC_T * p)2509 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2510 {
2511 int i;
2512 struct nfsusrgrp *usrp;
2513 u_char *cp = *cpp;
2514 uid_t tmp;
2515 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2516
2517 cnt = 0;
2518 tryagain:
2519 NFSLOCKNAMEID();
2520 if (nfsrv_dnsname) {
2521 /*
2522 * Always map nfsrv_defaultuid to "nobody".
2523 */
2524 if (uid == nfsrv_defaultuid) {
2525 i = nfsrv_dnsnamelen + 7;
2526 if (i > len) {
2527 NFSUNLOCKNAMEID();
2528 if (len > NFSV4_SMALLSTR)
2529 free(cp, M_NFSSTRING);
2530 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2531 *cpp = cp;
2532 len = i;
2533 goto tryagain;
2534 }
2535 *retlenp = i;
2536 NFSBCOPY("nobody@", cp, 7);
2537 cp += 7;
2538 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2539 NFSUNLOCKNAMEID();
2540 return;
2541 }
2542 hasampersand = 0;
2543 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) {
2544 if (usrp->lug_uid == uid) {
2545 if (usrp->lug_expiry < NFSD_MONOSEC)
2546 break;
2547 /*
2548 * If the name doesn't already have an '@'
2549 * in it, append @domainname to it.
2550 */
2551 for (i = 0; i < usrp->lug_namelen; i++) {
2552 if (usrp->lug_name[i] == '@') {
2553 hasampersand = 1;
2554 break;
2555 }
2556 }
2557 if (hasampersand)
2558 i = usrp->lug_namelen;
2559 else
2560 i = usrp->lug_namelen +
2561 nfsrv_dnsnamelen + 1;
2562 if (i > len) {
2563 NFSUNLOCKNAMEID();
2564 if (len > NFSV4_SMALLSTR)
2565 free(cp, M_NFSSTRING);
2566 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2567 *cpp = cp;
2568 len = i;
2569 goto tryagain;
2570 }
2571 *retlenp = i;
2572 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2573 if (!hasampersand) {
2574 cp += usrp->lug_namelen;
2575 *cp++ = '@';
2576 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2577 }
2578 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2579 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2580 NFSUNLOCKNAMEID();
2581 return;
2582 }
2583 }
2584 NFSUNLOCKNAMEID();
2585 cnt++;
2586 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0,
2587 NULL, p);
2588 if (ret == 0 && cnt < 2)
2589 goto tryagain;
2590 } else {
2591 NFSUNLOCKNAMEID();
2592 }
2593
2594 /*
2595 * No match, just return a string of digits.
2596 */
2597 tmp = uid;
2598 i = 0;
2599 while (tmp || i == 0) {
2600 tmp /= 10;
2601 i++;
2602 }
2603 len = (i > len) ? len : i;
2604 *retlenp = len;
2605 cp += (len - 1);
2606 tmp = uid;
2607 for (i = 0; i < len; i++) {
2608 *cp-- = '0' + (tmp % 10);
2609 tmp /= 10;
2610 }
2611 return;
2612 }
2613
2614 /*
2615 * Convert a string to a uid.
2616 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2617 * return 0.
2618 * If this is called from a client side mount using AUTH_SYS and the
2619 * string is made up entirely of digits, just convert the string to
2620 * a number.
2621 */
2622 APPLESTATIC int
nfsv4_strtouid(struct nfsrv_descript * nd,u_char * str,int len,uid_t * uidp,NFSPROC_T * p)2623 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp,
2624 NFSPROC_T *p)
2625 {
2626 int i;
2627 char *cp, *endstr, *str0;
2628 struct nfsusrgrp *usrp;
2629 int cnt, ret;
2630 int error = 0;
2631 uid_t tuid;
2632
2633 if (len == 0) {
2634 error = NFSERR_BADOWNER;
2635 goto out;
2636 }
2637 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2638 str0 = str;
2639 tuid = (uid_t)strtoul(str0, &endstr, 10);
2640 if ((endstr - str0) == len &&
2641 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2642 *uidp = tuid;
2643 goto out;
2644 }
2645 /*
2646 * Look for an '@'.
2647 */
2648 cp = strchr(str0, '@');
2649 if (cp != NULL)
2650 i = (int)(cp++ - str0);
2651 else
2652 i = len;
2653
2654 cnt = 0;
2655 tryagain:
2656 NFSLOCKNAMEID();
2657 /*
2658 * If an '@' is found and the domain name matches, search for the name
2659 * with dns stripped off.
2660 * Mixed case alpahbetics will match for the domain name, but all
2661 * upper case will not.
2662 */
2663 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2664 (len - 1 - i) == nfsrv_dnsnamelen &&
2665 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2666 len -= (nfsrv_dnsnamelen + 1);
2667 *(cp - 1) = '\0';
2668 }
2669
2670 /*
2671 * Check for the special case of "nobody".
2672 */
2673 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
2674 *uidp = nfsrv_defaultuid;
2675 NFSUNLOCKNAMEID();
2676 error = 0;
2677 goto out;
2678 }
2679
2680 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) {
2681 if (usrp->lug_namelen == len &&
2682 !NFSBCMP(usrp->lug_name, str, len)) {
2683 if (usrp->lug_expiry < NFSD_MONOSEC)
2684 break;
2685 *uidp = usrp->lug_uid;
2686 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2687 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2688 NFSUNLOCKNAMEID();
2689 error = 0;
2690 goto out;
2691 }
2692 }
2693 NFSUNLOCKNAMEID();
2694 cnt++;
2695 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
2696 str, p);
2697 if (ret == 0 && cnt < 2)
2698 goto tryagain;
2699 error = NFSERR_BADOWNER;
2700
2701 out:
2702 NFSEXITCODE(error);
2703 return (error);
2704 }
2705
2706 /*
2707 * Convert a gid to a string.
2708 * gid - the group id
2709 * cpp - points to a buffer of size NFSV4_SMALLSTR
2710 * (malloc a larger one, as required)
2711 * retlenp - pointer to length to be returned
2712 */
2713 APPLESTATIC void
nfsv4_gidtostr(gid_t gid,u_char ** cpp,int * retlenp,NFSPROC_T * p)2714 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p)
2715 {
2716 int i;
2717 struct nfsusrgrp *usrp;
2718 u_char *cp = *cpp;
2719 gid_t tmp;
2720 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
2721
2722 cnt = 0;
2723 tryagain:
2724 NFSLOCKNAMEID();
2725 if (nfsrv_dnsname) {
2726 /*
2727 * Always map nfsrv_defaultgid to "nogroup".
2728 */
2729 if (gid == nfsrv_defaultgid) {
2730 i = nfsrv_dnsnamelen + 8;
2731 if (i > len) {
2732 NFSUNLOCKNAMEID();
2733 if (len > NFSV4_SMALLSTR)
2734 free(cp, M_NFSSTRING);
2735 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2736 *cpp = cp;
2737 len = i;
2738 goto tryagain;
2739 }
2740 *retlenp = i;
2741 NFSBCOPY("nogroup@", cp, 8);
2742 cp += 8;
2743 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2744 NFSUNLOCKNAMEID();
2745 return;
2746 }
2747 hasampersand = 0;
2748 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) {
2749 if (usrp->lug_gid == gid) {
2750 if (usrp->lug_expiry < NFSD_MONOSEC)
2751 break;
2752 /*
2753 * If the name doesn't already have an '@'
2754 * in it, append @domainname to it.
2755 */
2756 for (i = 0; i < usrp->lug_namelen; i++) {
2757 if (usrp->lug_name[i] == '@') {
2758 hasampersand = 1;
2759 break;
2760 }
2761 }
2762 if (hasampersand)
2763 i = usrp->lug_namelen;
2764 else
2765 i = usrp->lug_namelen +
2766 nfsrv_dnsnamelen + 1;
2767 if (i > len) {
2768 NFSUNLOCKNAMEID();
2769 if (len > NFSV4_SMALLSTR)
2770 free(cp, M_NFSSTRING);
2771 cp = malloc(i, M_NFSSTRING, M_WAITOK);
2772 *cpp = cp;
2773 len = i;
2774 goto tryagain;
2775 }
2776 *retlenp = i;
2777 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
2778 if (!hasampersand) {
2779 cp += usrp->lug_namelen;
2780 *cp++ = '@';
2781 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
2782 }
2783 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2784 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2785 NFSUNLOCKNAMEID();
2786 return;
2787 }
2788 }
2789 NFSUNLOCKNAMEID();
2790 cnt++;
2791 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid,
2792 NULL, p);
2793 if (ret == 0 && cnt < 2)
2794 goto tryagain;
2795 } else {
2796 NFSUNLOCKNAMEID();
2797 }
2798
2799 /*
2800 * No match, just return a string of digits.
2801 */
2802 tmp = gid;
2803 i = 0;
2804 while (tmp || i == 0) {
2805 tmp /= 10;
2806 i++;
2807 }
2808 len = (i > len) ? len : i;
2809 *retlenp = len;
2810 cp += (len - 1);
2811 tmp = gid;
2812 for (i = 0; i < len; i++) {
2813 *cp-- = '0' + (tmp % 10);
2814 tmp /= 10;
2815 }
2816 return;
2817 }
2818
2819 /*
2820 * Convert a string to a gid.
2821 * If no conversion is possible return NFSERR_BADOWNER, otherwise
2822 * return 0.
2823 * If this is called from a client side mount using AUTH_SYS and the
2824 * string is made up entirely of digits, just convert the string to
2825 * a number.
2826 */
2827 APPLESTATIC int
nfsv4_strtogid(struct nfsrv_descript * nd,u_char * str,int len,gid_t * gidp,NFSPROC_T * p)2828 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp,
2829 NFSPROC_T *p)
2830 {
2831 int i;
2832 char *cp, *endstr, *str0;
2833 struct nfsusrgrp *usrp;
2834 int cnt, ret;
2835 int error = 0;
2836 gid_t tgid;
2837
2838 if (len == 0) {
2839 error = NFSERR_BADOWNER;
2840 goto out;
2841 }
2842 /* If a string of digits and an AUTH_SYS mount, just convert it. */
2843 str0 = str;
2844 tgid = (gid_t)strtoul(str0, &endstr, 10);
2845 if ((endstr - str0) == len &&
2846 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) {
2847 *gidp = tgid;
2848 goto out;
2849 }
2850 /*
2851 * Look for an '@'.
2852 */
2853 cp = strchr(str0, '@');
2854 if (cp != NULL)
2855 i = (int)(cp++ - str0);
2856 else
2857 i = len;
2858
2859 cnt = 0;
2860 tryagain:
2861 NFSLOCKNAMEID();
2862 /*
2863 * If an '@' is found and the dns name matches, search for the name
2864 * with the dns stripped off.
2865 */
2866 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname &&
2867 (len - 1 - i) == nfsrv_dnsnamelen &&
2868 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
2869 len -= (nfsrv_dnsnamelen + 1);
2870 *(cp - 1) = '\0';
2871 }
2872
2873 /*
2874 * Check for the special case of "nogroup".
2875 */
2876 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
2877 *gidp = nfsrv_defaultgid;
2878 NFSUNLOCKNAMEID();
2879 error = 0;
2880 goto out;
2881 }
2882
2883 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) {
2884 if (usrp->lug_namelen == len &&
2885 !NFSBCMP(usrp->lug_name, str, len)) {
2886 if (usrp->lug_expiry < NFSD_MONOSEC)
2887 break;
2888 *gidp = usrp->lug_gid;
2889 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
2890 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru);
2891 NFSUNLOCKNAMEID();
2892 error = 0;
2893 goto out;
2894 }
2895 }
2896 NFSUNLOCKNAMEID();
2897 cnt++;
2898 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
2899 str, p);
2900 if (ret == 0 && cnt < 2)
2901 goto tryagain;
2902 error = NFSERR_BADOWNER;
2903
2904 out:
2905 NFSEXITCODE(error);
2906 return (error);
2907 }
2908
2909 /*
2910 * Cmp len chars, allowing mixed case in the first argument to match lower
2911 * case in the second, but not if the first argument is all upper case.
2912 * Return 0 for a match, 1 otherwise.
2913 */
2914 static int
nfsrv_cmpmixedcase(u_char * cp,u_char * cp2,int len)2915 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
2916 {
2917 int i;
2918 u_char tmp;
2919 int fndlower = 0;
2920
2921 for (i = 0; i < len; i++) {
2922 if (*cp >= 'A' && *cp <= 'Z') {
2923 tmp = *cp++ + ('a' - 'A');
2924 } else {
2925 tmp = *cp++;
2926 if (tmp >= 'a' && tmp <= 'z')
2927 fndlower = 1;
2928 }
2929 if (tmp != *cp2++)
2930 return (1);
2931 }
2932 if (fndlower)
2933 return (0);
2934 else
2935 return (1);
2936 }
2937
2938 /*
2939 * Set the port for the nfsuserd.
2940 */
2941 APPLESTATIC int
nfsrv_nfsuserdport(u_short port,NFSPROC_T * p)2942 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p)
2943 {
2944 struct nfssockreq *rp;
2945 struct sockaddr_in *ad;
2946 int error;
2947
2948 NFSLOCKNAMEID();
2949 if (nfsrv_nfsuserd) {
2950 NFSUNLOCKNAMEID();
2951 error = EPERM;
2952 goto out;
2953 }
2954 nfsrv_nfsuserd = 1;
2955 NFSUNLOCKNAMEID();
2956 /*
2957 * Set up the socket record and connect.
2958 */
2959 rp = &nfsrv_nfsuserdsock;
2960 rp->nr_client = NULL;
2961 rp->nr_sotype = SOCK_DGRAM;
2962 rp->nr_soproto = IPPROTO_UDP;
2963 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
2964 rp->nr_cred = NULL;
2965 NFSSOCKADDRALLOC(rp->nr_nam);
2966 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in));
2967 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *);
2968 ad->sin_family = AF_INET;
2969 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */
2970 ad->sin_port = port;
2971 rp->nr_prog = RPCPROG_NFSUSERD;
2972 rp->nr_vers = RPCNFSUSERD_VERS;
2973 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0);
2974 if (error) {
2975 NFSSOCKADDRFREE(rp->nr_nam);
2976 nfsrv_nfsuserd = 0;
2977 }
2978 out:
2979 NFSEXITCODE(error);
2980 return (error);
2981 }
2982
2983 /*
2984 * Delete the nfsuserd port.
2985 */
2986 APPLESTATIC void
nfsrv_nfsuserddelport(void)2987 nfsrv_nfsuserddelport(void)
2988 {
2989
2990 NFSLOCKNAMEID();
2991 if (nfsrv_nfsuserd == 0) {
2992 NFSUNLOCKNAMEID();
2993 return;
2994 }
2995 nfsrv_nfsuserd = 0;
2996 NFSUNLOCKNAMEID();
2997 newnfs_disconnect(&nfsrv_nfsuserdsock);
2998 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam);
2999 }
3000
3001 /*
3002 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
3003 * name<-->id cache.
3004 * Returns 0 upon success, non-zero otherwise.
3005 */
3006 static int
nfsrv_getuser(int procnum,uid_t uid,gid_t gid,char * name,NFSPROC_T * p)3007 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p)
3008 {
3009 u_int32_t *tl;
3010 struct nfsrv_descript *nd;
3011 int len;
3012 struct nfsrv_descript nfsd;
3013 struct ucred *cred;
3014 int error;
3015
3016 NFSLOCKNAMEID();
3017 if (nfsrv_nfsuserd == 0) {
3018 NFSUNLOCKNAMEID();
3019 error = EPERM;
3020 goto out;
3021 }
3022 NFSUNLOCKNAMEID();
3023 nd = &nfsd;
3024 cred = newnfs_getcred();
3025 nd->nd_flag = ND_GSSINITREPLY;
3026 nfsrvd_rephead(nd);
3027
3028 nd->nd_procnum = procnum;
3029 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
3030 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
3031 if (procnum == RPCNFSUSERD_GETUID)
3032 *tl = txdr_unsigned(uid);
3033 else
3034 *tl = txdr_unsigned(gid);
3035 } else {
3036 len = strlen(name);
3037 (void) nfsm_strtom(nd, name, len);
3038 }
3039 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
3040 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
3041 NFSFREECRED(cred);
3042 if (!error) {
3043 mbuf_freem(nd->nd_mrep);
3044 error = nd->nd_repstat;
3045 }
3046 out:
3047 NFSEXITCODE(error);
3048 return (error);
3049 }
3050
3051 /*
3052 * This function is called from the nfssvc(2) system call, to update the
3053 * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
3054 */
3055 APPLESTATIC int
nfssvc_idname(struct nfsd_idargs * nidp)3056 nfssvc_idname(struct nfsd_idargs *nidp)
3057 {
3058 struct nfsusrgrp *nusrp, *usrp, *newusrp;
3059 struct nfsuserhashhead *hp;
3060 int i;
3061 int error = 0;
3062 u_char *cp;
3063
3064 if (nidp->nid_flag & NFSID_INITIALIZE) {
3065 cp = (u_char *)malloc(nidp->nid_namelen + 1,
3066 M_NFSSTRING, M_WAITOK);
3067 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp,
3068 nidp->nid_namelen);
3069 NFSLOCKNAMEID();
3070 if (nfsrv_dnsname) {
3071 /*
3072 * Free up all the old stuff and reinitialize hash lists.
3073 */
3074 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3075 nfsrv_removeuser(usrp);
3076 }
3077 free(nfsrv_dnsname, M_NFSSTRING);
3078 nfsrv_dnsname = NULL;
3079 }
3080 TAILQ_INIT(&nfsuserlruhead);
3081 for (i = 0; i < NFSUSERHASHSIZE; i++)
3082 LIST_INIT(&nfsuserhash[i]);
3083 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3084 LIST_INIT(&nfsgrouphash[i]);
3085 for (i = 0; i < NFSUSERHASHSIZE; i++)
3086 LIST_INIT(&nfsusernamehash[i]);
3087 for (i = 0; i < NFSGROUPHASHSIZE; i++)
3088 LIST_INIT(&nfsgroupnamehash[i]);
3089
3090 /*
3091 * Put name in "DNS" string.
3092 */
3093 if (!error) {
3094 nfsrv_dnsname = cp;
3095 nfsrv_dnsnamelen = nidp->nid_namelen;
3096 nfsrv_defaultuid = nidp->nid_uid;
3097 nfsrv_defaultgid = nidp->nid_gid;
3098 nfsrv_usercnt = 0;
3099 nfsrv_usermax = nidp->nid_usermax;
3100 }
3101 NFSUNLOCKNAMEID();
3102 if (error)
3103 free(cp, M_NFSSTRING);
3104 goto out;
3105 }
3106
3107 /*
3108 * malloc the new one now, so any potential sleep occurs before
3109 * manipulation of the lists.
3110 */
3111 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) +
3112 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK);
3113 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name,
3114 nidp->nid_namelen);
3115 if (error) {
3116 free((caddr_t)newusrp, M_NFSUSERGROUP);
3117 goto out;
3118 }
3119 newusrp->lug_namelen = nidp->nid_namelen;
3120
3121 NFSLOCKNAMEID();
3122 /*
3123 * Delete old entries, as required.
3124 */
3125 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
3126 hp = NFSUSERHASH(nidp->nid_uid);
3127 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3128 if (usrp->lug_uid == nidp->nid_uid)
3129 nfsrv_removeuser(usrp);
3130 }
3131 }
3132 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
3133 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3134 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3135 if (usrp->lug_namelen == newusrp->lug_namelen &&
3136 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3137 usrp->lug_namelen))
3138 nfsrv_removeuser(usrp);
3139 }
3140 }
3141 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
3142 hp = NFSGROUPHASH(nidp->nid_gid);
3143 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) {
3144 if (usrp->lug_gid == nidp->nid_gid)
3145 nfsrv_removeuser(usrp);
3146 }
3147 }
3148 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
3149 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
3150 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) {
3151 if (usrp->lug_namelen == newusrp->lug_namelen &&
3152 !NFSBCMP(usrp->lug_name, newusrp->lug_name,
3153 usrp->lug_namelen))
3154 nfsrv_removeuser(usrp);
3155 }
3156 }
3157 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) {
3158 if (usrp->lug_expiry < NFSD_MONOSEC)
3159 nfsrv_removeuser(usrp);
3160 }
3161 while (nfsrv_usercnt >= nfsrv_usermax) {
3162 usrp = TAILQ_FIRST(&nfsuserlruhead);
3163 nfsrv_removeuser(usrp);
3164 }
3165
3166 /*
3167 * Now, we can add the new one.
3168 */
3169 if (nidp->nid_usertimeout)
3170 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
3171 else
3172 newusrp->lug_expiry = NFSD_MONOSEC + 5;
3173 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
3174 newusrp->lug_uid = nidp->nid_uid;
3175 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp,
3176 lug_numhash);
3177 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name,
3178 newusrp->lug_namelen), newusrp, lug_namehash);
3179 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3180 nfsrv_usercnt++;
3181 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
3182 newusrp->lug_gid = nidp->nid_gid;
3183 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp,
3184 lug_numhash);
3185 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name,
3186 newusrp->lug_namelen), newusrp, lug_namehash);
3187 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru);
3188 nfsrv_usercnt++;
3189 } else
3190 FREE((caddr_t)newusrp, M_NFSUSERGROUP);
3191 NFSUNLOCKNAMEID();
3192 out:
3193 NFSEXITCODE(error);
3194 return (error);
3195 }
3196
3197 /*
3198 * Remove a user/group name element.
3199 */
3200 static void
nfsrv_removeuser(struct nfsusrgrp * usrp)3201 nfsrv_removeuser(struct nfsusrgrp *usrp)
3202 {
3203
3204 NFSNAMEIDREQUIRED();
3205 LIST_REMOVE(usrp, lug_numhash);
3206 LIST_REMOVE(usrp, lug_namehash);
3207 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru);
3208 nfsrv_usercnt--;
3209 FREE((caddr_t)usrp, M_NFSUSERGROUP);
3210 }
3211
3212 /*
3213 * This function scans a byte string and checks for UTF-8 compliance.
3214 * It returns 0 if it conforms and NFSERR_INVAL if not.
3215 */
3216 APPLESTATIC int
nfsrv_checkutf8(u_int8_t * cp,int len)3217 nfsrv_checkutf8(u_int8_t *cp, int len)
3218 {
3219 u_int32_t val = 0x0;
3220 int cnt = 0, gotd = 0, shift = 0;
3221 u_int8_t byte;
3222 static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
3223 int error = 0;
3224
3225 /*
3226 * Here are what the variables are used for:
3227 * val - the calculated value of a multibyte char, used to check
3228 * that it was coded with the correct range
3229 * cnt - the number of 10xxxxxx bytes to follow
3230 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
3231 * shift - lower order bits of range (ie. "val >> shift" should
3232 * not be 0, in other words, dividing by the lower bound
3233 * of the range should get a non-zero value)
3234 * byte - used to calculate cnt
3235 */
3236 while (len > 0) {
3237 if (cnt > 0) {
3238 /* This handles the 10xxxxxx bytes */
3239 if ((*cp & 0xc0) != 0x80 ||
3240 (gotd && (*cp & 0x20))) {
3241 error = NFSERR_INVAL;
3242 goto out;
3243 }
3244 gotd = 0;
3245 val <<= 6;
3246 val |= (*cp & 0x3f);
3247 cnt--;
3248 if (cnt == 0 && (val >> shift) == 0x0) {
3249 error = NFSERR_INVAL;
3250 goto out;
3251 }
3252 } else if (*cp & 0x80) {
3253 /* first byte of multi byte char */
3254 byte = *cp;
3255 while ((byte & 0x40) && cnt < 6) {
3256 cnt++;
3257 byte <<= 1;
3258 }
3259 if (cnt == 0 || cnt == 6) {
3260 error = NFSERR_INVAL;
3261 goto out;
3262 }
3263 val = (*cp & (0x3f >> cnt));
3264 shift = utf8_shift[cnt - 1];
3265 if (cnt == 2 && val == 0xd)
3266 /* Check for the 0xd800-0xdfff case */
3267 gotd = 1;
3268 }
3269 cp++;
3270 len--;
3271 }
3272 if (cnt > 0)
3273 error = NFSERR_INVAL;
3274
3275 out:
3276 NFSEXITCODE(error);
3277 return (error);
3278 }
3279
3280 /*
3281 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
3282 * strings, one with the root path in it and the other with the list of
3283 * locations. The list is in the same format as is found in nfr_refs.
3284 * It is a "," separated list of entries, where each of them is of the
3285 * form <server>:<rootpath>. For example
3286 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
3287 * The nilp argument is set to 1 for the special case of a null fs_root
3288 * and an empty server list.
3289 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
3290 * number of xdr bytes parsed in sump.
3291 */
3292 static int
nfsrv_getrefstr(struct nfsrv_descript * nd,u_char ** fsrootp,u_char ** srvp,int * sump,int * nilp)3293 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
3294 int *sump, int *nilp)
3295 {
3296 u_int32_t *tl;
3297 u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
3298 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
3299 struct list {
3300 SLIST_ENTRY(list) next;
3301 int len;
3302 u_char host[1];
3303 } *lsp, *nlsp;
3304 SLIST_HEAD(, list) head;
3305
3306 *fsrootp = NULL;
3307 *srvp = NULL;
3308 *nilp = 0;
3309
3310 /*
3311 * Get the fs_root path and check for the special case of null path
3312 * and 0 length server list.
3313 */
3314 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3315 len = fxdr_unsigned(int, *tl);
3316 if (len < 0 || len > 10240) {
3317 error = NFSERR_BADXDR;
3318 goto nfsmout;
3319 }
3320 if (len == 0) {
3321 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3322 if (*tl != 0) {
3323 error = NFSERR_BADXDR;
3324 goto nfsmout;
3325 }
3326 *nilp = 1;
3327 *sump = 2 * NFSX_UNSIGNED;
3328 error = 0;
3329 goto nfsmout;
3330 }
3331 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
3332 error = nfsrv_mtostr(nd, cp, len);
3333 if (!error) {
3334 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3335 cnt = fxdr_unsigned(int, *tl);
3336 if (cnt <= 0)
3337 error = NFSERR_BADXDR;
3338 }
3339 if (error)
3340 goto nfsmout;
3341
3342 /*
3343 * Now, loop through the location list and make up the srvlist.
3344 */
3345 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3346 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
3347 slen = 1024;
3348 siz = 0;
3349 for (i = 0; i < cnt; i++) {
3350 SLIST_INIT(&head);
3351 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3352 nsrv = fxdr_unsigned(int, *tl);
3353 if (nsrv <= 0) {
3354 error = NFSERR_BADXDR;
3355 goto nfsmout;
3356 }
3357
3358 /*
3359 * Handle the first server by putting it in the srvstr.
3360 */
3361 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3362 len = fxdr_unsigned(int, *tl);
3363 if (len <= 0 || len > 1024) {
3364 error = NFSERR_BADXDR;
3365 goto nfsmout;
3366 }
3367 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
3368 if (cp3 != cp2) {
3369 *cp3++ = ',';
3370 siz++;
3371 }
3372 error = nfsrv_mtostr(nd, cp3, len);
3373 if (error)
3374 goto nfsmout;
3375 cp3 += len;
3376 *cp3++ = ':';
3377 siz += (len + 1);
3378 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
3379 for (j = 1; j < nsrv; j++) {
3380 /*
3381 * Yuck, put them in an slist and process them later.
3382 */
3383 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3384 len = fxdr_unsigned(int, *tl);
3385 if (len <= 0 || len > 1024) {
3386 error = NFSERR_BADXDR;
3387 goto nfsmout;
3388 }
3389 lsp = (struct list *)malloc(sizeof (struct list)
3390 + len, M_TEMP, M_WAITOK);
3391 error = nfsrv_mtostr(nd, lsp->host, len);
3392 if (error)
3393 goto nfsmout;
3394 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3395 lsp->len = len;
3396 SLIST_INSERT_HEAD(&head, lsp, next);
3397 }
3398
3399 /*
3400 * Finally, we can get the path.
3401 */
3402 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3403 len = fxdr_unsigned(int, *tl);
3404 if (len <= 0 || len > 1024) {
3405 error = NFSERR_BADXDR;
3406 goto nfsmout;
3407 }
3408 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
3409 error = nfsrv_mtostr(nd, cp3, len);
3410 if (error)
3411 goto nfsmout;
3412 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
3413 str = cp3;
3414 stringlen = len;
3415 cp3 += len;
3416 siz += len;
3417 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
3418 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
3419 &cp2, &cp3, &slen);
3420 *cp3++ = ',';
3421 NFSBCOPY(lsp->host, cp3, lsp->len);
3422 cp3 += lsp->len;
3423 *cp3++ = ':';
3424 NFSBCOPY(str, cp3, stringlen);
3425 cp3 += stringlen;
3426 *cp3 = '\0';
3427 siz += (lsp->len + stringlen + 2);
3428 free((caddr_t)lsp, M_TEMP);
3429 }
3430 }
3431 *fsrootp = cp;
3432 *srvp = cp2;
3433 *sump = xdrsum;
3434 NFSEXITCODE2(0, nd);
3435 return (0);
3436 nfsmout:
3437 if (cp != NULL)
3438 free(cp, M_NFSSTRING);
3439 if (cp2 != NULL)
3440 free(cp2, M_NFSSTRING);
3441 NFSEXITCODE2(error, nd);
3442 return (error);
3443 }
3444
3445 /*
3446 * Make the malloc'd space large enough. This is a pain, but the xdr
3447 * doesn't set an upper bound on the side, so...
3448 */
3449 static void
nfsrv_refstrbigenough(int siz,u_char ** cpp,u_char ** cpp2,int * slenp)3450 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
3451 {
3452 u_char *cp;
3453 int i;
3454
3455 if (siz <= *slenp)
3456 return;
3457 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
3458 NFSBCOPY(*cpp, cp, *slenp);
3459 free(*cpp, M_NFSSTRING);
3460 i = *cpp2 - *cpp;
3461 *cpp = cp;
3462 *cpp2 = cp + i;
3463 *slenp = siz + 1024;
3464 }
3465
3466 /*
3467 * Initialize the reply header data structures.
3468 */
3469 APPLESTATIC void
nfsrvd_rephead(struct nfsrv_descript * nd)3470 nfsrvd_rephead(struct nfsrv_descript *nd)
3471 {
3472 mbuf_t mreq;
3473
3474 /*
3475 * If this is a big reply, use a cluster.
3476 */
3477 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
3478 nfs_bigreply[nd->nd_procnum]) {
3479 NFSMCLGET(mreq, M_WAITOK);
3480 nd->nd_mreq = mreq;
3481 nd->nd_mb = mreq;
3482 } else {
3483 NFSMGET(mreq);
3484 nd->nd_mreq = mreq;
3485 nd->nd_mb = mreq;
3486 }
3487 nd->nd_bpos = NFSMTOD(mreq, caddr_t);
3488 mbuf_setlen(mreq, 0);
3489
3490 if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
3491 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
3492 }
3493
3494 /*
3495 * Lock a socket against others.
3496 * Currently used to serialize connect/disconnect attempts.
3497 */
3498 int
newnfs_sndlock(int * flagp)3499 newnfs_sndlock(int *flagp)
3500 {
3501 struct timespec ts;
3502
3503 NFSLOCKSOCK();
3504 while (*flagp & NFSR_SNDLOCK) {
3505 *flagp |= NFSR_WANTSND;
3506 ts.tv_sec = 0;
3507 ts.tv_nsec = 0;
3508 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
3509 PZERO - 1, "nfsndlck", &ts);
3510 }
3511 *flagp |= NFSR_SNDLOCK;
3512 NFSUNLOCKSOCK();
3513 return (0);
3514 }
3515
3516 /*
3517 * Unlock the stream socket for others.
3518 */
3519 void
newnfs_sndunlock(int * flagp)3520 newnfs_sndunlock(int *flagp)
3521 {
3522
3523 NFSLOCKSOCK();
3524 if ((*flagp & NFSR_SNDLOCK) == 0)
3525 panic("nfs sndunlock");
3526 *flagp &= ~NFSR_SNDLOCK;
3527 if (*flagp & NFSR_WANTSND) {
3528 *flagp &= ~NFSR_WANTSND;
3529 wakeup((caddr_t)flagp);
3530 }
3531 NFSUNLOCKSOCK();
3532 }
3533
3534 APPLESTATIC int
nfsv4_getipaddr(struct nfsrv_descript * nd,struct sockaddr_storage * sa,int * isudp)3535 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa,
3536 int *isudp)
3537 {
3538 struct sockaddr_in *sad;
3539 struct sockaddr_in6 *sad6;
3540 struct in_addr saddr;
3541 uint32_t portnum, *tl;
3542 int af = 0, i, j, k;
3543 char addr[64], protocol[5], *cp;
3544 int cantparse = 0, error = 0;
3545 uint16_t portv;
3546
3547 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3548 i = fxdr_unsigned(int, *tl);
3549 if (i >= 3 && i <= 4) {
3550 error = nfsrv_mtostr(nd, protocol, i);
3551 if (error)
3552 goto nfsmout;
3553 if (strcmp(protocol, "tcp") == 0) {
3554 af = AF_INET;
3555 *isudp = 0;
3556 } else if (strcmp(protocol, "udp") == 0) {
3557 af = AF_INET;
3558 *isudp = 1;
3559 } else if (strcmp(protocol, "tcp6") == 0) {
3560 af = AF_INET6;
3561 *isudp = 0;
3562 } else if (strcmp(protocol, "udp6") == 0) {
3563 af = AF_INET6;
3564 *isudp = 1;
3565 } else
3566 cantparse = 1;
3567 } else {
3568 cantparse = 1;
3569 if (i > 0) {
3570 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3571 if (error)
3572 goto nfsmout;
3573 }
3574 }
3575 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3576 i = fxdr_unsigned(int, *tl);
3577 if (i < 0) {
3578 error = NFSERR_BADXDR;
3579 goto nfsmout;
3580 } else if (cantparse == 0 && i >= 11 && i < 64) {
3581 /*
3582 * The shortest address is 11chars and the longest is < 64.
3583 */
3584 error = nfsrv_mtostr(nd, addr, i);
3585 if (error)
3586 goto nfsmout;
3587
3588 /* Find the port# at the end and extract that. */
3589 i = strlen(addr);
3590 k = 0;
3591 cp = &addr[i - 1];
3592 /* Count back two '.'s from end to get port# field. */
3593 for (j = 0; j < i; j++) {
3594 if (*cp == '.') {
3595 k++;
3596 if (k == 2)
3597 break;
3598 }
3599 cp--;
3600 }
3601 if (k == 2) {
3602 /*
3603 * The NFSv4 port# is appended as .N.N, where N is
3604 * a decimal # in the range 0-255, just like an inet4
3605 * address. Cheat and use inet_aton(), which will
3606 * return a Class A address and then shift the high
3607 * order 8bits over to convert it to the port#.
3608 */
3609 *cp++ = '\0';
3610 if (inet_aton(cp, &saddr) == 1) {
3611 portnum = ntohl(saddr.s_addr);
3612 portv = (uint16_t)((portnum >> 16) |
3613 (portnum & 0xff));
3614 } else
3615 cantparse = 1;
3616 } else
3617 cantparse = 1;
3618 if (cantparse == 0) {
3619 if (af == AF_INET) {
3620 sad = (struct sockaddr_in *)sa;
3621 if (inet_pton(af, addr, &sad->sin_addr) == 1) {
3622 sad->sin_len = sizeof(*sad);
3623 sad->sin_family = AF_INET;
3624 sad->sin_port = htons(portv);
3625 return (0);
3626 }
3627 } else {
3628 sad6 = (struct sockaddr_in6 *)sa;
3629 if (inet_pton(af, addr, &sad6->sin6_addr)
3630 == 1) {
3631 sad6->sin6_len = sizeof(*sad6);
3632 sad6->sin6_family = AF_INET6;
3633 sad6->sin6_port = htons(portv);
3634 return (0);
3635 }
3636 }
3637 }
3638 } else {
3639 if (i > 0) {
3640 error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3641 if (error)
3642 goto nfsmout;
3643 }
3644 }
3645 error = EPERM;
3646 nfsmout:
3647 return (error);
3648 }
3649
3650 /*
3651 * Handle an NFSv4.1 Sequence request for the session.
3652 */
3653 int
nfsv4_seqsession(uint32_t seqid,uint32_t slotid,uint32_t highslot,struct nfsslot * slots,struct mbuf ** reply,uint16_t maxslot)3654 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
3655 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
3656 {
3657 int error;
3658
3659 error = 0;
3660 *reply = NULL;
3661 if (slotid > maxslot)
3662 return (NFSERR_BADSLOT);
3663 if (seqid == slots[slotid].nfssl_seq) {
3664 /* A retry. */
3665 if (slots[slotid].nfssl_inprog != 0)
3666 error = NFSERR_DELAY;
3667 else if (slots[slotid].nfssl_reply != NULL) {
3668 *reply = slots[slotid].nfssl_reply;
3669 slots[slotid].nfssl_reply = NULL;
3670 slots[slotid].nfssl_inprog = 1;
3671 } else
3672 error = NFSERR_SEQMISORDERED;
3673 } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
3674 m_freem(slots[slotid].nfssl_reply);
3675 slots[slotid].nfssl_reply = NULL;
3676 slots[slotid].nfssl_inprog = 1;
3677 slots[slotid].nfssl_seq++;
3678 } else
3679 error = NFSERR_SEQMISORDERED;
3680 return (error);
3681 }
3682
3683 /*
3684 * Cache this reply for the slot.
3685 */
3686 void
nfsv4_seqsess_cacherep(uint32_t slotid,struct nfsslot * slots,struct mbuf * rep)3687 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep)
3688 {
3689
3690 slots[slotid].nfssl_reply = rep;
3691 slots[slotid].nfssl_inprog = 0;
3692 }
3693
3694 /*
3695 * Generate the xdr for an NFSv4.1 Sequence Operation.
3696 */
3697 APPLESTATIC void
nfsv4_setsequence(struct nfsrv_descript * nd,struct nfsclsession * sep,int dont_replycache)3698 nfsv4_setsequence(struct nfsrv_descript *nd, struct nfsclsession *sep,
3699 int dont_replycache)
3700 {
3701 uint32_t *tl, slotseq = 0;
3702 int i, maxslot, slotpos;
3703 uint64_t bitval;
3704 uint8_t sessionid[NFSX_V4SESSIONID];
3705
3706 /* Find an unused slot. */
3707 slotpos = -1;
3708 maxslot = -1;
3709 mtx_lock(&sep->nfsess_mtx);
3710 do {
3711 bitval = 1;
3712 for (i = 0; i < sep->nfsess_foreslots; i++) {
3713 if ((bitval & sep->nfsess_slots) == 0) {
3714 slotpos = i;
3715 sep->nfsess_slots |= bitval;
3716 sep->nfsess_slotseq[i]++;
3717 slotseq = sep->nfsess_slotseq[i];
3718 break;
3719 }
3720 bitval <<= 1;
3721 }
3722 if (slotpos == -1)
3723 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
3724 PZERO, "nfsclseq", 0);
3725 } while (slotpos == -1);
3726 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
3727 bitval = 1;
3728 for (i = 0; i < 64; i++) {
3729 if ((bitval & sep->nfsess_slots) != 0)
3730 maxslot = i;
3731 bitval <<= 1;
3732 }
3733 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
3734 mtx_unlock(&sep->nfsess_mtx);
3735 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot"));
3736
3737 /* Build the Sequence arguments. */
3738 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
3739 bcopy(sessionid, tl, NFSX_V4SESSIONID);
3740 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
3741 nd->nd_slotseq = tl;
3742 *tl++ = txdr_unsigned(slotseq);
3743 *tl++ = txdr_unsigned(slotpos);
3744 *tl++ = txdr_unsigned(maxslot);
3745 if (dont_replycache == 0)
3746 *tl = newnfs_true;
3747 else
3748 *tl = newnfs_false;
3749 nd->nd_flag |= ND_HASSEQUENCE;
3750 }
3751
3752 /*
3753 * Free a session slot.
3754 */
3755 APPLESTATIC void
nfsv4_freeslot(struct nfsclsession * sep,int slot)3756 nfsv4_freeslot(struct nfsclsession *sep, int slot)
3757 {
3758 uint64_t bitval;
3759
3760 bitval = 1;
3761 if (slot > 0)
3762 bitval <<= slot;
3763 mtx_lock(&sep->nfsess_mtx);
3764 if ((bitval & sep->nfsess_slots) == 0)
3765 printf("freeing free slot!!\n");
3766 sep->nfsess_slots &= ~bitval;
3767 wakeup(&sep->nfsess_slots);
3768 mtx_unlock(&sep->nfsess_mtx);
3769 }
3770
3771