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