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