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