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