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