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