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