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