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