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