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